Chr*_*sco 11 tdd unit-testing laravel laravel-5 laravel-5.1
首先,我知道文档说明:
注意:您不应该模拟请求外观.相反,在运行测试时,将您想要的输入传递给HTTP帮助程序方法,例如调用和发布.
但是那些类型的测试更像是集成或功能,因为即使你正在测试一个控制器(SUT你),你也不会将它与它的依赖关系脱钩(Request和其他人一样,稍后会更多).
所以我在做什么,为了做正确的TDD循环,被嘲讽Repository,Response和Request(我有问题).
我的测试看起来像这样:
public function test__it_shows_a_list_of_categories() {
$categories = [];
$this->repositoryMock->shouldReceive('getAll')
->withNoArgs()
->once()
->andReturn($categories);
Response::shouldReceive('view')
->once()
->with('categories.admin.index')
->andReturnSelf();
Response::shouldReceive('with')
->once()
->with('categories', $categories)
->andReturnSelf();
$this->sut->index();
// Assertions as mock expectations
}
Run Code Online (Sandbox Code Playgroud)
这非常好用,它们遵循Arrange,Act,Assert风格.
问题在于Request,如下所示:
public function test__it_stores_a_category() {
Redirect::shouldReceive('route')
->once()
->with('categories.admin.index')
->andReturnSelf();
Request::shouldReceive('only')
->once()
->with('name')
->andReturn(['name' => 'foo']);
$this->repositoryMock->shouldReceive('create')
->once()
->with(['name' => 'foo']);
// Laravel facades wont expose Mockery#getMock() so this is a hackz
// in order to pass mocked dependency to the controller's method
$this->sut->store(Request::getFacadeRoot());
// Assertions as mock expectations
}
Run Code Online (Sandbox Code Playgroud)
如你所见,我嘲笑了Request::only('name')电话.但是当我运行时,$ phpunit我收到以下错误:
BadMethodCallException: Method Mockery_3_Illuminate_Http_Request::setUserResolver() does not exist on this mock object
Run Code Online (Sandbox Code Playgroud)
因为我不直接setUserResolver()从我的控制器调用,这意味着它是由执行直接调用的Request.但为什么?我模拟了方法调用,它不应该调用任何依赖.
我在这里做错了什么,为什么我收到此错误消息?
PS:作为奖励,我通过在Laravel框架上使用单元测试强制TDD来查看它是错误的方式,因为看起来文档通过耦合依赖关系和SUT之间的交互来进行集成测试$this->call()?
使用Laravel时对控制器进行单元测试似乎不是一个好主意.考虑到Controller的上下文,我不会关注在Request,Response甚至是存储库类上调用的各个方法.
此外,单元测试属于框架,因为要解耦它的依赖测试SUT是没有意义的,因为你只能使用控制器与那些依赖给出该框架的控制器.
由于请求,响应和其他类都经过全面测试(通过底层Symfony类或Laravel本身),作为开发人员,我只关心测试我拥有的代码.
我会写一个验收测试.
<?php
use App\User;
use App\Page;
use App\Template;
use App\PageType;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class CategoryControllerTest extends TestCase
{
use DatabaseTransactions;
/** @test */
public function test__it_shows_a_paginated_list_of_categories()
{
// Arrange
$categories = factory(Category::class, 30)->create();
// Act
$this->visit('/categories')
// Assert
->see('Total categories: 30')
// Additional assertions to verify the right categories can be seen may be a useful additional test
->seePageIs('/categories')
->click('Next')
->seePageIs('/categories?page=2')
->click('Previous')
->seePageIs('/categories?page=1');
}
}
Run Code Online (Sandbox Code Playgroud)
因为这个测试使用了DatabaseTransactions特征,所以很容易执行过程的排列部分,这几乎可以让你把它读作伪单元测试(但这只是想象力的一小部分).
最重要的是,此测试验证了我的期望得到满足.我的测试被调用test_it_shows_a_paginated_list_of_categories,我的测试版本就是这样.我觉得单元测试路由只断言调用了一堆方法,但是并没有验证我是否在页面上显示给定类别的列表.
| 归档时间: |
|
| 查看次数: |
8145 次 |
| 最近记录: |