Cześć,
Testuję walidację wniosku rejestracji. DAO to interfejs, stworzyłem klasę która go implementuje i dodałem w niej mechanizm przechowywania danych w pamięci na HashMapie.
Przykład testu:
Jeśli username z requestu istnieje w systemie, sprawdzam czy rzuci wyjątek.
Mam taką klase która tworzy obiekty User
do testów - UserBuilder
.
public class UserBuilder {
private final RoleDAO roleDAO;
private final PasswordEncoder encoder;
private Integer id = 20;
private String username = "Username";
private String email = "email@mail.mail";
private String password = "Password#3";
private Set<Role> roles = new HashSet<>();
public UserBuilder(RoleDAO roleDAO, PasswordEncoder encoder) {
this.roleDAO = roleDAO;
this.encoder = encoder;
}
public UserBuilder copy() {
UserBuilder copy = new UserBuilder(this.roleDAO, this.encoder);
copy.id = this.id;
copy.username = this.username;
copy.email = this.email;
copy.password = this.password;
copy.roles = new HashSet<>(this.roles);
return copy;
}
public UserBuilder withId(Integer id) {
this.id = id;
return this;
}
public UserBuilder withUsername(String username) {
this.username = username;
return this;
}
public UserBuilder withEmail(String email) {
this.email = email;
return this;
}
public UserBuilder withPassword(String password) {
this.password = password;
return this;
}
public UserBuilder withRole(UserRole roleName) {
Role role = roleDAO.findByName(roleName).orElseThrow(
() -> new RoleNotFoundException("Role not found " + roleName));
this.roles.add(role);
return this;
}
public User build() {
Role defaultRole = roleDAO.findByName(UserRole.ROLE_USER).orElseThrow(
() -> new RoleNotFoundException("Role not found " + UserRole.ROLE_USER));
if (!roles.contains(defaultRole)) {
this.roles.add(defaultRole);
}
User user = new User();
user.setId(this.id);
user.setUsername(this.username);
user.setEmail(this.email);
user.setPassword(this.encoder.encode(this.password));
user.setRoles(this.roles);
return user;
}
}
UserFixture - klasa pomocnicza
public class UserFixture {
private final UserBuilder userBuilder;
private final TransactionTemplate transactionTemplate;
private final UserDAO userDAO;
public UserFixture(UserBuilder userBuilder,
TransactionTemplate transactionTemplate,
UserDAO userDAO) {
this.userBuilder = userBuilder;
this.transactionTemplate = transactionTemplate;
this.userDAO = userDAO;
}
public void createUserWithId(Integer id) {
createUser(builder -> builder.withId(id));
}
public void createUserWithUsername(String username) {
createUser(builder -> builder.withUsername(username));
}
public void createUserWithEmail(String email) {
createUser(builder -> builder.withEmail(email));
}
public void createRegularUser() {
createUser(builder -> builder.withRole(UserRole.ROLE_USER));
}
public void createAdminUser() {
createUser(builder -> builder.withRole(UserRole.ROLE_ADMIN));
}
public void createUserWithUsernameAndPassword(String username, String password) {
createUser(builder -> builder.withUsername(username).withPassword(password));
}
private void createUser(Consumer<UserBuilder> config) {
UserBuilder builderCopy = userBuilder.copy();
config.accept(builderCopy);
User user = builderCopy.build();
saveUserAndAssignRoles(user);
}
private void saveUserAndAssignRoles(User user) {
transactionTemplate.executeWithoutResult(status -> {
int userId = userDAO.save(user);
user.getRoles().forEach(role -> userDAO.assignRoleToUser(userId, role.getId()));
});
}
}
Jak widzicie w UserFixture
mam zależność TransactionTemplate
.
Przejdźmy do klasy testowej.
class RequestValidationTest {
private RegistrationRequests requests;
private InMemoryUserDAO userDAO;
private InMemoryRoleDAO roleDAO;
private UserFixture userFixture;
private RequestValidation validation;
@BeforeEach
void setUp() {
roleDAO = new InMemoryRoleDAO();
userDAO = new InMemoryUserDAO(roleDAO);
roleDAO.addDefaultRoles();
validation = new RequestValidation(userDAO);
PasswordEncoder encoder = new BCryptPasswordEncoder();
UserBuilder userBuilder = new UserBuilder(roleDAO, encoder);
TransactionTemplate transactionTemplate = new MockTransactionTemplate(); // klasa mock?
userFixture = new UserFixture(userBuilder, transactionTemplate, userDAO);
requests = new RegistrationRequests();
}
@AfterEach
void cleanUp() {
roleDAO.clear();
userDAO.clear();
}
@Test
void whenUserWithUsernameExists_ThrowException() {
createUserWithUsername("Alex");
assertThrows(CredentialValidationException.class, () -> validate(requests.requestWithUsername("Alex")));
}
private void validate(RegisterRequest requests) {
validation.validate(requests);
}
private void createUserWithUsername(String username) {
userFixture.createUserWithUsername(username);
}
}
W klasie testowej tworzę instancję UserFixture
, która ma zależność TransactionTemplate
. W jaki sposób najlepiej utworzyć instancję TransactionTemplate
, zważywszy, że używam pamięci wewnętrznej opartej na HashMapie?
Na razie zrobiłem tak, że utworzyłem klasę MockTransactionTemplate
, która rozszerza TransactionTemplate
, i metody nadpisuję tak aby nic nie robiły. Czy to dobre rozwiązanie?