添加接口以使用 Mockery 进行模拟(硬依赖)
Adding interface to mock with Mockery (hard dependency)
我需要通过重载来模拟 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 */
}
}
重载方法通过拦截 autoload
机制来工作:它为 overloaded
class 注册一个自动加载器,加载 class 的模拟版本而不是原来的。
默认情况下,它不会向模拟 class 添加很多东西。但是,您可以配置任何您可能需要的东西。
通常,implementing one or more interfaces 可以通过提供以逗号分隔的完全限定名称列表来完成,第一个是 class:
$mock = Mockery::mock('MyClass, MyInterface, OtherInterface');
由于 Mockery::mock
方法的设置方式,这将不起作用。 (The author apologises in the source code)
但是,我们可以将接口作为第二个参数传递给 mock 方法:
Mockery::mock('overload:'.CurrencyEnum::class, BaseCurrency::class);
这将导致 MockConfigurationBuilder
添加 BaseCurrency
作为目标;因为它是一个接口,它将使模拟实现接口。
上面的另一种表示法是直接使用构建器:
Mockery::mock(
(new MockConfigurationBuilder())
->setInstanceMock(true)
->setName(CurrencyEnum::class)
->addTarget('stdClass')
->addTarget(BaseCurrency::class)
)
话虽如此,模拟枚举和值对象之类的东西是一种众所周知的糟糕做法。为什么不直接使用 actual CurrencyEnum
?像货币代码这样简单的东西根本不值得嘲笑。可能需要进行结构改进,这会同时为您的测试增加大量价值并使它们更易于阅读。
我需要通过重载来模拟 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 */
}
}
重载方法通过拦截 autoload
机制来工作:它为 overloaded
class 注册一个自动加载器,加载 class 的模拟版本而不是原来的。
默认情况下,它不会向模拟 class 添加很多东西。但是,您可以配置任何您可能需要的东西。
通常,implementing one or more interfaces 可以通过提供以逗号分隔的完全限定名称列表来完成,第一个是 class:
$mock = Mockery::mock('MyClass, MyInterface, OtherInterface');
由于 Mockery::mock
方法的设置方式,这将不起作用。 (The author apologises in the source code)
但是,我们可以将接口作为第二个参数传递给 mock 方法:
Mockery::mock('overload:'.CurrencyEnum::class, BaseCurrency::class);
这将导致 MockConfigurationBuilder
添加 BaseCurrency
作为目标;因为它是一个接口,它将使模拟实现接口。
上面的另一种表示法是直接使用构建器:
Mockery::mock(
(new MockConfigurationBuilder())
->setInstanceMock(true)
->setName(CurrencyEnum::class)
->addTarget('stdClass')
->addTarget(BaseCurrency::class)
)
话虽如此,模拟枚举和值对象之类的东西是一种众所周知的糟糕做法。为什么不直接使用 actual CurrencyEnum
?像货币代码这样简单的东西根本不值得嘲笑。可能需要进行结构改进,这会同时为您的测试增加大量价值并使它们更易于阅读。