PHPUnit 模拟对象类型

Posted

技术标签:

【中文标题】PHPUnit 模拟对象类型【英文标题】:PHP Unit mocked objects types 【发布时间】:2021-10-31 17:40:16 【问题描述】:

为模拟对象设置类型的正确方法是什么?

示例代码:

/**
 * @dataProvider getTestDataProvider
 * @throws Exception
 */
public function testExampleData(
    Request $request,
    Response $expected,
    SomeClass $someClassMock
): void 
    $result = $someClassMock->getData($request);

    $this->assertEquals($expected, $result);

在本例中,$someClassMock 的类型是类 SomeClass。还有一种名为MockObject 的类型也可以正常工作,但它会破坏该类中函数的自动完成。

我应该在这些模拟对象上使用哪些类型?实物类还是MockObject

【问题讨论】:

【参考方案1】:

为了确保模拟类和 MockObject 的自动完成功能,我所做的是告诉 php 它可以是任何一个类。这为两者添加了自动完成功能,也使得任何阅读代码的人都可以理解它是一个模拟以及它正在模拟什么对象。

在你的情况下,它看起来像这样:

/**
 * @dataProvider getTestDataProvider
 * @throws Exception
 */
public function testExampleData(
    Request $request,
    Response $expected,
    SomeClass|MockObject $someClassMock // <-- Change made here
): void 
    $result = $someClassMock->getData($request);

    $this->assertEquals($expected, $result);

您仍将传入 MockObject,但您的 IDE 不会抱怨任何未知函数。

编辑:为了使它适用于 8 之前的 PHP 版本,我建议这样(最小示例):

class ExampleTest extends TestCase 

    private someClass | MockObject $someClassMock;

    public function setUp(): void
    
        $this->someClassMock = $this->createMock(SomeClass::Class);
    

    public function testMe()
    
        $this->someClassMock->expects($this->once())->method('getData')->willReturn('someStuff');
    



在这种情况下,变量$someClassMock 被声明为两种类型,您可以在整个测试中使用它,并自动完成这两种类型。这也应该适用于您的数据提供者,尽管您可能需要稍微重写它。为了简单起见,我没有在示例中包含它。

【讨论】:

好主意,尽管我认为联合类型仅来自 PHP 8.0。我目前正在运行 7.3。 我看到您正在使用数据提供者来提供模拟。你真的为每次运行提供不同的模拟吗?您可以将$someClassMock 声明为类变量并在setUp() 函数中对其进行初始化。那么你也可以在php8之前使用多类型变量类型声明。我将用一个例子编辑我的答案 不,模拟在所有测试运行中总是相同的。这个问题的主要目的是找出在这些模拟上使用类型的最佳方法。无论哪种方式,代码都可以正常工作,我想知道是否有任何标准和良好的做法。 我已经添加了一个额外的例子,让我知道它是否有意义。 是的,我认为这很好。谢谢。

以上是关于PHPUnit 模拟对象类型的主要内容,如果未能解决你的问题,请参考以下文章

PHPUnit 模拟一个抽象类的所有方法

PHPUnit 模拟和类型提示方法

使用 PHPUnit 模拟 PDO 对象

在 PHPUnit 中实现给定接口的模拟对象上的未定义方法?

PHPUnit 问题断言模拟是使用 Laravel 的 ReflectionProperty 对象

不能用嘲弄 phpunit 来模拟对象