运行 测试 Controller 时方法 setUserService 的参数 0

Parameter 0 of method setUserService when run test Controller

我有 Spring 个安全应用程序。我添加了自定义 SpringDataUserDetailsService implements UserDetailsService。自动装配 setUserService.

public class SpringDataUserDetailsService implements UserDetailsService {

    private UserService userService;

    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        User user = userService.findByEmail(username);

        if (user == null) {
            throw new UsernameNotFoundException(username);
        }

        return new org.springframework.security.core.userdetails.User(
                user.getEmail(),
                user.getPassword(),
                convertAuthorities(user.getRoles()));
    }

    private Set<GrantedAuthority> convertAuthorities(Set<Role> userRoles) {
        Set<GrantedAuthority> authorities = new HashSet<>();
        for (Role ur : userRoles) {
            authorities.add(new SimpleGrantedAuthority(ur.getRole()));
        }
        return authorities;
    }
}
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    User findByEmail(String email);
}
@Service
public class UserService {

    private static final String DEFAULT_ROLE = "ROLE_USER";
    private final UserRepository userRepository;
    private final RoleRepository roleRepository;
    private final PasswordEncoder passwordEncoder;

    public UserService(UserRepository userRepository, RoleRepository roleRepository, PasswordEncoder passwordEncoder) {
        this.userRepository = userRepository;
        this.roleRepository = roleRepository;
        this.passwordEncoder = passwordEncoder;
    }

    public List<User> getAllUsers() {
        return userRepository.findAll();
    }

    public void registerNewUserAccount(User user) {
        if (emailExist(user.getEmail())) {
            throw new UserAlreadyExistException("There is an account with that email address: "
            + user.getEmail());
        }

        // set default role
        Role userRole = roleRepository.findRoleByRole(DEFAULT_ROLE);
        user.getRoles().add(userRole);

        // set hash password
        user.setPassword(passwordEncoder.encode(user.getPassword()));

        // save
        userRepository.save(user);
    }

    public User findByEmail(String email) {
        return userRepository.findByEmail(email);
    }

    private boolean emailExist(String email) {
        return userRepository.findByEmail(email) != null;
    }
}

我用浏览器测试过,没问题。我可以注册新用户(到数据库)然后登录到应用程序。现在我想为 CustomerController 编写测试,但收到错误。如果我删除 Autowired setUserService 测试通过,但我无法注册新用户。我需要在哪里找到问题?

Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'customUserDetailsService': Unsatisfied dependency expressed through method 'setUserService' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type '.service.UserService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

@ExtendWith(SpringExtension.class)
@WebMvcTest(CustomerController.class)
class CustomerControllerTest {

    @MockBean
    private CustomerService customerService;

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private WebApplicationContext context;

    @BeforeEach
    public void setup() {
        mockMvc = MockMvcBuilders
                .webAppContextSetup(context)
                .apply(springSecurity())
                .build();
    }

    @WithMockUser(value = "spring")
    @Test
    void shouldReturnViewWithPrefilledData() throws Exception {

        Customer customer = new Customer();
        customer.setId(1L);
        customer.setCustomerName("customer Name");

        when(customerService.getAllCustomers()).thenReturn(List.of(customer));

        this.mockMvc.perform(MockMvcRequestBuilders.get("/customer/list"))
                .andExpect(status().isOk())
                .andExpect(view().name("customer/customer-list"))
                .andExpect(MockMvcResultMatchers.model().attributeExists("customers"));

    }
}

你应该添加

@Import({UserService.class})

给你考class。结果将是

@ExtendWith(SpringExtension.class)
@WebMvcTest(CustomerController.class)
@Import({UserService.class})
class CustomerControllerTest {

您已经用“WebMvcTest”注释了您的 class。在这种情况下 spring 并没有完全启动它的整个上下文。例如,Bean 初始化仅针对 Controller 完成。如果你想让一切都初始化(因为你很懒或者因为你的 UserService 有更多的依赖必须手动导入)你可以替换

@WebMvcTest(CustomerController.class)

@SpringBootTest

然而,这将需要更长的时间来启动你的 unitTest,因为它必须初始化更多的 Context