使用 PHPUnit 模拟对象,是否有可能期望调用一个神奇的 __call() 方法?

2022-08-30 13:40:28

我在测试中有一个模拟对象。真正的对象 PageRepository 使用 __call() 实现了一个神奇的方法,因此,如果您调用 $pageRepository->findOneByXXXX($value_of_field_XXXX),它将在数据库中搜索与该参数匹配的记录。

有没有办法嘲笑这种方法?

真正的方法调用将如下所示:

$homepage = $pageRepository->findOneBySlug('homepage');

测试将如下所示:

$mockPageRepository->expects($this->any())
    ->method('findOneBySlug')
    ->will($this->returnValue(new Page()));

但它不起作用 - PHPUnit没有发现方法调用。让它看到该方法的唯一方法是在 PageRepository 中显式定义该方法。


答案 1

PHPUnit's采用第二个参数,一个包含要模拟的方法名称的数组。如果在此数组中包含方法名称,则 mock 对象将包含具有该名称的方法,该方法和朋友将处理该方法。getMock()expects()

这甚至适用于未在“real”类中定义的方法,因此类似于以下内容的方法应该可以解决问题:

$mockPageRepository = $this->getMock('PageRepository', array('findOneBySlug'));

请记住,您必须显式包含还需要模拟的任何其他方法,因为只有数组中命名的方法是为 mock 对象定义的。


答案 2

我找到了更好的方法来做到这一点。仍然不完美,但你不必手动指定所有模拟类方法,只需指定魔术方法:

    $methods = get_class_methods(PageRepository::class);
    $methods[] = 'findOneBySlug';
    $pageRepositoryMock = $this->getMockBuilder(PageRepository::class)
        ->disableOriginalConstructor()
        ->disableOriginalClone()
        ->disableArgumentCloning()
        ->disallowMockingUnknownTypes()
        ->setMethods($methods)
        ->getMock();

推荐