@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));
}
}
@RunWith(JUnit4.class) // or a different runner of your choice
public class YourTest
@Rule public MockitoRule rule = MockitoJUnit.rule();
@Mock public YourMock yourMock;
@Test public void yourTestMethod() { /* ... */ }
}
JUnit寻找subclasses of TestRule annotated with @Rule,并使用它们来 * Package Runner提供的测试语句 。这样做的结果是,您可以提取@Before方法、@After方法,甚至尝试......将 Package 器捕获到规则中。您甚至可以在测试中与它们交互,就像ExpectedException所做的那样。 MockitoRule的行为 * 与MockitoJUnitRunner 几乎完全相同,只是您可以使用任何其他runner,如Parameterized(它允许测试构造函数接受参数,以便测试可以运行多次),或者Robolectric的测试runner(因此其类加载器可以提供Android原生类的Java替代)。这使得它在最近的JUnit和Mockito版本中使用起来更加灵活。 总而言之:
@RunWith(MockitoJUnitRunner.class)
public class MyUnitTest {
@Mock
private MyFirstMock myFirstMock;
@Mock
private MySecondMock mySecondMock;
@Spy
private MySpiedClass mySpiedClass = new MySpiedClass();
// It's gonna inject the 2 mocks and the spied object per reflection to this object
// The java doc of @InjectMocks explains it really well how and when it does the injection
@InjectMocks
private MyClassToTest myClassToTest;
@Test
public void testSomething() {
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("aplicationContext.xml")
public class MyIntegrationTest {
@Mock
private MyFirstMock myFirstMock;
@Mock
private MySecondMock mySecondMock;
@Spy
private MySpiedClass mySpiedClass = new MySpiedClass();
// It's gonna inject the 2 mocks and the spied object per reflection to this object
// The java doc of @InjectMocks explains it really well how and when it does the injection
@InjectMocks
private MyClassToTest myClassToTest;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
@Test
public void testSomething() {
}
}
8条答案
按热度按时间pu3pd22g1#
对于模拟初始化,使用runner或
MockitoAnnotations.initMocks
是严格等效的解决方案。从MockitoJUnitRunner的javadoc中:JUnit 4.5 runner初始化使用Mock注解的mock,这样就不需要显式使用MockitoAnnotations.initMocks(Object)。在每个测试方法之前初始化mock。
当您已经在测试用例上配置了一个特定的runner(例如
SpringJUnit4ClassRunner
)时,可以使用第一个解决方案(使用MockitoAnnotations.initMocks
)。第二个解决方案(使用
MockitoJUnitRunner
)更经典,也是我最喜欢的。代码更简单。使用runner提供了自动验证框架使用的巨大优势(在此答案中由@David Wallace描述)。这两种解决方案都允许在测试方法之间共享模拟(和间谍)。与
@InjectMocks
结合使用,它们允许非常快速地编写单元测试。样板模拟代码减少了,测试更容易阅读。例如:优点:代码最少
缺点:黑魔法。IMO这主要是由于@InjectMocks注解。有了这个注解 “你松了代码的痛苦”(见@Brice的伟大评论)
第三个解决方案是在每个测试方法上创建你的模拟。它允许如@mlk在其答案中所解释的那样有“* 自包含测试 *"。
优点:你清楚地展示了你的API是如何工作的(BDD...)
缺点:有更多的样板代码。(模拟创建)
我的建议是一个折衷方案。请将
@Mock
注解与@RunWith(MockitoJUnitRunner.class)
一起使用,但不要使用@InjectMocks
:优点:你清楚地演示了你的API是如何工作的(我的
ArticleManager
是如何示例化的)。没有样板代码。缺点:测试不是独立的,代码的痛苦少
yfwxisqw2#
现在(从v1.10.7开始)有了第四种示例化mock的方法,即使用名为MockitoRule的JUnit 4 rule。
JUnit寻找subclasses of TestRule annotated with @Rule,并使用它们来 * Package Runner提供的测试语句 。这样做的结果是,您可以提取@Before方法、@After方法,甚至尝试......将 Package 器捕获到规则中。您甚至可以在测试中与它们交互,就像ExpectedException所做的那样。
MockitoRule的行为 * 与MockitoJUnitRunner 几乎完全相同,只是您可以使用任何其他runner,如Parameterized(它允许测试构造函数接受参数,以便测试可以运行多次),或者Robolectric的测试runner(因此其类加载器可以提供Android原生类的Java替代)。这使得它在最近的JUnit和Mockito版本中使用起来更加灵活。
总而言之:
Mockito.mock()
:直接调用,不支持注解或使用验证。MockitoAnnotations.initMocks(this)
:注解支持,无用法验证。MockitoJUnitRunner
:注解支持和使用验证,但必须使用该runner。MockitoRule
:支持任何JUnit运行程序的注解和使用验证。另请参阅:How JUnit @Rule works?
7qhs6swi3#
1.使用模拟注解。openMocks():
Mockito 2中的
MockitoAnnotations.initMock()
方法已被弃用,并在Mockito 3中被替换为MockitoAnnotations.openMocks()
。MockitoAnnotations.openMocks()
方法返回AutoClosable
的示例,该示例可用于在测试后关闭资源。下面是使用MockitoAnnotations.openMocks()
的示例。2.使用@ExtendWith(MockitoExtension.class):
自JUnit 5起,已删除
@RunWith
。下面是使用@ExtendWith
的示例:0ve6wy6x4#
JUnit 5 Jupiter的一个小例子,“RunWith”被删除了,现在您需要使用带有“@ExtendWith”注解的扩展。
vuktfyat5#
MockitoAnnotations & the runner在上面已经讨论得很好了,所以我打算把我的两便士扔给那些不被爱的人:
我使用这个是因为我发现它更有描述性,而且我更喜欢(而不是禁止)单元测试不使用成员变量,因为我喜欢我的测试(尽可能多地)是自包含的。
lfapxunr6#
有一个简洁的方法可以做到这一点。
8yoxcaq77#
在
Mockito
的最新版本中,不建议使用MockitoAnnotations.initMocks
方法首选方式是使用
MockitoJUnitRunner
或MockitoRule
(对于JUnit4
)JUnit5
的MockitoExtension
TestNG
的MockitoTestNGListener
如果您无法使用专用滑道/扩展,则可以使用
MockitoSession
3pmvbmvn8#
其他的答案很棒,如果你想/需要的话,包含更多的细节。
除此之外,我想补充一句TL;灾难恢复:
@RunWith(MockitoJUnitRunner.class)
@Rule public MockitoRule rule = MockitoJUnit.rule();
个@Before public void initMocks() { MockitoAnnotations.initMocks(this); }
X x = mock(X.class)
(1)和(3)是互斥的。
(4)可以与其它组合使用。