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

问题描述 投票:0回答:1

我正在尝试通过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的实例(验证结果)。当调用Illuminate\Support\MessageBag时,这又返回errors()的实例。 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);
    }

尽管经过一天的研究,该测试仍然有效,但是我很确定我在这里错过了一些非常重要的事情。我没有看过任何教程都提到,注释是必需的,以确保模拟对象的类型是特定的。最终,这是我实现这一目标的唯一途径。我还省去了创建实际的双精度类的尝试,并试图通过内置的功能使它们即时运行。但我知道可能性无限。

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

php laravel mocking phpunit lumen
1个回答
0
投票

[好,我很确定PHPUnit会因为传递给控制器​​的类型错误而引发错误。实际上,这是另外一回事。这些注释仅对于满足Intelephense关于getStub()getMock()方法的返回类型所必需。该测试正在运行,即使没有注释也没有任何错误。

© www.soinside.com 2019 - 2024. All rights reserved.