PhpUnit10已使非静态测试提供程序不再受欢迎.这使得在提供程序中创建双重测试成为问题,因为像createMock()createStub()这样的方法不是静态的.以下是一个证明这个问题的假测试:

public function provideFake(): array
{
    $someDate = $this->createMock(\DateTime::class);
    $someOtherDate = $this->createMock(\DateTime::class);
    return [
        'first test' => [$someDate],
        'second test' => [$someOtherDate],
    ];
}

/**
 * @dataProvider provideFake
 */
public function testFake(\DateTime $date): void
{
    self::assertTrue(true);
}

在PhpUnit10/PHP8.2中运行此测试,输出:

有1个PHPUnit弃用:数据提供程序方法ProvideFake()不是静态的

如果我将提供程序更改为静态,结果显然会更糟:

出现1个PHPUnit错误:为testFake指定的数据提供程序无效.在不在对象上下文中时使用$This

我可以在测试本身内而不是在提供程序内创建双重测试.在这个简单的例子中,它没有太大变化,因为我的替身只是没有固定行为的假人.

但在现实生活测试中,可能需要许多参数来定义这种行为.这意味着提供程序必须输出所有这些参数,而不是只输出一个对象,并且测试方法必须具有非常长的签名才能接受它们.

在我看来,这大大降低了代码的可读性.

有没有办法让静态提供程序创建测试替身?

推荐答案

我不知道这是一种好的方法还是坏的方法,但我一直在为一个松散相关的用例使用回调函数.根据您的示例进行调整,它可能如下所示:

private function mockDate(string $value): MockObject
{
    $mock = $this->createMock(\DateTime::class);
    $mock
        ->expects($this->any())
        ->method('format')
        ->with('y-m-d')
        ->willReturn($value);
    return $mock;
}

public static function provideFake(): array
{
    return [
        'first test' => [
            'dateCallback' => static fn (self $testCase) => $testCase->mockDate('2000-12-31'),
            'expected' => '2000-12-31',
        ],
        'second test' => [
            'dateCallback' => static fn (self $testCase) => $testCase->mockDate('2099-01-01'),
            'expected' => '2099-01-01',
        ],
    ];
}

/**
 * @dataProvider provideFake
 */
public function testFake(callable $dateCallback, string $expected): void
{
    $date = $dateCallback($this);
    self::assertInstanceOf(\DateTime::class, $date);
    self::assertEquals($expected, $date->format('y-m-d'));
}

请注意,完全提供程序甚至在实际测试开始之前立即运行,因此在try 进行复杂的安排时需要谨慎.当然,回调会将它们的执行延迟到测试本身(这就是重点),但数据提供程序很可能不适合执行复杂的逻辑,如数据库查询.

Php相关问答推荐

用户信息更新期间Laravel邮箱验证问题

如何使用ms graph php sdk v2列出具有已知路径的DriveItem的子项

从订单项目中获取ACF WooCommerce产品价值

PHP根据特定索引值从中删除子数组

如何从Laravel中的Spatie\Dns\Records\A对象中提取IP地址

htaccess重命名index.php以在URL中显示为SEO的友好名称

无法在Laravel中将日志(log)通道设置为空

即使在WooCommerce购物车中添加了两次产品,也要将所有项目设置为空白行

Rappasoft Datatables V2(我想在另一个表具有相同值列时显示数据)

将购物车按钮重定向到Checkout-Wooccommerce

如果所有请求都通过index.php路由,如何使用htaccess文件强制使用HTTPS?

在 PHP 中将字符串分解为数组(字符串类似于 WP 短代码)

启用 WooCommerce 我的帐户付款方式,允许客户添加付款方式

如何从 URL 核心 PHP 中的 API 获取 JSON?

如何搜索和替换 XML 文件中的一段文本?

来自 GoDaddy 的邮箱在 Gmail 中显示为via

为什么可以从 PHP 类访问 PHP Trait 的私有成员?

在 EasyAdmin 中添加全局操作,将我的按钮放在表格下方而不是上方

如何通过本地主机在同一台 PC 上同时运行 Microsoft IIS 和 WAMP

从 d-m-Y 日期格式 laravel 计算月份 = 01 的列的总和