1、简介
Laravel 为生成 HTTP 请求、测试输出、以及填充表单提供了流式API。举个例子,我们看下 tests
目录下包含的 ExampleTest.php
文件
:
<?php use Illuminate\Foundation\Testing\WithoutMiddleware; use Illuminate\Foundation\Testing\DatabaseTransactions; class ExampleTest extends TestCase{ /** * 基本功能测试示例 * * @return void */ public function testBasicExample() { $this->visit('/') ->see('Laravel 5') ->dontSee('Rails'); } }
visit
方法生成了一个GET请求, see
方法对我们从应用返回响应中应该看到的给定文本进行断言。 dontSee
方法对给定文本没有从应用响应中返回进行断言。在Laravel中这是最基本的有效性测试。
你还可以使用 visitRoute
方法通过命名路由生成GET请求:
$this->visitRoute('profile'); $this->visitRoute('profile', ['user' => 1]);
2、与应用交互
当然,除了对响应文本进行断言之外还有做更多测试,让我们看一些点击链接和填充表单的例子:
点击链接
在本测试中,我们将为应用生成请求,在返回的响应中“点击”链接,然后对访问URI进行断言。例如,假定响应中有一个“关于我们”的链接:
<a href=http://www.tuicool.com/articles/"/about -us">About Us
现在,让我们编写一个测试点击链接并断言用户访问页面是否正确:
public function testBasicExample(){ $this->visit('/') ->click('About Us') ->seePageIs('/about -us'); }
还可以使用 seeRouteIs
方法检查用户是否到达正确的命名路由:
->seeRouteIs('profile', ['user' => 1]);
处理表单
Laravel 还为处理表单提供了多个方法。 type
、 select
、 check
、 attach
和 press
方法允许你与所有表单输入进行交互。例如,我们假设这个表单存在于应用注册页面:
<form action="/register" method="POST"> {!! csrf_field() !!} <div> Name: <input type="text" name="name"> </div> <div> <input type="checkbox" value="yes" name="terms"> Accept Terms </div> <div> <input type="submit" value="Register"> </div> </form>
我们可以编写测试来完成表单并检查结果:
public function testNewUserRegistration(){ $this->visit('/register') ->type('Taylor', 'name') ->check('terms') ->press('Register') ->seePageIs('/dashboard'); }
当然,如果你的表单包含其他输入比如单选按钮或下拉列表,也可以轻松填写这些类型的字段。这里是所有表单操作方法列表:
方法 | 描述 |
---|---|
$this->type($text, $elementName)
|
“Type” 文本到给定字段 |
$this->select($value, $elementName)
|
“Select” 单选框或下拉列表 |
$this->check($elementName)
|
“Check” 复选框 |
$this->attach($pathToFile, $elementName)
|
“Attach” 文件到表单 |
$this->press($buttonTextOrElementName)
|
“Press” 给定文本或name的按钮 |
$this->uncheck($elementName)
|
“Uncheck”复选框 |
文件上传
如果表单包含 file
输入类型,可以使用 attach
方法添加文件到表单:
public function testPhotoCanBeUploaded(){ $this->visit('/upload') ->attach($pathToFile, 'photo') ->press('Upload') ->see('Upload Successful!'); }
3、测试JSON API
Laravel 还提供多个帮助函数用于测试 JSON API 及其响应。例如, json
、 get
、 post
、 put
、 patch
和 delete
方法用于通过多种 HTTP 请求方式发出请求。你还可以轻松传递数据和请求头到这些方法。作为开始,我们编写测试来生成 POST 请求到 /user
并断言返回的数据是否是我们所期望的:
<?php class ExampleTest extends TestCase { /** * A basic functional test example. * * @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 { /** * A basic functional test example. * * @return void */ public function testBasicExample() { $this->json('POST', '/user', ['name' => 'Sally']) ->seeJsonEquals(['created' => true,]); } }
验证数据结构匹配
还可以验证JSON响应是否与指定数据结构匹配,我们使用 seeJsonStructure
方法来实现这一功能:
<?php class ExampleTest extends TestCase{ /** * A basic functional test example. * * @return void */ public function testBasicExample() { $this->get('/user/1') ->seeJsonStructure([ 'name', 'pet' => [ 'name', 'age' ] ]); } }
上面的例子演示了期望获取一个包含 name
和嵌套 pet
对象(该对象包含 name
和 age
属性)的 JSON 数据。如果 JSON 响应中包含其它额外键 seeJsonStructure
也不会失败,例如,如果 pet
对象包含 weight
属性测试仍将通过。
你可以使用 *
来断言返回JSON结构包含一个列表,该列表中的每个数据项都包含至少如下示例中列出的属性:
<?php class ExampleTest extends TestCase{ /** * A basic functional test example. * * @return void */ public function testBasicExample() { // Assert that each user in the list has at least an id, name and email attribute. $this->get('/users') ->seeJsonStructure([ '*' => [ 'id', 'name', 'email' ] ]); } }
你还可以使用嵌套的*,在这种场景中,我们可以断言JSON响应中的每个用户都包含一个给定属性集合,而且每个用户的每个 pet
都包含给定属性集合:
$this->get('/users') ->seeJsonStructure([ '*' => [ 'id', 'name', 'email', `pets` => [ '*' => [ 'name', 'age' ] ] ] ]);
4、Session/认证
Laravel提供了多个辅助函数用于在测试期间处理Session,首先,可以使用 withSession
方法设置 session 值到给定数组。这在测试请求前获取 session 数据时很有用:
<?php class ExampleTest extends TestCase{ public function testApplication() { $this->withSession(['foo' => 'bar']) ->visit('/'); } }
当然,session的最常见的作用就是维护认证用户的状态。辅助函数 actingAs
为认证给定用户是当前用户提供了简单的实现方法,例如,我们使用模型工厂生成和认证用户:
$this->actingAs($user) ->withSession(['foo' => 'bar']) ->visit('/') ->see('Hello, '.$user->name); } }
还可以通过传递 guard
名称作为 actingAs
函数的第二个参数的方式来指定使用哪个 guard
来认证给定用户:
$this->actingAs($user, 'backend')
5、禁止中间件
测试应用时,为某些测试禁止中间件很方便。这种机制允许你将路由和控制器与中间件孤立开来做测试,Laravel包含了一个简单的 WithoutMiddleware
trait,可以使用该 trait 自动在测试类中禁止所有中间件:
use Illuminate\Foundation\Testing\DatabaseTransactions; class ExampleTest extends TestCase{ use WithoutMiddleware; // }
如果你只想在某些方法中禁止中间件,可以在测试方法中调用 withoutMiddleware
方法:
<?php class ExampleTest extends TestCase{ /** * 基本功能测试示例 * * @return void */ public function testBasicExample() { $this->withoutMiddleware(); $this->visit('/') ->see('Laravel 5'); } }
6、自定义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']);
7、PHPUnit断言方法
Laravel 为 PHPUnit 测试提供了额外的断言方法:
方法 | 描述 |
---|---|
->assertResponseOk();
|
断言客户端响应状态码是否为200 |
->assertResponseStatus($code);
|
断言客户端响应状态码是否是给定$code |
->assertViewHas($key, $value = null);
|
断言响应视图是否包含给定的绑定数据片段 |
->assertViewHasAll(array $bindings);
|
断言视图是否包含给定绑定数据列表 |
->assertViewMissing($key);
|
断言响应视图缺失绑定数据片段 |
->assertRedirectedTo($uri, $with = []);
|
断言客户端是否重定向到给定URI |
->assertRedirectedToRoute($name, $parameters = [], $with = []);
|
断言客户端是否重定向到给定路由 |
->assertRedirectedToAction($name, $parameters = [], $with = []);
|
断言客户端是否重定向到给定action |
->assertSessionHas($key, $value = null);
|
断言session是否包含给定值 |
->assertSessionHasAll(array $bindings);
|
断言session是否保护眼给定值列表 |
->assertSessionHasErrors($bindings = [], $format = null);
|
断言session是否包含错误绑定 |
->assertHasOldInput();
|
断言sessio包含上次输入数据 |
->assertSessionMissing($key);
|
断言session缺失给定key |