运行 测试 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
我有 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