I'm learning Unit Testing with JUnit and Mockito on a Spring boot application, I have a registration method I want to test, in my test method I create a User but I see that the value of the password is always null when using.encode(mypassword), resulting in an Assertion Error.
UserServiceImpl.java
@Service
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
public UserServiceImpl(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
@Override
public User register(User user) {
Role role = roleService.findByName(ERole.ROLE_USER);
Set<Role> roleSet = new HashSet<>();
user.setFullName(user.getFullName());
user.setEmailAddress(user.getEmailAddress());
user.setPassword(passwordEncoder.encode(user.getPassword()));
user.setConfirmPassword("");
user.setEmailVerified(true);
roleSet.add(role);
user.setRoles(roleSet);
if(userRepository.existsByEmailAddress(user.getEmailAddress())) {
throw new EmailAlreadyExistsException("Account already exists with this email");
}
return userRepository.save(user);
}
}
UserServiceImplTest.java
@ExtendWith(MockitoExtension.class)
class UserServiceImplTest {
@InjectMocks
private UserServiceImpl userService;
@Mock
private UserRepository userRepository;
@Mock
public PasswordEncoder passwordEncoder;
@BeforeEach
void setUp() {
userService = new UserServiceImpl(userRepository, passwordEncoder);
}
@Test
void testIfUserCanRegisterSuccessfully() {
User user = new User(1, "admin", "admin@gmail.com", passwordEncoder.encode("password"));
when(userRepository.save(any())).thenReturn(user);
User theUser = userService.register(user);
System.out.println("theUser: " + theUser);
assertNotNull(theUser);
assertEquals(1, theUser.getId());
assertEquals("admin@gmail.com", theUser.getEmailAddress());
assertTrue(passwordEncoder.matches("password", theUser.getPassword()));
}
}
SecurityConfig.java
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Value("${spring.security.ant.matchers}")
private String[] securityAntMatchers;
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Autowired
private JwtAuthenticationEntryPoint authenticationEntryPoint;
@Bean
public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() {
return new JwtAuthenticationTokenFilter();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Override
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable().formLogin().disable().httpBasic().disable();
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
.and()
.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
http
.authorizeRequests()
.antMatchers(securityAntMatchers)
.permitAll()
.anyRequest()
.authenticated();
}
}
The output of theUser is this, I'm not sure how to handle the password encryption when testing the method.
theUser: User{id=1, fullName='admin', emailAddress='admin@gmail.com', dateJoined=Tue Nov 15 00:06:01 CAT 2022, emailVerified=true, password='null'}
EDITED
@BeforeEach
void setUp() {
// Instantiating password encoder before every test, now I get the output
this.passwordEncoder = new BCryptPasswordEncoder();
userService = new UserServiceImpl(userRepository, passwordEncoder);
}
@Test
void testIfUserCanRegisterSuccessfully() {
User user = new User(1, "admin", "admin@gmail.com","password");
when(userRepository.save(any())).thenReturn(user);
User created = userService.register(user);
assertEquals(created.getPassword(), user.getPassword());
assertEquals(created.getEmailAddress(), user.getEmailAddress());
verify(userRepository).save(any());
}
Your services in the tests:
@Mock
private UserRepository userRepository;
@Mock
public PasswordEncoder passwordEncoder;
Are mocks, which means they won't actually do anything unless you explicitly tell them what to do by stubbing methods, as you do here:
when(userRepository.save(any())).thenReturn(user);
The issue is that you haven't stubbed any methods in the passwordEncoder
so it's methods will do nothing and return null
.
Also, it appears you are encoding your password twice (once in the test and once in the register
method), which could lead to errors down the line even with proper stubbing
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.