没有不值得去解决的问题,也没有不值得去学习的技术!

Create a GitHub Repository for yiisoft/yii2-app-advanced and Add a RESTful API App With Automated User Tests

Run the tests to get detailed output. You can see a step-by-step behavior report, which matches expectations

1. Delete the controller \api\controllers\SiteController.php. Delete the models \api\models\ContactForm.php, \api\models\LoginForm.php, \api\models\PasswordResetRequestForm.php, \api\models\ResetPasswordForm.php, and \api\models\SignupForm.php. Delete the directories (view-related) \api\views, \api\assets, and \api\web\css.

2. Delete the related test files (unit tests, functional tests, acceptance tests). Delete \api\tests\acceptance\HomeCest.php. Delete \api\tests\functional\AboutCest.php, \api\tests\functional\ContactCest.php, \api\tests\functional\HomeCest.php, \api\tests\functional\LoginCest.php, and \api\tests\functional\SignupCest.php. Delete \api\tests\unit\models\ContactFormTest.php, \api\tests\unit\models\PasswordResetRequestFormTest.php, \api\tests\unit\models\ResetPasswordFormTest.php, and \api\tests\unit\models\SignupFormTest.php.

3. Run all sample tests. The error reported is: FAILURES! Tests: 24, Assertions: 57, Failures: 5, as shown in Figure 1.

Run all sample tests. The error reported is: FAILURES! Tests: 24, Assertions: 57, Failures: 5
Figure 1
Plaintext
Codeception PHP Testing Framework v2.4.1
Powered by PHPUnit 7.0.3 by Sebastian Bergmann and contributors.
 
Frontend\tests.functional Tests (12) -------------------------------------------------------------------------------------------------------------------------
+ AboutCest: Check about (0.10s)
+ ContactCest: Check contact (0.19s)
x ContactCest: Check contact submit no data (0.04s)
x ContactCest: Check contact submit not correct email (0.02s)
+ ContactCest: Check contact submit correct data (0.08s)
+ HomeCest: Check open (0.01s)
x LoginCest: Check empty (0.02s)
+ LoginCest: Check wrong password (0.03s)
+ LoginCest: Check valid login (0.58s)
x SignupCest: Signup with empty fields (0.02s)
x SignupCest: Signup with wrong email (0.03s)
+ SignupCest: Signup successfully (0.59s)
--------------------------------------------------------------------------------------------------------------------------------------------------------------
 
Frontend\tests.unit Tests (8) --------------------------------------------------------------------------------------------------------------------------------
+ ContactFormTest: Send email (0.02s)
+ PasswordResetRequestFormTest: Send message with wrong email address (0.03s)
+ PasswordResetRequestFormTest: Not send emails to inactive user (0.03s)
+ PasswordResetRequestFormTest: Send email successfully (0.04s)
+ ResetPasswordFormTest: Reset wrong token (0.03s)
+ ResetPasswordFormTest: Reset correct token (0.59s)
+ SignupFormTest: Correct signup (1.14s)
+ SignupFormTest: Not correct signup (0.03s)
--------------------------------------------------------------------------------------------------------------------------------------------------------------
 
 
Time: 4.83 seconds, Memory: 26.00MB
 
There were 5 failures:
 
---------
1) ContactCest: Check contact submit no data
 Test  tests\functional\ContactCest.php:checkContactSubmitNoData
 Step  See "Name cannot be blank",".help-block"
 Fail  Failed asserting that any element by '.help-block' on user /index-test.php/site/contact
+ <p class="help-block help-block-error">Name不能为空。</p>
+ <p class="help-block help-block-error">Email不能为空。</p>
+ <p class="help-block help-block-error">Subject不能为空。</p>
+ <p class="help-block help-block-error">Body不能为空。</p>
+ <p class="help-block help-block-error">验证码不正确。</p>
contains text 'Name cannot be blank'
 
Scenario Steps:
 
 4. $I->see("Name cannot be blank",".help-block") at tests\_support\FunctionalTester.php:26
 3. $I->see("Contact","h1") at tests\functional\ContactCest.php:23
 2. $I->submitForm("#contact-form",[]) at tests\functional\ContactCest.php:22
 1. $I->amOnuser(["site/contact"]) at tests\functional\ContactCest.php:12
 
 
---------
2) ContactCest: Check contact submit not correct email
 Test  tests\functional\ContactCest.php:checkContactSubmitNotCorrectEmail
 Step  See "Email is not a valid email address.",".help-block"
 Fail  Failed asserting that any element by '.help-block' on user /index-test.php/site/contact
+ <p class="help-block help-block-error"></p>
+ <p class="help-block help-block-error">Email不是有效的邮箱地址。</p>
+ <p class="help-block help-block-error"></p>
+ <p class="help-block help-block-error"></p>
+ <p class="help-block help-block-error"></p>
contains text 'Email is not a valid email address.'
 
Scenario Steps:
 
 3. $I->see("Email is not a valid email address.",".help-block") at tests\_support\FunctionalTester.php:26
 2. $I->submitForm("#contact-form",{"ContactForm[name]":"tester","ContactForm[email]":"tester.email","ContactForm[subject]":"test subject","ContactForm[b...})
 at tests\functional\ContactCest.php:34
 1. $I->amOnuser(["site/contact"]) at tests\functional\ContactCest.php:12
 
 
---------
3) LoginCest: Check empty
 Test  tests\functional\LoginCest.php:checkEmpty
 Step  See "Username cannot be blank.",".help-block"
 Fail  Failed asserting that any element by '.help-block' on user /index-test.php/site/login
+ <p class="help-block help-block-error">Username不能为空。</p>
+ <p class="help-block help-block-error">Password不能为空。</p>
+ <p class="help-block help-block-error"></p>
contains text 'Username cannot be blank.'
 
Scenario Steps:
 
 3. $I->see("Username cannot be blank.",".help-block") at tests\_support\FunctionalTester.php:26
 2. $I->submitForm("#login-form",{"LoginForm[username]":"","LoginForm[password]":""}) at tests\functional\LoginCest.php:42
 1. $I->amOnRoute("site/login") at tests\functional\LoginCest.php:29
 
 
---------
4) SignupCest: Signup with empty fields
 Test  tests\functional\SignupCest.php:signupWithEmptyFields
 Step  See "Username cannot be blank.",".help-block"
 Fail  Failed asserting that any element by '.help-block' on user /index-test.php/site/signup
+ <p class="help-block help-block-error">Username不能为空。</p>
+ <p class="help-block help-block-error">Email不能为空。</p>
+ <p class="help-block help-block-error">Password不能为空。</p>
contains text 'Username cannot be blank.'
 
Scenario Steps:
 
 5. $I->see("Username cannot be blank.",".help-block") at tests\_support\FunctionalTester.php:26
 4. $I->submitForm("#form-signup",[]) at tests\functional\SignupCest.php:21
 3. $I->see("Please fill out the following fields to signup:") at tests\functional\SignupCest.php:20
 2. $I->see("Signup","h1") at tests\functional\SignupCest.php:19
 1. $I->amOnRoute("site/signup") at tests\functional\SignupCest.php:14
 
 
---------
5) SignupCest: Signup with wrong email
 Test  tests\functional\SignupCest.php:signupWithWrongEmail
 Step  See "Email is not a valid email address.",".help-block"
 Fail  Failed asserting that any element by '.help-block' on user /index-test.php/site/signup
+ <p class="help-block help-block-error"></p>
+ <p class="help-block help-block-error">Email不是有效的邮箱地址。</p>
+ <p class="help-block help-block-error"></p>
contains text 'Email is not a valid email address.'
 
Scenario Steps:
 
 5. $I->see("Email is not a valid email address.",".help-block") at tests\functional\SignupCest.php:39
 4. $I->dontSee("Password cannot be blank.",".help-block") at tests\functional\SignupCest.php:38
 3. $I->dontSee("Username cannot be blank.",".help-block") at tests\functional\SignupCest.php:37
 2. $I->submitForm("#form-signup",{"SignupForm[username]":"tester","SignupForm[email]":"ttttt","SignupForm[password]":"tester_password"}) at tests\functional\
SignupCest.php:32
 1. $I->amOnRoute("site/signup") at tests\functional\SignupCest.php:14
 
 
FAILURES!
Tests: 20, Assertions: 48, Failures: 5.
Bash
vendor/bin/codecept run

4. Step 22 in section (III) needs to be reverted, as this step caused the sample tests to fail. Adjust it so that the content negotiation feature is only supported for web applications.

(1) Revert the edits made to \common\config\main.php in step 22.
(2) Edit \backend\config\main.php and \frontend\config\main.php.

Note: If no language is detected in the request, the first configured item in [[languages]] is used.

PHP
    'bootstrap' => ['log', 'contentNegotiator'],
    'components' => [

        'contentNegotiator' => [
            'class' => 'yii\filters\ContentNegotiator',
            'languages' => [
                'en-US',
                'zh-CN',
            ],
        ],

    ],

(3) Edit \api\config\main.php.

PHP
    'bootstrap' => ['log', 'contentNegotiator'],
    'components' => [

        'contentNegotiator' => [
            'class' => 'yii\filters\ContentNegotiator',
            'formats' => [
                'application/json' => yii\web\Response::FORMAT_JSON,
                'application/xml' => yii\web\Response::FORMAT_XML,
            ],
            'languages' => [
                'en-US',
                'zh-CN',
            ],
        ],

    ],

Delete

PHP
        'response' => [
            'format' => yii\web\Response::FORMAT_JSON,
        ],

5. Open Windows PowerShell, run the init command, select dev as the environment, and then reconfigure the database connection.

Plaintext
.\init
0
yes
Yes
Yes
Yes
Yes
Yes

6. Run all sample tests. The results match expectations, as shown in Figure 2.

Run all sample tests. The results match expectations
Figure 2
Bash
vendor/bin/codecept run

7. To start writing API tests, create an API test suite by running the command, as shown in Figure 3.

To start writing API tests, create an API test suite by running the command
Figure 3
Bash
vendor/bin/codecept generate:suite api -c api

Plaintext
Helper \api\tests\Helper\Api was created in E:\wwwroot\github-shuijingwan-yii2-app-advanced\api\tests/_support\Helper\Api.php
Actor ApiTester was created in E:\wwwroot\github-shuijingwan-yii2-app-advanced\api\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

8. Edit \api\tests\api.suite.yml to enable the modules for this suite.

YAML
actor: ApiTester
modules:
    enabled:
        - REST:
            url: /v1
            depends: Yii2
        - \api\tests\Helper\Api
    config:
        - Yii2

9. Create a test: get user list (user/IndexEmpty), as shown in Figure 4.

Create a test: get user list (user/IndexEmpty)
Figure 4
Bash
vendor/bin/codecept generate:cest api user/IndexEmpty -c api

Plaintext
Test was created in E:\wwwroot\github-shuijingwan-yii2-app-advanced\api\tests\api\user\IndexEmptyCest.php

10. [[yii\base\Application::version|version]]. This property specifies the application version, which defaults to ‘1.0’. Configure it as 1.0.0 by editing \api\config\main.php. This value should match the tag on Git.

Plaintext
    'version' => '1.0.0',

11. Edit \api\tests\_support\Helper\Api.php to add a method for getting the current version number (minor version.patch version).

PHP
<?php
namespace api\tests\Helper;
 
use Yii;
use yii\helpers\StringHelper;
 
// here you can define custom actions
// all public methods declared in helper class will be available in $I
 
class Api extends \Codeception\Module
{
 
    // 获取当前版本号(次版本号.修订号)
    public function getMinorPatch() {
        $version = StringHelper::explode(Yii::$app->version, '.');
        return $version[1] . '.' . $version[2];
    }
 
}

12. Run the build command. The new feature has been added to the ApiTester class, as shown in Figure 5.

Run the build command. The new feature has been added to the ApiTester class
Figure 5
Bash
vendor/bin/codecept build -- -c api

13. \api\tests\_support\_generated\ApiTesterActions.php is successfully generated. The new method getMinorPatch() is added. View it, as shown in Figure 6.

\api\tests\_support\_generated\ApiTesterActions.php is successfully generated. The new method getMinorPatch() is added. View it
Figure 6

14. Install flow/jsonpath to check the response structure, as shown in Figure 7.

Install flow/jsonpath to check the response structure
Figure 7
Bash
composer require --prefer-dist flow/jsonpath

Plaintext
Using version ^0.4.0 for flow/jsonpath
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Installing flow/jsonpath (0.4.0): Downloading (100%)
Writing lock file
Generating autoload files

15. A common method needs to be implemented for each test. Let indexIsJson test getting the user list via the REST API (empty user list, JSON response). Let indexIsXml test getting the user list via the REST API (empty user list, XML response). Edit \api\tests\api\user\IndexEmptyCest.php.

PHP
<?php
namespace api\tests\user;
 
use Yii;
use api\tests\ApiTester;
use Codeception\Util\HttpCode;
use Codeception\Util\Xml;
 
class IndexEmptyCest
{
    public function _before(ApiTester $I)
    {
    }
 
    public function _after(ApiTester $I)
    {
    }
 
    // 获取用户列表(用户列表为空、JSON响应)
    public function indexIsJson(ApiTester $I)
    {
        $I->haveHttpHeader('Accept', 'application/json; version=' . $I->getMinorPatch() . '');
        $I->sendGET('/users');
        $I->seeResponseCodeIs(HttpCode::OK); // 200
        $I->seeResponseIsJson();
        // 检查响应的结构
        $I->seeResponseJsonMatchesJsonPath('$.code');
        $I->seeResponseJsonMatchesJsonPath('$.message');
        // 检查响应的数据
        $I->seeResponseContainsJson([
            'code' => 20001,
            'message' => Yii::t('error', '20001'),
        ]);
    }
 
    // 获取用户列表(用户列表为空、XML响应)
    public function indexIsXml(ApiTester $I)
    {
        $I->haveHttpHeader('Accept', 'application/xml; version=' . $I->getMinorPatch() . '');
        $I->sendGET('/users');
        $I->seeResponseCodeIs(HttpCode::OK); // 200
        $I->seeResponseIsXml();
        // 检查响应的结构
        $I->seeXmlResponseMatchesXpath('//code');
        $I->seeXmlResponseMatchesXpath('//message');
        // 检查响应的数据
        $I->seeXmlResponseIncludes(Xml::toXml(['code' => 20001]));
        $I->seeXmlResponseIncludes(Xml::toXml(['message' => Yii::t('error', '20001')]));
    }
}
 
 

16. Run the tests to get detailed output. You can see a step-by-step behavior report, which matches expectations, as shown in Figure 8.

Run the tests to get detailed output. You can see a step-by-step behavior report, which matches expectations
Figure 8
Bash
vendor/bin/codecept run --steps -- -c api

Plaintext
Codeception PHP Testing Framework v2.4.1
Powered by PHPUnit 7.1.2 by Sebastian Bergmann and contributors.

Api\tests.api Tests (2) -----------------------------------------------------
IndexEmptyCest: Index is json
Signature: api\tests\user\IndexEmptyCest:indexIsJson
Test: tests\api\user\IndexEmptyCest.php:indexIsJson
Scenario --
 I get minor patch
 I have http header "Accept","application/json; version=0.0"
 I send get "/users"
 I see response code is 200
 I see response is json
 I see response json matches json path "$.code"
 I see response json matches json path "$.message"
 I see response contains json {"code":20001,"message":"User list is empty"}
 PASSED

IndexEmptyCest: Index is xml
Signature: api\tests\user\IndexEmptyCest:indexIsXml
Test: tests\api\user\IndexEmptyCest.php:indexIsXml
Scenario --
 I get minor patch
 I have http header "Accept","application/xml; version=0.0"
 I send get "/users"
 I see response code is 200
 I see response is xml
 I see xml response matches xpath "//code"
 I see xml response matches xpath "//message"
 I see xml response includes "DOMDocument"
 I see xml response includes "DOMDocument"
 PASSED

-----------------------------------------------------------------------------

Api\tests.functional Tests (0) ----------------------------------------------
-----------------------------------------------------------------------------

Api\tests.unit Tests (0) ----------------------------------------------------
-----------------------------------------------------------------------------


Time: 1.11 seconds, Memory: 16.00MB

OK (2 tests, 12 assertions)

17. Create a test: get user list (user/Index).

Bash
vendor/bin/codecept generate:cest api user/Index -c api

18. A common method needs to be implemented for each test using Fixtures. Let indexIsJson test getting the user list via the REST API (successfully getting user list, JSON response). Let indexIsXml test getting the user list via the REST API (successfully getting user list, XML response). Edit \api\tests\api\user\IndexCest.php.

PHP
<?php
namespace api\tests\user;
 
use Yii;
use api\tests\ApiTester;
use Codeception\Util\HttpCode;
use Codeception\Util\Xml;
use api\fixtures\UserFixture;
 
class IndexCest
{
    public function _before(ApiTester $I)
    {
    }
 
    public function _after(ApiTester $I)
    {
    }
 
    /**
     * @return array
     */
    public function _fixtures()
    {
        return [
            'user' => [
                'class' => UserFixture::className(),
                'dataFile' => codecept_data_dir() . 'user.php'
            ]
        ];
    }
 
    // 获取用户列表(获取用户列表成功、JSON响应)
    public function indexIsJson(ApiTester $I)
    {
        $I->haveHttpHeader('Accept', 'application/json; version=' . $I->getMinorPatch() . '');
        $I->sendGET('/users');
        $I->seeResponseCodeIs(HttpCode::OK); // 200
        $I->seeResponseIsJson();
        // 检查响应的结构
        $I->seeResponseJsonMatchesJsonPath('$.code');
        $I->seeResponseJsonMatchesJsonPath('$.message');
        $I->seeResponseJsonMatchesJsonPath('$.data');
        $I->seeResponseJsonMatchesJsonPath('$.data.items');
        $I->seeResponseJsonMatchesJsonPath('$.data._links');
        $I->seeResponseJsonMatchesJsonPath('$.data._meta');
        // 检查响应的数据
        $I->seeResponseContainsJson([
            'code' => 10000,
            'message' => Yii::t('success', '10001'),
        ]);
    }
 
    // 获取用户列表(获取用户列表成功、XML响应)
    public function indexIsXml(ApiTester $I)
    {
        $I->haveHttpHeader('Accept', 'application/xml; version=' . $I->getMinorPatch() . '');
        $I->sendGET('/users');
        $I->seeResponseCodeIs(HttpCode::OK); // 200
        $I->seeResponseIsXml();
        // 检查响应的结构
        $I->seeXmlResponseMatchesXpath('//code');
        $I->seeXmlResponseMatchesXpath('//message');
        $I->seeXmlResponseMatchesXpath('//data');
        $I->seeXmlResponseMatchesXpath('//data/items');
        $I->seeXmlResponseMatchesXpath('//data/_links');
        $I->seeXmlResponseMatchesXpath('//data/_meta');
        // 检查响应的数据
        $I->seeXmlResponseIncludes(Xml::toXml(['code' => 10000]));
        $I->seeXmlResponseIncludes(Xml::toXml(['message' => Yii::t('success', '10001')]));
    }
}
 
 

19. Run the tests to get detailed output. You can see a step-by-step behavior report, which matches expectations.

Bash
vendor/bin/codecept run --steps -- -c api

Plaintext
IndexCest: Index is json
Signature: api\tests\user\IndexCest:indexIsJson
Test: tests\api\user\IndexCest.php:indexIsJson
Scenario --
 I get minor patch
 I have http header "Accept","application/json; version=0.0"
 I send get "/users"
 I see response code is 200
 I see response is json
 I see response json matches json path "$.code"
 I see response json matches json path "$.message"
 I see response json matches json path "$.data"
 I see response json matches json path "$.data.items"
 I see response json matches json path "$.data._links"
 I see response json matches json path "$.data._meta"
 I see response contains json {"code":10000,"message":"Get user list success"}
 PASSED

IndexCest: Index is xml
Signature: api\tests\user\IndexCest:indexIsXml
Test: tests\api\user\IndexCest.php:indexIsXml
Scenario --
 I get minor patch
 I have http header "Accept","application/xml; version=0.0"
 I send get "/users"
 I see response code is 200
 I see response is xml
 I see xml response matches xpath "//code"
 I see xml response matches xpath "//message"
 I see xml response matches xpath "//data"
 I see xml response matches xpath "//data/items"
 I see xml response matches xpath "//data/_links"
 I see xml response matches xpath "//data/_meta"
 I see xml response includes "DOMDocument"
 I see xml response includes "DOMDocument"
 PASSED

20. GET /users/{id}: Returns the details of user {id}. Create a test: get user details.

Bash
vendor/bin/codecept generate:cest api user/View -c api

21. Edit \api\tests\api\user\ViewCest.php to get user details (user ID: {id}, does not exist / user ID: {id}, status is deleted / successfully getting user details).

PHP
<?php
namespace api\tests\user;
 
use Yii;
use api\tests\ApiTester;
use Codeception\Util\HttpCode;
use Codeception\Util\Xml;
use api\fixtures\UserFixture;
 
class ViewCest
{
    const STATUS_DELETED = 0; //状态:已删除
    const STATUS_ACTIVE = 10; //状态:活跃
 
    public function _before(ApiTester $I)
    {
    }
 
    public function _after(ApiTester $I)
    {
    }
 
    /**
     * @return array
     */
    public function _fixtures()
    {
        return [
            'user' => [
                'class' => UserFixture::className(),
                'dataFile' => codecept_data_dir() . 'user.php'
            ]
        ];
    }
 
    // 获取用户详情(获取用户详情成功、JSON响应)
    public function viewIsJson(ApiTester $I)
    {
        $id = 1;
        $I->haveHttpHeader('Accept', 'application/json; version=' . $I->getMinorPatch() . '');
        $I->sendGET('/users/' . $id);
        $I->seeResponseCodeIs(HttpCode::OK); // 200
        $I->seeResponseIsJson();
        // 检查响应的结构
        $I->seeResponseJsonMatchesJsonPath('$.code');
        $I->seeResponseJsonMatchesJsonPath('$.message');
        $I->seeResponseJsonMatchesJsonPath('$.data');
        // 检查响应的数据
        $I->seeResponseContainsJson([
            'code' => 10000,
            'message' => Yii::t('success', '10002'),
        ]);
    }
 
    // 获取用户详情(获取用户详情成功、XML响应)
    public function viewIsXml(ApiTester $I)
    {
        $id = 1;
        $I->haveHttpHeader('Accept', 'application/xml; version=' . $I->getMinorPatch() . '');
        $I->sendGET('/users/' . $id);
        $I->seeResponseCodeIs(HttpCode::OK); // 200
        $I->seeResponseIsXml();
        // 检查响应的结构
        $I->seeXmlResponseMatchesXpath('//code');
        $I->seeXmlResponseMatchesXpath('//message');
        $I->seeXmlResponseMatchesXpath('//data');
        // 检查响应的数据
        $I->seeXmlResponseIncludes(Xml::toXml(['code' => 10000]));
        $I->seeXmlResponseIncludes(Xml::toXml(['message' => Yii::t('success', '10002')]));
    }
 
    // 获取用户详情,使用不存在的ID(用户ID:{id},不存在、JSON响应)
    public function viewWithNotExistIdIsJson(ApiTester $I)
    {
        $id = 9999;
        $I->haveHttpHeader('Accept', 'application/json; version=' . $I->getMinorPatch() . '');
        $I->sendGET('/users/' . $id);
        $I->seeResponseCodeIs(HttpCode::NOT_FOUND); // 404
        $I->seeResponseIsJson();
        // 检查响应的结构
        $I->seeResponseJsonMatchesJsonPath('$.code');
        $I->seeResponseJsonMatchesJsonPath('$.message');
        // 检查响应的数据
        $I->seeResponseContainsJson([
            'code' => 20002,
            'message' => Yii::t('error', Yii::t('error', Yii::t('error', '20002'), ['id' => $id])),
        ]);
    }
 
    // 获取用户详情,使用不存在的ID(用户ID:{id},不存在、XML响应)
    public function viewWithNotExistIdIsXml(ApiTester $I)
    {
        $id = 9999;
        $I->haveHttpHeader('Accept', 'application/xml; version=' . $I->getMinorPatch() . '');
        $I->sendGET('/users/' . $id);
        $I->seeResponseCodeIs(HttpCode::NOT_FOUND); // 404
        $I->seeResponseIsXml();
        // 检查响应的结构
        $I->seeXmlResponseMatchesXpath('//code');
        $I->seeXmlResponseMatchesXpath('//message');
        // 检查响应的数据
        $I->seeXmlResponseIncludes(Xml::toXml(['code' => 20002]));
        $I->seeXmlResponseIncludes(Xml::toXml(['message' => Yii::t('error', Yii::t('error', Yii::t('error', '20002'), ['id' => $id]))]));
    }
 
    // 获取用户详情(用户ID:{id},的状态为已删除、JSON响应)
    public function viewStatusDeletedIsJson(ApiTester $I)
    {
        $id = 2;
        $I->haveHttpHeader('Accept', 'application/json; version=' . $I->getMinorPatch() . '');
        $I->sendGET('/users/' . $id);
        $I->seeResponseCodeIs(HttpCode::OK); // 200
        $I->seeResponseIsJson();
        // 检查响应的结构
        $I->seeResponseJsonMatchesJsonPath('$.code');
        $I->seeResponseJsonMatchesJsonPath('$.message');
        // 检查响应的数据
        $I->seeResponseContainsJson([
            'code' => 20003,
            'message' => Yii::t('error', Yii::t('error', Yii::t('error', '20003'), ['id' => $id])),
        ]);
    }
 
    // 获取用户详情(用户ID:{id},的状态为已删除、XML响应)
    public function viewStatusDeletedIsXml(ApiTester $I)
    {
        $id = 2;
        $I->haveHttpHeader('Accept', 'application/xml; version=' . $I->getMinorPatch() . '');
        $I->sendGET('/users/' . $id);
        $I->seeResponseCodeIs(HttpCode::OK); // 200
        $I->seeResponseIsXml();
        // 检查响应的结构
        $I->seeXmlResponseMatchesXpath('//code');
        $I->seeXmlResponseMatchesXpath('//message');
        // 检查响应的数据
        $I->seeXmlResponseIncludes(Xml::toXml(['code' => 20003]));
        $I->seeXmlResponseIncludes(Xml::toXml(['message' => Yii::t('error', Yii::t('error', Yii::t('error', '20003'), ['id' => $id]))]));
    }
}
 
 

22. Run the tests to get detailed output. You can see a step-by-step behavior report, which matches expectations.

Bash
vendor/bin/codecept run --steps -- -c api

Plaintext
ViewCest: View is json
Signature: api\tests\user\ViewCest:viewIsJson
Test: tests\api\user\ViewCest.php:viewIsJson
Scenario --
 I get minor patch
 I have http header "Accept","application/json; version=0.0"
 I send get "/users/1"
 I see response code is 200
 I see response is json
 I see response json matches json path "$.code"
 I see response json matches json path "$.message"
 I see response json matches json path "$.data"
 I see response contains json {"code":10000,"message":"Get user details success"}
 PASSED

ViewCest: View is xml
Signature: api\tests\user\ViewCest:viewIsXml
Test: tests\api\user\ViewCest.php:viewIsXml
Scenario --
 I get minor patch
 I have http header "Accept","application/xml; version=0.0"
 I send get "/users/1"
 I see response code is 200
 I see response is xml
 I see xml response matches xpath "//code"
 I see xml response matches xpath "//message"
 I see xml response matches xpath "//data"
 I see xml response includes "DOMDocument"
 I see xml response includes "DOMDocument"
 PASSED

ViewCest: View with not exist id is json
Signature: api\tests\user\ViewCest:viewWithNotExistIdIsJson
Test: tests\api\user\ViewCest.php:viewWithNotExistIdIsJson
Scenario --
 I get minor patch
 I have http header "Accept","application/json; version=0.0"
 I send get "/users/9999"
 I see response code is 404
 I see response is json
 I see response json matches json path "$.code"
 I see response json matches json path "$.message"
 I see response contains json {"code":20002,"message":"User ID: 9999, does not exist"}
 PASSED

ViewCest: View with not exist id is xml
Signature: api\tests\user\ViewCest:viewWithNotExistIdIsXml
Test: tests\api\user\ViewCest.php:viewWithNotExistIdIsXml
Scenario --
 I get minor patch
 I have http header "Accept","application/xml; version=0.0"
 I send get "/users/9999"
 I see response code is 404
 I see response is xml
 I see xml response matches xpath "//code"
 I see xml response matches xpath "//message"
 I see xml response includes "DOMDocument"
 I see xml response includes "DOMDocument"
 PASSED

