美文网首页
Yii2的Codeception测试-2测试工作

Yii2的Codeception测试-2测试工作

作者: biaoqianwo | 来源:发表于2018-03-01 15:29 被阅读1292次

    这是一个系列文章,分3部分:
    1、准备工作--Yii2高级模板的安装,以及编写一个类(方法)和一个model的RETful
    2、测试工作--单元测试和API(REST规范的)测试
    3、力争上游--覆盖率、基础概念、引用文献等

    本文是第二部分,主要是单元测试和API测试。

    单元测试

    1、执行vendor/bin/codecept generate:cest -c common unit CustomeString
    新建了common\tests\unit\CustomeStringCest.php,开始写测试代码了,增加内容:

        public function tryToTest(UnitTester $I)
        {
            $len = 10;
            $prefix = 'pre';
            
            $string = CustomString::generateCode($len, $prefix);
            expect(strlen($string))->equals($len + 3);
            expect(substr($string, 0, 3))->equals($prefix);
            //等效于 expect($string)->startsWith($prefix);
           //这就是codeception的强大之处,封装了几乎所有测试需要的,官方说90%+,且不希望你重复造轮子
        }
    

    2、执行vendor/bin/codecept run -c common
    我们可以在命令终端看到测试运行的情况。

    至此,恭喜你,已经利用codeception进行了某个类的(方法的)测试。

    我们继续来书写如何测试一个model:
    4、执行vendor/bin/codecept generate:test -c common unit models/News
    新建一个common\test\unit\models\NewsTest.php,我们仿照LoginFormTest.php,编写NewsTest.php:

    <?php
    
    namespace common\tests\models;
    
    use common\fixtures\NewsFixture;
    use common\models\News;
    
    class NewsTest extends \Codeception\Test\Unit
    {
        public function _fixtures()
        {
            return [
                'news' => [
                    'class' => NewsFixture::class,
                    'dataFile' => codecept_data_dir() . 'news.php',
                ],
            ];
        }
        
        public function testValidate()
        {
            $model = new News(['title' => 'one title']);
            expect('model should create successfully', $model->save())->true();
            
            $model = new News(['code' => \Yii::$app->security->generateRandomString(33)]);
            expect('model should create fail', $model->save())->false();
            expect('error message should be set', $model->errors)->hasKey('code');
            
            $model = new News(['title' => null]);
            expect('model should create fail', $model->save())->false();
            expect('error message should be set', $model->errors)->hasKey('title');
            
            $model = new News(['title' => \Yii::$app->security->generateRandomString(256)]);
            expect('model should create fail', $model->save())->false();
            expect('error message should be set', $model->errors)->hasKey('title');
        }
        
        public function testData()
        {
            $data = News::find()->where(['title' => 'This is a title'])->one();
            expect(count($data))->equals(1);
        }
    }
    
    

    5、因为需要用到NewsFixture::classcodecept_data_dir() . 'news.php'
    所以我们需要在common的fixtures下新建NewFixture.php
    (具体位置无所谓,只需要保证命名空间是common\fixtures):

    <?php
    namespace common\fixtures;
    
    use yii\test\ActiveFixture;
    
    class NewsFixture extends ActiveFixture
    {
        public $modelClass = 'common\models\News';
    }
    

    然后在common\tests\_data下新建news.php,自己添加一些数据:

    <?php
    
    return [
        [
            'code' => 'abcdefg',
            'title' => 'This is a title',
            'content' => '<p>some Content</p>',
            'status' => 0,
            'created_at' => 1402312317,
            'updated_at' => 1402312317,
            'created_by' => 1,
            'updated_by' => 1,
        ],
        [
            'code' => '22222',
            'title' => 'This is second title',
            'content' => '<p>some Content</p>',
            'status' => 1,
            'created_at' => 1402312317,
            'updated_at' => 1402312317,
            'created_by' => 1,
            'updated_by' => 1,
        ],
    ];
    

    6、执行vendor/bin/codecept run -c common,查看测试运行情况。
    至此,单元测试算告一段落。

    单元测试,基本上就是对自定义的类的(方法的)测试,还有model的一些测试。
    当有新的自定义类或者model时,类似上述新增测试用例即可。

    7、 补充:
    由于codeception包含3种格式的测试文件:Cept, Cest and Test

    Cept are written as narrative scenarios. To make a PHP file a valid scenario, its name should have a Cept suffix.
    描述行语言,文件后缀是Cept,常用于功能、验收还有API测试。
    Cest combines scenario-driven test approach with OOP design. In case you want to group a few testing scenarios into one, you should consider using Cest format.
    Codeception can also execute PHPUnit test files for unit testing
    注意Test格式时,方法名需要以test开头,另外两种格式不要求。

    上述的例子是Test格式,当然可以写成Cept和Cest,实质上等效。
    我习惯单元测试用Cest,API测试用Cept。
    执行vendor/bin/codecept generate:cest -c common unit models/News
    新建一个common\test\unit\models\NewsCest.php,等效代码如下:

    <?php
    
    namespace common\tests\unit\models;
    
    use common\fixtures\NewsFixture;
    use common\models\News;
    use common\tests\UnitTester;
    
    class NewsCest
    {
        public function _before(UnitTester $I)
        {
            $I->haveFixtures([
                'news' => [
                    'class' => NewsFixture::class,
                    'dataFile' => codecept_data_dir() . 'news.php',
                ],
            ]);
        }
        
        public function _after(UnitTester $I)
        {
        }
        
        // tests
        public function tryToTestValidate(UnitTester $I)
        {
            $model = new News(['title' => 'one title']);
            expect('model should create successfully', $model->save())->true();
            
            $model = new News(['code' => \Yii::$app->security->generateRandomString(33)]);
            expect('model should create fail', $model->save())->false();
            expect('error message should be set', $model->errors)->hasKey('code');
            
            $model = new News(['title' => null]);
            expect('model should create fail', $model->save())->false();
            expect('error message should be set', $model->errors)->hasKey('title');
            
            $model = new News(['title' => \Yii::$app->security->generateRandomString(256)]);
            expect('model should create fail', $model->save())->false();
            expect('error message should be set', $model->errors)->hasKey('title');
        }
        
        public function toTestData()
        {
            $data = News::find()->where(['title' => 'This is a title'])->one();
            expect(count($data))->equals(1);
        }
    }
    
    

    功能和验收测试

    由于前后端分离,这里不再介绍codeception的功能和验收测试。
    你可以查看frontend/tests/下的functional和accptance部分。
    关于前端测试,可以参看CodeceptJS

    API测试

    接口的自动化测试,这里是一个方案,具体参看WebServices
    Postman的自动化接口测试也是一个不错的方案,有时间再整理。

    首先要执行vendor/bin/codecept g:suite api -c blog,输出:

    Helper \blog\tests\Helper\Api was created in /home/lijun/works/yii-application/blog/tests/_support/Helper/Api.php
    Actor ApiTester was created in /home/lijun/works/yii-application/blog/tests/_support/ApiTester.php
    Suite config api.suite.yml was created.
     
    Next steps:
    1. Edit api.suite.yml to enable modules for this suite
    2. Create first test with generate:cest testName ( or test|cept) command
    3. Run tests of this suite with codecept run api command
    Suite api generated
    

    按照提示继续下面的步骤:
    1)、编辑api.suite.yml,启用REST,且依赖Yii2。如下:

    #suite_namespace: blog\tests\api
    actor: ApiTester
    modules:
        enabled:
            - \blog\tests\Helper\Api
            - REST:
                #url:
                depends: Yii2
                #part: Json
    

    2)、执行vendor/bin/codecept g:cept api -c blog News创建测试文件blog\tests\api\NewsCept.php。

    <?php
    
    use blog\tests\ApiTester;
    use Codeception\Util\HttpCode;
    
    $I = new ApiTester($scenario);
    
    //create
    $data = ['code' => 'code1', 'title' => 'first title', 'content' => 'first content'];
    $I->wantTo('create a news');
    $I->sendPOST('/news', $data);
    $I->seeResponseCodeIs(HttpCode::CREATED);
    $I->seeResponseIsJson();
    //{"code":"code1","title":"first title","content":"first content","id":16}
    $I->seeResponseContainsJson($data);
    
    //view
    $I->wantTo('view a news');
    $id = $I->grabDataFromResponseByJsonPath('$.id')[0];
    $I->sendGET('/news/' . $id);
    $I->seeResponseCodeIs(HttpCode::OK);
    $I->seeResponseIsJson();
    $I->seeResponseMatchesJsonType([
        'id' => 'integer',
        'title' => 'string',
        'content' => 'string|null',
    ]);
    
    //update
    $I->wantTo('update news');
    $id = $I->grabDataFromResponseByJsonPath('$.id')[0];
    $I->sendPUT('/news/' . $id, ['content' => 'updated content']);
    $I->seeResponseCodeIs(HttpCode::OK);
    $I->seeResponseContainsJson(['content' => 'updated content']);
    
    //index
    $I->wantTo('list news');
    $I->sendGET('/news');
    $I->seeResponseCodeIs(HttpCode::OK);
    //{"items":[{"id":49,"code":"code1","title":"first title","content":"first content","status":0,"created_at":0,"created_by":0,"updated_at":0,"updated_by":0}],"_links":{"self":{"href":"http://localhost/index-test.php/news?page=1"}},"_meta":{"totalCount":1,"pageCount":1,"currentPage":1,"perPage":20}}
    $I->seeResponseJsonMatchesJsonPath('$.items..title');
    $I->seeResponseJsonMatchesXpath('//_meta//totalCount');
    
    
    //delete
    $I->wantTo('delete a news');
    $id = $I->grabDataFromResponseByJsonPath('$.items..id');
    $I->sendDELETE('/news/' . $id[0]);
    $I->seeResponseCodeIs(HttpCode::NO_CONTENT);
    
    //index
    $I->wantTo('list empty news');
    $I->sendGET('/news');
    $I->seeResponseCodeIs(HttpCode::OK);
    
    

    3)、运行测试vendor/bin/codecept run -c blog
    提示需要安装flow/jsonpath,执行composer require -dev "flow/jsonpath"。待安装之后再次执行测试即可。

    至此,REST的API测试完成。
    Yii2下使用codeception进行单元测试和API测试到此告一段落,后面可以继续熟悉codeception的强大吧。

    上一篇:准备工作
    下一篇:力争上游

    相关文章

      网友评论

          本文标题:Yii2的Codeception测试-2测试工作

          本文链接:https://www.haomeiwen.com/subject/qtngxftx.html