Categories
Development

Quicker JUnit Spring context tests in Maven

This is probably fairly well known, but I couldn’t find any doc on it when I searched so I’ll put it up here.

First off: Don’t load your Spring Context in your tests unless you absolutely have to. Some integration tests should load it, but keep it to a minimum. Loading the context is expensive, especially if you load up Hibernate and maybe H2 in that context.

Avoid loading the context is important both for speed and design. I have seen way too many tests where the context is loaded just because someone don’t want to do mocking. Besides, if you have to do a lot of mocking your design is usually too coupled, and should be changed.

So how can you speed up your tests in Maven?

Spring will cache the context and make sure it is only loaded once. But due to details I have not studied; in Maven, this only works for the tests that are in the same suite. It should work with fork=once on the surefire-plugin, but for some reason we need the suites too. Test which one works for you.

Drawbacks? If there is state in your context (database, stateful services) you will have created a dependency between your tests. That’s why, when it comes to database-testing you should use the AbstractTransactionalSpringContextTests which will automatically roll back your changes at the end of your tests. If state is modified in a way that has nothing to do with your database use setDirty() to signal to Spring that the context should be recreated for the next test. Of course then you get the time penalty of recreation.

3 replies on “Quicker JUnit Spring context tests in Maven”

You’re right that Spring integration tests can be slow to load and that can really make testing quite a pain. For example, if you run a suite of JUnit tests in ant they all run by default in their own JVM – which can be very time consuming.

I disagree that the integration tests can be avoided. Relying on testing via mocks or plain unit tests can only take you so far, and still doesn’t give you much confidence that the code will work end to end.

The Spring integration testing issue is one of the fundamental problems addressed in Impala (http://impala.googlecode.com/). Because it uses modules you don’t need to specify application context locations explicitly. As an integration test suite runs it incrementally loads modules as required – it doesn’t need to reload the whole application context each time the test changes. The result is that big integration test suites (including ones with Hibernate) run in seconds rather than minutes.

Hey Phil. Impala looks very interesting, I’ll have to look into that. At first glance the concepts reminds me a little bit of OSGi.

I didn’t mean that integration tests could be avoided all together, but in my experience most projects have too many of them. Logic that can’t be tested without the database or mocking is often a sign of bad design. This doesn’t mean that you don’t need to test the database or integration. It just means that your logic should have unit tests before you do integration testing. In my experience this will reduce the number of tests that load the context or needs to mock, and give faster as well as more maintainable tests.

Leave a Reply to Phil Zoio Cancel reply

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