ViewCest: View status deleted is json
Signature: api\tests\user\ViewCest:viewStatusDeletedIsJson
Test: tests\api\user\ViewCest.php:viewStatusDeletedIsJson
Scenario --
 I get minor patch
 I have http header "Accept","application/json; version=0.0"
 I send get "/users/2"
 I see response code is 200
 I see response is json
 I see response json matches json path "$.code"
 I see response json matches json path "$.message"
 I see response contains json {"code":20003,"message":"User ID: 2, status is deleted"}
 PASSED

ViewCest: View status deleted is xml
Signature: api\tests\user\ViewCest:viewStatusDeletedIsXml
Test: tests\api\user\ViewCest.php:viewStatusDeletedIsXml
Scenario --
 I get minor patch
 I have http header "Accept","application/xml; version=0.0"
 I send get "/users/2"
 I see response code is 200
 I see response is xml
 I see xml response matches xpath "//code"
 I see xml response matches xpath "//message"
 I see xml response includes "DOMDocument"
 I see xml response includes "DOMDocument"
 PASSED

23. POST /users: Create a new user. Create a test: create user.

Bash
vendor/bin/codecept generate:cest api user/Create -c api

24. Edit \api\tests\api\user\CreateCest.php to support (successfully creating user / data validation failed: {firstErrors}).

PHP
<?php
namespace api\tests\user;
 
use Yii;
use api\tests\ApiTester;
use Codeception\Util\HttpCode;
use Codeception\Util\Xml;
use api\fixtures\UserFixture;
 
class CreateCest
{
    public function _before(ApiTester $I)
    {
    }
 
    public function _after(ApiTester $I)
    {
    }
 
    /**
     * @return array
     */
    public function _fixtures()
    {
        return [
            'user' => [
                'class' => UserFixture::className(),
                'dataFile' => codecept_data_dir() . 'user.php'
            ]
        ];
    }
 
    // 创建用户(创建用户成功、JSON响应)
    public function createIsJson(ApiTester $I)
    {
        $data = [
            'username' => '111111',
            'email' => '111111@163.com',
            'password' => '111111',
        ];
        $I->haveHttpHeader('Accept', 'application/json; version=' . $I->getMinorPatch() . '');
        $I->sendPOST('/users', $data);
        $I->seeResponseCodeIs(HttpCode::CREATED); // 201
        $I->seeResponseIsJson();
        // 检查响应的结构
        $I->seeResponseJsonMatchesJsonPath('$.code');
        $I->seeResponseJsonMatchesJsonPath('$.message');
        $I->seeResponseJsonMatchesJsonPath('$.data');
        $I->seeResponseJsonMatchesJsonPath('$.data.username');
        $I->seeResponseJsonMatchesJsonPath('$.data.email');
        // 检查响应的数据
        $I->seeResponseContainsJson([
            'code' => 10000,
            'message' => Yii::t('success', '10003'),
            'data' => [
                'username' => $data['username'],
                'email' => $data['email'],
            ],
        ]);
    }
 
    // 创建用户(创建用户成功、XML响应)
    public function createIsXml(ApiTester $I)
    {
        $data = [
            'username' => '111111',
            'email' => '111111@163.com',
            'password' => '111111',
        ];
        $I->haveHttpHeader('Accept', 'application/xml; version=' . $I->getMinorPatch() . '');
        $I->sendPOST('/users', $data);
        $I->seeResponseCodeIs(HttpCode::CREATED); // 201
        $I->seeResponseIsXml();
        // 检查响应的结构
        $I->seeXmlResponseMatchesXpath('//code');
        $I->seeXmlResponseMatchesXpath('//message');
        $I->seeXmlResponseMatchesXpath('//data');
        $I->seeXmlResponseMatchesXpath('//data//username');
        $I->seeXmlResponseMatchesXpath('//data//email');
        // 检查响应的数据
        $I->seeXmlResponseIncludes(Xml::toXml(['code' => 10000]));
        $I->seeXmlResponseIncludes(Xml::toXml(['message' => Yii::t('success', '10003')]));
        $I->seeXmlResponseIncludes(Xml::toXml(['username' => $data['username']]));
        $I->seeXmlResponseIncludes(Xml::toXml(['email' => $data['email']]));
    }
 
    // 创建用户,使用空的字段值(数据验证失败:{firstErrors}、JSON响应)
    public function createWithEmptyFieldsIsJson(ApiTester $I)
    {
        $data = [];
        $I->haveHttpHeader('Accept', 'application/json; version=' . $I->getMinorPatch() . '');
        $I->sendPOST('/users', $data);
        $I->seeResponseCodeIs(HttpCode::UNPROCESSABLE_ENTITY); // 422
        $I->seeResponseIsJson();
        // 检查响应的结构
        $I->seeResponseJsonMatchesJsonPath('$.code');
        $I->seeResponseJsonMatchesJsonPath('$.message');
        // 检查响应的数据
        $I->seeResponseContainsJson(['code' => 20004]);
        $I->seeResponseContainsJson(['message' => 'Data validation failed: Username cannot be blank.']);
    }
 
    // 创建用户,使用空的字段值(数据验证失败:{firstErrors}、XML响应)
    public function createWithEmptyFieldsIsXml(ApiTester $I)
    {
        $data = [];
        $I->haveHttpHeader('Accept', 'application/xml; version=' . $I->getMinorPatch() . '');
        $I->sendPOST('/users', $data);
        $I->seeResponseCodeIs(HttpCode::UNPROCESSABLE_ENTITY); // 422
        $I->seeResponseIsXml();
        // 检查响应的结构
        $I->seeXmlResponseMatchesXpath('//code');
        $I->seeXmlResponseMatchesXpath('//message');
        // 检查响应的数据
        $I->seeXmlResponseIncludes(Xml::toXml(['code' => 20004]));
        $I->seeXmlResponseIncludes(Xml::toXml(['message' => 'Data validation failed: Username cannot be blank.']));
    }
 
    // 创建用户,使用错误的邮箱(数据验证失败:{firstErrors}、JSON响应)
    public function createWithWrongEmailIsJson(ApiTester $I)
    {
        $data = [
            'username' => '111111',
            'email' => '111111',
            'password' => '111111',
        ];
        $I->haveHttpHeader('Accept', 'application/json; version=' . $I->getMinorPatch() . '');
        $I->sendPOST('/users', $data);
        $I->seeResponseCodeIs(HttpCode::UNPROCESSABLE_ENTITY); // 422
        $I->seeResponseIsJson();
        // 检查响应的结构
        $I->seeResponseJsonMatchesJsonPath('$.code');
        $I->seeResponseJsonMatchesJsonPath('$.message');
        // 检查响应的数据
        $I->seeResponseContainsJson(['code' => 20004]);
        $I->seeResponseContainsJson(['message' => 'Data validation failed: Email is not a valid email address.']);
    }
 
    // 创建用户,使用错误的邮箱(数据验证失败:{firstErrors}、XML响应)
    public function createWithWrongEmailIsXml(ApiTester $I)
    {
        $data = [
            'username' => '111111',
            'email' => '111111',
            'password' => '111111',
        ];
        $I->haveHttpHeader('Accept', 'application/xml; version=' . $I->getMinorPatch() . '');
        $I->sendPOST('/users', $data);
        $I->seeResponseCodeIs(HttpCode::UNPROCESSABLE_ENTITY); // 422
        $I->seeResponseIsXml();
        // 检查响应的结构
        $I->seeXmlResponseMatchesXpath('//code');
        $I->seeXmlResponseMatchesXpath('//message');
        // 检查响应的数据
        $I->seeXmlResponseIncludes(Xml::toXml(['code' => 20004]));
        $I->seeXmlResponseIncludes(Xml::toXml(['message' => 'Data validation failed: Email is not a valid email address.']));
    }
 
    // 创建用户,使用已经存在的字段值(数据验证失败:{firstErrors}、JSON响应)
    public function createWithExistFieldsIsJson(ApiTester $I)
    {
        $data = [
            'username' => 'troy.becker',
            'email' => 'nicolas.dianna@hotmail.com',
            'password' => 'some_password',
        ];
        $I->haveHttpHeader('Accept', 'application/json; version=' . $I->getMinorPatch() . '');
        $I->sendPOST('/users', $data);
        $I->seeResponseCodeIs(HttpCode::UNPROCESSABLE_ENTITY); // 422
        $I->seeResponseIsJson();
        // 检查响应的结构
        $I->seeResponseJsonMatchesJsonPath('$.code');
        $I->seeResponseJsonMatchesJsonPath('$.message');
        // 检查响应的数据
        $I->seeResponseContainsJson(['code' => 20004]);
        $I->seeResponseContainsJson(['message' => 'Data validation failed: Username "troy.becker" has already been taken.']);
    }
 
    // 创建用户,使用已经存在的字段值(数据验证失败:{firstErrors}、XML响应)
    public function createWithExistFieldsIsXml(ApiTester $I)
    {
        $data = [
            'username' => 'troy.becker',
            'email' => 'nicolas.dianna@hotmail.com',
            'password' => 'some_password',
        ];
        $I->haveHttpHeader('Accept', 'application/xml; version=' . $I->getMinorPatch() . '');
        $I->sendPOST('/users', $data);
        $I->seeResponseCodeIs(HttpCode::UNPROCESSABLE_ENTITY); // 422
        $I->seeResponseIsXml();
        // 检查响应的结构
        $I->seeXmlResponseMatchesXpath('//code');
        $I->seeXmlResponseMatchesXpath('//message');
        // 检查响应的数据
        $I->seeXmlResponseIncludes(Xml::toXml(['code' => 20004]));
        $I->seeXmlResponseIncludes(Xml::toXml(['message' => 'Data validation failed: Username "troy.becker" has already been taken.']));
    }
}
 

