Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Running Spring tests in parallel with maven

I have a collection of integration tests running with SpringJUnit4ClassRunner. I'm trying to run these in parallel using maven surefire. However, I have noticed that the the code is blocking before entering the synchronized block in CacheAwareContextLoaderDelegate.loadContext().

Is there a way to bypass this cache? I tried doing this, but it seems like there is more shared state than just the cache itself since my application deadlocked inside Spring code. Or could the synchronization be made more fine-grained by somehow synchronizing on the map key rather than the entire map?

My motivation for parallelising tests is twofold:

  1. In some tests, I replace beans with mocks. Since mocks are inherently stateful, I have to build a fresh ApplicationContext for every test method using @DirtiesContext.
  2. In other tests, I only want to deploy a subset of Jersey resources. To do this, I specify a subset of Spring configuration classes. Since Spring uses the MergedContextConfiguration as a key in the context cache, these tests will be unable to share ApplicationContexts.
like image 636
hertzsprung Avatar asked May 07 '13 09:05

hertzsprung


People also ask

How can you use Maven to run unit tests in parallel?

Maven Dependencies In a nutshell, Surefire provides two ways of executing tests in parallel: Multithreading inside a single JVM process. Forking multiple JVM processes.

Should integration tests be run in parallel?

Are your automated tests running in parallel? If not, then they probably should be. Together with continuous integration, parallel testing the best way to fail fast during software development and ultimately enforce higher software quality.

Does surefire run tests in parallel?

The surefire offers a variety of options to execute tests in parallel, allowing you to make best use of the hardware at your disposal. But forking in particular can also help keeping the memory requirements low.


1 Answers

It is possible that may get a better turn-around time for your test suit if you disable the parallell test execution. In the testing chapter of Spring's reference docs there is a paragraph about Context caching:

Once the TestContext framework loads an ApplicationContext (or WebApplicationContext) for a test, that context will be cached and reused for all subsequent tests that declare the same unique context configuration within the same test suite.

Why is it implemented like this?

This means that the setup cost for loading an application context is incurred only once (per test suite), and subsequent test execution is much faster.

How does the cache work?

The Spring TestContext framework stores application contexts in a static cache. This means that the context is literally stored in a static variable. In other words, if tests execute in separate processes the static cache will be cleared between each test execution, and this will effectively disable the caching mechanism.

To benefit from the caching mechanism, all tests must run within the same process or test suite. This can be achieved by executing all tests as a group within an IDE. Similarly, when executing tests with a build framework such as Ant, Maven, or Gradle it is important to make sure that the build framework does not fork between tests. For example, if the forkMode for the Maven Surefire plug-in is set to always or pertest, the TestContext framework will not be able to cache application contexts between test classes and the build process will run significantly slower as a result.

like image 81
matsev Avatar answered Oct 11 '22 13:10

matsev