11

Hi I don't understand what advantages give me usage of @ContextHierarchy like below:

@ContextHierarchy({
  @ContextConfiguration("/test-db-setup-context.xml"),
  @ContextConfiguration("FirstTest-context.xml")
})
@RunWith(SpringJUnit4ClassRunner.class)
public class FirstTest {
 ...
}

@ContextHierarchy({
  @ContextConfiguration("/test-db-setup-context.xml"),
  @ContextConfiguration("SecondTest-context.xml")
})
@RunWith(SpringJUnit4ClassRunner.class)
public class SecondTest {
 ...
}

over usage of single @ContextConfiguration with locations argument, like below:

@ContextConfiguration(locations = {"classpath:test-db-setup-context.xml", "FirstTest-context.xml", "SecondTest-context.xml" })

In each case, application contexts are shared across diffrent junit test classes.

2 Answers2

2

The difference is that beans in each context within the context hierarchy can't see beans in the other the context. So you can isolate different parts of your item under test.

Guy
  • 3,353
  • 24
  • 28
0

An imortant thing to note here is that In case of @ContextHierarchy we get SEPARATE contexts that have SEPARATE life-cycles (initialization, shutdown). This is important because for example they can fail independently.

A practical example from my yard. We have a Spring application that communicates with some external services. We wanted an E2E test that starts these dependent services and the runs the tests. So we added an initializer to our @ContextConfiguration:

@ContextConfiguration{classes = TheApp.class, initializers = DockerInitializer.class}
public class TheAppE2ETests {
    // ...
}

The initializer was preparing the external services (starting Dockers), customizing the properties so that The App can run and attaching to the close context event so that the Dockers could be cleaned up. There was a problem with this approach when The App context was failing to load (e.g. due to a bug):

  1. After a failed initialization the ContextClosedEvent is not fired - the dockers were not stopped and cleaned up.
  2. When the context fails to load the initializer is called over and over for every test which is run (not only for every test class - for every test method!).

So the tests kept on killing our CI environment every time a bug in The App's context caused the initialization to fail. The containers for the dependent services were started for every single test method and then not cleaned up.

We ended up using @ContextConfiguration and having two separate contexts for dockers and The App itself. This way in case of an above-mentioned situation the dockers are started in a separate context and therefore live there own live and can even be shared across multiple Spring tests (due to Spring's context caching mechanism).

jannis
  • 4,843
  • 1
  • 23
  • 53