If you are working with SpringBoot, you probably, at some point ended up with conditional beans. Beans that are only loaded if a certain property is set, or if a certain class is present on the classpath. Testing these beans can be a pain, especially if you want to test the behavior of your application with different configurations.
There are sane ways to do this, and then there is the insane way. This post is about the insane way. I think there is a lot we can learn from this approach, even if we don't want to use it in our own projects.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.assertj.core.api.Assertions;
import org.junit.experimental.runners.Enclosed;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
@RunWith(Enclosed.class)
class ApplicationTest {
@Nested
@EnabledIfSystemProperty(named = "enableContextTest", matches = "true")
@SpringBootTest
class ContextLoads {
@Autowired
private ApplicationContext applicationContext;
@Test
void contextLoads() {
Assertions.assertThat(applicationContext).isNotNull();
}
}
}
Whoa, what is going on here? Let's break it down.
First, if we were to not use a nested class, the @SpringBootTest annotation would just load the application context, regardless of the system property check. This is because the @SpringBootTest annotation is processed before the test class is instantiated.
Right, so we need to use a nested class. So, we add the @Nested annotation. This tells JUnit that this class is a nested test class.
Then we have to use @RunWith(Enclosed.class) on the outer class. This tells JUnit to run the nested classes as separate test classes.
Finally, we add the @EnabledIfSystemProperty annotation to the nested class. This tells JUnit to only run this test class if the specified system property is set to the specified value.
And there you have it, a conditional SpringBoot test. Now all you have to do is to add -DenableContextTest=true as an argument or whatever to your test runner, and the test will run. If you don't add this argument, the test will be skipped.
I think this is totally insane. Now, you might ask: "What is the sane way to do this?" Well, I am not telling you.
Well, okay. Fine, use profiles. You can create a test profile for each configuration you want to test, and then use the '@ActiveProfiles' annotation to specify which profile to use for each test class.