过去我总是偶然发现 phpspec 的某个问题:
假设我有一个方法调用另一个对象的多个方法
class Caller {
public function call(){
$this->receiver->method1();
...
$this->receiver->method2();
}
}
在 BDD 中,我会首先编写一个测试,以确保调用 method1。
function it_calls_method1_of_receiver(Receiver $receiver){
$receiver->method1()->shouldBeCalled();
$this->call();
}
然后我将编写下一个测试以确保调用 method2。
function it_calls_method2_of_receiver(Receiver $receiver){
$receiver->method2()->shouldBeCalled();
$this->call();
}
但此测试在 phpspec 中失败,因为 method1 在 method2 之前被调用。 为了满足 phpspec,我必须检查这两个方法调用。
function it_calls_method2_of_receiver(Receiver $receiver){
$receiver->method1()->shouldBeCalled();
$receiver->method2()->shouldBeCalled();
$this->call();
}
我的问题是,它会使每个测试都膨胀。在此示例中,它只是一个额外的行,但可以想象一个方法可以构建一个具有大量 setter 的对象。 我需要为每个测试编写所有 setter 。很难看出测试的目的,因为每个测试都很大而且看起来都一样。
我很确定这不是 phpspec 或 bdd 的问题,而是我的体系结构的问题。什么是更好(更可测试)的编写方式?
例如:
public function handleRequest($request, $endpoint){
$endpoint->setRequest($request);
$endpoint->validate();
$endpoint->handle();
}
我在这里验证请求是否为特定端点提供了所有必要的信息(或抛出异常),然后处理请求。我选择这种模式来将验证与端点逻辑分开。
最佳答案
Prophecy , PhpSpec 使用的模拟框架,很有主见。它遵循 mockist 方法(TDD 伦敦学院),该方法捍卫我们应该一次描述一种行为。
模拟是一种测试,因此您希望每次测试都保留一个模拟。您可以模拟所有调用,但这看起来并不优雅。推荐的方法是分离您正在测试的行为并选择该行为所需的模拟,对其余调用进行 stub 。如果您发现自己在一个测试中创建了大量的 stub ,表明对功能的嫉妒——您应该考虑将行为转移给被调用者,或者在中间添加一个人。
假设您决定继续并描述您拥有的代码,而不进行重构。如果您对第二个调用感兴趣,根据您的示例,您应该使用 willReturn
或类似方法对其他调用进行 stub 。例如。 $endpoint->setRequest(Argument::type(Request::class))->willReturn()
而不是 shouldBeCalled()
。
关于php - 在 phpspec 中测试多个方法的调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34474097/