Reputation: 343
I'm creating a new Spring Boot app from the scratch and want to write tests for it. I've just implemented authentication into my app and want to learn how roles work.
When I use my UserRepository in the authentication process, everything works as it should. However, when I want to use UserRepository in tests, it says that the object is null, the same one that's OK when I use it in the app code. Why is that? Here's the code.
Security configuration class:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private PowderizeUserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.logout().permitAll();
}
@Override
public void configure(AuthenticationManagerBuilder authenticationManager) {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setPasswordEncoder(passwordEncoder());
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationManager.authenticationProvider(authenticationProvider);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12);
}
}
User class:
@Entity
@Table(name = "USERS")
@NoArgsConstructor
@Getter
public class User extends BaseEntity {
private String firstName;
private String lastName;
private String emailAddress;
private String nickname;
private String password;
private boolean accountNonExpired;
private boolean accountNonLocked;
private boolean credentialsNonExpired;
private boolean enabled;
@ManyToMany(mappedBy = "users_roles")
private Set<Role> roles;
}
Repository:
public interface UserRepository extends CrudRepository<User, Long> {
public Optional<User> findByEmailAddress(String email);
}
UserDetailsService implementation class, that uses the repository with no problems:
@Service
public class PowderizeUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
return new PowderizePrincipal(
userRepository.findByEmailAddress(email)
.orElseThrow(() -> new UsernameNotFoundException("User '" + email + "' not found."))
);
}
}
And the test class that returns NullPointerException:
@SpringBootTest
public class UsersAndRolesTest {
@Autowired
private UserRepository userRepository;
@Test
public void ww(){
assertThat(userRepository, notNullValue());
}
@Test
public void userExistsInDatabase(){
assertThat(userRepository.findByEmailAddress("[email protected]").isPresent(), notNullValue());
}
}
I've tried using annotations like @Repository, @EnableJpaRepositories, actually every solution I've found. IntelliJ also highlights the userRepository
with "Could not autowire. No beans of 'UserRepository' type found."
Upvotes: 0
Views: 480
Reputation: 343
I've found the solution, guided by vanillaSugar's answer. What I was lacking was the @RunWith(SpringRunner.class)
annotation, but it was not enough. I've realized that the problem was also connected to the package the test suite was located. I didn't add the package
line of code in the question, and it was the part of the problem as well.
From what I've found, @SpringBootApplication
scans for components below it in the package hierarchy in the app. Just adding @RunWith
annotation led me to this problem with another exception:
java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test
.
What I also had to do is to move my test class from previous package - security.UsersAndRolesTest
to com.powderize.security.UsersAndRolesTest
, which "mirrors" the packages in the app code. Probably obvious for more advanced Spring developers, but took me a while to discover it.
Upvotes: 2
Reputation: 551
Add this annotation to your UsersAndRolesTest class
@RunWith(SpringRunner.class)
Upvotes: 2