codeception测试使用框架模块Module
使用模块Module
使用框架模块
Codeception目前含有的模块有这些(最新的当前codeception版本:3.1.2):
- \Helper\Unit
- \Helper\Acceptance
- \Helper\Functional
- Asserts ( https://codeception.com/docs/modules/Asserts )
- PhpBrowser ( https://codeception.com/docs/modules/PhpBrowser )
- REST ( https://codeception.com/docs/modules/REST )
- Db ( https://codeception.com/docs/modules/Db )
- SOAP ( https://codeception.com/docs/modules/SOAP )
- Filesystem ( https://codeception.com/docs/modules/Filesystem )
- WebDriver ( https://codeception.com/docs/modules/WebDriver )
- Laravel5 ( https://codeception.com/docs/modules/Laravel5 )
- Lumen ( https://codeception.com/docs/modules/Lumen )
- Symfony ( https://codeception.com/docs/modules/Symfony )
- Doctrine2 ( https://codeception.com/docs/modules/Doctrine2 )
- Yii2 ( https://codeception.com/docs/modules/Yii2 )
- ZF2 ( https://codeception.com/docs/modules/ZF2 )
- Phalcon ( https://codeception.com/docs/modules/Phalcon )
- Redis ( https://codeception.com/docs/modules/Redis )
- MongoDb ( https://codeception.com/docs/modules/MongoDb )
- Memcache ( https://codeception.com/docs/modules/Memcache )
- FTP ( https://codeception.com/docs/modules/FTP )
- Cli ( https://codeception.com/docs/modules/Cli )
- Queue ( https://codeception.com/docs/modules/Queue )
- Sequence ( https://codeception.com/docs/modules/Sequence )
- DataFactory ( https://codeception.com/docs/modules/DataFactory )
- Apc ( https://codeception.com/docs/modules/Apc )
- AMQP ( https://codeception.com/docs/modules/AMQP )
- ZendExpressive ( https://codeception.com/docs/modules/ZendExpressive )
具体想看当前版本安装的codecept.phar包含了哪些模块,可以通过PhpStorm等IDE工具看包里的源代码:
模块定义文件在路径: codecept.phar > src > Module 目录下。
想查询哪个模块的具体用法,有哪些具体参数,可以点击查看模块源文件。
比如查看Db模块信息:
查看Db模块的配置有哪些参数,和哪些参数是必须的:
查看源码:
<?php class Db extends CodeceptionModule implements DbInterface { /** * @var array */ protected $config = [ 'populate' => false, 'cleanup' => false, 'reconnect' => false, 'waitlock' => 0, 'dump' => null, 'populator' => null, ]; /** * @var array */ protected $requiredFields = ['dsn', 'user', 'password'];
$config 就是配置参数,$requiredFields 就是必须填写的参数。
数据库连接配置参考:
* ## Example * * modules: * enabled: * - Db: * dsn: 'mysql:host=localhost;dbname=testdb' * user: 'root' * password: '' * dump: 'tests/_data/dump.sql' * populate: true * cleanup: true * reconnect: true * waitlock: 10 * ssl_key: '/path/to/client-key.pem' * ssl_cert: '/path/to/client-cert.pem' * ssl_ca: '/path/to/ca-cert.pem' * ssl_verify_server_cert: false * ssl_cipher: 'AES256-SHA' * initial_queries: * - 'CREATE DATABASE IF NOT EXISTS temp_db;' * - 'USE temp_db;' * - 'SET NAMES utf8;' * * ## Example with multi-dumps * modules: * enabled: * - Db: * dsn: 'mysql:host=localhost;dbname=testdb' * user: 'root' * password: '' * dump: * - 'tests/_data/dump.sql' * - 'tests/_data/dump-2.sql' * * ## Example with multi-databases * * modules: * enabled: * - Db: * dsn: 'mysql:host=localhost;dbname=testdb' * user: 'root' * password: '' * databases: * db2: * dsn: 'mysql:host=localhost;dbname=testdb2' * user: 'userdb2' * password: ''
连接到MySQL数据库:
* For MySQL: * * ```yaml * modules: * enabled: * - Db: * dsn: 'mysql:host=localhost;dbname=testdb' * user: 'root' * password: '' * dump: 'tests/_data/dump.sql' * populate: true # run populator before all tests * cleanup: true # run populator before each test * populator: 'mysql -u $user -h $host $dbname < $dump' * initial_queries: * - 'CREATE DATABASE IF NOT EXISTS temp_db;' * - 'USE temp_db;' * - 'SET NAMES utf8;'
连接到PostgreSQL:
* For PostgreSQL (using pg_restore) * * ``` * modules: * enabled: * - Db: * dsn: 'pgsql:host=localhost;dbname=testdb' * user: 'root' * password: '' * dump: 'tests/_data/db_backup.dump' * populate: true # run populator before all tests * cleanup: true # run populator before each test * populator: 'pg_restore -u $user -h $host -D $dbname < $dump'
实践
配置连接数据库模块Db:
目前的unit.suite.xml配置文件:
actor: UnitTester modules: enabled: - Asserts - \Helper\Unit step_decorators: ~
我们要增加几个模块,比如数据库模块Db,PhpBrowser, Filesystem等模块:
actor: UnitTester modules: enabled: - Asserts - \Helper\Unit - Db: dsn: 'mysql:host=localhost;dbname=testdb' user: 'root' password: 'root' dump: 'tests/_data/dump.sql' - PhpBrowser: url: http://localhost - Filesystem step_decorators: ~
编写单元测试文件tests/unit/ExampleTest.php代码:
<?php class ExampleTest extends Codeception\Test\Unit { /** * @var \UnitTester */ protected $tester; protected function _before() { } protected function _after() { } // tests public function testSomeFeature() { $this->assertTrue(true); $dbh = $this->getModule('Db')->_getDbh(); // dbh: contains the PDO connection 返回一个PDO连接对象 // $dbh是一个PDO对象,就可以说使用任何PDO对象的方法 (https://www.php.net/manual/en/class.pdo.php) $sql = "SELECT username, email FROM `member` where username = 'lajox' ORDER BY id"; // 比如使用PDO::query()方法 foreach ($dbh->query($sql) as $row) { $this->assertContains('lajox', $row['username']); // $row['username']变量值是否包含字符串lajox $this->assertContains('blueno@yeah.net', $row['email']); // $row['email']变量值是否包含字符串blueno@yeah.net } $this->getModule('Db')->seeNumRecords(1, 'member', ['username' => 'lajox']); // 判断member表里username='lajox'的数据记录数是不是1(条) $this->getModule('Db')->seeInDatabase('member', ['username' => 'lajox', 'email like' => '%yeah.net%']); // 判断member表里username='lajox' AND email like '%yeah.net%'是否存在记录 $this->getModule('Db')->dontSeeInDatabase('member', ['email like' => '%163.com%']); // 判断member表里email like '%163.com%'是否不存在记录 } }
Debug打印变量:
用内置的 codecept_debug() 方法来打印变量:
<?php class ExampleTest extends Codeception\Test\Unit { /** * @var \UnitTester */ protected $tester; protected function _before() { } protected function _after() { } // tests public function testSomeFeature() { $this->assertTrue(true); $dbh = $this->getModule('Db')->_getDbh(); // dbh: contains the PDO connection 返回一个PDO连接对象 // $dbh是一个PDO对象,就可以说使用任何PDO对象的方法 (https://www.php.net/manual/en/class.pdo.php) $sql = "SELECT username, email FROM `member` where username = 'lajox' ORDER BY id"; // 比如使用PDO::query()方法 foreach ($dbh->query($sql) as $row) { $this->assertContains('lajox', $row['username']); // $row['username']变量值是否包含字符串lajox $this->assertContains('blueno@yeah.net', $row['email']); // $row['email']变量值是否包含字符串blueno@yeah.net } $this->getModule('Db')->seeNumRecords(1, 'member', ['username' => 'lajox']); // 判断member表里username='lajox'的数据记录数是不是1(条) $this->getModule('Db')->seeInDatabase('member', ['username' => 'lajox', 'email like' => '%yeah.net%']); // 判断member表里username='lajox' AND email like '%yeah.net%'是否存在记录 $this->getModule('Db')->dontSeeInDatabase('member', ['email like' => '%163.com%']); // 判断member表里email like '%163.com%'是否不存在记录 $number = $this->getModule('Db')->grabNumRecords('member', ['username' => 'lajox']); // 获取member表里username='lajox'的记录数 $mails = $this->getModule('Db')->grabColumnFromDatabase('member', 'email', array('username' => 'lajox')); // 获取member表里username='lajox'的邮箱字段email的数组列表 //$email = $this->getModule('Db')->grabFromDatabase('member', 'email', ['email like' => '%blueno%']); // 获取member表里email like '%blueno%'的第一条数据的email字段值 $this->debugSection('number', $number); $this->debugSection('MailList', $mails); } protected function debugSection($title, $message) { if (is_array($message) or is_object($message)) { $message = stripslashes(json_encode($message)); } \codecept_debug("[$title] $message"); } }
命令行下,codecept run命令加上 --debug参数, 例如:
codecept run unit ExampleTest.php --steps --debug --fail-fast
解释:命令行增加 --debug 参数才能完整详细输出打印信息:
又假如我们要验证测试一个点赞功能的正确性,可以这么做:
<?php class ExampleTest extends Codeception\Test\Unit { /** * @var \UnitTester */ protected $tester; protected function _before() { } protected function _after() { } // tests public function testSomeFeature() { $testBookId = 99; //要测试的书籍ID $bookSupport = $this->getModule('Db')->grabFromDatabase('book', 'support', ['id' => $testBookId]); //从数据库取出书籍点赞记录 //打印原始点赞数值 $this->debugSection('bookSupport', $bookSupport); //假设这是对 ID为99的一本书进行"赞/喜欢"操作, 如果成功,结果应该是 喜欢数 support字段值 就会自动 + 1 了 $this->getModule('PhpBrowser')->sendAjaxPostRequest('/book/support.do', ['id' => $testBookId]); $this->getModule('Db')->seeInDatabase('book', [ 'id' => $testBookId, 'support' => $bookSupport + 1, ]); //断言support字段是否被加1了 $this->getModule('Db')->dontSeeInDatabase('book', [ 'id' => $testBookId, 'support' => $bookSupport, ]); //或者断言不会是原来的值 } protected function debugSection($title, $message) { if (is_array($message) or is_object($message)) { $message = stripslashes(json_encode($message)); } \codecept_debug("[$title] $message"); } }
更多Db模块的方法用例,请查阅: https://codeception.com/docs/modules/Db
查阅文档:https://github.com/Codeception/codeception.github.com/blob/master/docs/modules/Db.md
PhpStorm配置codeception单元测试运行参数:
编辑工具栏的Debug配置:
弹出的Run/Debug Configurations窗口中,Test Runner Options 填入附加运行参数: --steps --debug
编辑配置文件 codeception.yml , 在默认开启的 extensions 可能只有 Codeception\Extension\RunFailed ,
需要增加几个 extensions 拓展选项开启,例如增加开启 Codeception\Extension\SimpleReporter,Codeception\Extension\DotReporter 等拓展:
include: paths: tests: tests output: tests/_output data: tests/_data support: tests/_support envs: tests/_envs actor_suffix: Tester bootstrap: _bootstrap.php settings: colors: true memory_limit: 1024M extensions: enabled: - Codeception\Extension\RunBefore - Codeception\Extension\RunProcess - Codeception\Extension\RunFailed - Codeception\Extension\SimpleReporter - Codeception\Extension\DotReporter
这样调试输出打印的运行日志信息会更多。
记住,修改yml配置文件之后,一般都要再运行 codecept build 构建代码:
最后点运行按钮 进行Debug单元测试:
全方面的单元测试:
例如配置unit.suite.yml配置文件,增加几个模块:Db, PhpBrowser, REST等模块引入:
actor: UnitTester bootstrap: _bootstrap.php modules: enabled: - Asserts - \Helper\Unit - Db: dsn: 'mysql:host=localhost;dbname=testdb' user: 'root' password: 'root' dump: 'tests/_data/dump.sql' - PhpBrowser: url: http://www.lancms.com - REST: url: http://www.lancms.com depends: PhpBrowser part: Json - Filesystem step_decorators: ~
注释:bootstrap: _bootstrap.php 这个配置是引入了 _bootstrap.php 加载文件,可以往里面加你要引入的文件或类库。比如:
<?php # 文件 tests/unit/_bootstrap.php # 引入单元测试方法拓展基类 require_once __DIR__ . '/UnitBase.php';
新建一个 tests/unit/UnitBase.php 文件:
<?php # 文件 tests/unit/UnitBase.php class UnitBase extends Codeception\Test\Unit { /** * 调用类的私有方法 * @param object $object * @param string $className * @param string $methodName * @param array $params * @return mixed */ protected function callPrivateMethod($object, string $className, string $methodName, array $params) { $method = $this->getPrivateMethod($className, $methodName); return $method->invokeArgs($object, $params); } /** * 获取对象的私有属性 * @param object $object * @param string $className * @param string $propertyName * @return mixed */ protected function getPrivatePropertyValue($object, string $className, string $propertyName) { $property = $this->getPrivateProperty($className, $propertyName); return $property->getValue($object); } /** * getPrivateProperty * * @param string $className * @param string $propertyName * @return ReflectionProperty * @author Joe Sexton <joe@webtipblog.com> */ protected function getPrivateProperty(string $className, string $propertyName): \ReflectionProperty { $reflector = new ReflectionClass($className); $property = $reflector->getProperty($propertyName); $property->setAccessible(true); return $property; } /** * getPrivateMethod * * @param string $className * @param string $methodName * @return ReflectionMethod * @author Joe Sexton <joe@webtipblog.com> */ protected function getPrivateMethod(string $className, string $methodName): \ReflectionMethod { $reflector = new ReflectionClass($className); $method = $reflector->getMethod($methodName); $method->setAccessible(true); return $method; } }
修改 tests/unit/ExampleTest.php,就可以把 继承方法 class ExampleTest extends Codeception\Test\Unit 改为: class ExampleTest extends UnitBase
编辑unit单元测试文件:tests/unit/ExampleTest.php
<?php # 文件 tests/unit/ExampleTest.php class ExampleTest extends Codeception\Test\Unit { /** * @var \UnitTester */ protected $tester; public function _before() { } public function _after() { } // tests public function testSomeFeature() { $this->assertTrue(true); $this->_testDB(); # 测试数据库模块: Db $this->_testPhpBrowser(); # 测试模块: PhpBrowser $this->_testREST(); # 测试api测试模块: REST $this->_testCept(); # 场景测试 $this->_testScratch(); # 综合测试,混用 $this->_testThinPHP(); # 测试ThinkPHP 5.1方法 } protected function _testDB() { // 可以查看文档: https://codeception.com/docs/modules/Db $dbh = $this->getModule('Db')->_getDbh(); // dbh: contains the PDO connection 返回一个PDO连接对象 // $dbh是一个PDO对象,就可以说使用任何PDO对象的方法 (https://www.php.net/manual/en/class.pdo.php) $sql = "SELECT username, email FROM `member` where username = 'lajox' ORDER BY id"; // 比如使用PDO::query()方法 foreach ($dbh->query($sql) as $row) { $this->assertContains('lajox', $row['username']); // $row['username']变量值是否包含字符串lajox $this->assertContains('blueno@yeah.net', $row['email']); // $row['email']变量值是否包含字符串blueno@yeah.net } $this->getModule('Db')->seeNumRecords(1, 'member', ['username' => 'lajox']); // 判断member表里username='lajox'的数据记录数是不是1(条) $this->getModule('Db')->seeInDatabase('member', ['username' => 'lajox', 'email like' => '%yeah.net%']); // 判断member表里username='lajox' AND email like '%yeah.net%'是否存在记录 $this->getModule('Db')->dontSeeInDatabase('member', ['email like' => '%163.com%']); // 判断member表里email like '%163.com%'是否不存在记录 $number = $this->getModule('Db')->grabNumRecords('member', ['username' => 'lajox']); // 获取member表里username='lajox'的记录数 $mails = $this->getModule('Db')->grabColumnFromDatabase('member', 'email', array('username' => 'lajox')); // 获取member表里username='lajox'的邮箱字段email的数组列表 $email = $this->getModule('Db')->grabFromDatabase('member', 'email', ['email like' => '%blueno%']); // 获取member表里email like '%blueno%'的数据列表(数组) $this->debugSection('number', $number); $this->debugSection('MailList', $mails); $this->debugSection('Email', $email); } protected function _testPhpBrowser() { // 可以查看文档: https://codeception.com/docs/modules/PhpBrowser $this->getModule('PhpBrowser')->haveHttpHeader('accept', 'application/json'); // $this->getModule('PhpBrowser')->haveHttpHeader('Content-Type', 'application/x-www-form-urlencoded'); // 普通表单形式发送 $this->getModule('PhpBrowser')->haveHttpHeader('content-type', 'application/json'); // 发送JSON形式数据 // AJAX请求 //$this->getModule('PhpBrowser')->sendAjaxPostRequest('/api/test/demo', ['name' => 'test', 'email' => 'test@163.com']); $this->getModule('PhpBrowser')->sendAjaxRequest('POST', 'http://www.lancms.com/api/test/demo', [ 'name' => 'test', 'email' => 'test@163.com', ]); $this->getModule('PhpBrowser')->seeResponseCodeIs(\Codeception\Util\HttpCode::OK); // 200 } protected function _testREST() { # 发送请求api地址: http://www.lancms.com/api/test/demo # 请求参数: {"name":"test","email":"test@163.com"} # 响应结果: {"code":1,"msg":"success","data":[]} $this->getModule('REST')->haveHttpHeader('accept', 'application/json'); // $I->haveHttpHeader('Content-Type', 'application/x-www-form-urlencoded'); // 普通表单形式发送 $this->getModule('REST')->haveHttpHeader('content-type', 'application/json'); // 发送JSON形式数据 $this->getModule('REST')->sendPOST('/api/test/demo', [ 'name' => 'test', 'email' => 'test@163.com', ]); $this->getModule('REST')->seeResponseCodeIs(\Codeception\Util\HttpCode::OK); // 200 $this->getModule('REST')->seeResponseCodeIs(200); $this->getModule('REST')->seeResponseIsJson(); $this->getModule('REST')->seeResponseContains('success'); $this->getModule('REST')->seeResponseContainsJson([ "code" => "1", ]); $this->getModule('REST')->seeResponseJsonMatchesJsonPath("$.data"); $this->getModule('REST')->seeResponseJsonMatchesXpath('//data'); $this->getModule('REST')->seeResponseMatchesJsonType([ 'code' => 'integer', 'msg' => 'string', 'data' => 'string|array|null', ]); } /** * 测试场景 * @var \UnitTester $this->tester */ protected function _testCept() { $this->tester->amOnPage('/index/test/show'); $this->tester->see('show_test'); } /** * 综合测试,混用 * @var \UnitTester $this->tester */ protected function _testScratch() { # 因为unit.suite.yml已经配置了引入Db、PhpBrowser、REST等模块, # 所以 $this->tester引用对象就会自动包含各个模块的所有方法。可以用 $this->tester 简化替代 $this->getModule() 方法。 # 模块Db方法: $this->getModule('Db')->seeNumRecords(1, 'member', ['username' => 'lajox']); $this->tester->seeNumRecords(1, 'member', ['username' => 'lajox']); # 模块PhpBrowser方法: $this->getModule('PhpBrowser')->sendAjaxPostRequest('/api/test/demo', ['name' => 'test', 'email' => 'test@163.com']); $this->tester->sendAjaxPostRequest('/api/test/demo', ['name' => 'test', 'email' => 'test@163.com']); # 模块REST方法: $this->getModule('REST')->sendPOST('/api/test/demo', ['name' => 'test', 'email' => 'test@163.com']); $this->tester->sendPOST('/api/test/demo', ['name' => 'test', 'email' => 'test@163.com']); } /** * 测试ThinkPHP的方法 */ protected function _testThinPHP() { $app = new \app\index\controller\Test(); // 假设 index/test/show 方法返回的字符串中包含 "show_test" $this->assertContains('show_test', $app->show()); } protected function debugSection($title, $message) { if (is_array($message) or is_object($message)) { $message = stripslashes(json_encode($message)); } \codecept_debug("[$title] $message"); } }
phpstorm快速Debug测试unit单元测试方法:
就能快速运行Debug单元测试了:
编辑Debug工具栏, 配置此方法的选项:
弹出的Run/Debug Configurations窗口中,Test Runner Options 填入附加运行参数: --steps --debug
再次点击 运行按钮,就可以看到更多的Debug调试信息了:
高级用法:
我们回顾一下,unit.suite.yml 配置文件默认是开启了 \Helper\Unit 模块:
那么这个\Helper\Unit模块定义文件在哪呢?
我们看下tests/ 目录下的文件结构,就会发现:\Helper\Unit 模块定义文件在: tests/_support/Helper/Unit.php 文件中:
修改 tests/_support/Helper/Unit.php 文件代码,我们增加了一个自定义方法 seeResponseIsValidate() :
<?php namespace Helper; // here you can define custom actions // all public methods declared in helper class will be available in $I class Unit extends \Codeception\Module { public function seeResponseIsValidate() { $this->getModule('REST')->haveHttpHeader('accept', 'application/json'); $this->getModule('REST')->haveHttpHeader('content-type', 'application/json'); // 发送JSON形式数据 $this->getModule('REST')->sendPOST('/api/test/demo', [ 'name' => 'test', 'email' => 'test@163.com', ]); $this->getModule('REST')->seeResponseCodeIs(\Codeception\Util\HttpCode::OK); // 200 $this->getModule('REST')->seeResponseCodeIs(200); $this->getModule('REST')->seeResponseIsJson(); $this->getModule('REST')->seeResponseContains('success'); $response = $this->getModule('REST')->grabResponse(); $this->assertContains('success', $response); } }
修改文件:文件 tests/unit/ExampleTest.php,内容为:
<?php # 文件 tests/unit/ExampleTest.php class ExampleTest extends UnitBase { /** * @var \UnitTester */ protected $tester; public function _before() { } public function _after() { } // tests public function testSomeFeature() { $this->assertTrue(true); $this->_testHelperUnit(); # 测试业务代码: tests/_support/Helper/Unit.php } /** * 测试业务代码放入 tests/_support/Helper/Unit.php 文件中 */ protected function _testHelperUnit() { $this->getModule('\Helper\Unit')->seeResponseIsValidate(); } protected function debugSection($title, $message) { if (is_array($message) or is_object($message)) { $message = stripslashes(json_encode($message)); } \codecept_debug("[$title] $message"); } }
运行一下Debug按钮:
添加新模块文件:
通过命令 codecept generate:helper "Unit\MyModule" 就会自动在 tests/_support/Helper/ 目录下生成一个文件夹Unit和Unit文件夹下的文件 MyModule.php:
当然,你也可以手动新建目录Unit和文件 Unit/MyModule.php ,如果你不嫌麻烦的话。
codecept generate:helper "Unit\MyModule"
编辑文件 tests/_support/Helper/Unit/MyModule.php ,代码写入:
<?php # 文件 tests/_support/Helper/Unit/MyModule.php namespace Helper\Unit; // here you can define custom actions // all public methods declared in helper class will be available in $I class MyModule extends \Codeception\Module { public function seeMyModuleIsValidate() { $this->assertTrue(false); } }
配置 unit.suite.yml 配置文件,加入引入模块代码:\Helper\Unit\MyModule
# Codeception Test Suite Configuration # # Suite for unit or integration tests. actor: UnitTester bootstrap: _bootstrap.php modules: enabled: - Asserts - \Helper\Unit - \Helper\Unit\MyModule - Db: dsn: 'mysql:host=localhost;dbname=testdb' user: 'root' password: 'root' dump: 'tests/_data/dump.sql' - PhpBrowser: url: http://www.lancms.com - REST: url: http://www.lancms.com depends: PhpBrowser part: Json - Filesystem step_decorators: ~
然后命令行执行命令 codecept build 构建代码。
看到 includes modules: 和 \Helper\Unit\MyModule 提示文字表示新的模块已经引用进来:
编辑 tests/_support/Helper/Unit.php ,代码:
<?php # 文件 tests/_support/Helper/Unit.php namespace Helper; // here you can define custom actions // all public methods declared in helper class will be available in $I class Unit extends \Codeception\Module { public function seeResponseIsValidate() { $this->getModule('REST')->haveHttpHeader('accept', 'application/json'); $this->getModule('REST')->haveHttpHeader('content-type', 'application/json'); // 发送JSON形式数据 $this->getModule('REST')->sendPOST('/api/test/demo', [ 'name' => 'test', 'email' => 'test@163.com', ]); $this->getModule('REST')->seeResponseCodeIs(\Codeception\Util\HttpCode::OK); // 200 $this->getModule('REST')->seeResponseCodeIs(200); $this->getModule('REST')->seeResponseIsJson(); $this->getModule('REST')->seeResponseContains('success'); $response = $this->getModule('REST')->grabResponse(); $this->assertContains('success', $response); } public function seeMyModule() { $this->getModule('\Helper\Unit\MyModule')->seeMyModuleIsValidate(); } }
编辑文件:tests/unit/ExampleTest.php ,代码:
<?php # 文件 tests/unit/ExampleTest.php class ExampleTest extends UnitBase { /** * @var \UnitTester */ protected $tester; public function _before() { } public function _after() { } // tests public function testSomeFeature() { $this->assertTrue(true); $this->_testHelperUnit(); # 测试业务代码: tests/_support/Helper/Unit.php } /** * 测试业务代码放入 tests/_support/Helper/Unit.php 文件中 */ protected function _testHelperUnit() { $this->getModule('\Helper\Unit')->seeResponseIsValidate(); $this->getModule('\Helper\Unit')->seeMyModule(); $this->getModule('\Helper\Unit\MyModule')->seeMyModuleIsValidate(); $this->_testCept(); // 测试场景 # debug输出一条信息 $this->debugSection('CurrentMethod', __METHOD__); // 就会输出: [CurrentMethod] ExampleTest::_testHelperUnit } /** * 测试场景 * @var \UnitTester $this->tester */ protected function _testCept() { $this->tester->amOnPage('/index/test/show'); $this->tester->see('show_test'); # 可以将场景测试代码移入文件 tests/_support/UnitTester.php 中 $this->tester->seeUnitTester(); } protected function debugSection($title, $message) { if (is_array($message) or is_object($message)) { $message = stripslashes(json_encode($message)); } \codecept_debug("[$title] $message"); } }
编辑文件 tests/_support/UnitTester.php, 代码:
<?php # 文件 tests/_support/UnitTester.php /** * Inherited Methods * @method void wantToTest($text) * @method void wantTo($text) * @method void execute($callable) * @method void expectTo($prediction) * @method void expect($prediction) * @method void amGoingTo($argumentation) * @method void am($role) * @method void lookForwardTo($achieveValue) * @method void comment($description) * @method void pause() * * @SuppressWarnings(PHPMD) */ class UnitTester extends \Codeception\Actor { use _generated\UnitTesterActions; /** * Define custom actions here */ public function seeUnitTester() { $this->amOnPage('/index/test/show'); $this->see('show_test'); # 因为unit.suite.yml已经配置了引入Db、PhpBrowser、REST等模块, # 所以 $this引用对象就会自动包含各个模块的所有方法 # 使用Db模块方法, 可以查看文档: https://codeception.com/docs/modules/Db $this->seeNumRecords(1, 'member', ['username' => 'lajox']); # 使用PhpBrowser模块方法, 可以查看文档: https://codeception.com/docs/modules/PhpBrowser $this->sendAjaxRequest('POST', '/api/test/demo', [ 'name' => 'test', 'email' => 'test@163.com', ]); # 使用REST模块方法, 可以查看文档: https://codeception.com/docs/modules/REST $this->sendPOST('/api/test/demo', [ 'name' => 'test', 'email' => 'test@163.com', ]); # debug输出一条信息 $this->debugSection('CurrentMethod', __METHOD__); // 就会输出: [CurrentMethod] UnitTester::seeUnitTester } /** * debug */ protected function debugSection($title, $message) { if (is_array($message) or is_object($message)) { $message = stripslashes(json_encode($message)); } \codecept_debug("[$title] $message"); } }
点击运行一下Debug按钮,查看测试运行效果:
创建更多的单元测试文件,以文件夹Common, Controller 等为归组:
codecept generate:test unit "Common\Common" codecept generate:test unit "Controller\Controller"
注:
codecept generate:test unit "Common\Common" 命令会在 tests/unit/ 目录下生成 Common/CommonTest.php (文件名以Test.php为后缀)
codecept generate:test unit "Common\Controller" 命令会在 tests/unit/ 目录下生成 Controller/ControllerTest.php (文件名以Test.php为后缀)
文件 tests/unit/Common/CommonTest.php 的生成默认代码:
<?php # 文件 tests/unit/Common/CommonTest.php namespace Common; class CommonTest extends \Codeception\Test\Unit { /** * @var \UnitTester */ protected $tester; protected function _before() { } protected function _after() { } // tests public function testSomeFeature() { } }
phpstorm配置只运行unit类型的单元测试:
注: unit单元测试文件的类可以继承 Codeception\Test\Unit ,也可以写成继承 Codeception\TestCase\Test
<?php # 文件 tests/unit/ExampleTest.php class ExampleTest extends Codeception\TestCase\Test { /** * @var \UnitTester */ protected $tester; public function _before() { } public function _after() { } // tests public function testSomeFeature() { } }
上面单元测试实例源码已经放到Github上了: https://github.com/lajox/thinkphp-codeception-example
模块参考资料:
https://codeception.com/docs/06-ModulesAndHelpers
https://github.com/Codeception/codeception.github.com
http://www.kkh86.com/it/codeception/guide-cept-test-base.html
https://www.cloudxns.net/Support/detail/id/1005.html