在 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.
设置测试数据库的所有详细信息
根据 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.
设置测试数据库的所有详细信息