Java Mockito验证是否只调用了预期的方法

Java Mockito验证是否只调用了预期的方法,java,mockito,Java,Mockito,我在一个项目中工作,有一个服务类和一个充当门面的客户机(不知道这在设计模式的世界中是否是正确的术语,但我会尽量澄清)服务的方法可能非常昂贵,因为它们可能与一个或多个数据库通信、长时间检查等,因此每个客户端方法都应该调用一个且仅调用一个服务方法 服务类结构类似 public class Service { public void serviceA(){...} public SomeObject serviceB(){...} // can grow in the futu

我在一个项目中工作,有一个
服务
类和一个充当门面的
客户机(不知道这在设计模式的世界中是否是正确的术语,但我会尽量澄清)<代码>服务
的方法可能非常昂贵,因为它们可能与一个或多个数据库通信、长时间检查等,因此每个
客户端
方法都应该调用一个且仅调用一个
服务
方法

服务
类结构类似

public class Service {
    public void serviceA(){...}
    public SomeObject serviceB(){...}
    // can grow in the future
}
public class Client {
    private Service myService; // Injected somehow
    public void callServiceA() {
        // some preparation
        myService.serviceA();
        // something else
    }

    public boolean callServiceB(){...}
}
public class ClientTest{
    private Client client; // Injected or instantiated in @Before method
    private Service serviceMock = mock(Service.class);

    @Test
    public void callServiceA_onlyCallsServiceA() {
        client.callServiceA();
        ????
    }
}
Client
应该是

public class Service {
    public void serviceA(){...}
    public SomeObject serviceB(){...}
    // can grow in the future
}
public class Client {
    private Service myService; // Injected somehow
    public void callServiceA() {
        // some preparation
        myService.serviceA();
        // something else
    }

    public boolean callServiceB(){...}
}
public class ClientTest{
    private Client client; // Injected or instantiated in @Before method
    private Service serviceMock = mock(Service.class);

    @Test
    public void callServiceA_onlyCallsServiceA() {
        client.callServiceA();
        ????
    }
}
Client
的测试类中,我想要

public class Service {
    public void serviceA(){...}
    public SomeObject serviceB(){...}
    // can grow in the future
}
public class Client {
    private Service myService; // Injected somehow
    public void callServiceA() {
        // some preparation
        myService.serviceA();
        // something else
    }

    public boolean callServiceB(){...}
}
public class ClientTest{
    private Client client; // Injected or instantiated in @Before method
    private Service serviceMock = mock(Service.class);

    @Test
    public void callServiceA_onlyCallsServiceA() {
        client.callServiceA();
        ????
    }
}
??
部分,我想要类似于
verifyOnly(serviceMock).serviceA()
的语句,即“验证
serviceMock.serviceA()
只调用了一次,并且没有调用
服务
类中的其他方法”。在Mockito或其他一些mocking库中是否有类似的内容?我不想对每个方法都使用
verify(serviceMock,never()).serviceXXX()
,因为正如我所说的,
Service
类将来可能会增长,我将不得不在每个测试中添加验证(这对我来说不是一项愉快的任务),所以我需要一些更一般的东西

提前感谢您的回答

编辑#1 这篇文章和其他文章的区别在于,答案添加了锅炉板代码,这在我的案例中是不需要的,因为这是一个非常大的项目,我必须添加尽可能少的代码

而且,即使每次测试都不鼓励使用,也可以是一个很好的选择,不需要额外的锅炉板代码

简单地说,这并没有解决我的问题

还有另一个问题:我正在为另一个团队编写的代码编写测试,而不是自己遵循TDD过程,因此我的测试应该是额外的防御性的,正如mockito文档中引用的。我正在测试的方法通常非常长,因此我需要检查测试中的方法是否只调用必要的服务,而不调用其他服务(因为正如我所说的,它们很昂贵)。也许
verifyNoMoreInteractions
现在已经足够好了,但我希望看到的是,对于同一个API创建者团队的每一次测试,都不会有什么不鼓励的地方

希望这有助于澄清我的观点和问题。致以最良好的祝愿

verify(serviceMock, times(1)).serviceA();
verifyNoMoreInteractions(serviceMock);
从Mockito的javadoc开始:

您可以在验证模拟后使用此方法,以确保没有在模拟上调用任何其他内容

此外:

警告:一些做了很多经典的expect run verify模拟的用户倾向于经常使用verifyNoMoreInteractions(),即使是在每个测试方法中。不建议在所有测试方法中使用verifyNoMoreInteractions()。verifyNoMoreInteractions()是来自交互测试工具包的一个方便的断言。只有在相关的时候才使用它。滥用它会导致过度指定、不易维护的测试

您可以可靠地验证您的服务只被调用过一次,并且只从您指定的方法调用过一次,而不是从任何其他方法调用过一次的唯一方法是测试每个方法,并断言您的
serviceA
方法从未被调用。但是你无论如何都在测试其他方法,所以这不应该是一个很大的提升

// In other test cases...
verify(serviceMock, never()).serviceA();

虽然从代码编写的角度来看,这是不可取的,但它打开了将您的服务划分为更小、更负责的块的大门,这样您就可以保证只调用一个特定的服务。从那时起,围绕代码的测试用例和保证变得更小、更铁。

我认为您需要的是Mockito.verify和Mockito.times

import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

verify(mockObject, atLeast(2)).someMethod("was called at least twice");
verify(mockObject, times(3)).someMethod("was called exactly three times");
这里是另一个问题相同的线程:


可能重复的@GonzaloMatheu:这是一个很好的重复,因为这个问题是类似的,但问题比这稍微深一点。可能重复的@KilleKat:考虑到代码目前的编写方式,这是唯一可验证的方法。如果他们重构了自己的代码并划分了责任,那么就没有更好的方法了。那么verifyNoMoreInteractions()呢?@MatiasElorriaga:如果目的是验证模拟上的方法从未被调用,那么
never()
将是合适的。这是关于意图
verifyNoMoreInteractions
意味着与整个mock的交互已经发生,但没有清楚地表明该mock上的特定方法或字段没有交互
never()
清楚地告诉我,作为一名维护人员和未来的测试人员,不,实际上从未调用过此方法,也不打算从此方法调用此方法。此+BDDMockito样式
then(mock).should(times(1)).serviceA()如果只检查一次调用
次数(1)
应该是不必要的。