gpt4 book ai didi

unit-testing - Laravel 5.1 中的模拟请求用于(实际)单元测试

转载 作者:行者123 更新时间:2023-12-04 02:07:12 25 4
gpt4 key购买 nike

首先,我知道 docs状态:

Note: You should not mock the Request facade. Instead, pass the input you desire into the HTTP helper methods such as call and post when running your test.



但是即使您正在测试 ,这些类型的测试更像是集成或功能测试。 Controller ( SUT ),您并没有将它与它的依赖项分离( Request 和其他人,稍后会详细介绍)。

所以我在做什么,为了做正确的 TDD循环,正在 mock Repository , ResponseRequest (我有问题)。

我的测试是这样的:

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
}

这工作得非常好,它们遵循安排、行动、断言的风格。

问题出在 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
}

正如你所看到的,我 mock 了 Request::only('name')称呼。但是当我运行 $ phpunit我收到以下错误:

BadMethodCallException: Method Mockery_3_Illuminate_Http_Request::setUserResolver() does not exist on this mock object

因为我不是直接打电话 setUserResolver()从我的 Controller ,这意味着它是由 Request 的实现直接调用的.但为什么?我 mock 了方法调用,它不应该调用任何依赖项。

我在这里做错了什么,为什么会收到此错误消息?

PS:作为奖励,我是否通过在 Laravel 框架上强制使用单元测试进行 TDD 来寻找错误的方法,因为似乎文档通过将依赖项和 SUT 之间的交互与 $this->call() 耦合来面向集成测试?

最佳答案

在使用 Laravel 时对 Controller 进行单元测试似乎不是一个好主意。考虑到 Controller 的上下文,我不会关心在请求、响应甚至存储库类上调用的各个方法。

此外,对属于框架的 Controller 进行单元测试是没有意义的,因为您希望将测试 sut 与其依赖项分离,因为您只能在具有给定依赖项的框架中使用该 Controller 。

由于请求、响应和其他类都经过了全面测试(通过底层 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');
}

}

因为这个测试使用了 DatabaseTransactions trait,很容易执行该过程的安排部分,这几乎可以让您将其视为伪单元测试(但这只是想象力的轻微延伸)。

最重要的是,这个测试验证了我的期望是否得到满足。我的测试叫做 test_it_shows_a_paginated_list_of_categories我的测试版本正是这样做的。我觉得单元测试路由只断言调用了一堆方法,但从未验证我是否在页面上显示给定类别的列表。

关于unit-testing - Laravel 5.1 中的模拟请求用于(实际)单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31822541/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com