有很多方法可以使用MockIto初始化模拟对象.
1.
public class SampleBaseTestCase {
@Before public void initMocks() {
MockitoAnnotations.initMocks(this);
}
@RunWith(MockitoJUnitRunner.class)
mock(XXX.class);
如果还有比这些更好的方法,请建议我...
有很多方法可以使用MockIto初始化模拟对象.
1.
public class SampleBaseTestCase {
@Before public void initMocks() {
MockitoAnnotations.initMocks(this);
}
@RunWith(MockitoJUnitRunner.class)
mock(XXX.class);
如果还有比这些更好的方法,请建议我...
使用流道或MockitoAnnotations.initMocks
是严格等价的解决方案.从MockitoJUnitRunner个国家的javadoc:
JUnit 4.5 runner初始化用Mock注释的Mock,以便显式使用MockitoAnnotations.initMocks(对象)不是必需的.在每个测试方法之前,都会初始化模拟.
当您已经在测试用例上配置了特定的运行程序(例如SpringJUnit4ClassRunner
)时,可以使用第一个解决方案(使用MockitoAnnotations.initMocks
).
第二种解决方案(MockitoJUnitRunner
)更classic ,也是我最喜欢的.代码更简单.使用流道提供了100的巨大优势(由this answer中的@David Wallace描述).
这两种解决方案都允许在测试方法之间共享模拟(和间谍).再加上@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这主要是由于@InjectMock注释造成的.使用此注释"you loose the pain of code"(请参阅@Brice的精彩注释)
第三个解决方案是在每个测试方法上创建您的模拟. 正如@mlk在其答复中所解释,它允许具有"self contained test".
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…)
缺点:有更多的样板代码.(模仿创作)
My建议是一种妥协.使用@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是如何工作的(my ArticleManager
是如何实例化的).没有样板代码.
缺点:测试不是自包含的,代码痛苦较少