Best practices for integration tests with Maven?

JavaTestingMaven 2Integration Testing

Java Problem Overview


I have a project which I am building with Maven which uses Hibernate (and Spring) to retrieve data from a database, etc.

My "tests" for the DAOs in my project extend Spring's AbstractTransactionalDataSourceSpringContextTests so that a DataSource can be wired into my class under test to be able to actually run the query/Hibernate logic, to fetch data, etc.

On several other projects I've used these types of test in concert with a HSQL database (either in-memory or pointed at a file) to be able to efficiently test the actual database querying logic without relying on an external database. This works great, since it avoids any external dependencies and the "state" of the database prior to running the tests (each of which are wrapped in a transaction which is rolled back) is well defined.

I'm curious though about the best way to organize these tests, which are really a loose flavor of integration tests, with Maven. It feels a bit dirty to keep these tests in src/test/java, but from what I've read there doesn't seem to be a consistent strategy or practice for organizing integration tests with Maven.

From what I've read so far, seems like I can use the Failsafe plugin (or a second instance of Surefire) and bind it to the integration-test phase, and that I can also bind custom start-up or shutdown logic (such as for starting/stopping the HSQL instance) to pre-integration-test or post-integration-test. But, is this really the best method?

So my question basically is - what is the generally accepted best practice on organizing this with Maven? I'm having trouble finding any sort of consistent answer in the documentation.

What I'd like is to:

  • Seperate unit tests from integration tests, so only unit tests are run during the test phase
  • The ability to bind custom startup/shutdown logic to pre-integration-test and post-integration-test
  • Have the reports from the integration-tests merged/presented with the unit test Surefire reports

Java Solutions


Solution 1 - Java

A very simple way of doing this is to use JUnit categories.

You can then easily run some tests during the test phase and another during the integration-test phase.

It takes minutes and requires only 3 steps.

  1. Define a marker interface
  2. Annotate the classes you wish to split
  3. Configure Maven plugins.

A full example is given here. https://stackoverflow.com/a/10381662/1365383

Solution 2 - Java

There is this codehaus page with some guidelines. I found the failsafe plugin a bit of a hack, and it makes running the unit tests in Eclipse fiendishly complicated. I do broadly what you're describing.

Define integration tests in src/itest/java In the pre-integration-test phase:

  • Clear target/test-classes
  • Use the build-helper-maven-plugin's add-test-source goal to add the itest source location
  • Use a custom Mojo to remove src/test/java from the configuration so the unit tests are not compiled again (I don't really like this, but it's needed to maintain the separation of unit and integration tests).
  • Use the compiler-plugin to compile the integration tests

Then in the integration-test phase, use the surefire-plugin to run the tests.

Finally, bind any tidy up goals to the post-integration-test phase (though normally they're not needed as you can use the test teardown() to tidy up).

I've not yet found a way to merge the test results as the reporting phase has passed, but I tend to view the integration tests as an added bonus, so as long as they pass the report is not so important.

Update: I think it's worth pointing out that you can run Jetty from within your integration tests rather than using a jetty goal. This gives you much finer control over the tests. You can get more details from this answer and the referenced blogs.

Solution 3 - Java

This good blog post suggests three options;

  1. Separate module for integration tests

  2. Different source directories

  3. Different file name patterns

I'm yet to try all three, so can't offer an opinion on which I favour.

Solution 4 - Java

I prefer the second option, Different source directories ,but I found quite annoying have to end with IT the integration tests or excluding packages.

To avoid this, I've ended up with this config:

<properties>
    <testSource>src/test/java</testSource>
    <testSourceResource>src/test/resources</testSourceResource>
</properties>
<build>
    <testSourceDirectory>${testSource}</testSourceDirectory>
	<testResources>
     		<testResource>
       		<directory>${testSourceResource}</directory>
      		</testResource>
    	</testResources>
.....
.....

and then I override both variables in different profiles for integration and acceptance test:

<profiles>
  <profile>
   <id>acceptance-tests</id>
   <properties>
    <testSource>src/acceptance-test/java</testSource>
    <testSourceResource>src/acceptance-test/resources</testSourceResource>
   </properties>
  </profile>
 <profile>
   <id>integration-tests</id>
    <properties>
	<testSource>src/integration-test/java</testSource>
	<testSourceResource>src/integration-test/resources</testSourceResource>
    </properties>
  </profile>
.....
.....
.....

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionmatt bView Question on Stackoverflow
Solution 1 - JavaJohn DobieView Answer on Stackoverflow
Solution 2 - JavaRich SellerView Answer on Stackoverflow
Solution 3 - JavaMikeView Answer on Stackoverflow
Solution 4 - JavaPablo GutierrezView Answer on Stackoverflow