RestController with few classes - spring

I have a few classes in the JPA Base made with the use of SpringData and SpringBoot. I would like to create a controller which shows the rest out of a few classes and not only one. Sadly, I can't find any examples.
This is my controller:
#RestController
#RequestMapping("/user")
public class UserController {
private final UserRepository userRepository;
#Autowired
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}
#RequestMapping(method = RequestMethod.POST)//add
public void addUser(#RequestBody User user) {
userRepository.save(user);
}
#RequestMapping(method = RequestMethod.GET)
public List<User> getUser(){
return userRepository.findAll();
}
}

Related

Test Result showing null while performing jUnit5 Test

I am writing a jUnit5 test to test my getUserByEmail(String email) using Mockito and when running the test, it is failing.
#SpringBootTest
#ExtendWith(MockitoExtension.class)
class UserServiceTest {
#MockBean
private UsersRepository userRepository;
#Autowired
private UserService userService;
#Test
void check_email_existInDB_thenReturn_True() {
// given - precondition or setup
UserDetails userdetails2 = new UserDetails(101L, "Anthony Ji", "anthony#gmail.com", "password2");
userRepository.save(userdetails2);
// when - action or behaviour that we are going test
when(userRepository.save(userdetails2)).thenReturn(userdetails2);
// then - verify the result or output using assert statements
assertEquals(userdetails2.getEmail(), userService.getUserByEmail("anthony#gmail.com"));
//assertTrue(userService.getUserByEmail(userdetails2.getEmail()));
}
}
This is my interface with extending of JPARepository
public interface UsersRepository extends JpaRepository<UserDetails, Long>{
}
This is my service level class
#Service
public interface UserService {
public Optional<UserDetails> getUserByEmail(String email);
public UserDetails saveUserDetails(UserDetails userDetails);
}
And this is the serviceImpl Class..
#Service
public class UserServiceImpl implements UserService{
#Autowired
private UsersRepository userRepository;
#Override
public Optional<UserDetails> getUserByEmail(String email) {
List<UserDetails> allUsers = this.userRepository.findAll();
Optional<UserDetails> userInfo = allUsers.stream().filter(user -> user.getEmail().equalsIgnoreCase(email)).findAny();
return userInfo;
}
#Override
public UserDetails saveUserDetails(UserDetails userDetails) {
UserDetails savedUserDetails = this.userRepository.save(userDetails);
return savedUserDetails;
}
}
and finally, this is my controller class while using jersey framework.
#Path(value = "/user")
public class RegistrationResources {
private static Logger logger = LoggerFactory.getLogger(RegistrationResources.class);
#Autowired
private UserService userService;
#POST
#Path("/registration")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Response registerUser(UserDetails userDetails, #Context UriInfo uriInfo) {
logger.info("Inside the registration resource and registering the user");
boolean isEmailExists = isEmailExists(userDetails.getEmail());
if(isEmailExists) {
logger.info("Email Already Registered");
return Response.status(404).entity("Email Address already registered").build();
}
else {
this.userService.saveUserDetails(userDetails);
logger.info("User successfully registered");
return Response.status(200).entity("User successfully registered").build();
}
}
public boolean isEmailExists(String email) {
UserDetails userByEmail = this.userService.getUserByEmail(email).orElse(null);
if(userByEmail == null) {
return false;
}
return true;
}
I tried as above explained in the code.

I have a problem with testing adding user with password encoder