25. Run the tests to get detailed output. You can see a step-by-step behavior report, which matches expectations.

Bash
vendor/bin/codecept run --steps -- -c api

Plaintext
CreateCest: Create is json
Signature: api\tests\user\CreateCest:createIsJson
Test: tests\api\user\CreateCest.php:createIsJson
Scenario --
 I get minor patch
 I have http header "Accept","application/json; version=0.0"
 I send post "/users",{"username":"111111","email":"111111@163.com","password":"111111"}
 I see response code is 201
 I see response is json
 I see response json matches json path "$.code"
 I see response json matches json path "$.message"
 I see response json matches json path "$.data"
 I see response json matches json path "$.data.username"
 I see response json matches json path "$.data.email"
 I see response contains json {"code":10000,"message":"Create user success","data":{"username":"111111","email":"111...}
 PASSED

CreateCest: Create is xml
Signature: api\tests\user\CreateCest:createIsXml
Test: tests\api\user\CreateCest.php:createIsXml
Scenario --
 I get minor patch
 I have http header "Accept","application/xml; version=0.0"
 I send post "/users",{"username":"111111","email":"111111@163.com","password":"111111"}
 I see response code is 201
 I see response is xml
 I see xml response matches xpath "//code"
 I see xml response matches xpath "//message"
 I see xml response matches xpath "//data"
 I see xml response matches xpath "//data//username"
 I see xml response matches xpath "//data//email"
 I see xml response includes "DOMDocument"
 I see xml response includes "DOMDocument"
 I see xml response includes "DOMDocument"
 I see xml response includes "DOMDocument"
 PASSED

CreateCest: Create with empty fields is json
Signature: api\tests\user\CreateCest:createWithEmptyFieldsIsJson
Test: tests\api\user\CreateCest.php:createWithEmptyFieldsIsJson
Scenario --
 I get minor patch
 I have http header "Accept","application/json; version=0.0"
 I send post "/users",[]
 I see response code is 422
 I see response is json
 I see response json matches json path "$.code"
 I see response json matches json path "$.message"
 I see response contains json {"code":20004}
 I see response contains json {"message":"Data validation failed: Username cannot be blank."}
 PASSED

CreateCest: Create with empty fields is xml
Signature: api\tests\user\CreateCest:createWithEmptyFieldsIsXml
Test: tests\api\user\CreateCest.php:createWithEmptyFieldsIsXml
Scenario --
 I get minor patch
 I have http header "Accept","application/xml; version=0.0"
 I send post "/users",[]
 I see response code is 422
 I see response is xml
 I see xml response matches xpath "//code"
 I see xml response matches xpath "//message"
 I see xml response includes "DOMDocument"
 I see xml response includes "DOMDocument"
 PASSED

CreateCest: Create with wrong email is json
Signature: api\tests\user\CreateCest:createWithWrongEmailIsJson
Test: tests\api\user\CreateCest.php:createWithWrongEmailIsJson
Scenario --
 I get minor patch
 I have http header "Accept","application/json; version=0.0"
 I send post "/users",{"username":"111111","email":"111111","password":"111111"}
 I see response code is 422
 I see response is json
 I see response json matches json path "$.code"
 I see response json matches json path "$.message"
 I see response contains json {"code":20004}
 I see response contains json {"message":"Data validation failed: Email is not a valid email address."}
 PASSED

CreateCest: Create with wrong email is xml
Signature: api\tests\user\CreateCest:createWithWrongEmailIsXml
Test: tests\api\user\CreateCest.php:createWithWrongEmailIsXml
Scenario --
 I get minor patch
 I have http header "Accept","application/xml; version=0.0"
 I send post "/users",{"username":"111111","email":"111111","password":"111111"}
 I see response code is 422
 I see response is xml
 I see xml response matches xpath "//code"
 I see xml response matches xpath "//message"
 I see xml response includes "DOMDocument"
 I see xml response includes "DOMDocument"
 PASSED

CreateCest: Create with exist fields is json
Signature: api\tests\user\CreateCest:createWithExistFieldsIsJson
Test: tests\api\user\CreateCest.php:createWithExistFieldsIsJson
Scenario --
 I get minor patch
 I have http header "Accept","application/json; version=0.0"
 I send post "/users",{"username":"troy.becker","email":"nicolas.dianna@hotmail.com","password":"some_password"}
 I see response code is 422
 I see response is json
 I see response json matches json path "$.code"
 I see response json matches json path "$.message"
 I see response contains json {"code":20004}
 I see response contains json {"message":"Data validation failed: Username "troy.becker" has already been taken."}
 PASSED

CreateCest: Create with exist fields is xml
Signature: api\tests\user\CreateCest:createWithExistFieldsIsXml
Test: tests\api\user\CreateCest.php:createWithExistFieldsIsXml
Scenario --
 I get minor patch
 I have http header "Accept","application/xml; version=0.0"
 I send post "/users",{"username":"troy.becker","email":"nicolas.dianna@hotmail.com","password":"some_password"}
 I see response code is 422
 I see response is xml
 I see xml response matches xpath "//code"
 I see xml response matches xpath "//message"
 I see xml response includes "DOMDocument"
 I see xml response includes "DOMDocument"
 PASSED

26. PUT /users/{id}: Update a user. Copy \api\tests\api\user\CreateCest.php to \api\tests\api\user\UpdateCest.php. Update user (user ID: {id}, does not exist / data validation failed: {firstErrors} / successfully updating user). Edit.

PHP
<?php
namespace api\tests\user;
 
use Yii;
use api\tests\ApiTester;
use Codeception\Util\HttpCode;
use Codeception\Util\Xml;
use api\fixtures\UserFixture;
 
class UpdateCest
{
    public function _before(ApiTester $I)
    {
    }
 
    public function _after(ApiTester $I)
    {
    }
 
    /**
     * @return array
     */
    public function _fixtures()
    {
        return [
            'user' => [
                'class' => UserFixture::className(),
                'dataFile' => codecept_data_dir() . 'user.php'
            ]
        ];
    }
 
    // 更新用户(更新用户成功、JSON响应)
    public function updateIsJson(ApiTester $I)
    {
        $id = 1;
        $data = [
            'email' => '111111@163.com',
            'password' => '111111',
            'status' => 0,
        ];
        $I->haveHttpHeader('Accept', 'application/json; version=' . $I->getMinorPatch() . '');
        $I->sendPUT('/users/' . $id, $data);
        $I->seeResponseCodeIs(HttpCode::OK); // 200
        $I->seeResponseIsJson();
        // 检查响应的结构
        $I->seeResponseJsonMatchesJsonPath('$.code');
        $I->seeResponseJsonMatchesJsonPath('$.message');
        $I->seeResponseJsonMatchesJsonPath('$.data');
        $I->seeResponseJsonMatchesJsonPath('$.data.email');
        $I->seeResponseJsonMatchesJsonPath('$.data.status');
        // 检查响应的数据
        $I->seeResponseContainsJson([
            'code' => 10000,
            'message' => Yii::t('success', '10004'),
            'data' => [
                'email' => $data['email'],
                'status' => $data['status'],
            ],
        ]);
    }
 
    // 更新用户(更新用户成功、XML响应)
    public function updateIsXml(ApiTester $I)
    {
        $id = 1;
        $data = [
            'email' => '111111@163.com',
            'password' => '111111',
            'status' => 0,
        ];
        $I->haveHttpHeader('Accept', 'application/xml; version=' . $I->getMinorPatch() . '');
        $I->sendPUT('/users/' . $id, $data);
        $I->seeResponseCodeIs(HttpCode::OK); // 200
        $I->seeResponseIsXml();
        // 检查响应的结构
        $I->seeXmlResponseMatchesXpath('//code');
        $I->seeXmlResponseMatchesXpath('//message');
        $I->seeXmlResponseMatchesXpath('//data');
        $I->seeXmlResponseMatchesXpath('//data//email');
        $I->seeXmlResponseMatchesXpath('//data//status');
        // 检查响应的数据
        $I->seeXmlResponseIncludes(Xml::toXml(['code' => 10000]));
        $I->seeXmlResponseIncludes(Xml::toXml(['message' => Yii::t('success', '10004')]));
        $I->seeXmlResponseIncludes(Xml::toXml(['email' => $data['email']]));
        $I->seeXmlResponseIncludes(Xml::toXml(['status' => $data['status']]));
    }
 
    // 更新用户,使用不存在的ID(数据验证失败:{firstErrors}、JSON响应)
    public function updateWithNotExistIdIsJson(ApiTester $I)
    {
        $id = 9999;
        $data = [
            'email' => '111111@163.com',
            'password' => '111111',
            'status' => 0,
        ];
        $I->haveHttpHeader('Accept', 'application/json; version=' . $I->getMinorPatch() . '');
        $I->sendPUT('/users/' . $id, $data);
        $I->seeResponseCodeIs(HttpCode::NOT_FOUND); // 404
        $I->seeResponseIsJson();
        // 检查响应的结构
        $I->seeResponseJsonMatchesJsonPath('$.code');
        $I->seeResponseJsonMatchesJsonPath('$.message');
        // 检查响应的数据
        $I->seeResponseContainsJson(['code' => 20002]);
        $I->seeResponseContainsJson(['message' => 'User ID: 9999, does not exist']);
    }
 
    // 更新用户,使用不存在的ID(数据验证失败:{firstErrors}、JSON响应)
    public function updateWithNotExistIdIsXml(ApiTester $I)
    {
        $id = 9999;
        $data = [
            'email' => '111111@163.com',
            'password' => '111111',
            'status' => 0,
        ];
        $I->haveHttpHeader('Accept', 'application/xml; version=' . $I->getMinorPatch() . '');
        $I->sendPUT('/users/' . $id, $data);
        $I->seeResponseCodeIs(HttpCode::NOT_FOUND); // 404
        $I->seeResponseIsXml();
        // 检查响应的结构
        $I->seeXmlResponseMatchesXpath('//code');
        $I->seeXmlResponseMatchesXpath('//message');
        // 检查响应的数据
        $I->seeXmlResponseIncludes(Xml::toXml(['code' => 20002]));
        $I->seeXmlResponseIncludes(Xml::toXml(['message' => 'User ID: 9999, does not exist']));
    }
 
    // 更新用户,使用空的字段值(数据验证失败:{firstErrors}、JSON响应)
    public function updateWithEmptyFieldsIsJson(ApiTester $I)
    {
        $id = 1;
        $data = [];
        $I->haveHttpHeader('Accept', 'application/json; version=' . $I->getMinorPatch() . '');
        $I->sendPUT('/users/' . $id, $data);
        $I->seeResponseCodeIs(HttpCode::UNPROCESSABLE_ENTITY); // 422
        $I->seeResponseIsJson();
        // 检查响应的结构
        $I->seeResponseJsonMatchesJsonPath('$.code');
        $I->seeResponseJsonMatchesJsonPath('$.message');
        // 检查响应的数据
        $I->seeResponseContainsJson(['code' => 20004]);
        $I->seeResponseContainsJson(['message' => 'Data validation failed: Email cannot be blank.']);
    }
 
    // 更新用户,使用空的字段值(数据验证失败:{firstErrors}、JSON响应)
    public function updateWithEmptyFieldsIsXml(ApiTester $I)
    {
        $id = 1;
        $data = [];
        $I->haveHttpHeader('Accept', 'application/xml; version=' . $I->getMinorPatch() . '');
        $I->sendPUT('/users/' . $id, $data);
        $I->seeResponseCodeIs(HttpCode::UNPROCESSABLE_ENTITY); // 422
        $I->seeResponseIsXml();
        // 检查响应的结构
        $I->seeXmlResponseMatchesXpath('//code');
        $I->seeXmlResponseMatchesXpath('//message');
        // 检查响应的数据
        $I->seeXmlResponseIncludes(Xml::toXml(['code' => 20004]));
        $I->seeXmlResponseIncludes(Xml::toXml(['message' => 'Data validation failed: Email cannot be blank.']));
    }
 
    // 更新用户,使用错误的邮箱(数据验证失败:{firstErrors}、JSON响应)
    public function updateWithWrongEmailIsJson(ApiTester $I)
    {
        $id = 1;
        $data = [
            'email' => '111111',
            'password' => '111111',
            'status' => 0,
        ];
        $I->haveHttpHeader('Accept', 'application/json; version=' . $I->getMinorPatch() . '');
        $I->sendPUT('/users/' . $id, $data);
        $I->seeResponseCodeIs(HttpCode::UNPROCESSABLE_ENTITY); // 422
        $I->seeResponseIsJson();
        // 检查响应的结构
        $I->seeResponseJsonMatchesJsonPath('$.code');
        $I->seeResponseJsonMatchesJsonPath('$.message');
        // 检查响应的数据
        $I->seeResponseContainsJson(['code' => 20004]);
        $I->seeResponseContainsJson(['message' => 'Data validation failed: Email is not a valid email address.']);
    }
 
    // 更新用户,使用错误的邮箱(数据验证失败:{firstErrors}、JSON响应)
    public function updateWithWrongEmailIsXml(ApiTester $I)
    {
        $id = 1;
        $data = [
            'email' => '111111',
            'password' => '111111',
            'status' => 0,
        ];
        $I->haveHttpHeader('Accept', 'application/xml; version=' . $I->getMinorPatch() . '');
        $I->sendPUT('/users/' . $id, $data);
        $I->seeResponseCodeIs(HttpCode::UNPROCESSABLE_ENTITY); // 422
        $I->seeResponseIsXml();
        // 检查响应的结构
        $I->seeXmlResponseMatchesXpath('//code');
        $I->seeXmlResponseMatchesXpath('//message');
        // 检查响应的数据
        $I->seeXmlResponseIncludes(Xml::toXml(['code' => 20004]));
        $I->seeXmlResponseIncludes(Xml::toXml(['message' => 'Data validation failed: Email is not a valid email address.']));
    }
 
    // 更新用户,使用已经存在的字段值(数据验证失败:{firstErrors}、JSON响应)
    public function updateWithExistFieldsIsJson(ApiTester $I)
    {
        $id = 1;
        $data = [
            'email' => 'nicolas.dianna@hotmail.com',
            'password' => '111111',
            'status' => 0,
        ];
        $I->haveHttpHeader('Accept', 'application/json; version=' . $I->getMinorPatch() . '');
        $I->sendPUT('/users/' . $id, $data);
        $I->seeResponseCodeIs(HttpCode::UNPROCESSABLE_ENTITY); // 422
        $I->seeResponseIsJson();
        // 检查响应的结构
        $I->seeResponseJsonMatchesJsonPath('$.code');
        $I->seeResponseJsonMatchesJsonPath('$.message');
        // 检查响应的数据
        $I->seeResponseContainsJson(['code' => 20004]);
        $I->seeResponseContainsJson(['message' => 'Data validation failed: Email "nicolas.dianna@hotmail.com" has already been taken.']);
    }
 
    // 更新用户,使用已经存在的字段值(数据验证失败:{firstErrors}、JSON响应)
    public function updateWithExistFieldsIsXml(ApiTester $I)
    {
        $id = 1;
        $data = [
            'email' => 'nicolas.dianna@hotmail.com',
            'password' => '111111',
            'status' => 0,
        ];
        $I->haveHttpHeader('Accept', 'application/xml; version=' . $I->getMinorPatch() . '');
        $I->sendPUT('/users/' . $id, $data);
        $I->seeResponseCodeIs(HttpCode::UNPROCESSABLE_ENTITY); // 422
        $I->seeResponseIsXml();
        // 检查响应的结构
        $I->seeXmlResponseMatchesXpath('//code');
        $I->seeXmlResponseMatchesXpath('//message');
        // 检查响应的数据
        $I->seeXmlResponseIncludes(Xml::toXml(['code' => 20004]));
        $I->seeXmlResponseIncludes(Xml::toXml(['message' => 'Data validation failed: Email "nicolas.dianna@hotmail.com" has already been taken.']));
    }
 
    // 更新用户,使用超出范围的状态值(数据验证失败:{firstErrors}、JSON响应)
    public function updateWithNotRangeStatusIsJson(ApiTester $I)
    {
        $id = 1;
        $data = [
            'email' => '111111@163.com',
            'password' => '111111',
            'status' => 5,
        ];
        $I->haveHttpHeader('Accept', 'application/json; version=' . $I->getMinorPatch() . '');
        $I->sendPUT('/users/' . $id, $data);
        $I->seeResponseCodeIs(HttpCode::UNPROCESSABLE_ENTITY); // 422
        $I->seeResponseIsJson();
        // 检查响应的结构
        $I->seeResponseJsonMatchesJsonPath('$.code');
        $I->seeResponseJsonMatchesJsonPath('$.message');
        // 检查响应的数据
        $I->seeResponseContainsJson(['code' => 20004]);
        $I->seeResponseContainsJson(['message' => 'Data validation failed: Status is invalid.']);
    }
 
    // 更新用户,使用超出范围的状态值(数据验证失败:{firstErrors}、JSON响应)
    public function updateWithNotRangeStatusIsXml(ApiTester $I)
    {
        $id = 1;
        $data = [
            'email' => '111111@163.com',
            'password' => '111111',
            'status' => 5,
        ];
        $I->haveHttpHeader('Accept', 'application/xml; version=' . $I->getMinorPatch() . '');
        $I->sendPUT('/users/' . $id, $data);
        $I->seeResponseCodeIs(HttpCode::UNPROCESSABLE_ENTITY); // 422
        $I->seeResponseIsXml();
        // 检查响应的结构
        $I->seeXmlResponseMatchesXpath('//code');
        $I->seeXmlResponseMatchesXpath('//message');
        // 检查响应的数据
        $I->seeXmlResponseIncludes(Xml::toXml(['code' => 20004]));
        $I->seeXmlResponseIncludes(Xml::toXml(['message' => 'Data validation failed: Status is invalid.']));
    }
 
}
 

27. Run the tests to get detailed output. You can see a step-by-step behavior report, which matches expectations.

Bash
vendor/bin/codecept run --steps -- -c api

Plaintext
UpdateCest: Update is json
Signature: api\tests\user\UpdateCest:updateIsJson
Test: tests\api\user\UpdateCest.php:updateIsJson
Scenario --
 I get minor patch
 I have http header "Accept","application/json; version=0.0"
 I send put "/users/1",{"email":"111111@163.com","password":"111111","status":0}
 I see response code is 200
 I see response is json
 I see response json matches json path "$.code"
 I see response json matches json path "$.message"
 I see response json matches json path "$.data"
 I see response json matches json path "$.data.email"
 I see response json matches json path "$.data.status"
 I see response contains json {"code":10000,"message":"Update user success","data":{"email":"111111@163.com","status...}
 PASSED

UpdateCest: Update is xml
Signature: api\tests\user\UpdateCest:updateIsXml
Test: tests\api\user\UpdateCest.php:updateIsXml
Scenario --
 I get minor patch
 I have http header "Accept","application/xml; version=0.0"
 I send put "/users/1",{"email":"111111@163.com","password":"111111","status":0}
 I see response code is 200
 I see response is xml
 I see xml response matches xpath "//code"
 I see xml response matches xpath "//message"
 I see xml response matches xpath "//data"
 I see xml response matches xpath "//data//email"
 I see xml response matches xpath "//data//status"
 I see xml response includes "DOMDocument"
 I see xml response includes "DOMDocument"
 I see xml response includes "DOMDocument"
 I see xml response includes "DOMDocument"
 PASSED

UpdateCest: Update with not exist id is json
Signature: api\tests\user\UpdateCest:updateWithNotExistIdIsJson
Test: tests\api\user\UpdateCest.php:updateWithNotExistIdIsJson
Scenario --
 I get minor patch
 I have http header "Accept","application/json; version=0.0"
 I send put "/users/9999",{"email":"111111@163.com","password":"111111","status":0}
 I see response code is 404
 I see response is json
 I see response json matches json path "$.code"
 I see response json matches json path "$.message"
 I see response contains json {"code":20002}
 I see response contains json {"message":"User ID: 9999, does not exist"}
 PASSED

UpdateCest: Update with not exist id is xml
Signature: api\tests\user\UpdateCest:updateWithNotExistIdIsXml
Test: tests\api\user\UpdateCest.php:updateWithNotExistIdIsXml
Scenario --
 I get minor patch
 I have http header "Accept","application/xml; version=0.0"
 I send put "/users/9999",{"email":"111111@163.com","password":"111111","status":0}
 I see response code is 404
 I see response is xml
 I see xml response matches xpath "//code"
 I see xml response matches xpath "//message"
 I see xml response includes "DOMDocument"
 I see xml response includes "DOMDocument"
 PASSED

UpdateCest: Update with empty fields is json
Signature: api\tests\user\UpdateCest:updateWithEmptyFieldsIsJson
Test: tests\api\user\UpdateCest.php:updateWithEmptyFieldsIsJson
Scenario --
 I get minor patch
 I have http header "Accept","application/json; version=0.0"
 I send put "/users/1",[]
 I see response code is 422
 I see response is json
 I see response json matches json path "$.code"
 I see response json matches json path "$.message"
 I see response contains json {"code":20004}
 I see response contains json {"message":"Data validation failed: Email cannot be blank."}
 PASSED

UpdateCest: Update with empty fields is xml
Signature: api\tests\user\UpdateCest:updateWithEmptyFieldsIsXml
Test: tests\api\user\UpdateCest.php:updateWithEmptyFieldsIsXml
Scenario --
 I get minor patch
 I have http header "Accept","application/xml; version=0.0"
 I send put "/users/1",[]
 I see response code is 422
 I see response is xml
 I see xml response matches xpath "//code"
 I see xml response matches xpath "//message"
 I see xml response includes "DOMDocument"
 I see xml response includes "DOMDocument"
 PASSED

UpdateCest: Update with wrong email is json
Signature: api\tests\user\UpdateCest:updateWithWrongEmailIsJson
Test: tests\api\user\UpdateCest.php:updateWithWrongEmailIsJson
Scenario --
 I get minor patch
 I have http header "Accept","application/json; version=0.0"
 I send put "/users/1",{"email":"111111","password":"111111","status":0}
 I see response code is 422
 I see response is json
 I see response json matches json path "$.code"
 I see response json matches json path "$.message"
 I see response contains json {"code":20004}
 I see response contains json {"message":"Data validation failed: Email is not a valid email address."}
 PASSED

UpdateCest: Update with wrong email is xml
Signature: api\tests\user\UpdateCest:updateWithWrongEmailIsXml
Test: tests\api\user\UpdateCest.php:updateWithWrongEmailIsXml
Scenario --
 I get minor patch
 I have http header "Accept","application/xml; version=0.0"
 I send put "/users/1",{"email":"111111","password":"111111","status":0}
 I see response code is 422
 I see response is xml
 I see xml response matches xpath "//code"
 I see xml response matches xpath "//message"
 I see xml response includes "DOMDocument"
 I see xml response includes "DOMDocument"
 PASSED

UpdateCest: Update with exist fields is json
Signature: api\tests\user\UpdateCest:updateWithExistFieldsIsJson
Test: tests\api\user\UpdateCest.php:updateWithExistFieldsIsJson
Scenario --
 I get minor patch
 I have http header "Accept","application/json; version=0.0"
 I send put "/users/1",{"email":"nicolas.dianna@hotmail.com","password":"111111","status":0}
 I see response code is 422
 I see response is json
 I see response json matches json path "$.code"
 I see response json matches json path "$.message"
 I see response contains json {"code":20004}
 I see response contains json {"message":"Data validation failed: Email "nicolas.dianna@hotmail.com" has already bee...}
 PASSED

UpdateCest: Update with exist fields is xml
Signature: api\tests\user\UpdateCest:updateWithExistFieldsIsXml
Test: tests\api\user\UpdateCest.php:updateWithExistFieldsIsXml
Scenario --
 I get minor patch
 I have http header "Accept","application/xml; version=0.0"
 I send put "/users/1",{"email":"nicolas.dianna@hotmail.com","password":"111111","status":0}
 I see response code is 422
 I see response is xml
 I see xml response matches xpath "//code"
 I see xml response matches xpath "//message"
 I see xml response includes "DOMDocument"
 I see xml response includes "DOMDocument"
 PASSED

UpdateCest: Update with not range status is json
Signature: api\tests\user\UpdateCest:updateWithNotRangeStatusIsJson
Test: tests\api\user\UpdateCest.php:updateWithNotRangeStatusIsJson
Scenario --
 I get minor patch
 I have http header "Accept","application/json; version=0.0"
 I send put "/users/1",{"email":"111111@163.com","password":"111111","status":5}
 I see response code is 422
 I see response is json
 I see response json matches json path "$.code"
 I see response json matches json path "$.message"
 I see response contains json {"code":20004}
 I see response contains json {"message":"Data validation failed: Status is invalid."}
 PASSED

UpdateCest: Update with not range status is xml
Signature: api\tests\user\UpdateCest:updateWithNotRangeStatusIsXml
Test: tests\api\user\UpdateCest.php:updateWithNotRangeStatusIsXml
Scenario --
 I get minor patch
 I have http header "Accept","application/xml; version=0.0"
 I send put "/users/1",{"email":"111111@163.com","password":"111111","status":5}
 I see response code is 422
 I see response is xml
 I see xml response matches xpath "//code"
 I see xml response matches xpath "//message"
 I see xml response includes "DOMDocument"
 I see xml response includes "DOMDocument"
 PASSED

28. DELETE /users/{id}: Delete a user. Copy \api\tests\api\user\ViewCest.php to \api\tests\api\user\DeleteCest.php. Delete user (user ID: {id}, does not exist / successfully deleting user). Edit.

PHP
<?php
namespace api\tests\user;
 
use Yii;
use api\tests\ApiTester;
use Codeception\Util\HttpCode;
use Codeception\Util\Xml;
use api\fixtures\UserFixture;
 
class DeleteCest
{
    public function _before(ApiTester $I)
    {
    }
 
    public function _after(ApiTester $I)
    {
    }
 
    /**
     * @return array
     */
    public function _fixtures()
    {
        return [
            'user' => [
                'class' => UserFixture::className(),
                'dataFile' => codecept_data_dir() . 'user.php'
            ]
        ];
    }
 
    // 删除用户(删除用户成功、JSON响应)
    public function deleteIsJson(ApiTester $I)
    {
        $id = 1;
        $I->haveHttpHeader('Accept', 'application/json; version=' . $I->getMinorPatch() . '');
        $I->sendDELETE('/users/' . $id);
        $I->seeResponseCodeIs(HttpCode::OK); // 200
        $I->seeResponseIsJson();
        // 检查响应的结构
        $I->seeResponseJsonMatchesJsonPath('$.code');
        $I->seeResponseJsonMatchesJsonPath('$.message');
        // 检查响应的数据
        $I->seeResponseContainsJson([
            'code' => 10000,
            'message' => Yii::t('success', '10005'),
        ]);
    }
 
    // 删除用户(删除用户成功、XML响应)
    public function deleteIsXml(ApiTester $I)
    {
        $id = 1;
        $I->haveHttpHeader('Accept', 'application/xml; version=' . $I->getMinorPatch() . '');
        $I->sendDELETE('/users/' . $id);
        $I->seeResponseCodeIs(HttpCode::OK); // 200
        $I->seeResponseIsXml();
        // 检查响应的结构
        $I->seeXmlResponseMatchesXpath('//code');
        $I->seeXmlResponseMatchesXpath('//message');
        // 检查响应的数据
        $I->seeXmlResponseIncludes(Xml::toXml(['code' => 10000]));
        $I->seeXmlResponseIncludes(Xml::toXml(['message' => Yii::t('success', '10005')]));
    }
 
    // 获取用户详情,使用不存在的ID(用户ID:{id},不存在、JSON响应)
    public function deleteWithNotExistIdIsJson(ApiTester $I)
    {
        $id = 9999;
        $I->haveHttpHeader('Accept', 'application/json; version=' . $I->getMinorPatch() . '');
        $I->sendDELETE('/users/' . $id);
        $I->seeResponseCodeIs(HttpCode::NOT_FOUND); // 404
        $I->seeResponseIsJson();
        // 检查响应的结构
        $I->seeResponseJsonMatchesJsonPath('$.code');
        $I->seeResponseJsonMatchesJsonPath('$.message');
        // 检查响应的数据
        $I->seeResponseContainsJson([
            'code' => 20002,
            'message' => Yii::t('error', Yii::t('error', Yii::t('error', '20002'), ['id' => $id])),
        ]);
    }
 
    // 获取用户详情,使用不存在的ID(用户ID:{id},不存在、XML响应)
    public function deleteWithNotExistIdIsXml(ApiTester $I)
    {
        $id = 9999;
        $I->haveHttpHeader('Accept', 'application/xml; version=' . $I->getMinorPatch() . '');
        $I->sendDELETE('/users/' . $id);
        $I->seeResponseCodeIs(HttpCode::NOT_FOUND); // 404
        $I->seeResponseIsXml();
        // 检查响应的结构
        $I->seeXmlResponseMatchesXpath('//code');
        $I->seeXmlResponseMatchesXpath('//message');
        // 检查响应的数据
        $I->seeXmlResponseIncludes(Xml::toXml(['code' => 20002]));
        $I->seeXmlResponseIncludes(Xml::toXml(['message' => Yii::t('error', Yii::t('error', Yii::t('error', '20002'), ['id' => $id]))]));
    }
}
 
 

29. Run the tests, testing only api user/CreateCest.php. Get detailed output. You can see a step-by-step behavior report, which matches expectations, as shown in Figure 9.

Run the tests, testing only api user/CreateCest.php. Get detailed output. You can see a step-by-step behavior report, which matches expectations
Figure 9
Bash
vendor/bin/codecept run --steps -- -c api api user/DeleteCest.php

Plaintext
Codeception PHP Testing Framework v2.4.1
Powered by PHPUnit 7.1.2 by Sebastian Bergmann and contributors.

Api\tests.api Tests (4) ------------------------------------------------------------------------------------------------
DeleteCest: Delete is json
Signature: api\tests\user\DeleteCest:deleteIsJson
Test: tests\api\user\DeleteCest.php:deleteIsJson
Scenario --
 I get minor patch
 I have http header "Accept","application/json; version=0.0"
 I send delete "/users/1"
 I see response code is 200
 I see response is json
 I see response json matches json path "$.code"
 I see response json matches json path "$.message"
 I see response contains json {"code":10000,"message":"Delete user success"}
 PASSED

DeleteCest: Delete is xml
Signature: api\tests\user\DeleteCest:deleteIsXml
Test: tests\api\user\DeleteCest.php:deleteIsXml
Scenario --
 I get minor patch
 I have http header "Accept","application/xml; version=0.0"
 I send delete "/users/1"
 I see response code is 200
 I see response is xml
 I see xml response matches xpath "//code"
 I see xml response matches xpath "//message"
 I see xml response includes "DOMDocument"
 I see xml response includes "DOMDocument"
 PASSED

DeleteCest: Delete with not exist id is json
Signature: api\tests\user\DeleteCest:deleteWithNotExistIdIsJson
Test: tests\api\user\DeleteCest.php:deleteWithNotExistIdIsJson
Scenario --
 I get minor patch
 I have http header "Accept","application/json; version=0.0"
 I send delete "/users/9999"
 I see response code is 404
 I see response is json
 I see response json matches json path "$.code"
 I see response json matches json path "$.message"
 I see response contains json {"code":20002,"message":"User ID: 9999, does not exist"}
 PASSED

DeleteCest: Delete with not exist id is xml
Signature: api\tests\user\DeleteCest:deleteWithNotExistIdIsXml
Test: tests\api\user\DeleteCest.php:deleteWithNotExistIdIsXml
Scenario --
 I get minor patch
 I have http header "Accept","application/xml; version=0.0"
 I send delete "/users/9999"
 I see response code is 404
 I see response is xml
 I see xml response matches xpath "//code"
 I see xml response matches xpath "//message"
 I see xml response includes "DOMDocument"
 I see xml response includes "DOMDocument"
 PASSED

------------------------------------------------------------------------------------------------------------------------


Time: 1.25 seconds, Memory: 16.00MB

OK (4 tests, 24 assertions)

30. OPTIONS /users: Show the verbs supported by the endpoint /users; OPTIONS /users/{id}: Show the verbs supported by the endpoint /users/{id}. Copy \api\tests\api\user\IndexCest.php to \api\tests\api\user\OptionsCest.php. Edit.

PHP
<?php
namespace api\tests\user;
 
use Yii;
use api\tests\ApiTester;
use Codeception\Util\HttpCode;
use Codeception\Util\Xml;
use api\fixtures\UserFixture;
 
class OptionsCest
{
    public function _before(ApiTester $I)
    {
    }
 
    public function _after(ApiTester $I)
    {
    }
 
    /**
     * @return array
     */
    public function _fixtures()
    {
        return [
            'user' => [
                'class' => UserFixture::className(),
                'dataFile' => codecept_data_dir() . 'user.php'
            ]
        ];
    }
 
    // 显示关于末端 /users 支持的动词(JSON响应)
    public function optionsIsJson(ApiTester $I)
    {
        $I->haveHttpHeader('Accept', 'application/json; version=' . $I->getMinorPatch() . '');
        $I->sendOPTIONS('/users');
        $I->seeResponseCodeIs(HttpCode::OK); // 200
        // 检查响应的数据
        $I->seeHttpHeader('Allow', 'GET, POST, HEAD, OPTIONS');
        $I->seeResponseEquals('');
    }
 
    // 显示关于末端 /users 支持的动词(XML响应)
    public function optionsIsXml(ApiTester $I)
    {
        $I->haveHttpHeader('Accept', 'application/xml; version=' . $I->getMinorPatch() . '');
        $I->sendOPTIONS('/users');
        $I->seeResponseCodeIs(HttpCode::OK); // 200
        // 检查响应的数据
        $I->seeHttpHeader('Allow', 'GET, POST, HEAD, OPTIONS');
        $I->seeResponseEquals('');
    }
 
    // 显示关于末端 /users/{id} 支持的动词(JSON响应)
    public function optionsIdIsJson(ApiTester $I)
    {
        $id = 1;
        $I->haveHttpHeader('Accept', 'application/json; version=' . $I->getMinorPatch() . '');
        $I->sendOPTIONS('/users/' . $id);
        $I->seeResponseCodeIs(HttpCode::OK); // 200
        // 检查响应的数据
        $I->seeHttpHeader('Allow', 'GET, PUT, PATCH, DELETE, HEAD, OPTIONS');
        $I->seeResponseEquals('');
    }
 
    // 显示关于末端 /users/{id} 支持的动词(XML响应)
    public function optionsIdIsXml(ApiTester $I)
    {
        $id = 1;
        $I->haveHttpHeader('Accept', 'application/xml; version=' . $I->getMinorPatch() . '');
        $I->sendOPTIONS('/users/' . $id);
        $I->seeResponseCodeIs(HttpCode::OK); // 200
        // 检查响应的数据
        $I->seeHttpHeader('Allow', 'GET, PUT, PATCH, DELETE, HEAD, OPTIONS');
        $I->seeResponseEquals('');
    }
}
 

31. Run the tests, testing only api user/OptionsCest.php. Get detailed output. You can see a step-by-step behavior report, which matches expectations.

Bash
vendor/bin/codecept run --steps -- -c api api user/OptionsCest.php

Plaintext
Codeception PHP Testing Framework v2.4.1
Powered by PHPUnit 7.1.2 by Sebastian Bergmann and contributors.

Api\tests.api Tests (4) ------------------------------------------------------------------------------------------------
OptionsCest: Options is json
Signature: api\tests\user\OptionsCest:optionsIsJson
Test: tests\api\user\OptionsCest.php:optionsIsJson
Scenario --
 I get minor patch
 I have http header "Accept","application/json; version=0.0"
 I send options "/users"
 I see response code is 200
 I see http header "Allow","GET, POST, HEAD, OPTIONS"
 I see response equals ""
 PASSED

OptionsCest: Options is xml
Signature: api\tests\user\OptionsCest:optionsIsXml
Test: tests\api\user\OptionsCest.php:optionsIsXml
Scenario --
 I get minor patch
 I have http header "Accept","application/xml; version=0.0"
 I send options "/users"
 I see response code is 200
 I see http header "Allow","GET, POST, HEAD, OPTIONS"
 I see response equals ""
 PASSED

OptionsCest: Options id is json
Signature: api\tests\user\OptionsCest:optionsIdIsJson
Test: tests\api\user\OptionsCest.php:optionsIdIsJson
Scenario --
 I get minor patch
 I have http header "Accept","application/json; version=0.0"
 I send options "/users/1"
 I see response code is 200
 I see http header "Allow","GET, PUT, PATCH, DELETE, HEAD, OPTIONS"
 I see response equals ""
 PASSED

OptionsCest: Options id is xml
Signature: api\tests\user\OptionsCest:optionsIdIsXml
Test: tests\api\user\OptionsCest.php:optionsIdIsXml
Scenario --
 I get minor patch
 I have http header "Accept","application/xml; version=0.0"
 I send options "/users/1"
 I see response code is 200
 I see http header "Allow","GET, PUT, PATCH, DELETE, HEAD, OPTIONS"
 I see response equals ""
 PASSED

------------------------------------------------------------------------------------------------------------------------


Time: 1.19 seconds, Memory: 14.00MB

OK (4 tests, 12 assertions)

32. Run all sample tests. The results match expectations, as shown in Figure 10.

Run all sample tests. The results match expectations
Figure 10
Bash
vendor/bin/codecept run

系列导航

关于作者 · 持续学习与技术实践

我是一名拥有 15 年以上开发经验的技术从业者,自 2013 年起持续运营个人技术博客,记录工作与个人项目中遇到的真实问题,以及解决问题过程中的探索、实践和思考。

除了技术写作,我也在持续开发和维护自己的独立项目,探索新技术和新工具在实际场景中的应用。我始终相信,没有不值得去解决的问题,也没有不值得去学习的技术。

如果这篇文章对你有所帮助,欢迎浏览博客中的其他文章,也欢迎交流技术经验与想法。

关于我  ·  GitHub  ·  邮件联系