Örneklerin başlatılması için , koşucu veya MockitoAnnotations.initMockskullanımı kesinlikle eşdeğer çözümlerdir. Bir javadoc itibaren 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.
İlk çözüm (ile MockitoAnnotations.initMocks) belirli bir koşucuyu önceden yapılandırdığınızda kullanılabilir (SpringJUnit4ClassRunner , test durumunuzda örneğin) .
İkinci çözüm (ile MockitoJUnitRunner) daha klasik ve benim favorim. Kod daha basit. Bir kaçak büyük avantajı sağlar kullanarak çerçeve kullanım otomatik doğrulama ile (tarif edildiği @ David Wallace bölgesindeki Bu yanıt ).
Her iki çözüm de test yöntemleri arasında taklitleri (ve casusları) paylaşmaya izin verir. İle birleştiğinde @InjectMocks, birim testlerinin çok hızlı bir şekilde yazılmasına izin verirler. Klişe alay kodu azaltılır, testlerin okunması daha kolaydır. Örneğin:
@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));
}
}
Artıları: Kod minimum düzeydedir
Eksileri: Kara büyü. IMO, esas olarak @InjectMocks ek açıklamasından kaynaklanmaktadır. Bu ek açıklamayla "kodun acısını kaybedersiniz" ( @Brice'ın harika yorumlarına bakın )
Üçüncü çözüm, her test yönteminde kendi modelinizi oluşturmaktır. @Mlk tarafından yanıtında açıklandığı gibi " kendi kendine yeten test " e sahip olmasına izin verir .
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));
}
}
Artıları: API'nizin nasıl çalıştığını açıkça gösteriyorsunuz (BDD ...)
Eksileri: daha fazla standart kod var. (Sahte yaratma)
Benim tavsiyem bir uzlaşmadır. @MockEk açıklamayı ile kullanın @RunWith(MockitoJUnitRunner.class), ancak @InjectMocksşunları kullanmayın :
@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));
}
}
Artıları: API'nizin nasıl çalıştığını açıkça gösterirsiniz (Nasıl ArticleManagerörneklenir). Standart kod yok.
Eksileri: Test bağımsız değildir, daha az kod zahmeti