9
Given the following test scenario, where I have the interface:
public interface UserService {
/**
* Registra um usuário no sistema.
*
* @param user
* Usuário à ser registrado. Não deve ser {@code null}
* @return Inteiro maior que zero representando o id do usuário registrado,
* ou 0 caso o registro falhe
* @throws IllegalArgumentException
* Caso o usuário seja {@code null}
*/
long register(User user);
}
And a possible implementation that meets the interface javadoc contract:
public class UserServiceImpl implements UserService {
private UserDao userDao = // Inicializa ou injeta o DAO
@Override
public long register(User user) {
if (user == null) {
throw new IllegalArgumentException("Usuário não pode ser null");
}
try {
userDao.insert(user);
long insertedId = user.getId();
return insertedId;
} catch (SomeException e) {
logger.error("Erro ao registrar o usuário " + user.getUsername(), e);
return 0;
}
}
}
The moment I write my unit tests for the method register(User user)
, should test the implementation UserServiceImpl
directly? For example:
public class UserServiceImplTest {
private UserService service;
@Before
public void setUp() {
service = new UserServiceImpl();
}
@Test
public void shouldReturnIdGreaterThanZero() {
User user = // Inicializa um usuário pronto para inserção
long insertedId = service.register(user);
Assert.assertTrue(insertedId > 0);
}
}
Or test only the interface, injecting the implementation through a Servicelocator, for example?
public class UserServiceTest { // Note que até mudei o nome da classe de testes
private UserService service;
@Before
public void setUp() {
service = // Obtém a implementação através de algo parecido com um ServiceLocator
}
@Test
public void shouldReturnIdGreaterThanZero() {
User user = // Inicializa um usuário pronto para inserção
long insertedId = service.register(user);
Assert.assertTrue(insertedId > 0);
}
}
Which approach should I adopt? It is worth mentioning that new implementations may arise, but I only refer to the interface UserService
in my domain code.
Some snippets of code and javadoc have been omitted to simplify code.
Option 1 ;) And by your example, the ideal would be to mock the Userdao, so you do not directly access the bank...
– Icaro Bombonato
Test the implementation. It makes no sense to test abstraction because otherwise you would have a pluggable test, able to test one implementation or another, so if you have more than one implementation you will have one of them without a test or have two tests pluggable but each linked to a single implementation, making it useless to plug it. Also, testing abstraction the way you suggested the test is dependent on the "service Locator" that will have its own dependencies and the more dependencies worse, as they are more opportunities to fail the test of a code that is working.
– Caffé