支持的测试类型

Codeception 支持三种测试类型,单元、功能和验收测试。

测试类型 单元测试( Unit Tests) 功能测试(Functional Tests) 验收测试(Acceptance Tests)
测试范围 单个 PHP 类 PHP 框架(路由、控制器等) 浏览器中的页面(Chrome、Firefox 或 PhpBrowser)
测试计算机需要访问项目的 PHP 文件 是的 是的
需要网络服务器 是的
脚本 是的
需要其他软件 没有 没有 用于浏览器测试的Selenium
速度
配置文件 unit.suite.yml functional.suite.yml acceptance.suite.yml
优点 1.最快的测试; 2.能把测试覆盖到特别刁钻的程序逻辑上, 这是 functional 或者 acceptance 所做不到的; 3.允许你测试最核心代码, 确定核心代码的健壮性; 4.写单元测试的程序要都是好程序员 。 1.跟 Acceptance tests 类似, 但是少了打开浏览器来渲染, 速度快多了; 2.能提供更详细的分析, 如数据库或者 email; 3.可读性很强, 虽然没法让测试人员看到打开浏览器模拟人工测试, 但是还是可以让别人信服; 4.比较稳定, 只有当大规模的代码变更, 或者把代码从一个框架转移到另一个框架的时候, 才会有影响. 1.可用来测试任何网站; 2.完全基于浏览器, 可以测试 Javascript 甚至是 ajax 请求; 3.可以把运行状态给 产品经理 或者 客户看, 让人信服; 4.不需要多余的配置, 对 App 源码修改要求最少, 代码适应性好, 可以当成整个应用来测试, 不在乎内部实现.
缺点 1.因为是单元测试, 会把代码分为多个小单元单独测试, 但是各个单元之间的对接测试不到; 2.对代码的修改非常敏感, 很多项目的 test 最后没用上就是因为测试跟不上业务逻辑代码的修改. 1.无法测试 javascript 和 ajax; 2.因为使用代码相对简单的模拟一个浏览器请求, 测试的可行度, 或者说完整性, 会相对较差; 3.需要一个框架的支持; 1.测试速度缓慢, 因为需要运行在浏览器和真实的数据库上; 2.相比单元测试, 做不到完全的测试, 有些细微的逻辑可能会错过; 3.在运行的时候有时候会发生不可控的事情, 因为浏览器的渲染, javascript 的运行, 有时候会有意想不到的情况发生. 4.再一次强调, 此测试会非常慢;

安装

单个项目:

composer require "codeception/codeception" --dev

如果想全局使用,可以直接下载可执行文件,然后把文件放到php执行文件所在的目录。

wget https://codeception.com/codecept.phar

快速全局使用:

如果是windows系统,可以把下面代码放入codecept.bat,然后把这个文件放到codecept.phar同级。

@php "%~dp0codecept.phar" %*

Mac和Linux更简单了,直接设置一个别名即可:

alias codecept='php vendor/bin/codecept'

然后就可以愉快的全局使用了。

PS D:WWWlaravel-test> codecept
Codeception 4.1.31

Usage:
  command [options] [arguments]

Options:
  -h, --help             Display this help message
  -q, --quiet            Do not output any message
  -V, --version          Display this application version
      --ansi             Force ANSI output
      --no-ansi          Disable ANSI output
  -n, --no-interaction   Do not ask any interactive question
  -c, --config[=CONFIG]  Use custom path for config
  -v|vv|vvv, --verbose   Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

Available commands:
  build                 Generates base classes for all suites
  clean                 Recursively cleans log and generated code
  console               Launches interactive test console
  dry-run               Prints step-by-step scenario-driven test or a feature
  help                  Display help for a command
  init                  Creates test suites by a template
  list                  List commands
  run                   Runs the test suites
  self-update           [selfupdate] Upgrade D:laragonbinphpphp-7.4.28-Win32-vc15-x64codecept.phar to the latest version
 config
  config:validate       Validates and prints config to screen
 generate
  generate:cept         Generates empty Cept file in suite
  generate:cest         Generates empty Cest file in suite
  generate:environment  Generates empty environment config
  generate:feature      Generates empty feature file in suite
  generate:groupobject  Generates Group subscriber
  generate:helper       Generates new helper
  generate:pageobject   Generates empty PageObject class
  generate:scenarios    Generates text representation for all scenarios
  generate:snapshot     Generates empty Snapshot class
  generate:stepobject   Generates empty StepObject class
  generate:suite        Generates new test suite
  generate:test         Generates empty unit test file in suite
 gherkin
  gherkin:snippets      Fetches empty steps from feature files of suite and prints code snippets for them
  gherkin:steps         Prints all defined feature steps

