My application does some nontrivial custom initialization, using the data from a database. I would like to make an integration test to test this behavior. It would:
- Start the application
- Interact with the application (e.g. register a user, simulate some user activity...)
- Shut it down
- Start it again
- Verify that the application is initialized properly with respect to 2.
Since I am working with the Spring Boot framework, I do not need to actually restart the application, all I need is to destroy and re-create the beans that I want to test. However, any approach that I considered has some gruesome flaw.
This does not work for me, since I would have to have two different test methods. One to perform the above-mentioned step 2 and another one to perform step 5. The starting and shutting down of the application would be accomplished by annotating the test class with:
@TestInstance(TestInstance.Lifecycle.PER_METHOD)
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
But unfortunately in Junit5 it is not possible to specify the order of tests. So I cannot be certain that 2 is executed before 5.
I tried to annotate the first test method with @BeforeAll
and @BeforeEach
, but this somehow negates the effects of the @DirtiesContext
annotation and the ApplicationContext does not get reset.
- The manual use of
ApplicationContext
:
I would re-create the bean I am testing manually.
@Test
fun test(@Autowired applicationContext: ApplicationContext)
{
simulateUserActionAsInStep2()
val factory = applicationContext.autowireCapableBeanFactory
factory.destroyBean(service)
val reCreatedService = factory.createBean(Service::class.java)
factory.autowireBean(reCreatedService)
testServiceAsInStep5(reCreatedService)
}
Apart from not winning the beauty contest, this solution comes to me as brittle and potentially incorrect, since I am re-creating only a single bean. There may be other affected beans that need re-creating in order for the test not to give a false negative result.
- The manual order solution
I could just butcher in some extra code to make the two methods do the things I want in a specified order:
@Test
fun testMethod1()
{
// If this method is being executed as the first one
if (serviceUntouched())
simulateUserActionAsInStep2()
else
testServiceAsInStep5(reCreatedService)
}
@Test
fun testMethod2()
{
testMethod1()
}
All in all, it seems like there are no good choices, yet this seems like a common enough problem. Am I missing some obvious solution?