0

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:

  1. Start the application
  2. Interact with the application (e.g. register a user, simulate some user activity...)
  3. Shut it down
  4. Start it again
  5. 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.

  1. The @DirtiesContext annotation as proposed here and here:

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.

  1. 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.

  1. 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?

Martin Drozdik
  • 12,742
  • 22
  • 81
  • 146
  • 1
    Your test is not a Unit test. Thats why JUnit is giving you such a hard time. If you depend on order for your tests try something different (RestAssured, Cucumber, MockMVC, etc) which one will depend on your requirements and the nature of your app – Camilo Sanchez Jul 31 '18 at 19:44
  • TBH, I have never seen anyone start, stop, and restart the entire application within a single test class. Do you actually have a concrete need for that? – Sam Brannen Aug 01 '18 at 09:05
  • @SamBrannen Yes, I want to test that the application is properly initialized with a non-empty database. – Martin Drozdik Aug 01 '18 at 09:51
  • Then why don't you simply execute some SQL setup scripts against the database as the `ApplicationContext` is loading? That should suffice. – Sam Brannen Aug 01 '18 at 09:59
  • @SamBrannen because I do not know how to do it. It seems that no matter what, by the time I am putting something into the database, the context is already initialized. Also, I would prefer to have a self-contained test rather than a test + script. – Martin Drozdik Aug 01 '18 at 12:53
  • 1
    Spring Boot provides support for [automatically initializing your database](https://docs.spring.io/spring-boot/docs/current/reference/html/howto-database-initialization.html#howto-initialize-a-database-using-spring-jdbc). You might also find [this article](http://www.baeldung.com/spring-boot-data-sql-and-schema-sql) useful as a brief introduction. – Sam Brannen Aug 02 '18 at 11:04
  • If you really don't want to use SQL scripts or something like Liquibase or Flyway, I suppose your workaround for ordering the test methods would suffice until JUnit Jupiter has first-class support for ordering. – Sam Brannen Aug 02 '18 at 11:07

0 Answers0