I'm new to JPA and Spring Data and I've faced problem with testing my application. I have two entities in my Spring boot application:
@Getter
@Setter
@Entity
public class User extends SomeBasicEntity {
@NotNull
@Column(unique = true)
private String login;
@NotNull
private String password;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "user", cascade = CascadeType.ALL)
@JsonManagedReference
private List<Role> roles;
}
@Getter
@Setter
@Entity
@Table(name = "ROLE")
public class Role extends SomeBasicEntity {
@NotNull
private String name;
@ManyToOne
@NotNull
@JsonBackReference
private User user;
}
I have implemented dedicated JPA repositories for them (as JpaRepository). I have also implemented transactional facade for the management:
@Service
@Transactional
public class Facade {
@Autowired
private UserRepository userRepository;
@Autowired
private RoleRepository roleRepository;
public User addNewUser(User user) {
return userRepository.save(user);
}
public Role addNewRole(Role role, User user) {
role.setUser(user);
return roleRepository.save(role);
}
public User findUserByLogin(String login) {
User user = userRepository.findByLogin(login);
if (user != null) {
return user;
} else {
throw new FacadeRuntimeException("User " + login + " does not exists");
}
}
}
Finally, I've created RestController for using the facade (I've hardcoded login name value just for test purposes):
@RestController
@RequestMapping(value = "/users")
public class UserController {
@Autowired
private Facade facade;
@RequestMapping(value = "/login", method = RequestMethod.GET)
public User getUserByLogin() {
User user = facade.findUserByLogin("jahu");
return user;
}
}
And now when I run the application, use facade methods to create user and role (code is irrelevant so I dont paste it here) and check REST response on localhost/users/login there is properly serialized User object WITH list of roles (with single role I've created actually).
Question 1: Why roles are present in Json object whereas I didn't explictly call getRoles on the user object? With lazy fetch type I believe collection should be retrived only when getter is called (maybe JSON serializer is calling the method?)
Nevertheless, I have second problem as I want to test my facade with jUnit (on h2 db), however in test method the roles on User object are always null (even if I explicltly call getter):
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = FacadeApplication.class)
@Transactional
public class FacadeTest {
private static final String USER_LOGIN = "jahu";
private static final String ROLE_NAME = "role name";
@Autowired
Facade sut;
@Before
public void setUp() throws Exception {
User user = new User();
user.setLogin(USER_LOGIN);
user.setPassword("jahu");
user = sut.addNewUser(user);
Role role = new Role();
role.setName(ROLE_NAME);
sut.addNewRole(role, user);
}
@Test
public void shouldFindUserRoles() {
User user = sut.findUserByLogin(USER_LOGIN);
assertThat(user).isNotNull();
assertThat(user.getLogin()).isEqualTo(USER_LOGIN);
List<Role> roles = user.getRoles(); // HERE I call the getter
assertThat(roles).isNotNull().isNotEmpty();
}
}
Question 2: Why can I not access roles in test context even though I am using the same method as in RestController (where roles are always obtained)? Without it I am not able to fully test my app and it concerns me very much.
Note: entity names are just for description of the problem, so please don't suggest that I should remodel my entities in order to assign Role to User.