初始化

codecept bootstrap

生成的目录文件结构如下:

D:WWWLaravel-testtests
├─acceptance
├─Feature
├─functional
├─Unit
├─_data
├─_output
└─_support
    ├─Helper
    └─_generated

测试

验收测试

我们先设想这样一个场景:当技术人员开发完毕, 其客户, 产品经理, 或者是测试人员, 他们怎么确定产品的可用性? 一般情况下, 他们都是执行以下几个步骤进行测试:

  • 打开浏览器;

  • 输入 url;

  • 看到一些信息, 并确定了这个页面是可用的;

  • 点击某个 url;

  • 填写表单, 并提交表单, 看到了某些信息, 并确定此功能是可用的。

这种测试方式我们称之为 手动测试, 或 人工测试, 与其相反的是 自动化测试, Codeception 的 Acceptance Tests 会利用浏览器的编程接口, 做到以上的 人工测试 涉及到的步骤完全自动化, 大大节省了人工成本.

生成一个验收测试:

D:WWWlaravel-test>codecept generate:cest acceptance First
Test was created in D:WWWlaravel-testtestsacceptanceFirstCest.php

具体代码

<?php

class FirstCest
{
    public function _before(AcceptanceTester $I)
    {
        echo 'Test Begin:';
    }

    // tests
    public function tryToTest(AcceptanceTester $I)
    {
        $I->amOnPage('/index/about');
        $I->see('我的介绍');
    }
}

运行测试

D:WWWlaravel-test>codecept run --steps

可以看到验收测试通过。现在我们把文本从“我的介绍”改成“我的11介绍”,理论上这时候测试应该通过不了,看看测试出错是啥情况。果然,报告验收错误。

功能测试

功能测试模拟一个 web 请求 (模拟 $_GET 和 $_POST 等变量), 发送给 App, 应用返回 HTML 结果, 在测试的过程中, 可以分析并进行 assert 判定返回的数据, 甚至可以检查数据是否正常的存储到数据库.

函数测试需要有一个测试环境, 几个有名的框架, 像 Laravel 就有现成的 Package 可以用来集成.

共享内存

在功能测试中,与传统方式运行应用程序不同,PHP 应用程序在处理完请求后不会停止。由于所有请求都在一个内存容器中运行,因此它们不是隔离的。因此,如果您发现您的测试在不应该失败时神秘地失败 – 请尝试执行单个测试。这将显示测试是否失败,因为它们在运行期间未被隔离。保持内存清洁,避免内存泄漏,并清理全局和静态变量。

配置

codecept generate:test functional First

配置框架支持特性,例如Laravel的支持:

# D:WWWlaravel-testtestsfunctional.suite.yml


actor: FunctionalTester
modules:
    enabled:
        - Laravel5
        # add a framework module here
        - HelperFunctional
    step_decorators: ~                

还需要安装一些拓展:

codecept init upgrade4

具体代码

public function tryLogin(FunctionalTester $I)
{
    $I->amOnPage('/');
    $I->click('Sign Up');
    $I->submitForm('#signup', array('username' => 'MilesDavis', 'email' => 'miles@davis.com'));
    $I->see('Thank you for Signing Up!');
    $I->seeEmailSent('miles@davis.com', 'Thank you for registration');
    $I->seeInDatabase('users', array('email' => 'miles@davis.com'));  # 不是所有框架都有这个方法
}

单元与集成测试

单元测试(又称为模块测试, Unit Testing)是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作, 当 functional 或者 acceptance 测试都检查不到 最小单位 的逻辑时, 还能通过 单元测试 确认深藏在代码里面的某些功能仍然可用, 单元测试能消除程序单元的不可靠性.

Codeception 的单元测试功能是基于 PHPUnit 之上的, 你可以照样写 PHPUnit 的测试代码, Codeception 一样能运行.

