PHPUnit:使用注解返回特定类型真的有必要吗?

Posted

技术标签:

【中文标题】PHPUnit:使用注解返回特定类型真的有必要吗?【英文标题】:PHPUnit: Is using annotations to return a specific type really necessary? 【发布时间】:2020-07-18 18:53:32 【问题描述】:

我正在尝试使用 Lumen 中的一个小 API 来熟悉 php 中的单元测试。 在一些教程的帮助下编写前几个测试非常好,但现在我遇到了必须模拟/存根依赖项的一点。

我的控制器依赖于构造函数中提示的特定自定义接口类型。 当然,我在 ServiceProvider 中定义了这个接口/实现绑定。

    public function __construct(CustomValidatorContract $validator)
    
        // App\Contracts\CustomValidatorContract
        $this->validator = $validator;
    

    public function resize(Request $request)
    
        // Illuminate\Contracts\Validation\Validator
        $validation = $this->validator->validate($request->all());

        if ($validation->fails()) 
            $response = array_merge(
                $validation
                ->errors() // Illuminate\Support\MessageBag
                ->toArray(), 
                ['error' => 'Invalid request data.']
            );

            // response is global helper
            return response()->json($response, 400, ['Content-Type' => 'application/json']);
        
    

如您所见,我的CustomValidatorContract 有一个方法validate(),它返回一个Illuminate\Contracts\Validation\Validator 的实例(验证结果)。当调用errors() 时,这又会返回Illuminate\Support\MessageBag 的实例。 MessageBag 然后有一个toArray() 方法。

现在我想测试我的控制器的行为,以防验证失败。

    /** @test */
    public function failing_validation_returns_400()
    
        $EmptyErrorMessageBag = $this->createMock(MessageBag::class);
        $EmptyErrorMessageBag
            ->expects($this->any())
            ->method('toArray')
            ->willReturn(array());

        /** @var ValidationResult&\PHPUnit\Framework\MockObject\MockObject $AlwaysFailsTrueValidationResult */
        $AlwaysFailsTrueValidationResult = $this->createStub(ValidationResult::class);
        $AlwaysFailsTrueValidationResult
            ->expects($this->atLeastOnce())
            ->method('fails')
            ->willReturn(true);
        $AlwaysFailsTrueValidationResult
            ->expects($this->atLeastOnce())
            ->method('errors')
            ->willReturn($EmptyErrorMessageBag);

        /** @var Validator&\PHPUnit\Framework\MockObject\MockObject $CustomValidatorAlwaysFailsTrue */
        $CustomValidatorAlwaysFailsTrue = $this->createStub(Validator::class);
        $CustomValidatorAlwaysFailsTrue
            ->expects($this->once())
            ->method('validate')
            ->willReturn($AlwaysFailsTrueValidationResult);

        $controller = new ImageResizeController($CustomValidatorAlwaysFailsTrue);
        $response = $controller->resize(new Request);

        $this->assertEquals(400, $response->status());
        $this->assertEquals(
            'application/json',
            $response->headers->get('Content-Type')
        );
        $this->assertJson($response->getContent());
        $response = json_decode($response->getContent(), true);
        $this->assertArrayHasKey('error', $response);
    

尽管经过一天的研究,这个测试正在发挥作用,但我很确定我在这里错过了一些非常重要的东西。我见过的教程都没有提到,注释是确保模拟的对象类型是特定类型所必需的。最终,这是我完成这项工作的唯一方法。 我也放弃了创建实际的双重类,并尝试使用内置功能即时制作它们。但我知道可能性是存在的。

如果这至少接近预期的测试方法,如果您能给我一个建议,我将不胜感激。 如果我必须处理特定的对象类型,我真的必须编写注释吗? 我的架构是否仍然存在问题,以至于感觉如此“过度设计”?

【问题讨论】:

【参考方案1】:

好的,我很确定 PHPUnit 抛出了错误,因为传递给控制器​​的类型错误。实际上,这是另一回事。 这些注解只需要满足 Intelephense 关于 getStub()getMock() 方法的返回类型的要求。 即使没有注释,测试也可以正常运行。

【讨论】:

以上是关于PHPUnit:使用注解返回特定类型真的有必要吗?的主要内容,如果未能解决你的问题,请参考以下文章

Spring中的@Configuration注解你真的了解吗?

真的有必要用rxjava吗

PHPDoc:@return void 有必要吗?

phpunit可以使用多个数据提供者吗

调用_freea 真的有必要吗?

引用 url() 的值真的有必要吗?