I have a problem when testing a method with using passwordencoder:
Cannot invoke "org.springframework.security.crypto.password.PasswordEncoder.encode(java.lang.CharSequence)" because the return value of "com.store.restAPI.user.UserConfig.passwordEncoder()" is null`
Thats my test class method:
#ExtendWith(MockitoExtension.class)
class UserServiceTest {
private UserService underTest;
#Mock
private UserRepository userRepository;
#Mock
private UserConfig userConfig;
#BeforeEach
void setUp(){
underTest = new UserService(userRepository, userConfig);
}
#Test
void itShouldFindAllUsers() {
//when
underTest.findAll();
//then
verify(userRepository).findAll();
}
#Test
void addNewUser() {
//given
User expected = new User(
"mateusz#gmail.com",
"123"
);
//when
underTest.addNewUser(expected);
//then
ArgumentCaptor<User> userArgumentCaptor =
ArgumentCaptor.forClass(User.class);
verify(userRepository).save(userArgumentCaptor.capture());
User capturedUser = userArgumentCaptor.getValue();
assertThat(capturedUser).isEqualTo(expected);
}
#Test
#Disabled
void loginUser() {
}
}
And thats UserService method that i want to test:
#Service
public class UserService {
private final UserRepository userRepository;
private final UserConfig userConfig;
#Autowired
public UserService(UserRepository userRepository, UserConfig userConfig) {
this.userRepository = userRepository;
this.userConfig = userConfig;
}
public List<User> findAll() {
return userRepository.findAll();
}
public void addNewUser(User user) {
Optional<User> userOptional = userRepository.findUserByEmail(user.getEmail());
if(userOptional.isPresent()){
throw new IllegalStateException("email taken");
}
String hashedPassword = userConfig.passwordEncoder().encode(user.getPassword());
user.setPassword(hashedPassword);
userRepository.save(user);
}
public void loginUser(User user){
Optional<User> userOptional = userRepository.findUserByEmail(user.getEmail());
if(userOptional.isEmpty()){
throw new IllegalStateException("no account under that email");
}
else
if(!userConfig.passwordEncoder().matches(user.getPassword(),
userOptional.get().getPassword())){
throw new IllegalStateException("wrong password");
}
//!userOptional.get().getPassword().equals(user.getPassword())
}
}
Password encoder is a bean in class UserConfig.
#Configuration
public class UserConfig {
#Bean
CommandLineRunner commandLineRunnerUser(UserRepository repository) {
return args -> {
User iza = new User(
"iza#gmail.com",
"$2a$10$U87IFlm9DYXRITUSnfdfDuknz8ijJCcK9UVR4D4kUDu7w13zPuURK"
);
User andrzej = new User(
"andrzej#gmail.com",
"$2a$10$fmYOxyvWBr47wAg1m/ryy.G4J1PbT2LRj6m7oENkBtEsGocansE9G"
);
User tomek = new User(
"tomek#gmail.com",
"$2a$10$chrySvbZSZcje4r3Q0PZv.FrO6/k2WvM42GX3x2EmySZc/dAA2glC"
);
repository.saveAll(
List.of(iza,andrzej,tomek)
);
};
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Do i need to create another method with password encoder inside my test class? I don't know what am i doing wrong. Why does it say that result is null?
Does someone know what am i doing wrong?
In your UserServiceTest, you're currently mocking UserConfig. A mock is basically an implementation that has no behavior at all. This means that userConfig.passwordEncoder() will return null in your test.
To solve this, you have to tell Mockito what the behavior is of your UserConfig class. For example:
Mockito.when(userConfig.passwordEncoder()).thenReturn(new BCryptPasswordEncoder());
This also allows you to use a different (eg. a dummy) password encoder in your unit tests.
Another suggestion, unrelated to your question, is that you can directly autowire PasswordEncoder in your UserService in stead of autowiring UserConfig. This works because you annotated UserConfig with #Configuration and UserConfig.passwordEncoder() with #Bean:
#Service
public class UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder; // Change this
// And change the constructor parameter
#Autowired
public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder; // And this
}
// The rest of your code...
}

Springboot does not save user properly using JpaRepository

I couldn't use userRepo to saveUser properly, the mysql query showed wrong order of insertion, therefore not working. Here's my UserRepository:
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Integer> {
Optional<User> findUserByUsername(String username);
}
Here's my user service:
#Service
public class UserServiceImpl implements IUserService, UserDetailsService {
private Logger logger = LogManager.getLogger(UserServiceImpl.class);
#Autowired
private UserRepository userRepo;
#Autowired
private BCryptPasswordEncoder encoder;
//field name not in correct order, can not use it
#Override
public Integer saveUser(User user) {
String passwd = user.getPassword();
String encodedPasswod = encoder.encode(passwd);
logger.log(Level.ERROR, "passwd:" + encodedPasswod);
user.setPassword(encodedPasswod);
ArrayList<String> roles = new ArrayList<String>();
roles.add("Member");
user.setRoles(roles);
user = userRepo.save(user);
return user.getUserid();
}
public UserServiceImpl(UserRepository userRepository) {
this.userRepo = userRepository;
}
...
Someone can help? So frustrated with springboot.
M.
Look like you missing #Transactional on the saveUser method.

How to use annotation and avoid xml configuration in spring framework

I have designed a packing structure.
Controller
Delegates (which is helper class) - this class do all the business and return the value to Controllers.
Service
Service Implementation
DAO
DAO Implementation.
I want to implement autowired (Annotation) concept and would like to avoid xml configuration such as service and DAO configuration on spring-bean.xml.
This code is not working if I want to avoid xml configuration.
I have done those changes
bean id :loginDelegate, userService, userDao
added the #Service & #Repository annotation to the corresponding service & DAO implementation.
#Controller("loginController")
public class LoginController {
#Autowired
private LoginDelegate loginDelegate;
public LoginDelegate getLoginDelegate() {
return this.loginDelegate;
}
public void setLoginDelegate(LoginDelegate tLoginDelegate) {
this.loginDelegate = tLoginDelegate;
}
#RequestMapping(value="/login.do",method=RequestMethod.GET)
public ModelAndView displayLogin(HttpServletRequest request, HttpServletResponse response) {
log.info("<---displayLogin()--->");
ModelAndView model = new ModelAndView("login");
LoginBean loginBean = new LoginBean();
model.addObject("loginBean", loginBean);
return model;
}
}
public class LoginDelegate {
#Autowired
private IUserService userService;
public IUserService getUserService() {
return this.userService;
}
public void setUserService(IUserService userService) {
this.userService = userService;
}
public boolean isValidUser(String username, String password) throws Exception {
return userService.isValidUser(username, password);
}
}
public interface IUserService {
public boolean isValidUser(UserBean userObj);
public int addUsers(UserBean userObj);
}
public class UserServiceImpl implements IUserService {
#Autowired
private IUserDao userDao;
public IUserDao getUserDao() {
return this.userDao;
}
public void setUserDao(IUserDao userDao) {
this.userDao = userDao;
}
public boolean isValidUser(UserBean userObj) {
return userDao.isExistUser(userObj);
}
#Override
public int addUser(final UserBean userObj) {
return userDao.saveUserDetails(userObj);
}
}
public interface IUserDao {
public boolean isExistUser(UserBean userObj);
public int saveUserDetails(UserBean userObj);
}
public class UserDaoImpl implements IUserDao {
#Autowired
UserBean userObj;
#Autowired
DataSource dataSource ;
public DataSource getDataSource(){
return this.dataSource;
}
public void setDataSource(DataSource dataSource){
this.dataSource = dataSource;
}
Use Java-based configuration if you want to completely get rid of XML-based configuration
#Configuration
#ComponentScan(basePackages = "com.acme")
public class AppConfig {
...
}
The above normal Java class when annotated with #Configuration, makes it a 'Spring Configuration class' (analogous to XML-based configuration).
#ComponentScan annotation scans for classes annotated with #Component, #Controller, #Service, #Repository classes from the package defined during start-up time to get them registered as Spring beans. This can be done in XML also with <context:component-scan base-package="com.acme" />
Refer:http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/beans.html#beans-java-instantiating-container-scan

Spring controller testing with Mockito

I'm trying to test My Spring controllers using Mockito, but I can't actually get how can I do that without making everything #Mock.
Moreover test method returns me NullPointerException, as it can see no user and actually no user role at all.
Is there a way to test my controllers somehow?
(Controller class)
#Controller
#SessionAttributes("user")
#RequestMapping("/login.htm")
public class LoginController{
#Autowired
private UserDao userDao;
#Autowired
private LoginValidator loginValidator;
public LoginValidator getLoginValidator() {
return loginValidator;
}
public void setLoginValidator(LoginValidator loginValidator) {
this.loginValidator = loginValidator;
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
#RequestMapping(method = RequestMethod.GET)
public String getSendEmptyForm(ModelMap model, HttpServletRequest req) {
req.getSession().invalidate();
model.addAttribute("loginForm", new LoginForm());
return "login";
}
#RequestMapping(method = RequestMethod.POST)
public String postSubmittedForm(ModelMap model, #ModelAttribute("loginForm") LoginForm loginForm,
BindingResult result, SessionStatus status) {
//validate form
loginValidator.validate(loginForm, result);
if (result.hasErrors()) {
return "login";
}
User user = userDao.findByLogin(loginForm.getLogin());
model.addAttribute("user", user);
if (user.getRole().getName().equals("Admin")) {
model.addAttribute("usersList", userDao.findAll());
return "viewAllUsersPage";
}
if (user.getRole().getName().equals("User")){
return "userPage";
}
model.addAttribute("error", "Your role is not User or Admin");
return "errorPage";
}
}
And my testing class
#RunWith(MockitoJUnitRunner.class)
public class LoginControllerTest {
#InjectMocks
private LoginController controllerUT = new LoginController();
#Mock
private ModelMap model;
#Mock
private LoginForm loginForm;
#Mock
private BindingResult result;
#Mock
private SessionStatus status;
#Mock
private LoginValidator validator;
#Mock
private UserDao userDao;
#Mock
private User useк;
#Test
public void testSendRedirect(){
final String target = "login";
String nextPage = controllerUT.postSubmittedForm(model, loginForm, result, status);
assertEquals(target, nextPage);
}
}
First off you seem to be missing stubbing for loginForm.getLogin() and userDao.findByLogin(loginForm.getLogin()) and user.getRole().getName(). Without such stubbing, these methods called on a mock will return a default value (i.e. null).
So you may want to add :
when(loginForm.getLogin()).thenReturn(login);
when(userDao.findByLogin(login)).thenReturn(user);
when(user.getRole()).thenReturn(role);
when(role.getName()).thenReturn("Admin");
You will want to vary the return values for different tests.
Depending on your implementation classes for User and Role, you could simply supply real instances.
For a test that simulates the result to have errors you'll want to add this stubbing :
when(result.hasErrors()).thenReturn(true);
since otherwise the default false is returned.

Resources