สำหรับการเริ่มต้นล้อเลียนโดยใช้ตัววิ่งหรือMockitoAnnotations.initMocks
วิธีแก้ปัญหาที่เทียบเท่ากันอย่างเคร่งครัด จาก javadoc ของ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.
วิธีแก้ปัญหาแรก (พร้อมด้วยMockitoAnnotations.initMocks
) สามารถใช้ได้เมื่อคุณกำหนดค่านักวิ่งเฉพาะ ( SpringJUnit4ClassRunner
ตัวอย่าง) ไว้แล้วในกรณีทดสอบของคุณ
วิธีที่สอง (พร้อมด้วยMockitoJUnitRunner
) เป็นวิธีที่คลาสสิกและเป็นที่ชื่นชอบของฉัน รหัสง่ายกว่า การใช้นักวิ่งให้ประโยชน์อย่างมากในการตรวจสอบการใช้เฟรมเวิร์กโดยอัตโนมัติ (อธิบายโดย@David Wallaceในคำตอบนี้ )
ทั้งสองวิธีนี้อนุญาตให้แบ่งปันการล้อเลียน (และสายลับ) ระหว่างวิธีการทดสอบ นอกจาก@InjectMocks
นี้ยังอนุญาตให้เขียนการทดสอบหน่วยได้อย่างรวดเร็ว รหัสจำลองแบบสำเร็จรูปลดลงการทดสอบอ่านง่ายขึ้น ตัวอย่างเช่น:
@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));
}
}
ข้อดี: โค้ดมีน้อย
จุดด้อย: มนต์ดำ IMO ส่วนใหญ่เกิดจากคำอธิบายประกอบ @InjectMocks ด้วยคำอธิบายประกอบนี้ "คุณหลวมความเจ็บปวดของรหัส" (ดูความคิดเห็นที่ยอดเยี่ยมของ@Brice )
วิธีที่สามคือสร้างการจำลองของคุณในแต่ละวิธีการทดสอบ อนุญาตตามที่@mlkอธิบายไว้ในคำตอบว่ามี " การทดสอบในตัวเอง "
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));
}
}
ข้อดี: คุณแสดงให้เห็นอย่างชัดเจนว่า api ของคุณทำงานอย่างไร (BDD ... )
จุดด้อย: มีรหัสสำเร็จรูปมากกว่า (การสร้างล้อเลียน)
คำแนะนำของฉันคือการประนีประนอม ใช้@Mock
คำอธิบายประกอบกับ@RunWith(MockitoJUnitRunner.class)
แต่อย่าใช้@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));
}
}
ข้อดี: คุณแสดงให้เห็นอย่างชัดเจนว่า API ของคุณทำงานอย่างไร (การArticleManager
สร้างอินสแตนซ์ของฉันเป็นอย่างไร) ไม่มีรหัสสำเร็จรูป
จุดด้อย: การทดสอบไม่มีอยู่ในตัวความเจ็บปวดของรหัสน้อยลง