Codeception 在 PHPUnit 的基础上提供了一系列工具能让单元测试更加简单, 代码可读性更高. 单元测试是最复杂最繁琐的测试, 并且是会跟着业务逻辑代码的改变而改变, 在实际开发中技术人员会经常因为需求、业务的变更而修改单元测试, 提高其可读性和易用性可以帮助相关人员更加快速的跟上一切变化.

codecept generate:test unit First

如果要测试数据库模块,需要先安装Db模块,并配置。

composer require codeception/module-db --dev

还要进行配置:

# D:WWWlaravel-testcodeception.yml
...
params:
    - .env # load params from environment vars
modules:
    config:
        Db:
            dsn: "mysql:host=%DB_HOST%;dbname=%DB_DATABASE%"
            user: "%DB_USERNAME%"
            password: "%DB_PASSWORD%"
            populate: false
            cleanup: false
            reconnect: true

具体代码:

public function testUpdateUser()
{
    $id = $this->tester->haveRecord('users', ['name' => 'YSP Conn AAA', 'email' => 'bill@qq.com', 'password' => 'sadfasdd',]);
    // access model
    $user = User::find($id);
    $user->name = 'bill';
    $user->save();
    // verify data was saved using framework methods
    $this->tester->seeRecord('users', ['name' => 'bill']);
    $this->tester->dontSeeRecord('users', ['name' => 'YSP Conn AAA']);
}

运行测试:

codecept run unit --steps

接口测试

生成配置:

codecept generate:suite api

REST API

注意:REST API 测试需要安装codeception/module-rest包。

REST Web 服务通过 HTTP 使用标准方法访问:GETPOSTPUTDELETE 。它们允许用户从服务接收和操作实体。访问 Web 服务需要 HTTP 客户端,因此要使用它,您需要设置PhpBrowser模块或框架模块之一。例如,我们可以将Symfony模块用于 Symfony2 应用程序,以便在内部忽略 Web 服务器并测试 Web 服务。

api.suite.yml中配置模块:

REST 模块将根据此配置进行连接PhpBrowser。根据 Web 服务的不同,我们可能会处理 XML 或 JSON 响应。Codeception可以很好地处理这两种数据格式,但是如果您不需要其中一种格式,则可以显式指定将使用模块的JSON或XML部分:

actor: ApiTester
modules:
    enabled:
        - REST:
            url: http://serviceapp/api/v1/
            depends: PhpBrowser
            part: Json

API测试可以是功能性的,可以使用Symfony,Laravel,Zend或任何其他框架模块执行。您将需要稍微更新一下配置:

actor: ApiTester
modules:
    enabled:
        - REST:
            url: /api/v1/
            depends: Laravel5

配置新的测试套件后,我们可以创建第一个示例测试:

codecept generate:cest api CreateUser

它将被称为CreateUserCest.php 。我们需要为每个测试实现一个公共方法。让我们通过 REST API 测试用户的创建。

<?php
class CreateUserCest
{
    // tests
    public function createUserViaAPI(ApiTester $I)
    {
        $I->amHttpAuthenticated('service_user', '123456');
        $I->haveHttpHeader('Content-Type', 'application/x-www-form-urlencoded');
        $I->sendPost('/users', [
          'name' => 'davert', 
          'email' => 'davert@codeception.com'
        ]);
        $I->seeResponseCodeIsSuccessful();
        $I->seeResponseIsJson();
        $I->seeResponseContains('{"result":"ok"}');
        
    }
}

授权

若要授权对外部资源的请求,提供程序通常要求您使用标头进行授权。可以使用haveHttpHeader命令在请求之前设置其他标头:

<?php
$I->haveHttpHeader('api_key', 'special-key');

对于常见的授权模式,请使用下列方法之一:

  • amAWSAuthenticated

  • amBearerAuthenticated

  • amDigestAuthenticated

  • amHttpAuthenticated

  • amNTLMAuthenticated

发送请求

测试中的实际操作仅在发送请求时发生。在请求之前,您可以提供其他 http 标头,这些标头将在下一个请求中用于设置授权或预期的内容格式。

<?php
$I->haveHttpHeader('accept', 'application/json');
$I->haveHttpHeader('content-type', 'application/json');

设置标头后,您可以发送请求。使用sendGet设置数据:

