Reputation: 625
Spring Boot integration testing here. I have the following service class:
@Service
public class PasswordService implements PasswordEncoder {
private BCryptPasswordEncoder passwordEncoder;
private PasswordGenerator passwordGenerator;
private CharacterCharacteristicsRule passwordCharacteristicsRule;
private Integer minPasswordLength;
@Autowired
public PasswordService(
BCryptPasswordEncoder passwordEncoder,
PasswordGenerator passwordGenerator,
CharacterCharacteristicsRule passwordCharacteristicsRule,
@Value("${myapp.users.passwords.min-length}") Integer minPasswordLength) {
this.passwordEncoder = passwordEncoder;
this.passwordGenerator = passwordGenerator;
this.passwordCharacteristicsRule = passwordCharacteristicsRule;
this.minPasswordLength = minPasswordLength;
}
public String generatePassword() {
return passwordGenerator.generatePassword(minPasswordLength, passwordCharacteristicsRule.getRules());
}
public String protectPassword(String plaintextPassword) {
return passwordEncoder.encode(plaintextPassword);
}
@Override
public String encode(CharSequence rawPassword) {
return protectPassword(rawPassword.toString());
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return protectPassword(rawPassword.toString()).equals(encodedPassword);
}
}
I have a unit test for each method, but because its generatePassword()
method is so important and depends so heavily on its dependencies, I also want to create an integration test for it that actually autowires/injects it with real instances of all of its dependencies.
My best attempt:
public class PasswordServiceIT {
@Inject
private BCryptPasswordEncoder passwordEncoder;
@Inject
private PasswordGenerator passwordGenerator;
@Inject
private CharacterCharacteristicsRule passwordCharacteristicsRule;
private PasswordService passwordService;
@BeforeEach
public void setup() {
passwordService = new PasswordService(passwordEncoder, passwordGenerator, passwordCharacteristicsRule, 10);
}
@Test
public void when_generatePassword_should_generate_valid_password() {
String password = passwordService.generatePassword();
System.out.println(String.format("Password is: %s", password));
}
}
Throws NPEs because passwordEncoder
and passwordGenerator
are being injected as null
. Again I'm looking for the real BCryptPasswordEncoder
and the real PasswordGenerator
and the real CharacterCharacteristicsRule
to be injected into my PasswordService
instance here, so I can take it for a real test spin.
Can anybody spot where I'm going awry here? Thanks in advance!
Upvotes: 0
Views: 83
Reputation: 8674
Do not create an instance for your service PasswordService
using the new
keyword. If you do, all the @Inject
/@Autowire
members will be null. You need to inject the PassworService
also.
And annotate the test class with org.springframework.boot.test.context.SpringBootTest
so when running the tests, a spring context will be created.
So you test class will as follows.
@SpringBootTest
public class PasswordServiceIT {
@Inject
private PasswordService passwordService;
@Test
public void when_generatePassword_should_generate_valid_password() {
String password = passwordService.generatePassword();
System.out.println(String.format("Password is: %s", password));
}
}
You don't need to inject other classes unless you directly use it in your tests in this class.
Note: For this, you need org.springframework.boot:spring-boot-starter-test
should be in the test scope dependency.
Upvotes: 1
Reputation: 1069
You can try to add @RunWith(SpringRunner.class) @SpringBootTest to your class. I think spring does not see your injecting, so it might help.
And you can replace all your injects by
@Autowired
private PasswordService passwordService;
Upvotes: 1