【问题标题】:Adding interface to mock with Mockery (hard dependency)使用 Mockery 添加模拟接口(硬依赖)
【发布时间】:2019-02-19 07:59:52
【问题描述】:

我需要通过重载来模拟 CurrencyEnum,但这不是结束,因为我需要向这个模拟添加接口。 这不起作用:

Mockery::mock('overload:'.CurrencyEnum::class);

错误:(..) must be an instance of \BaseCurrency, instance of \CurrencyEnum given。 我查看了Mockery\Container::mock,但我不知道该怎么做。 例如我想测试TestingClass::first() 方法

class CurrencyEnum implements BaseCurrency
{
    /* methods */
}


class TestingClass
{
    public function first(string $currencySymbol)
    {
        $abc = 'some_string';

        return $this->second($abc, new CurrencyEnum($currencySymbol));
    }

    private function second(string $abc, BaseCurrency $currency)
    {
        /* code */
    }
}

【问题讨论】:

  • 添加更多描述也许你不需要重载
  • 你想在这个例子中测试什么?为什么要模拟这种硬依赖?

标签: php unit-testing phpunit mockery


【解决方案1】:

重载方法通过拦截autoload 机制工作:它为overloaded 类注册一个自动加载器,加载该类的模拟版本而不是原始版本。 默认情况下,它不会向模拟类添加很多东西。但是,您几乎可以配置任何您可能需要的东西。

通常,implementing one or more interfaces 可以通过提供以逗号分隔的完全限定名称列表来完成,第一个是类:

$mock = Mockery::mock('MyClass, MyInterface, OtherInterface');

由于Mockery::mock 方法的设置方式,这将不起作用。 (The author apologises in the source code)

但是,我们可以将接口作为第二个参数传递给模拟方法:

Mockery::mock('overload:'.CurrencyEnum::class, BaseCurrency::class);

这将导致MockConfigurationBuilder 添加BaseCurrency 作为目标;因为它是一个接口,它会让 mock 实现这个接口。

上述的另一种表示法是直接使用构建器:

Mockery::mock(
    (new MockConfigurationBuilder())
        ->setInstanceMock(true)
        ->setName(CurrencyEnum::class)
        ->addTarget('stdClass')
        ->addTarget(BaseCurrency::class)
)

话虽如此,模拟枚举和值对象之类的东西是出了名的糟糕做法。为什么不直接使用实际 CurrencyEnum?像货币代码这样简单的东西根本不值得嘲笑。可能需要对结构进行改进,这会同时为您的测试增加大量价值并使它们更易于阅读。

【讨论】:

    猜你喜欢
    • 2021-09-03
    • 2013-10-29
    • 1970-01-01
    • 2020-09-03
    • 2018-03-26
    • 1970-01-01
    • 1970-01-01
    • 2014-11-05
    • 2023-03-05
    相关资源
    最近更新 更多