<?php
// pass in query params in second argument
$response = $I->sendGet('/posts', [ 'status' => 'pending' ]);
$I->seeResponseCodeIs(200);
$I->seeResponseIsJson();

要创建或更新数据,您可以使用其他常用方法:

  • sendPost

  • sendPut

  • sendPatch

  • sendDelete

  • sendPatch

使用自定义send方法发送请求:

<?php
$response = $I->send('TRACE', '/posts');

sendAsJson 方法在模块 rest 1.4.1 中引入

如果 API 终端节点接受 JSON,则可以使用带AsJson后缀的send方法自动转换数据。在这种情况下,会发送Content-Type:application/json的标头和响应:

$I->sendPostAsJson('/users', ['name' => 'old name']);
$users = $I->sendGetAsJson('/users');
$I->sendPutAsJson('/users/' . $users[0]['id'], ['name' => 'new name']);
$I->sendDeleteAsJson('/users/' . $users[1]['id']);

要启用带有AsJson后缀的步骤,请在套件配置中启用CodeceptionStepAsJson步骤装饰器:

actor: ApiTester
step_decorators:
    - CodeceptionStepAsJson

重建操作:

codecept build

sendGetAsJson、sendPutAsJson和其他部分作为步骤装饰器实现。

JSON 结构验证

如果我们期望收到JSON响应,我们可以使用JSONPath检查其结构。它的外观和声音都像XPath,但旨在处理JSON数据,但是我们可以将JSON转换为XML并使用XPath来验证结构。这两种方法都是有效的,可以在 REST 模块中使用:

<?php
$I->sendGet('/users');
$I->seeResponseCodeIs(HttpCode::OK); // 200
$I->seeResponseIsJson();
$I->seeResponseJsonMatchesJsonPath('$[0].user.login');
$I->seeResponseJsonMatchesXpath('//user/login');

如果需要验证响应中的字段类型,则可以应用更详细的检查。您可以通过使用 seeResponseMatchesJsonType 操作来执行此操作,在该操作中定义 JSON 响应的结构。

<?php
$I->sendGet('/users/1');
$I->seeResponseCodeIs(HttpCode::OK); // 200
$I->seeResponseIsJson();
$I->seeResponseMatchesJsonType([
    'id' => 'integer',
    'name' => 'string',
    'email' => 'string:email',
    'homepage' => 'string:url|null',
    'created_at' => 'string:date',
    'is_active' => 'boolean'
]);

Codeception使用这种简单而轻量级的定义格式,可以很容易地学习和扩展

使用响应

响应从send*方法返回:

<?php

$users = $I->sendGet('/users');

// alternatively

$users = $I->grabResponse();

当您需要从响应中获取值并在下一个请求中使用它时,可以使用grab*方法。例如grabDataFromResponseByJsonPath,使用允许查询 JSON 以获取值。

<?php
list($id) = $I->grabDataFromResponseByJsonPath('$.id');
$I->sendGet('/pet/' . $id);

验证数据 JSON 响应

上一示例的最后一行验证了响应是否包含提供的字符串。但是,我们不应该依赖它,因为根据内容格式,我们可以使用相同的数据接收不同的结果。我们实际需要的是检查响应是否可以解析,并且它包含我们期望的一些值。在JSON的情况下,我们可以使用seeResponseContainsJson方法。

<?php
// matches {"result":"ok"}'
$I->seeResponseContainsJson(['result' => 'ok']);
// it can match tree-like structures as well
$I->seeResponseContainsJson([
  'user' => [
      'name' => 'davert',
      'email' => 'davert@codeception.com',
      'status' => 'inactive'
  ]
]);

您可能希望对响应执行更复杂的断言。这可以通过在 Helper 类中编写自己的方法来完成。要访问最新的 JSON 响应,您需要获取REST模块的response属性。让我们用seeResponseIsHtml方法进行演示:

<?php
namespace Helper;

class Api extends CodeceptionModule
{
  public function seeResponseIsHtml()
  {
    $response = $this->getModule('REST')->response;
    $this->assertRegExp('~^<!DOCTYPE HTML(.*?)<html>.*?</html>~m', $response);
  }
}

测试文件类型

Codeception支持3种测试格式,之前讲过的基于场景的Cept格式,Codeception也可以执行PHPUnit 单元测试测试文件和Cest格式。

