当前位置: 首页 > 知识库问答 >
问题:

如何使用 PHP 单元测试模拟方法链

闻人嘉木
2023-03-14

我试图模拟一个方法链(嵌套)以返回所需的值,这是代码:

public function __construct($db)
{
$this->db = $db;
}

public function getResults()
{
return $this->db->getFinder()->find($this->DBTable);
}

我试过这个模拟,但它不起作用:

$dbMock = $this->createMock(DB::class);
        $dbMock = $dbMock
            ->expects(self::any())
            ->method('getFinder')
            ->method('find')
            ->with('questions')
            ->will($this->returnValue('7'));

任何解决方案如何解决这样的问题?

非常感谢。

共有3个答案

乐正翰
2023-03-14

虽然@BVengerov他的答案绝对有效,但我建议改为更改设计。我相信链接模拟不是要走的路,它会损害可读性,更重要的是,损害测试的简单性。

我建议您使Finder类成为您的类的成员。因此,您现在只需模拟Finder

class MyClass {

    private $finder;

    public function __construct(Finder $finder) {
        $this->finder = $finder;
    }

    public function getResults() {
        return $this->finder->find($this->DBTable);
    }
}

此更改使单元测试此函数(和类!)易于理解的

“但我需要在类的其他位置使用$db变量!”首先,这可能表明您当前类中的某个类非常渴望被提取。保持课堂小而简单。

然而,作为一种快速而肮脏的解决方案,考虑添加一个只供测试使用的setFinder()setter。

周马鲁
2023-03-14

链由一个接一个地调用的对象组成。因此,您需要实现一系列模拟。只需以这样的方式模拟方法,即它们返回模拟的对象。

这样的做法应该有效:

$finderMock = $this->createMock(Finder::class);
$finderMock = $finderMock
    ->expects(self::any)
    ->method('find')
    ->with('questions')
    ->will($this->returnValue('7'));

$dbMock = $this->createMock(DB::class);
$dbMock = $dbMock
    ->expects(self::any())
    ->method('getFinder')
    ->will($this->returnValue($finderMock));

在这篇很酷的博文中阅读更多关于模拟链接的内容。

不过,我真的不明白测试链的意义。IMO,最好将测试限制在一次测试1个模块(功能)或2个模块(交互)。

颛孙晗昱
2023-03-14

现在,模拟Demeter链和Fluent接口更简单

简单地说

$dbMock = $dbMock
        ->expects(self::any())
        ->method('getFinder->find')
        ->with('questions')
        ->will($this->returnValue('7'));

嘲弄博士的另一个例子

$object->foo()->bar()->zebra()->alpha()->selfDestruct();

您想使selfDestruct返回10

$mock = \Mockery::mock('CaptainsConsole');
$mock->shouldReceive('foo->bar->zebra->alpha->selfDestruct')->andReturn(10);

 类似资料:
  • 我有一个这样的方法。 > 如果我模拟记录器,是否必须将方法更改为post(字符串json,记录器记录器)?否则,如何使此模拟与该方法交互?

  • 问题内容: 我刚开始使用Node,现在正在编写一些单元测试。对于前几个函数,我可以正常运行,但是现在我碰到了一个包含其中的函数。我的函数的简化版本如下所示: 我尝试使用基本节点断言测试库进行测试: 由于执行此操作的时间(以及结果)总是不同的,因此它将始终失败。 在Python中,我可以设置模拟类和对象。有没有一种方法可以在Node中解决此问题而无需将moment.utc()作为函数的参数? 问题答

  • 由于一个人在单元测试和模拟之前没有经验,我使用Mockito学习了关于JUnit的初学者教程,并进行了一些实践。 现在,我需要对一些在MySQL数据库上执行基本数据库操作的类方法进行单元测试。我不想对数据库进行真正的更改。 在不访问真实数据库的情况下,是否存在验证类似方法的方法?还是我误解了单元测试和嘲笑的概念?

  • 为了获得可重用和可测试的rxjava代码,我使用ObservableTransformers分离了代码的各个部分。它在生产中工作得很好,但是测试它并不像预期的那么容易,因为我似乎无法模拟那些观察到的ransformers。 when(observableTransformer.apply(any())).thenreturn(observable.just(“mockedtext”)); 一旦调用

  • 我有一个问题与存根我的存储库。有人建议我只创建另一个application.properties(我没有这样做),并使用像H2这样的内存数据库。不过,我想知道我是否可以只是存根调用,这样当调用MyDataService.FindById(id)而不是试图从数据库中获取它时,就可以返回一个模拟对象?

  • 问题内容: 嗨,我真的希望您能为我提供帮助,我感觉我已经把头发拉了好几天了。 我正在尝试为方法A编写单元测试。方法A调用静态方法B。我想模拟静态方法B。 我知道以前已经有人问过这个问题,但是我觉得Android从那时起已经成熟,并且必须有一种方法可以执行如此简单的任务,而无需重写我要测试的方法。 这是一个示例,首先是我要测试的方法: 接下来,我要模拟的静态方法: 在其他语言中,这是如此简单,但我无