Örneklerin başlatılması için , koşucu veya MockitoAnnotations.initMocks
kullanı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. @Mock
Ek 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