Untuk inisialisasi tiruan , menggunakan pelari atau solusi MockitoAnnotations.initMocksyang benar-benar setara. Dari javadoc dari 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.
Solusi pertama (dengan MockitoAnnotations.initMocks) dapat digunakan ketika Anda telah mengkonfigurasi pelari tertentu (SpringJUnit4ClassRunner misalnya) pada kasus pengujian Anda.
Solusi kedua (dengan MockitoJUnitRunner) adalah yang lebih klasik dan favorit saya. Kodenya lebih sederhana. Menggunakan runner memberikan keuntungan besar dari validasi otomatis penggunaan framework (dijelaskan oleh @David Wallace dalam jawaban ini ).
Kedua solusi memungkinkan untuk berbagi tiruan (dan mata-mata) di antara metode pengujian. Ditambah dengan @InjectMocks, mereka memungkinkan untuk menulis tes unit dengan sangat cepat. Kode tiruan boilerplate dikurangi, pengujian lebih mudah dibaca. Sebagai contoh:
@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));
}
}
Kelebihan: Kodenya minimal
Kekurangan: Ilmu hitam. IMO ini terutama karena anotasi @InjectMocks. Dengan anotasi ini "Anda kehilangan rasa sakit kode" (lihat komentar bagus @Brice )
Solusi ketiga adalah membuat tiruan Anda pada setiap metode pengujian. Ini memungkinkan seperti yang dijelaskan oleh @mlk dalam jawabannya untuk memiliki " tes mandiri ".
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));
}
}
Pro: Anda dengan jelas menunjukkan cara kerja api Anda (BDD ...)
Kekurangan: ada lebih banyak kode boilerplate. (Penciptaan mengejek)
Rekomendasi saya adalah kompromi. Gunakan @Mockanotasi dengan @RunWith(MockitoJUnitRunner.class), tapi jangan gunakan @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));
}
}
Kelebihan: Anda dengan jelas menunjukkan bagaimana api Anda bekerja (How my ArticleManager is instantiated). Tidak ada kode boilerplate.
Cons: Tes ini tidak mandiri, lebih sedikit kesulitan kode