您好,欢迎访问一九零五行业门户网

[ Laravel 5.2 文档 ] 服务 -- 测试

1、简介 laravel 植根于测试,实际上,内置使用 phpunit对测试提供支持是即开即用的,并且 phpunit.xml文件已经为应用设置好了。框架还提供了方便的辅助方法允许你对应用进行富有表现力的测试。
tests目录中提供了一个 exampletest.php文件,安装完新的 laravel 应用后,只需简单在命令行运行 phpunit来运行测试。
1.1 测试环境 运行测试的时候,laravel 自动设置配置环境为 testing。laravel在测试时自动配置 session 和 cache 驱动为数组驱动,这意味着测试时不会持久化存储 session 和 cache。
如果需要的话你也可以创建其它测试环境配置。 testing环境变量可以在 phpunit.xml文件中配置。
1.2 定义&运行测试 要创建一个新的测试用例,可以使用如下artisan命令:
php artisan make:test usertest
该命令将会在 tests目录下生成一个新的 usertest类。然后你可以使用phpunit 定义测试方法。要运行测试,简单从终端执行 phpunit命令即可:
asserttrue(true); }}
注意:如果你在测试类中定义自己的 setup方法,确保在其中调用 parent::setup。
2、应用测试 laravel 为生成 http请求、测试输出、以及填充表单提供了平滑的api。举个例子,我们看下 tests目录下包含的 exampletest.php文件:
visit('/') ->see('laravel 5') ->dontsee('rails'); }}
visit方法生成了一个get请求, see方法对我们从应用返回响应中应该看到的给定文本进行断言。 dontsee方法对给定文本没有从应用响应中返回进行断言。在laravel中这是最基本的有效应用测试。
2.1 与应用交互 当然,除了对响应文本进行断言之外还有做更多测试,让我们看一些点击链接和填充表单的例子:
点击链接
在本测试中,我们将为应用生成请求,在返回的响应中“点击”链接,然后对访问uri进行断言。例如,假定响应中有一个“关于我们”的链接:
about us
现在,让我们编写一个测试点击链接并断言用户访问页面是否正确:
public function testbasicexample(){ $this->visit('/') ->click('about us') ->seepageis('/about-us');}
处理表单
laravel 还为处理表单提供了多个方法。 type, select, check, attach, 和 press方法允许你与所有表单输入进行交互。例如,我们假设这个表单存在于应用注册页面:
{!! csrf_field() !!} name:
accept terms

