在 Laravel 5.3 项目中使用 PHPUnit 存根类方法调用的问题

Posted

技术标签:

【中文标题】在 Laravel 5.3 项目中使用 PHPUnit 存根类方法调用的问题【英文标题】:Problems Stubbing class method call using PHPUnit in Laravel 5.3 Project 【发布时间】:2017-03-09 01:02:55 【问题描述】:

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

我的测试:

$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);   

感谢十亿!

【问题讨论】:

我想你自己回答了这个问题:“......我错过了一个“注入”测试假人的步骤......” 那么我走对了吗?文档中没有任何额外的步骤,这只是我对问题的分析。如果我确实需要“注入”这个存根,我该怎么做呢?这是我正在使用的文档:phpunit.de/manual/current/en/… 【参考方案1】:

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

所以,如果你想让 CategoriesController->index() 方法调用你模拟的 Categories 类而不是真正的 Categories 类,你必须将 Categories 类注入到 CategoriesController 类中。像这样的东西应该可以工作:

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

【讨论】:

【参考方案2】:

将你的模拟实例绑定到类名:

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

【讨论】:

感谢您的回复,我期待这样的事情。不幸的是,它对我不起作用。我仍然得到返回的实际数据库数据,而不是预期的 $shouldReturn。 你可以试试更新的线吗?我认为bind 不是正确的方法。 再次感谢,非常感谢您的帮助!尽管如此,它仍然无法正常工作并返回整个数据库输出。

以上是关于在 Laravel 5.3 项目中使用 PHPUnit 存根类方法调用的问题的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 5.3 NotFoundHttpException

Laravel 5.3 中以 API 为中心的应用程序

找不到路线返回页面 Laravel 5.3

在 Laravel 5.3 Passport 中添加 Access-Control-Allow-Origin 标头响应

我无法运行 composer update 命令 laravel 5.3 项目

无法在 Laravel 5.3 迁移中应用约束/外部