Codeception的cest和cept有什么区别:

他们的格式是唯一的区别: Cept是基于场景的格式, Cest是基于类的格式.

Cest是OOP设计结合了场景驱动测试,如果你想组合一些测试场景到一个中你应该考虑使用Cest格式,下面的例子我们用一个单独的文件测试CRUD操作,但其中有几个测试,每次操作一个。

cest例子:

<?php
class FirstCest
{
    public function _before(AcceptanceTester $I)
    {
    }

    // tests
    public function tryToTest(AcceptanceTester $I)
    {
        $I->wantTo('log in as regular user');
        $I->amOnPage('/login');
        $I->fillField('Username','john');
        $I->fillField('Password','secret');
        $I->click('Login');
        $I->see('Hello john'); 
    }
}

cept例子:

<?php 
$I = new AcceptanceTester($scenario);
$I->wantTo('log in as regular user');
$I->amOnPage('/login');
$I->fillField('Username','john');
$I->fillField('Password','secret');
$I->click('Login');
$I->see('Hello john');

如果驱动版本不对,需要下载对应的工具:

http://chromedriver.storage.googleapis.com/index.html

https://registry.npmmirror.com/binary.html?path=chromedriver/

错误报告

默认情况下,Codeception 使用E_ALL & ~E_STRICT & ~E_DEPRECATED错误报告级别。在功能测试中,您可能希望根据框架的错误策略更改此级别。可以在套件配置文件中设置错误报告级别:

actor: FunctionalTester
...
error_level: E_ALL & ~E_STRICT & ~E_DEPRECATED

error_level也可以在codeception.yml文件中全局设置。为此,您需要指定error_levelsettings 的一部分。有关详细信息,请参阅全局配置。请注意,特定于套件的error_level值将覆盖全局值。

运行测试

通过运行 run 命令开始运行测试:

codecept run

通过第一个参数可以运行一个套件。

codecept run acceptance

指定第二个参数可以运行一个测试,从套件目录指定一个本来路径。

codecept run acceptance SigninCept.php

另外你还可以提供一个完整的测试文件路径:

codecept run tests/acceptance/SigninCept.php

你可以从一个测试类(Cest or 单元测试格式)里执行一个测试:

codecept run tests/acceptance/SignInCest.php:anonymousLogin
codecept run api ExportCest.php:ajaxTask --html

你还可以提供一个目录路径:

codecept run tests/acceptance/backend

上面命令是执行 tests/acceptance/backend 目录里的所有测试。

要执行一组存储不在同目录的测试时,你可以用groups 组织它们。

我们获取详细的输出:

codecept run acceptance --steps
codecept run api -v

测试报告:

你可以通过 –xml 选项生成JUnit XML,通过–html输出HTML报告。

codecept run api  --steps --xml --html myTest.html # 自定义html报告文件名
codecept run api SpiderReportV2Cest.php:stat --html test.html # 指定运行某个测试文件里面的某个方法

上面这个命令将执行所有套件的测试,逐步显示,并且构建将HTML和XML报告存储到tests/_output/目录。

了解所有可用的选项运行这个命令:

php codecept.phar help run

使用模块

例如想使用db模块功能,需要获取相应driver

DB相关操作参考文档:https://codeception.com/docs/modules/Db

# 使用redis使用session
public function getLoginSession()
{
   // 这里只需要设置redis的session值即可,程序dev也从redis获取session值,文件的时候可能是docker与windows之间有些不兼容的地方还是怎么的
   // 使用文件作为session驱动的时候不能识别session信息
   $key = 'wsoc' . Api::SESSION_ID;
   $redis = $this->getModule('Redis');
   $session = file_get_contents(__DIR__ . '/../../' . Api::SESSION_ID . '.txt'); //设置session id
   $redis->haveInRedis('string', $key, $session);
}

拓展

PHP自动测试框架Top 10 – 简书 (jianshu.com)

https://wiki.apipost.cn/document/00091641-1e36-490d-9caf-3e47cd38bcde/f7e8e8a3-0c6d-48ce-af23-cd1460915a52)

所有用户都可以去薅羊毛,192元充值200元话费!先到先得!导航栏话费充值,正规可靠,快充慢充自由选择。
欧阳逸资源站 » Codeception快速开始测试

发表评论