Printemps de service de l'unité de test à l'aide d'mockito
Jusqu'à présent, les réponses de SORTE a été totalement satisfaisant pour mes problèmes. Je suis en train d'apprendre les tests unitaires avec Junit et Mockito et je veux tester ma classe de service qui est une partie de mon Ressort de l'application web. J'ai lu de nombreux tutoriels et articles et j'ai toujours des problèmes pour rédiger les tests unitaires pour ma couche de service. Je voudrais savoir des réponses à mes questions, mais d'abord je colle le code:
Classe de Service
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!");
}
}
}
Mon inachevé de la classe de test
@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));
}
}
Questions:
- Quel est le meilleur moyen de faire des tests unitaires où j'ai méthodes en méthodes comme dans ma classe de service? Puis-je les tester séparément, comme ci-dessus? [J'ai divisé mon code en quelques méthodes pour avoir plus propre code]
- Est testRegisterNewAccount() bon test unitaire pour ma méthode de service? Test est vert mais je ne suis pas sûr à ce sujet.
- Je suis d'échec dans ma testShouldSetRoleToAccount. Ce que je fais mal?
- Comment tester checkIfUsernameExists?
Peut-être que quelqu'un va m'aider parce que j'ai passé une couple de jours et je n'ai pas fait un progrès 🙁
Mise à JOUR
Fini de la classe de test
@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());
}
}
OriginalL'auteur Mariusz Grodek | 2012-01-23
Vous devez vous connecter pour publier un commentaire.
Question 1 - Vous avez un couple d'options ici.
Option 1 - écrire des tests distincts pour chaque comportement de chaque méthode publique, basée sur ce qui est nécessaire pour que les comportements. Il conserve chaque test propre et distincte, mais cela veut dire que la logique dans le secondaire des méthodes (telles que
checkIfUsernameExists
) sera exercé à deux reprises. Dans un sens, c'est la répétition inutile, mais l'avantage de cette option est que si vous changez la mise en œuvre, mais pas le comportement requis, vous aurez toujours de bons tests basés sur le comportement.Option 2 - utilisation d'une Mockito Espion. C'est un peu comme un simulacre, sauf que vous créez à partir d'un objet réel, et le comportement par défaut, c'est que toutes les méthodes d'exécution comme d'habitude. Vous pouvez ensuite éteindre et de vérifier les méthodes secondaires, afin de tester les méthodes qui les appellent.
Question 2 - Cela ressemble à un bon test pour le "succès" de cas de
registerNewAccount
. S'il vous plaît penser quelles circonstances pourrait provoquerregisterNewAccount
à échouer et retourner faux; et de tester ce cas.Question 3 - je n'ai pas eu un bon coup d'oeil à cela; mais essayez de courir avec le débogueur, et découvrez à quel point votre les objets diffèrent de ce que vous attendez. Si vous ne pouvez pas travailler, publier à nouveau et je vais avoir un autre regard.
Question 4 - Pour tester le négatif cas, le talon de votre maquette de la
AccountDao
de jeter le nécessaire exception. Sinon, voir mes réponses à la question 1.Désolé, ça m'a pris du temps avant de revenir à vous. Si ces tests échouent à l'exception, ce qui signifie que l'exception n'est pas réellement se faire jeter. Êtes-vous sûr que
roleDao
etaccountDao
ont été mis à la on se moque? Vous pouvez vérifier cela avec le débogueur. Aussi, vous n'êtes pas à l'aide deanyString()
correctement - c'est pour cogner et de vérifier, pas réellement en cours d'exécution de votre méthode, je ne sais pas si c'est la cause de votre problème. Dans le sens où vous avez réellement exécuter vos méthodes, mettre la valeur réelle que vous voulez passer, au lieu deanyString()
.Hein lol, je suis stupide. Cette erreur dont je parlais, c'était juste de la console des informations à partir de l'enregistreur. Dans roleDao lorsque l'exception est interceptée, il est bûcheron.erreur(..) :P. j'ai regardé mon code de test à fond et maintenant tout est ok. "attendus" dans testShouldNotSetRoleToAccount et testCheckIfUsernameExistsIsFalse n'est pas nécessaire. Plus tard, je vais mettre à jour ma classe de test et on peut fermer cette discussion. Merci une fois de plus David, vos conseils ont été très utiles 🙂
OriginalL'auteur Dawood ibn Kareem