Lumen 6 中文文档 测试
简介
Lumen 在创建时就已考虑到测试的部分。事实上,Lumen 默认就支持用 PHPUnit 来做测试,并为你的应用程序创建好了 phpunit.xml
文件。 框架还提供了一些便利的辅助函数,让你可以更直观的测试应用程序的 JSON 响应。
在 tests
目录下已经提供了一个 ExampleTest.php
示例文件。安装新的 Lumen 应用程序之后,只需在命令行上运行 phpunit
就可以进行测试。
测试环境
在运行测试时,Lumen 自动将缓存驱动配置为 array
,意味着在测试的时候不会保存任何的缓存数据。
你可以随意创建其他必要的测试配置环境。 testing
的环境变量可以在 phpunit.xml
文件中进行修改。
定义和运行测试
要创建一个测试用例,直接将新的测试文件创建到 tests
文件夹下即可。测试文件必须继承 TestCase
。接着就可以像平常使用 PHPUnit 一样来定义测试方法。要运行测试只需要在命令行上运行 phpunit
命令即可:
<?php
class FooTest extends TestCase
{
public function testSomethingIsTrue()
{
$this->assertTrue(true);
}
}
注意: 如果要在你的类自定义
setUp
方法,请确保调用了parent::setUp
。
应用测试
Lumen 提供了一个非常好用的 API,用来向你的应用发起 HTTP 请求,并查看输出结果。
测试 JSON API 接口
Lumen 同样提供了一些辅助函数用于测试 JSON API 及其响应。例如,get
,post
,put
,patch
和 delete
方法可以被用于发起各种方式的 HTTP 请求。同样,你也可以很轻松地给这些方法传递数据或者头部信息。首先,我们要创建一个测试,向 /user
发起 POST
请求,并且断言以 JSON 格式返回一个指定的数组:
<?php
class ExampleTest extends TestCase
{
/**
* 一个简单的测试例子
*
* @return void
*/
public function testBasicExample()
{
$this->json('POST', '/user', ['name' => 'Sally'])
->seeJson([
'created' => true,
]);
}
}
seeJson
方法将给定的数组转换成 JSON,并验证这个 JSON 片段发生在应用返回的整个 JSON 响应的 任意位置 。所以,即使在 JSON 响应中存在其他属性,只要指定的片段存在,这个测试仍然会成功。
验证完全匹配的 JSON
如果你想验证传入的数组是否与应用程序返回的 JSON 完全 匹配, 你可以用 seeJsonEquals
方法:
<?php
class ExampleTest extends TestCase
{
/**
* 一个简单的测试例子
*
* @return void
*/
public function testBasicExample()
{
$this->post('/user', ['name' => 'Sally'])
->seeJsonEquals([
'created' => true,
]);
}
}
认证
actingAs
辅助函数提供了简单的方式来让指定的用户认证为当前的用户:
<?php
class ExampleTest extends TestCase
{
public function testApplication()
{
$user = factory('App\User')->create();
$this->actingAs($user)
->get('/user');
}
}
自定义 HTTP 请求
如果你想要创建一个自定义的 HTTP 请求到应用程序上,并获取完整的 Illuminate\Http\Response
对象,可以使用 call
方法:
public function testApplication()
{
$response = $this->call('GET', '/');
$this->assertEquals(200, $response->status());
}
如果你想构造 POST
, PUT
, 或者 PATCH
请求,可以在请求时传入一个数组作为请求参数。当然,你也可以在路由及控制器中通过 Request 实例 来获取传过来的参数:
$response = $this->call('POST', '/user', ['name' => 'Taylor']);
使用数据库
Lumen 还提供了各种有用的工具,使测试数据库驱动的应用程序变得更容易。首先,你可以使用 seeInDatabase
辅助函数来断言数据库中存在与给定条件集匹配的数据。例如,我们想要验证 users
表中有一条 email
的值为 sally@example.com
的记录,我们可以按如下操作:
public function testDatabase()
{
// Make call to application...
$this->seeInDatabase('users', ['email' => 'sally@foo.com']);
}
当然, seeInDatabase
方法和其他类似的辅助函数就是为了方便使用。你也可以在测试中自由使用 PHPUnit 的内置断言方法。
每次测试之后重置数据库
在每次测试后重置数据库是非常有必要的,这样之前的测试数据不会影响后面的测试。
使用迁移
有一个选择是每次测试之后回滚数据库,并且在下一次测试之前将其迁移。Lumen 提供了一个简单的 DatabaseMigrations
trait,它可以自动为您处理。简单的在您的测试类中运用这个 trait 如下:
<?php
use Laravel\Lumen\Testing\DatabaseMigrations;
use Laravel\Lumen\Testing\DatabaseTransactions;
class ExampleTest extends TestCase
{
use DatabaseMigrations;
/**
* A basic functional test example.
*
* @return void
*/
public function testBasicExample()
{
$this->get('/foo');
}
}
使用事务
另一个选择是将每一个测试用例包装在数据库事务中。同样,Lumen 提供了一个便利的 DatabaseTransactions
trait,可以为您自动的执行这些:
<?php
use Laravel\Lumen\Testing\DatabaseMigrations;
use Laravel\Lumen\Testing\DatabaseTransactions;
class ExampleTest extends TestCase
{
use DatabaseTransactions;
/**
* A basic functional test example.
*
* @return void
*/
public function testBasicExample()
{
$this->get('/foo');
}
}
模型工厂
在测试时,通常需要在执行测试之前将少量的数据记录插入到数据库。Lumen 允许您使用「factories」为每个 Eloquent 模型定义一组默认属性,而不是在创建这些数据时手动指定每一列的值。首先,请查看应用中的 database/factories/ModelFactory.php
文件。开箱即用,此文件包含一个工厂定义:
$factory->define('App\User', function ($faker) {
return [
'name' => $faker->name,
'email' => $faker->email,
];
});
在作为工厂定义的闭包中,您可以返回模型上所有属性的默认测试值。 闭包将接收 Faker PHP 库的一个实例,它允许您方便地生成各种随机数据以用于测试。
当然,您可以自由地将自己的附加工厂添加到 ModelFactory.php
文件中 。
多种工厂类型
有时您可能希望同一个 Eloquent 模型有多种工厂。例如,也许您希望除了普通的用户之外还为「Administrator」用户提供工厂。您可以使用 defineAs
方法定义这些工厂:
$factory->defineAs('App\User', 'admin', function ($faker) {
return [
'name' => $faker->name,
'email' => $faker->email,
'admin' => true,
];
});
您可以使用 raw
方法检索其基本属性,而不是复制基本用户工厂中的所有属性。获取属性后,只需用您所需的任何其他值补充它们即可:
$factory->defineAs('App\User', 'admin', function ($faker) use ($factory) {
$user = $factory->raw('App\User');
return array_merge($user, ['admin' => true]);
});
在测试中使用工厂
在工厂定义后,就可以在测试或是数据库的填充文件中,通过全局的 factory
函数来生成模型实例。接着让我们来看几个创建模型的例子。首先我们会使用 make
方法创建模型,但不将它们保存至数据库:
public function testDatabase()
{
$user = factory('App\User')->make();
// 在测试中使用模型...
}
如果你想重写模型中的某些默认值,则可以传递一个包含数值的数组至 make
方法。只有指定的数值会被替换,其余的值仍设置为工厂指定的默认值:
$user = factory('App\User')->make([
'name' => 'Abigail',
]);
你还可以创建许多模型的集合或创建给定类型的模型:
// Create three App\User instances...
$users = factory('App\User', 3)->make();
// Create an App\User "admin" instance...
$user = factory('App\User', 'admin')->make();
// Create three App\User "admin" instances...
$users = factory('App\User', 'admin', 3)->make();
持久化工厂模型
create
方法不仅创建模型实例,还使用 Eloquent 的 save
方法将它们保存到数据库:
public function testDatabase()
{
$user = factory('App\User')->create();
// Use model in tests...
}
同样,你也可以通过将数组传递给 create
方法来覆盖模型上的属性:
$user = factory('App\User')->create([
'name' => 'Abigail',
]);
添加关联至模型
你甚至可以将多个模型持久化到数据库中。在本例中,我们甚至将一个关联附加到创建的模型上。当使用 create
方法创建多个模型时,将返回一个 Eloquent 集合实例,让你能使用集合提供的便捷函数,例如 each
函数:
$users = factory('App\User', 3)
->create()
->each(function($u) {
$u->posts()->save(factory('App\Post')->make());
});
模拟
模拟事件
如果你大量地使用 Lumen 的事件系统,你可能会希望在测试时静默或者需要模拟某些事件。例如,如果你在测试用户注册,你可能不希望所有的 UserRegistered
事件被触发,因为它们会发送「欢迎」邮件,等等。
Lumen 提供了简便的 expectsEvents
方法,以验证是否触发了预期的事件,但是会阻止该事件的任何处理程序的运行:
<?php
class ExampleTest extends TestCase
{
public function testUserRegistration()
{
$this->expectsEvents('App\Events\UserRegistered');
// 测试用户注册功能...
}
}
如果你想阻止所有的事件处理程序运行,你可以使用 withoutEvents
方法:
<?php
class ExampleTest extends TestCase
{
public function testUserRegistration()
{
$this->withoutEvents();
// Test user registration code...
}
}
模拟任务
有时,你可能希望在向应用发送请求时,简单的测试控制器是否调度了特定的任务(Jobs)。这允许你隔离测试路由或控制器——与你的任务(Job)逻辑分开。当然,此后你可以在一个单独的测试类中测试该任务(Job)。
Lumen 提供了一个简便的 expectsJobs
方法,以验证预期的任务有没有被派送,但任务本身不会被运行:
<?php
class ExampleTest extends TestCase
{
public function testPurchasePodcast()
{
$this->expectsJobs('App\Jobs\PurchasePodcast');
// 测试购买播客代码……
}
}
注意: 该方法只检测通过全局辅助函数
dispatch
或者由路由或控制器中的$this->dispatch
方法派送的任务。它并不会检测被直接发送到Queue::push
的任务。
模拟 Facades
在测试时,经常需要模拟对 Lumen facade的调用。例如,考虑如下控制器的操作:
<?php
namespace App\Http\Controllers;
use Cache;
class UserController extends Controller
{
/**
* 展示应用程序所有用户的列表。
*
* @return Response
*/
public function index()
{
$value = Cache::get('key');
//
}
}
我们可以使用 shouldReceive
方法来模拟调用 Cache
facade,它会返回一个 Mockery mock 的实例。因为门面实际上由 Lumen 的 服务容器 解析和管理,它们比典型的静态类更具有可测性。例如,让我们模拟调用 Cache
门面:
<?php
class FooTest extends TestCase
{
public function testGetIndex()
{
Cache::shouldReceive('get')
->once()
->with('key')
->andReturn('value');
$this->get('/users');
}
}
猜你喜欢:注意: 你不应该模拟
Request
门面。应该在测试时使用如call
及post
这样的 HTTP 辅助函数来传递你想要的数据。