【问题标题】:Mocking a singleton class in laravel 5.8 in my phpunit tests在我的 phpunit 测试中模拟 laravel 5.8 中的单例类
【发布时间】:2019-12-14 21:51:07
【问题描述】:

我试图模拟一个作为依赖注入另一个类的单例类。由于显而易见的原因(单例发生在模拟之前,在服务容器级别/AppServiceProvider 级别),该类是常规实例而不是模拟对象。

类构造函数如下所示:

    /**
     * constructor.
     */
    public function __construct()
    {
        $this->classToBeMocked = resolve('ClassToBeMocked');
    }

我不得不把它改成

   /**
     * constructor.
     */
    public function __construct(ClassToBeMocked $classToBeMocked)
    {
        $this->classToBeMocked = $classTobeMocked;
    }

并停止使用单例。

关于如何在 laravel 中模拟单例或重新实例化单例的任何见解,以便在测试中模拟一次后生效。

谢谢

【问题讨论】:

  • 您的示例代码完全相同,通常您将所有内容模拟并在测试中调用 api,然后首先将其实例化,我可以看看您如何调用您的应用程序吗?

标签: laravel mocking phpunit singleton laravel-5.8


【解决方案1】:

通常你会将服务提供者中的单例定义为:

$this->app->singleton('ClassToBeMocked');

如果您正在这样做,那么您可以通过在测试设置中交换其实例来在测试中模拟它:

 protected function setUp():void {
    parent::setUp();
    $mockInstance = $this->getMockBuilder('ClassToBeMocked')->getMock();
    // Define behaviour
    $this->app->instance('ClassToBeMocked', $mockInstance);
 }

这样,当您的依赖注入容器尝试解析单例时,将改为获取模拟实例。这将适用于 resolve('ClassToBeMocked')resolve('ClassWhichTakesClassToBeMockedAsAConstructorArgument')

【讨论】:

  • 看起来合乎逻辑,但从模拟 POV 来看有点局限。我必须为整个测试类定义一个固定的行为。
  • 您可以在单独的测试函数中移动此设置(如果您是这个意思)
  • 是的,但我的意思是,如果类似: $this->app->re-instance(Class) 这样就可以在同一个测试类中设置不同的模拟行为而不必为每个模拟行为创建一个新的测试类
  • 每个测试都是独立运行的,所以如果你在测试用例函数本身中执行$this->app->instance('ClassToMock', $mock),它应该可以工作
猜你喜欢
  • 2018-12-27
  • 2019-02-13
  • 1970-01-01
  • 2011-09-07
  • 1970-01-01
  • 2013-08-12
  • 2020-03-05
  • 1970-01-01
  • 2019-08-04
相关资源
最近更新 更多