代码之家  ›  专栏  ›  技术社区  ›  alexmcfarlane

在不创建工厂的情况下,在Laravel中用构造函数参数对外部模拟类进行单元测试?

  •  0
  • alexmcfarlane  · 技术社区  · 1 年前

    在Laravel单元测试中,我们测试并嘲笑ReCaptcha\ReCaptcha(以及NZTim\Mailchimp\Mailchimp)。工作测试代码如下:

    $this->mock(\ReCaptcha\ReCaptcha::class, function ($mock) use ($mock_response) {
                $mock->shouldReceive('make')
                    ->once()
                    ->andReturn($mock);
                $mock->shouldReceive('verify')
                    ->once()
                    ->andReturn($mock_response);
            });
    

    在控制器中,我们有:

    $recaptcha = app(ReCaptcha::class)->make();
    

    为了实现这一点,由于ReCaptcha类需要一个构造函数变量,我们创建了以下工厂:

    // ReCaptchaFactory.php
    
    public function make()
    {
         $secret = config('services.recaptcha.secret');
         return new ReCaptcha($secret);
    }
    

    如果没有所需的构造函数变量,我们可以用1行代码来完成这一任务,并删除额外的工厂和AppServiceProvider更新:

    $recaptcha = app(ReCaptcha::class);
    

    以下内容?

    $recaptcha = resolve(ReCaptcha::class, ['param1'=>config('services.recaptcha.secret'));
    

    只是感觉我们有很多额外的不必要的代码。

    1 回复  |  直到 1 年前
        1
  •  0
  •   apokryfos    1 年前

    您可以使用 contextual binding 在服务提供商中:

    app()->when(ReCaptcha::class)
              ->needs('$secret')
              ->give(config('services.recaptcha.secret');
    

    然后在您的控制器中,您只需使用:

    $recaptcha = app(ReCaptcha::class);
    

    这将导致您的控制器在构造repatcha类时向其提供已配置的秘密。

    您的测试只需要:

    $this->mock(\ReCaptcha\ReCaptcha::class, function ($mock) use ($mock_response) {
        $mock->shouldReceive('verify')
            ->once()
            ->andReturn($mock_response);
     });
    

    这应该有效,因为 $this->mock 为应用程序容器提供了一个预先创建的(在本例中是模拟的)实例,因此容器将不需要构造新的实例,也不需要查找上下文绑定。

    推荐文章