SpringBoot學習筆記-單元測試(4)-Mockito
前言
部分文章內容來自於古老師在hahow的課程,還有古老師的部落格,想要做筆記的原因是因為,邊記變做會比較容易記住,改天忘了也可以用自己的方式去理解。
Mock測試目的與特性
單元測試的特性為下:
1.可以被自動化運行
2.各個單元測試互相獨立,彼此之間不能有依賴關係
3.測試結果穩定,不受外部服務影響
在前面的筆記,如果要測試Service層的話,應該會這樣寫:
@SpringBootTest
public class StudentServiceImplMockTest {
@Autowired StudentService studentService;
@Test
public void getById(){
Student student=studentService.getById(3);
assertNotNull(student);
assertEquals(3,student.getId());
assertEquals("Judy",student.getName());
}
}
在上面的測試單元裡,StudentService其實用到了StudentDao這個Bean,
並不符合地2點,Bean之前在上面是有依賴關係的,所以Mock測試的
- 目的:避免測試某一個單元測試,而去建構整個bean的依賴。
- 作法:創造一個假的bean,替換掉容器原有的bean。
在程式裡面Mock的意思為「假的」的意思,而非英文單字模仿。
Mockito
Mockito是Spring Boot中,進行Mock測試的工具
功能大致上分為:
- 模擬方法的返回值
- 模擬拋出Exception
- 記錄方法的使用次數、順序
@MockBean
@Test
public void getById(){
//第二步
Student mockStudent = new Student();
mockStudent.setId(100);
mockStudent.setName("mockname");
//這句話的意思就是,當有人使用studentDao.getById(3)時,固定return mockStudent這個object
Mockito.when(studentDao.getById(3)).thenReturn(mockStudent);
Student student=studentService.getById(3);
assertNotNull(student);
assertEquals(3,student.getId());
assertEquals("Judy",student.getName());
}
執行結果:
org.opentest4j.AssertionFailedError:
Expected :3
Actual :100
再把
assertEquals(3,student.getId());
改成assertEquals(3,student.getId());
就會顯示測試成功了
使用MockBean注意事項
承上,如果把Student student=studentService.getById(3)
改成了Student student=studentService.getById(2)
下面的單元測試依然會運行錯誤,原因是因為在沒有定義返回值是多少的情況下,這個假的mockbean預設會傳NULL
@Test
public void getById(){
Student mockStudent = new Student();
mockStudent.setId(100);
mockStudent.setName("mockname");
Mockito.when(studentDao.getById(3)).thenReturn(mockStudent);
Student student=studentService.getById(2);
assertNotNull(student);
assertEquals(3,student.getId());
assertEquals("Judy",student.getName());
}
所以我們會利用
Mockito.any()
來固定返回mockStudent這個數值
由Mockito.when(studentDao.getById(3)).thenReturn(mockStudent);
變成Mockito.when(studentDao.getById(Mockito.any())).thenReturn(mockStudent);
這樣不論參數是多少,都還是會固定返回mockStudent出來。
補充thenReturn doReturn
其實只是寫法上的不同,下面的程式碼是等價的
Mockito.when(studentDao.getById(Mockito.any())).thenReturn(mockStudent);
Mockito.doReturn(mockStudent).when(studentDao.getById(Mockito.any()));
Throw Expection
Mockito.when(studentDao.insert(Mockito.any())).thenThrow(new RuntimeException());
Mockito.doThrow(new RuntimeException()).when(studentDao).deleteById(Mockito.any());
Verify
用來記錄方法的使用次數、順序(少用)
Mockito.doThrow(new RuntimeException()).when(studentDao).deleteById(Mockito.any());
Mockito 的限制
上述就是 Mockito 的 mock 對象使用方法,不過當使用 Mockito 在 mock 對象時,有一些限制需要遵守
-
不能 mock 靜態方法
-
不能 mock private 方法
-
不能 mock final class