Reputation: 61
I want to write a test for a @NotNull
, @NotEmpty
validation of @ConfigurationProperties
.
@Configuration
@ConfigurationProperties(prefix = "myPrefix", ignoreUnknownFields = true)
@Getter
@Setter
@Validated
public class MyServerConfiguration {
@NotNull
@NotEmpty
private String baseUrl;
}
My Test looks like this:
@RunWith(SpringRunner.class)
@SpringBootTest()
public class NoActiveProfileTest {
@Test(expected = org.springframework.boot.context.properties.bind.validation.BindValidationException.class)
public void should_ThrowException_IfMandatoryPropertyIsMissing() throws Exception {
}
}
When I run the test, it reports a failure to start the application before the test is run:
***************************
APPLICATION FAILED TO START
***************************
Description:
Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'myPrefix' to com.xxxxx.configuration.MyServerConfiguration$$EnhancerBySpringCGLIB$$4b91954c failed:
How can I expect an Exception to write a negative test? Even if I replace the BindException.class
with Throwable.class
the application fails to start.
Upvotes: 5
Views: 2034
Reputation: 5369
I'd use an ApplicationContextRunner
for this, e.g.
new ApplicationContextRunner()
.withUserConfiguration(MyServerConfiguration.class)
.withPropertyValues("foo=bar")
.run(context -> {
var error = assertThrows(IllegalStateException.class, () -> context.getBean(MyServerConfiguration.class));
var validationError = (BindValidationException) ExceptionUtils.getRootCause(error);
var fieldViolation = (FieldError) validationError.getValidationErrors().iterator().next();
var fieldInError = fieldViolation.getObjectName() + "." + fieldViolation.getField();
assertThat(fieldInError, is(expectedFieldInError));
assertThat(fieldViolation.getDefaultMessage(), is(expectedMessage));
});
Upvotes: 3
Reputation: 7521
Try to load Spring Boot Application context programmatically:
Simple version
public class AppFailIT {
@Test
public void testFail() {
try {
new AnnotationConfigServletWebServerApplicationContext(MyApplication.class);
}
catch (Exception e){
Assertions.assertThat(e).isInstanceOf(UnsatisfiedDependencyException.class);
Assertions.assertThat(e.getMessage()).contains("nested exception is org.springframework.boot.context.properties.bind.BindException: Failed to bind properties");
return;
}
fail();
}
}
Extended version with ability to load environment from application-test.properties and add own key:values to test environment on method level:
@TestPropertySource("classpath:application-test.properties")
public class AppFailIT {
@Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
@Autowired
private ConfigurableEnvironment configurableEnvironment;
@Test
public void testFail() {
try {
MockEnvironment mockEnvironment = new MockEnvironment();
mockEnvironment.withProperty("a","b");
configurableEnvironment.merge(mockEnvironment);
AnnotationConfigServletWebServerApplicationContext applicationContext = new AnnotationConfigServletWebServerApplicationContext();
applicationContext.setEnvironment(configurableEnvironment);
applicationContext.register(MyApplication.class);
applicationContext.refresh();
}
catch (Exception e){
Assertions.assertThat(e.getMessage()).contains("nested exception is org.springframework.boot.context.properties.bind.BindException: Failed to bind properties");
return;
}
fail();
}
}
Upvotes: -1