Maven Test Isolation

By | May 9, 2015
Reading Time: 2 minutes

The other day I ran into a problem that made me quite puzzled. I was working on a project which build and ran without any problems. Then I enabled the use of a third-party library during the execution of the tests in the project and suddenly there were out of memory errors in PermGen during the build.
I had changed nothing in my own code and the application were working as expected when being run.

Allocating More PermGen Memory

The first obvious attempt was to allocate more PermGen memory when running the tests using the -XX:MaxPermSize=256m Maven option. In Linux or similar, this is set by executing the following line in a terminal window:

export MAVEN_OPTS="-XX:MaxPermSize=256m"

Unfortunately this only delayed the seemingly inevitable out of memory error.

Java 8 and PermGen

If you read this and have the option to build using Java 8 or later, then do try that option. I tried to run my build under Java 8, in which PermGen has been completely removed, and it worked without errors.
Unfortunately I didn’t have the option to use Java 8 so I had to soldier on.

Testing In Isolation

The Maven Surfire plug-in can be configured as to allow multiple tests to be run in parallel and whether a new JVM process is to be started for each new fork or not. In addition you can set memory allocation arguments to be used when running tests.
In the default configuration, tests will not run in parallel and the JVM process in which tests run will be reused. The latter is what may cause PermGen out of memory problems.
By adding the following plug-in configuration to the build section of your Maven pom file, each test will run in a new JVM process and only one single test at a time will be executed:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.18.1</version>
    <configuration>
        <argLine>-Xmx512m -XX:MaxPermSize=256m</argLine>
        <forkCount>1</forkCount>
        <reuseForks>false</reuseForks>
    </configuration>
</plugin>

With the above configuration in place, the entire build ran without memory problems.

I imagine running tests in parallel can be useful but it will also include additional complexity and problems. One problem that immediately comes to mind is mock servers; each mock server started in parallel would have to listen on a unique port. The Surefire plug-in does have a feature that makes it possible to accomplish but as of today, I am not sure it is worth the effort to parallelize my tests.

 

4 thoughts on “Maven Test Isolation

  1. Mare

    Hi Ivan,

    Was performance noticeably affected by this change?

    Thanks

    Reply
    1. Ivan Krizsan Post author

      Hello!
      It depends on how timeconsuming the test setup is. In my case the fastest option is to set up the environment once and let all the tests in a class execute in the same environment. If I use the technique described in the article, a new JVM will be started for each test and the environment will also have to be set up for each test. Thus in my case, the tests required significantly longer time to run.
      I see this as a kind of measure to be taken, more or less, as a last resort or if you want to make absolutely sure that the environment in which a test is run is pristine.
      In my case I had to resort to this in order to be able to run the tests on the buildserver.
      Best wishes!

      Reply
  2. Jose

    Thanks for sharing this.

    Any chance you know how can I run each test *method* in isolation? It seems that:
    1
    false
    only run test *classes* in isolation, and I would like to run test *methods* in isolation.

    Thanks in advance.

    Reply
    1. Ivan Krizsan Post author

      Sorry, no, I do not know of a way to run individual methods in isolation. The obvious approach that comes to mind is to refactor each test method to its own class. I do realize that it is a somewhat ugly solution.

      Reply

Leave a Reply to Jose Cancel reply

Your email address will not be published. Required fields are marked *