Para la inicialización de los simulacros , usar el corredor o MockitoAnnotations.initMocksson soluciones estrictamente equivalentes. Desde el javadoc de MockitoJUnitRunner :
JUnit 4.5 runner initializes mocks annotated with Mock, so that explicit usage of MockitoAnnotations.initMocks(Object) is not necessary. Mocks are initialized before each test method.
La primera solución (con el MockitoAnnotations.initMocks) podría usarse cuando ya haya configurado un corredor específico ( SpringJUnit4ClassRunnerpor ejemplo) en su caso de prueba.
La segunda solución (con la MockitoJUnitRunner) es la más clásica y mi favorita. El código es más sencillo. El uso de un corredor proporciona la gran ventaja de la validación automática del uso del marco (descrito por @David Wallace en esta respuesta ).
Ambas soluciones permiten compartir los simulacros (y espías) entre los métodos de prueba. Junto con @InjectMocks, permiten escribir pruebas unitarias muy rápidamente. El código burlón repetitivo se reduce, las pruebas son más fáciles de leer. Por ejemplo:
@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));
}
}
Ventajas: el código es mínimo
Contras: magia negra. En mi opinión, se debe principalmente a la anotación @InjectMocks. Con esta anotación "pierdes el dolor del código" (mira los grandes comentarios de @Brice )
La tercera solución es crear su simulacro de cada método de prueba. Permite, como explica @mlk en su respuesta, tener una " prueba autónoma ".
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));
}
}
Ventajas: demuestra claramente cómo funciona su api (BDD ...)
Contras: hay más código repetitivo. (La creación de las burlas)
Mi recomendación es un compromiso. Utilice la @Mockanotación con @RunWith(MockitoJUnitRunner.class), pero no utilice @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));
}
}
Ventajas: demuestra claramente cómo funciona su api (cómo ArticleManagerse crea una instancia de my ). Sin código repetitivo.
Contras: la prueba no es autónoma, menos dolor de código