2016-09-15 97 views
1

使用API​​編寫我的webapp測試,測試控制器方法。控制器使用我想要模擬的服務方法。 測試代碼:使用模擬方法

@Mock 
private UserService userService; 
@Mock 
private PasswordEncoder passwordEncoder; 
@InjectMocks 
private UserApi userApi; 

    MockitoAnnotations.initMocks(this); 
    mockMvc = MockMvcBuilders.standaloneSetup(userApi).build(); 

@Test 
public void addUser() throws Exception { 
    Role role = new Role(1L, "ROLE_USER"); 
    User user = new User (null, "Test user", "Test password", true, role); 
    when(roleService.findByName(role.getName())).thenReturn(role); 
    when(passwordEncoder.encode(user.getPassword())).thenReturn("Encoded password"); 
    when(userService.save(user)).thenReturn(1L); 


    mockMvc.perform(MockMvcRequestBuilders.post("/user").content(user.toJson())).andDo(print()) 
      .andExpect(status().isOk()) 
      .andExpect(content().contentType("application/json")) 
      .andExpect(content().string(user.toJson())); 

} 

當UserService.save(用戶)調用時都會將用戶的id屬性設置爲一些獨特的長值,如果它爲空。我可以設置UserService.save(用戶)的模擬更改保存的用戶的ID,因爲真正的save()嗎? 與PasswordEncoder相同,當調用PasswordEncoder.encode(string)時,它將字符串值更改爲編碼值,PasswordEncoder的Mock如何執行相同的操作?

回答

1

婉婷這是一個測試的氣味,可能意味着你正在測試太多;因此,我不會推薦它。您的單元測試正在測試Spring控制器,並且它不在測試UserServicePasswordEncoder,並且確保用戶的ID已更改或密碼已編碼,這不是Spring控制器的責任。您可以驗證是否調用了userServicepasswordEncoder,但是就控制器應該執行的測試而言。

這聽起來像你真正想要做的不是模擬UserServicePasswordEncoder,而是在一個測試數據庫上執行一個真實類的端到端測試。您可以從控制器開始發佈您的新用戶,然後從測試數據庫中取回並驗證您的結果是否正確。在這種情況下,您不是對Spring控制器進行單元測試,而是對整個真正的鏈進行單元測試。

這就是說,你可以做你通過設置使用thenAnswer代替thenReturn自定義的答案問什麼:

when(userService.save(user)).thenAnswer(new Answer<Long>() { 
    @Override 
    public Long answer(InvocationOnMock invocation) { 
     user.setId(1L); 
     return 1L; 
    } 
}); 

當方法在仿調用,這個定製的答案將被調用。其結果將是模擬方法返回的結果。在這裏,它還會在返回之前設置用戶的ID。這仍然非常可怕,並且有一個適當的集成測試將是一個更好的選擇。

+0

謝謝,是的,我喜歡完整性測試:) – zzheads

+0

保存方法(模擬)後用戶的id屬性更改爲null在控制器中調用。 「真正的」save()完全不同,找不到可以在「模擬」版本中設置user.id的內容...... – zzheads

1

假設你是單元測試,而不是功能/集成測試,如果你嘲笑UserServiceUser那麼你不關心他們的行爲,你是「嘲笑」它。這意味着您可以告訴它返回以前設置User或模擬User

即剛剛設置的用戶ID在創建User對象

+0

同意,但我必須確保用戶的密碼已編碼,當新用戶使用post(「/ user」)創建時。我如何檢查它? – zzheads

+1

我不確定應用程序的完整結構,但單元測試應該在每個測試的一個對象上測試一件事情,其他所有事情都應該被嘲笑。如果你正在測試的東西被稱爲和其他東西編碼的密碼,那麼該測試是一個候選人的兩個單獨的測試 –