单元测试(Unit Testing),是指对软件中的最小可测试单元进行检查和验证
单元测试是在软件开发过程中要进行的最低级别的测试活动,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试
Yii 的单元测试框架 Codeception 基于 PHPUnit,使用方式几乎一模一样
PHPUnit 是一个轻量级的 PHP 测试框架。它是在 PHP5 下面对 JUnit3 系列版本的完整移植,是 xUnit 测试框架家族的一员 (它们都基于模式先锋 Kent Beck 的设计)
单元测试是几个现代敏捷开发方法的基础,使得 PHPUnit 成为许多大型 PHP 项目的关键工具。这个工具也可以被 Xdebug 扩展用来生成代码覆盖率报告 ,并且可以与 phing 集成来自动测试,最合它还可以和 Selenium 整合来完成大型的自动化集成测试。
最近一个老项目前端机所在的服务器之一宕机了,在更换新服务器后发现这个项目没有单元测试,在验证时比较麻烦
现在需要一步步为这个 Yii2.0.12 项目引入单元测试
Yii2 Codeception
首先看是否已安装了本包,在 Yii 项目中使用 Composer 可能会提示如下错误:
yiisoft/yii2 requires bower-asset/jquery@stable -> no matching package found.
这时需要安装这个 Composer 管理前端依赖的包,在下载中需要配置一个 GitHub 的 Token:
composer global require "fxp/composer-asset-plugin"
全部安装好后,在 vendor/bin 下能找到一个可执行文件 codecept
在项目根目录需要有一个配置文件,默认配置了 3 个测试模块:
# global codeception file to run tests from all apps
include:
- common
- frontend
- backend
paths:
log: console/runtime/logs
settings:
colors: true
如果是项目是完整的,里面已经包含了单元测试的例子,部分结果如下:
$ vendor/bin/codecept run
Codeception PHP Testing Framework v2.5.6
Powered by PHPUnit 7.5.18 by Sebastian Bergmann and contributors.
Running with seed:
[common\tests]: tests from D:\WWW\yii2-app-advanced-2.0.11\common
Common\tests.unit Tests (3) ----------------------------------------------------
E LoginFormTest: Login no user (2.89s)
E LoginFormTest: Login wrong password (2.01s)
E LoginFormTest: Login correct (2.00s)
启动引导
但是像我的项目经过了各种删减,原用例和配置都不在了,需要重新生成:
vendor\bin\codecept bootstrap
这个命令会在当前目录中生成配置文件和一个 tests/ 目录
添加套件
如果是刚安装好的,在 tests/ 下已经有了 functional
和 unit
两个套件。自己想添加新的套件,使用 generate:suite 命令:
vendor\bin\codecept generate:suite api
这将在 tests/ 目录下创建 api.suite.yml 配置文件和 api/ 目录,现在使用 generate:cest 命令生成具体测试用例
vendor\bin\codecept generate:cest api GetChatLog
然后使用 build 命令构建测试
运行测试
在写好你的 GetChatLog 用例后:
public function tryToTest(ApiTester $I)
{
$I->sendPOST('index/get-chat-log', ['from_id' => 1, 'to_id' => 1]);
$I->seeResponseCodeIs(Codeception\Util\HttpCode::OK);
$I->seeResponseIsJson();
$I->seeResponseContainsJson(['code' => 0]);
}
运行测试查看结果
vendor\bin\codecept run api
Laravel5 PHPUnit
回顾一下以前用 Laravel 5.5 时使用单元测试的方式
如果是使用 Laravel 安装器创建的项目,则已经安装好了 PHPUnit
快速创建用例
php artisan make:test UserTest
该命令会创建一个基础的测试类
<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;
class UserTest extends TestCase
{
public function testExample()
{
$this->assertTrue(true);
}
}
Web测试
断言某 GET 请求的响应码为 200 的示例方法 ExampleTest 如下:
public function testBasicTest()
{
$response = $this->get('/');
$response->assertStatus(200);
}
接口测试
下面的测试是断言 /user
这个 POST 接口会返回给定数组的 JSON 格式:
$this->json('POST', '/user', ['name' => 'Sally'])
->seeJson([
'created' => true,
]) ;
seeJson
方法会转换给定的数组为 JSON,并且会验证应用响应的完整 JSON 中是否会出现相应的片段
所以,如果响应中还含有其他 JSON 属性,那么这个测试依然会被通过
验证完全匹配的 JSON
如果希望验证完整的 JSON 响应,你可以使用 seeJsonEquals()
方法,JSON 与所给定的数组完全匹配:
$this->json('POST', '/user', ['name' => 'Sally'])
->seeJsonEquals([
'created' => true,
]);
验证匹配 JSON 结构
使用 seeJsonStructure()
方法并传递嵌套的键列表:
$this->get('/user/1')
->seeJsonStructure([
'name',
'pet' => [
'name', 'age'
]
]);
在上面的例子中表明了期望获取一个含有 name 和 pet 属性的 JSON,并且 pet 键是一个含有 name 和 age 属性的对象
如果含有额外的键,seeJsonStructure
方法并不会失败。比如,如果 pet 还含有 weight 属性,那么测试依然会被通过
你可以使用 *
来断言所返回的 JSON 结构中的每一项都应该包含所列出的这些属性:
$this->get('/users')
->seeJsonStructure([
'*' => [
'id', 'name', 'email'
]
]);
你也可以嵌套使用 *,下面的例子中,我们断言 JSON 响应返回的每一个用户都应该包含所列出的属性,并且 pet 属性应该也包含所给定的属性:
$this->get('/users')
->seeJsonStructure([
'*' => [
'id', 'name', 'email', 'pets' => [
'*' => [
'name', 'age'
]
]
]
]);