在 Laravel 5.3 项目中使用 PHPUnit 存根 class 方法调用时出现问题

Problems Stubbing class method call using PHPUnit in Laravel 5.3 Project

根据 phpunit 文档,我想出了以下代码。测试失败,输出显示它不是在调用存根方法,而是调用实际方法,访问数据库并从数据库返回数据。我相信我错过了 "inject" 测试虚拟机的步骤,以便调用它而不是实际的 class 方法。谁能指出我在这里做错了什么?

我的测试:

$shouldReturn = '[{"name":"A Category Name 1"},{"name":"A Category Name 2"},{"name":"A Category Name 3"}]';

// Create a mock for the CategoryClass,
$catClassMock = $this->getMockBuilder(CategoryClass::class)->getMock();

// Set up the Test Dummy for the findAll method and stub what should be returned.
$catClassMock->expects($this->once())
    ->method('findAll')
    ->with($this->returnValue($shouldReturn));

// Setup the controller object, and call the index method.
$CategoriesController = new CategoriesController();
$returnedResults = $CategoriesController->index();

// Assert the results equal what we told the method to return.
$this->assertEquals($returnedResults, $shouldReturn);

CategoriesController 方法:

public function index() {
    // List all category
    return $this->categoryClass->findAll();
}

注意:$this->categoryClass是在CategoriesController的构造方法中被实例化的。 $this->categoryClass = new CategoryClass;

CategoryClass的findAll方法:

public function findAll() {
    // List all categories
    $categories = Category::all(); // Eloquent call to database.
    return json_encode($categories);   
}

感谢十亿!

将您的模拟实例绑定到 class 名称:

$this->app->instance(CategoryClass::class, $catClassMock);

当您在模拟的 class 对象中模拟方法时,您必须使用该模拟的 class 对象来获取模拟方法的响应。

所以,如果你想让 CategoriesController->index() 方法调用你的模拟类别 class 而不是真正的类别 class,你必须注入类别 class 进入类别控制器 class。这样的事情应该有效:

$shouldReturn = '[{"name":"A Category Name 1"},{"name":"A Category Name 2"},{"name":"A Category Name 3"}]';

$catClassMock = $this->getMockBuilder(CategoryClass::class)
    ->setMethods(['findAll'])
    ->getMock();

// Set up the Test Dummy for the findAll method and stub what should be returned.
$catClassMock
    ->method('findAll')
    ->willReturn($shouldReturn);


// Setup the controller object, and call the index method.
$CategoriesController = new CategoriesController();
$CategoriesController->categoryClass = $catClassMock;
$returnedResults = $CategoriesController->index();

// Assert the results equal what we told the method to return.
$this->assertEquals($returnedResults, $shouldReturn);

我还应该提到,创建一个在每次测试之前播种的内存中 sqlite 数据库也可以工作,并且无需模拟您 Eloquent 查询。在长运行中也可能更容易维护。查看 https://laracasts.com/series/phpunit-testing-in-laravel 以了解有关如何为 Laravel 的 Eloquent.

设置测试数据库的所有详细信息