Şimdiye kadar SO cevaplarım benim için tamamen tatmin edici olmuştur. Ben Junit ve Mockito ile birim testi öğreniyorum ve Spring web uygulamasının bir parçası olan hizmet sınıfımı test etmek istiyorum. Pek çok dersi ve makaleyi okudum ve hizmet katmanım için uygun birim testleri yazmakta hala sorun yaşıyorum. Benim sorulara yanıt bilmek istiyorum, ama önce bazı kodu yapıştırın:Spring service unit testing mockito kullanarak
Servis sınıfı
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!");
}
}
}
Benim bitmemiş test sınıf
@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));
}
}
Sorular :
- Hizmet sınıfımda olduğu gibi yöntemlerde yöntemlerim olduğunda birim sınamalarını yapmanın en iyi yolu nedir? Onları yukarıdaki gibi ayrı ayrı test edebilir miyim? [Kodumu temiz kodlara sahip olmak için birkaç yönteme ayırdım]
- Hizmet yöntemim için testRegisterNewAccount() iyi birim sınaması var mı? Test yeşil ancak bundan emin değilim.
- TestShouldSetRoleToAccount'ta hata alıyorum. Neyi yanlış yapıyorum?
- CheckIfUsernameExists nasıl test edilir?
Ben birkaç gün ödedim ve bir ilerleme :(
GÜNCELLEME yapmadığını çünkü Belki birisi bana bu konuda yardımcı olacaktır
Biten test sınıf
@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());
}
}
Teşekkürler David. Soru 1'e cevap verin tamamen anlayın ve seçenek 1'i seçtim. Soru 3 Hakkında Bir problemi çözmeyi başardım. Mock Hesabını yeni operatör tarafından oluşturulan Hesap ile değiştirmek zorunda kaldım ve bu o oldu [sic!] :). Soru 4 de bana yardımcı oldu, ama başka sorunlarım var. İpuçlarını gördüğünüz gibi, tüm yöntemlerim için testler yazmayı başardım. TestShouldNotSetRoleToAccount ve testShouldNotLoadUserByUsername haricinde çalışırlar. Her ikisi de "beklenen = ..." olduğunda başarısız olur. Onsuz tamam. Ayrıca ilk olarak aynı zamanda hata yapar ve test Hatadır. Bana yardım eder misin? –
Üzgünüz, size geri dönmem biraz zaman aldı. Bu testler beklenen istisna setiyle başarısız olursa, istisna aslında atılmadığı anlamına gelir. 'RolDao' ve 'accountDao' un aslında sahtekarlara ayarlandığından emin misiniz? Bunu hata ayıklayıcı ile kontrol edebilirsiniz. Ayrıca, "anyString()" işlevini doğru bir şekilde kullanmıyorsunuz - bu, aslında yönteminizi çalıştırmamak için, saplama ve doğrulama amaçlıdır; Bunun senin sorununun sebebi olup olmadığını bilmiyorum. Yöntemlerinizi gerçekten çalıştırdığınız satırlarda, "anyString()" yerine geçirmek istediğiniz gerçek değeri koyun. –
Eh, ben aptalım. Bu konuda konuştuğum bu hata sadece logger'dan konsol bilgisi idi. Özel durum yakalandığında roleDao'de logger.error (..): P var. Test koduma iyice baktım ve şimdi her şey yolunda. testShouldNotSetRoleToAccount'ta "beklenen" ve testCheckIfUsernameExistsIsFalse gerekli değildir. Daha sonra test sınıfımı güncelleyeceğim ve bu tartışmayı kapatabiliriz. Bir kez daha teşekkürler David, ipuçlarınız çok yardımcı oldu :) –