【问题标题】:I have a problem with testing adding user with password encoder我在测试使用密码编码器添加用户时遇到问题
【发布时间】:2023-01-23 18:16:05
【问题描述】:

使用 passwordencoder 测试方法时遇到问题:

无法调用“org.springframework.security.crypto.password.PasswordEncoder.encode(java.lang.CharSequence)”因为“com.store.restAPI.user.UserConfig.passwordEncoder()”的返回值为空`

那是我的测试类方法:

    @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() {
        }
    }

这就是我要测试的 UserService 方法:

    @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())
         }
    }

密码编码器是 UserConfig 类中的一个 bean。

    @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();
        }
    }

我是否需要在我的测试类中创建另一个带有密码编码器的方法?我不知道我做错了什么。为什么说结果为空? 有人知道我做错了什么吗?

【问题讨论】:

  • 请不要使用代码图像。如果我们想自己测试,我们现在必须完全自己打字。
  • 您正在使用模拟,模拟的默认设置是在不存在任何行为时返回 null
  • 没有行为是什么意思?对不起,我不明白我是新手。

标签: spring spring-boot unit-testing spring-data-jpa spring-data


【解决方案1】:

在你的UserServiceTest中,你目前正在嘲笑UserConfig。模拟基本上是一种完全没有行为的实现。这意味着 userConfig.passwordEncoder() 将在您的测试中返回 null

要解决这个问题,您必须告诉 Mockito 您的 UserConfig 类的行为是什么。例如:

Mockito.when(userConfig.passwordEncoder()).thenReturn(new BCryptPasswordEncoder());

这也允许您在单元测试中使用不同的(例如虚拟的)密码编码器。


另一个与您的问题无关的建议是,您可以直接在您的UserService 中自动装配PasswordEncoder,而不是自动装配UserConfig。这是有效的,因为你用@Configuration注释了UserConfig,用@Bean注释了UserConfig.passwordEncoder()

 @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...
}

【讨论】:

    猜你喜欢
    • 2020-05-06
    • 1970-01-01
    • 2016-08-31
    • 1970-01-01
    • 2013-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多