到目前爲止,來自SO的答案已經完全滿足我的問題。我正在學習Junit和Mockito的單元測試,我想測試我的服務類,這是我的Spring Web應用程序的一部分。我閱讀了許多教程和文章,但仍然遇到問題需要爲我的服務層編寫適當的單元測試。我想知道我的問題的答案,但首先我粘貼一些代碼:使用mockito進行彈簧服務單元測試
服務類
public class AccountServiceImpl implements AccountService {
@Autowired
AccountDao accountDao, RoleDao roleDao, PasswordEncoder passwordEncoder, SaltSource saltSource;
@PersistenceContext
EntityManager entityManager;
public Boolean registerNewAccount(Account newAccount) {
entityManager.persist(newAccount);
newAccount.setPassword(passwordEncoder.encodePassword(newAccount.getPassword(), saltSource.getSalt(newAccount)));
setRoleToAccount("ROLE_REGISTERED", newAccount);
return checkIfUsernameExists(newAccount.getUsername());
}
public void setRoleToAccount(String roleName, Account account) {
List<Role> roles = new ArrayList<Role>();
try {
roles.add(roleDao.findRole(roleName));
} catch(RoleNotFoundException rnf) {
logger.error(rnf.getMessage());
}
account.setRoles(roles);
}
public Boolean checkIfUsernameExists(String username) {
try {
loadUserByUsername(username);
} catch(UsernameNotFoundException unf) {
return false;
}
return true;
}
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
try {
Account loadedAccount = accountDao.findUsername(username);
return loadedAccount;
} catch (UserNotFoundException e) {
throw new UsernameNotFoundException("User: " + username + "not found!");
}
}
}
我未完成的測試類
@RunWith(MockitoJUnitRunner.class)
public class AccountServiceImplTest {
private AccountServiceImpl accountServiceImpl;
@Mock private Account newAccount;
@Mock private PasswordEncoder passwordEncoder;
@Mock private SaltSource saltSource;
@Mock private EntityManager entityManager;
@Mock private AccountDao accountDao;
@Mock private RoleDao roleDao;
@Before
public void init() {
MockitoAnnotations.initMocks(this);
accountServiceImpl = new AccountServiceImpl();
ReflectionTestUtils.setField(accountServiceImpl, "entityManager", entityManager);
ReflectionTestUtils.setField(accountServiceImpl, "passwordEncoder", passwordEncoder);
ReflectionTestUtils.setField(accountServiceImpl, "saltSource", saltSource);
ReflectionTestUtils.setField(accountServiceImpl, "accountDao", accountDao);
ReflectionTestUtils.setField(accountServiceImpl, "roleDao", roleDao);
}
@Test
public void testRegisterNewAccount() {
Boolean isAccountCreatedSuccessfully = accountServiceImpl.registerNewAccount(newAccount);
verify(entityManager).persist(newAccount);
verify(newAccount).setPassword(passwordEncoder.encodePassword(newAccount.getPassword(), saltSource.getSalt(newAccount)));
assertTrue(isAccountCreatedSuccessfully);
}
@Test
public void testShouldSetRoleToAccount() throws RoleNotFoundException{
Role role = new Role(); //Maybe I can use mock here?
role.setName("ROLE_REGISTERED");
when(roleDao.findRole("ROLE_REGISTERED")).thenReturn(role);
accountServiceImpl.setRoleToAccount("ROLE_REGISTERED", newAccount);
assertTrue(newAccount.getRoles().contains(role));
}
}
問題 :
- 在我的服務類中有方法的情況下進行單元測試的最佳方式是什麼?我可以像上面那樣分別測試它們嗎? [我把我的代碼分成幾種方法來得到更清晰的代碼]
- TestRegisterNewAccount()對我的服務方法來說是很好的單元測試嗎?測試是綠色的,但我不確定。
- 我在我的testShouldSetRoleToAccount失敗。我究竟做錯了什麼?
- 如何測試checkIfUsernameExists?
也許有人會幫我,因爲我花了幾天,我沒有做一個進度:(
UPDATE
成品測試類
@RunWith(MockitoJUnitRunner.class)
public class AccountServiceImplTest extends BaseTest {
private AccountServiceImpl accountServiceImpl;
private Role role;
private Account account;
@Mock private Account newAccount;
@Mock private PasswordEncoder passwordEncoder;
@Mock private SaltSource saltSource;
@Mock private EntityManager entityManager;
@Mock private AccountDao accountDao;
@Mock private RoleDao roleDao;
@Before
public void init() {
accountServiceImpl = new AccountServiceImpl();
role = new Role();
account = new Account();
ReflectionTestUtils.setField(accountServiceImpl, "entityManager", entityManager);
ReflectionTestUtils.setField(accountServiceImpl, "passwordEncoder", passwordEncoder);
ReflectionTestUtils.setField(accountServiceImpl, "saltSource", saltSource);
ReflectionTestUtils.setField(accountServiceImpl, "accountDao", accountDao);
ReflectionTestUtils.setField(accountServiceImpl, "roleDao", roleDao);
}
@Test
public void testShouldRegisterNewAccount() {
Boolean isAccountCreatedSuccessfully = accountServiceImpl.registerNewAccount(newAccount);
verify(entityManager).persist(newAccount);
verify(newAccount).setPassword(passwordEncoder.encodePassword(newAccount.getPassword(), saltSource.getSalt(newAccount)));
assertTrue(isAccountCreatedSuccessfully);
}
@Test(expected = IllegalArgumentException.class)
public void testShouldNotRegisterNewAccount() {
doThrow(new IllegalArgumentException()).when(entityManager).persist(account);
accountServiceImpl.registerNewAccount(account);
}
@Test
public void testShouldSetRoleToAccount() throws RoleNotFoundException {
when(roleDao.findRole(anyString())).thenReturn(role);
accountServiceImpl.setRoleToAccount("ROLE_REGISTERED", account);
assertTrue(account.getRoles().contains(role));
}
@Test
public void testShouldNotSetRoleToAccount() throws RoleNotFoundException {
when(roleDao.findRole(anyString())).thenThrow(new RoleNotFoundException());
accountServiceImpl.setRoleToAccount("ROLE_RANDOM", account);
assertFalse(account.getRoles().contains(role));
}
@Test
public void testCheckIfUsernameExistsIsTrue() throws UserNotFoundException {
when(accountDao.findUsername(anyString())).thenReturn(account);
Boolean userExists = accountServiceImpl.checkIfUsernameExists(anyString());
assertTrue(userExists);
}
@Test
public void testCheckIfUsernameExistsIsFalse() throws UserNotFoundException {
when(accountDao.findUsername(anyString())).thenThrow(new UserNotFoundException());
Boolean userExists = accountServiceImpl.checkIfUsernameExists(anyString());
assertFalse(userExists);
}
@Test
public void testShouldLoadUserByUsername() throws UserNotFoundException {
when(accountDao.findUsername(anyString())).thenReturn(account);
Account foundAccount = (Account) accountServiceImpl.loadUserByUsername(anyString());
assertEquals(account, foundAccount);
}
@Test(expected = UsernameNotFoundException.class)
public void testShouldNotLoadUserByUsername() throws UserNotFoundException {
when(accountDao.findUsername(anyString())).thenThrow(new UsernameNotFoundException(null));
accountServiceImpl.loadUserByUsername(anyString());
}
}
感謝大衛·我的答案。回答問題1我完全理解,我選擇了選項1.關於問題3我設法解決了一個問題。我不得不用新操作員創建的帳戶替換模擬帳戶,這是[原創!] :)。問題4也幫助了我,但我還有其他問題。正如你可以看到感謝你的提示,我設法爲我的所有方法編寫測試。他們的工作除了testShouldNotSetRoleToAccount和testShouldNotLoadUserByUsername確定。當有「預期= ...」時,兩者都失敗。沒有它就沒關係。另外首先還會使en錯誤和測試是錯誤。你可以幫幫我嗎? –
對不起,我花了一段時間回到你身邊。如果這些測試失敗且預期的異常設置,則意味着該異常實際上不會被拋出。你確定'roleDao'和'accountDao'實際上已經設置爲mock嗎?你可以用調試器來檢查。另外,你沒有使用'anyString()'正確的 - 這是磕碰和驗證,實際上沒有運行你的方法;我不知道這是否是你的問題的原因。在實際運行你的方法行,把要傳遞的實際值,而不是'anyString()'。 –
呃哈哈,我很笨。我剛纔談到的這個錯誤只是來自記錄器的控制檯信息。在發生異常時,在roleDao中有logger.error(..):P。我徹底查看了我的測試代碼,現在一切正常。 「預計」在testShouldNotSetRoleToAccount並且不需要testCheckIfUsernameExistsIsFalse。稍後我會更新我的測試課程,我們可以結束這個討論。再次感謝大衛,你的提示非常有幫助:) –