对于模拟初始化,使用运行器或严格等效的解决方案。来自MockitoJUnitRunner的javadoc:MockitoAnnotations.initMocks
JUnit 4.5 运行器初始化用 Mock 注释的模拟,因此不需要显式使用 MockitoAnnotations.initMocks(Object)。在每个测试方法之前初始化模拟。
第一个解决方案(带有 ) 可以在测试用例上配置特定运行器(例如)时使用。MockitoAnnotations.initMocks
SpringJUnit4ClassRunner
第二种解决方案(带有)是更经典和我最喜欢的。代码更简单。使用运行器提供了自动验证框架使用情况的巨大优势(由@David Wallace在此答案中描述)。MockitoJUnitRunner
两种解决方案都允许在测试方法之间共享模拟(和间谍)。再加上@InjectMocks
,它们允许非常快速地编写单元测试。样板模拟代码减少了,测试更易于阅读。例如:
@RunWith(MockitoJUnitRunner.class)
public class ArticleManagerTest {
@Mock private ArticleCalculator calculator;
@Mock(name = "database") private ArticleDatabase dbMock;
@Spy private UserProvider userProvider = new ConsumerUserProvider();
@InjectMocks private ArticleManager manager;
@Test public void shouldDoSomething() {
manager.initiateArticle();
verify(database).addListener(any(ArticleListener.class));
}
@Test public void shouldDoSomethingElse() {
manager.finishArticle();
verify(database).removeListener(any(ArticleListener.class));
}
}
优点:代码很少
缺点:黑魔法。IMO它主要是由于@InjectMocks注释。有了这个注释,“你减轻了代码的痛苦”(请参阅@Brice)
第三种解决方案是在每个测试方法上创建模拟。正如@mlk在其答案中所解释的那样,它允许进行“自足测试”。
public class ArticleManagerTest {
@Test public void shouldDoSomething() {
// given
ArticleCalculator calculator = mock(ArticleCalculator.class);
ArticleDatabase database = mock(ArticleDatabase.class);
UserProvider userProvider = spy(new ConsumerUserProvider());
ArticleManager manager = new ArticleManager(calculator,
userProvider,
database);
// when
manager.initiateArticle();
// then
verify(database).addListener(any(ArticleListener.class));
}
@Test public void shouldDoSomethingElse() {
// given
ArticleCalculator calculator = mock(ArticleCalculator.class);
ArticleDatabase database = mock(ArticleDatabase.class);
UserProvider userProvider = spy(new ConsumerUserProvider());
ArticleManager manager = new ArticleManager(calculator,
userProvider,
database);
// when
manager.finishArticle();
// then
verify(database).removeListener(any(ArticleListener.class));
}
}
优点:您清楚地演示了 API 的工作原理(BDD...)
缺点:有更多的样板代码。(嘲笑创造)
我的建议是一种妥协。将批注与 一起使用 ,但不要使用 :@Mock
@RunWith(MockitoJUnitRunner.class)
@InjectMocks
@RunWith(MockitoJUnitRunner.class)
public class ArticleManagerTest {
@Mock private ArticleCalculator calculator;
@Mock private ArticleDatabase database;
@Spy private UserProvider userProvider = new ConsumerUserProvider();
@Test public void shouldDoSomething() {
// given
ArticleManager manager = new ArticleManager(calculator,
userProvider,
database);
// when
manager.initiateArticle();
// then
verify(database).addListener(any(ArticleListener.class));
}
@Test public void shouldDoSomethingElse() {
// given
ArticleManager manager = new ArticleManager(calculator,
userProvider,
database);
// when
manager.finishArticle();
// then
verify(database).removeListener(any(ArticleListener.class));
}
}
优点:你清楚地演示了你的api是如何工作的(我的是如何实例化的)。无样板代码。ArticleManager
缺点:测试不是自成一体的,代码的痛苦更少