简体   繁体   中英

Using BCryptPasswordEncoder in Unit Test returns a null value

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM