Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring: unit and integration tests

I'm looking for best practices for setting up unit and integration tests using Spring.

I usually use 3 kind of tests:

  • "real" unit tests (no dependencies)
  • tests run either as "unit" test (in-memory db, local calls, mock objects,...) or as integration test (persistent db, remote calls,...)
  • tests run only as integration tests

Currently I only have tests of the second category, which is the tricky part. I set-up a base test class like:

@ContextConfiguration(locations = { "/my_spring_test.xml" })
public abstract class AbstractMyTestCase extends AbstractJUnit4SpringContextTests

And "unit" tests like:

public class FooTest extends AbstractMyTestCase

with autowired attributes.

What's the best way to run the test in a different (integration test) environment? Subclass the test and override the ContextConfiguration?

@ContextConfiguration(locations = { "/my_spring_integration_test.xml" })
public class FooIntegrationTest extends FooTest

Would this work (I cannot currently easily test it here)? The problem with this approach is that "@ContextConfiguration(locations = { "/my_spring_integration_test.xml" })" is duplicated a lot.

Any suggestions?

Regards, Florian

like image 425
Puce Avatar asked Jan 04 '11 12:01

Puce


Video Answer


1 Answers

I extended the GenericXmlContextLoader

public class MyContextLoader extends GenericXmlContextLoader {

and overrote the

protected String[] generateDefaultLocations(Class<?> clazz)

method to collect the config file names of a directory which I can specify by a SystemProperty (-Dtest.config=).

I also modified the follwowing method to NOT modify any locations

@Override
protected String[] modifyLocations(Class<?> clazz, String... locations) {
    return locations;
}

I use this context loader like this

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = MyContextLoader.class)
public class Test { .... }

Running the test with a SystemProperty indicating the source of the config files enables you now to use completely different configurations.

The usage of a SystemProperty is of course only one strategy to specify the configuration location. You can do whatever you want in generateDefaultLocations().


EDIT:

This solution enables you to use complete different application context configurations (e.g. for mock objects) and not only different properties. You do not need a build step to deploy everything to your "classpath" location. My concrete implementation also used the users name as default to look for a configuration directory (src/test/resources/{user}) if no system property is given (makes it easy to maintain specific test environments for all developers on the project).

The usage of the PropertyPlaceholder ist still possible and recommended.


EDIT:

Spring Version 3.1.0 will support XML profiles/Environment Abstraction which is similar to my solution and will enable the choice of configuration files for different environments/profiles.

like image 170
FrVaBe Avatar answered Sep 22 '22 07:09

FrVaBe