我们可以编写测试完成表单并检查结果:
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') ->name('file name', 'name') ->attach($absolutepathtofile, 'photo') ->press('upload') ->see('upload successful!');}
2.2 测试json api laravel 还提供多个帮助函数用于测试 json api 及其响应。例如, get, post, put, patch, 和 delete方法用于通过多种 http 请求方式发出请求。你还可以轻松传递数据和头到这些方法。作为开始,我们编写测试来生成 post 请求到 /user并断言返回的数据是否是 json 格式:
post('/user', ['name' => 'sally']) ->seejson([ 'created' => true, ]); }}
seejson方法将给定数组转化为 json,然后验证应用返回的整个 json 响应中的 json 片段。因此,如果在 json 响应中有其他属性,只要给定片段存在的话测试依然会通过。
验证json值匹配
如果你想要验证给定数组和应用返回的json能够精确匹配,使用 seejsonequals方法:
post('/user', ['name' => 'sally']) ->seejsonequals([ 'created' => true, ]); }}
验证json数据结构匹配
还可以验证json响应是否与指定数据结构匹配,我们使用 seejsonstructure方法来实现这一功能:
get('/user/1') ->seejsonstructure([ 'name', 'pet' => [ 'name', 'age' ] ]); }}
上面的例子演示了期望获取一个包含 name和嵌套 pet对象(该对象包含 name和 age属性)的 json 数据。如果 json 响应中包含其它额外键 seejsonstructure也不会失败,例如,如果 pet对象包含 weight属性测试仍将通过。
你可以使用*来断言返回json结构包含一个列表,该列表中的每个数据项都包含至少如下示例中列出的属性:
get('/users') ->seejsonstructure([ '*' => [ 'id', 'name', 'email' ] ]); }}
你还可以使用嵌套的*,在这种场景中,我们可以断言json响应中的每个用户都包含一个给定属性集合,而且每个用户的每个 pet都包含给定属性集合:
$this->get('/users') ->seejsonstructure([ '*' => [ 'id', 'name', 'email', `pets` => [ '*' => [ 'name', 'age' ] ] ] ]);
2.3 session/认证 laravel提供了多个辅助函数用于在测试期间处理session,首先,可以使用 withsession方法设置 session 值到给定数组。这在测试请求前获取 session 数据时很有用:
withsession(['foo' => 'bar']) ->visit('/'); }}
当然,session的通常用于操作用户状态,例如认证用户。辅助函数 actingas提供了认证给定用户为当前用户的简单方法,例如,我们使用模型工厂生成和认证用户:
create(); $this->actingas($user) ->withsession(['foo' => 'bar']) ->visit('/') ->see('hello, '.$user->name); }}
还可以通过传递 guard名称作为 actingas函数的第二个参数的方式来指定使用哪个 guard来认证给定用户:
$this->actingas($user, 'backend')
2.4 禁止中间件 测试应用时,为某些测试禁止中间件很方便。这种机制允许你将路由和控制器与中间件孤立开来做测试,laravel包含了一个简单的 withoutmiddlewaretrait,可以使用该 trait 自动在测试类中禁止所有中间件:
visit('/') ->see('laravel 5'); }}
2.5 自定义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']);
2.6 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包含上次输入数据
3、处理数据库 laravel还提供了多种有用的工具让测试数据库驱动的应用更加简单。首先,你可以使用帮助函数 seeindatabase来断言数据库中的数据是否和给定数据集合匹配。例如,如果你想要通过 email 值为 sally@example.com的条件去数据表 users查询是否存在该记录 ,我们可以这样做:
public function testdatabase(){ // 调用应用... $this->seeindatabase('users', ['email' => 'sally@foo.com']);}
当然, seeindatabase方法和其它类似辅助方法都是为了方便起见进行的封装,你也可以使用其它phpunit内置的断言方法来进行测试。
3.1 每次测试后重置数据库 每次测试后重置数据库通常很有用,这样的话上次测试的数据不会影响下一次测试。
使用迁移
一种方式是每次测试后回滚数据库并在下次测试前重新迁移。laravel提供了一个简单的 databasemigrationstrait来自动为你处理。在测试类上简单使用该trait如下:
visit('/') ->see('laravel 5'); }}
使用事务
另一种方式是将每一个测试用例包裹到一个数据库事务中,laravel提供了方便的 databasetransactionstrait自动为你处理:
visit('/') ->see('laravel 5'); }}
注意:该trait只在事务中封装默认数据库连接。
3.2 模型工厂 测试时,通常需要在执行测试前插入新数据到数据库。在创建测试数据时,laravel允许你使用“factories”为每个eloquent模型定义默认的属性值集合,而不用手动为每一列指定值。作为开始,我们看一下 database/factories/modelfactory.php文件,该文件包含了一个工厂定义:
$factory->define(app\user::class, function (faker\generator $faker) { return [ 'name' => $faker->name, 'email' => $faker->email, 'password' => bcrypt(str_random(10)), 'remember_token' => str_random(10), ];});
在闭包中,作为工厂定义,我们返回该模型上所有属性默认测试值。该闭包接收php库 faker实例,从而允许你方便地为测试生成多种类型的随机数据。
当然,你可以添加更多工厂到 modelfactory.php文件。
多个工厂类型
有时候你可能想要为同一个eloquent模型类生成多个工厂,例如,除了正常用户外可能你想要为“管理员”用户生成一个工厂,你可以使用 defineas方法定义这些工厂:
$factory->defineas(app\user::class, 'admin', function ($faker) { return [ 'name' => $faker->name, 'email' => $faker->email, 'password' => str_random(10), 'remember_token' => str_random(10), 'admin' => true, ];});
你可以使用 raw方法获取基本属性而不用重复基本用户工厂中的所有属性,获取这些属性后,只需将你要求的额外值增补进去即可:
$factory->defineas(app\user::class, 'admin', function ($faker) use ($factory) { $user = $factory->raw(app\user::class); return array_merge($user, ['admin' => true]);});
在测试中使用工厂
定义好工厂后,可以在测试或数据库填充文件中通过全局的 factory方法使用它们来生成模型实例,所以,让我们看一些生成模型的例子,首先,我们使用 make方法,该方法创建模型但不将其保存到数据库:
public function testdatabase(){ $user = factory(app\user::class)->make(); // 用户模型测试...}
如果你想要覆盖模型的一些默认值,可以传递数组值到 make方法。只有指定值被替换,其他数据保持不变:
$user = factory(app\user::class)->make([ 'name' => 'abigail',]);
还可以创建多个模型集合或者创建给定类型的集合:
// 创建3个 app\user 实例...$users = factory(app\user::class, 3)->make();// 创建1个 app\user admin 实例...$user = factory(app\user::class, 'admin')->make();// 创建3个 app\user admin 实例...$users = factory(app\user::class, 'admin', 3)->make();
持久化工厂模型
create方法不仅能创建模型实例,还可以使用eloquent的 save方法将它们保存到数据库:
public function testdatabase(){ $user = factory(app\user::class)->create(); //用户模型测试...}
你仍然可以通过传递数组到 create方法覆盖模型上的属性:
$user = factory(app\user::class)->create([ 'name' => 'abigail',]);
添加关联关系到模型
你甚至可以持久化多个模型到数据库。在本例中,我们添加一个关联到创建的模型,使用 create方法创建多个模型的时候,会返回一个eloquent集合实例,从而允许你使用集合提供的所有便利方法,例如 each:
$users = factory(app\user::class, 3) ->create() ->each(function($u) { $u->posts()->save(factory(app\post::class)->make()); });
4、 模拟 4.1 模拟事件 如果你在重度使用laravel的时间系统,可能想要在测试时模拟特定事件。例如,如果你在测试用户注册,你可能不想所有 userregistered的时间处理器都被触发,因为这可能会发送欢迎邮件,等等。
laravel提供可一个方便的 expectsevents方法来验证期望的事件被触发,但同时阻止该事件的其它处理器运行:
expectsevents(app\events\userregistered::class); // 测试用户注册代码... }}
可以使用 doesntexpectevents方法来验证给定事件没有被触发:
expectsevents(app\events\podcastwaspurchased::class); $this->doesntexpectevents(app\events\paymentwasdeclined::class); // test purchasing podcast... }}
如果你想要阻止所有事件运行,可以使用 withoutevents方法:
withoutevents(); // 测试用户注册代码... }}
4.2 模拟队列任务 有时候,你可能想要在请求时简单测试控制器分发的指定任务,这允许你孤立的测试路由/控制器——将其从任务逻辑中分离出去,当然,接下来你可以在一个独立测试类中测试任务本身。
laravel提供了一个方便的 expectsjobs方法来验证期望的任务被分发,但该任务本身不会被测试:
expectsjobs(app\jobs\purchasepodcast::class); // 测试购买播客代码... }}
注意:这个方法只检查通过 dispatchesjobstrait分发方法分发的任务,并不检查直接通过 queue::push分发的任务。
4.3 模拟门面 测试的时候,你可能经常想要模拟laravel门面的调用,例如,看看下面的控制器动作:
with('key') ->andreturn('value'); $this->visit('/users')->see('value'); }}
注意:不要模拟 request门面,取而代之地,在测试时传递输入到http帮助函数如 call和 post。
其它类似信息

推荐信息