JUnit & Spring – What You Don’t Know



When using JUnit in Spring there are several features added that many developers are not aware of.

First, if you are including the Spring Context in your tests, it becomes an Integration Test, no longer a Unit Test.


1. Default Searching of Context File(s)

To instruct Spring to load beans for the tests in the class, we annotate the class with @ContextConfiguration


1a. No File Specified

@ContextConfiguration – with no parameters, (by Default) looks for the config file as the same name as the class with the suffix “-context.xml“. For example,

Using


package com.gordondickens.sample;

@ContextConfiguration
public class UtilsTest {
  ...
}
...

Is equivalent to

  ...
@ContextConfiguration("classpath:/com/gordondickens/sample/UtilsTest-context.xml")
  ...

Will look for a file called UtilsTest-context.xml in the Classpath under the same package as the test. If we are using the standard Maven structure, Spring will search for:

  • src/test/java/com/gordondickens/sample/UtilsTest-context.xml
  • src/test/resources/com/gordondickens/sample/UtilsTest-context.xml
  • src/main/java/com/gordondickens/sample/UtilsTest-context.xml
  • src/main/resources/com/gordondickens/sample/UtilsTest-context.xml


1b. File specified (without a starting Slash)

Using

package com.gordondickens.sample;

@ContextConfiguration("utils-context.xml")
public class UtilsTest {
  ...
}
  ...

Is equivalent to

  ...
@ContextConfiguration("classpath:/com/gordondickens/sample/utils-context.xml")
  ...

Spring searches for utils-context.xml in each classpath’s directory for package and does NOT traverse subdirectories (packages).


1c. File specified with a Starting Slash

One Simple change can ruin your whole day! Add a Starting Slash to the file name.

Using

  ...
@ContextConfiguration(value = "/META-INF/spring/utils-context.xml")
  ...

Is equivalent to

  ...
@ContextConfiguration("classpath:/META-INF/spring/utils-context.xml")
  ...


1d. Multiple Files

Pulling multiple configuration files into the application context for your tests.

  ...
@ContextConfiguration(locations = {"utils-context.xml", "app-context.xml"})
  ...

BEST PRACTICE TIP

Create an XML file per test that imports only the application’s context files that are needed.
This can save test execution time, where we only load beans necessary for these tests.





2. Spring Aware Test Options

We can load configuration files for the tests, but we want the added benefit of using Spring Annotations.

NOTE: This requires JUnit 4.5 or later.

Annotate the test class with @RunWith(SpringJUnit4ClassRunner.class).


2a. Autowiring Beans

@Autowired Autowire (inject) in dependencies

Tip: If you want access to the ApplicationContext you can simply autowire this into your test class.

  ...
@Autowired
ApplicationContext applicationContext;
  ...


2b. Transactional Test Methods

@Transactional At the method level, method is transactional. Class level, all methods are transactional
@TransactionConfiguration Define default transaction parameters for the class
@Rollback Change rollback settings for methods
@BeforeTransaction Method to execute before a transaction
@AfterTransaction Method to execute after a transaction

NOTE: Transactions are rolled back by default in tests. Allowing repeat execution to perform the same db actions.


2c. Profiles - Evaluating Environment

@ProfileValueSourceConfiguration Class level settings for all tests, defaults to system properties
@IfProfileValue Specify name and value(s) that must match to execute the test method


2d. Timeout, Repeating & Invalidating Context

@Timed Defined maximum time that method has to execute
@Repeat Specify the number of times the test method will repeat
@DirtiesContext At class or method level, mark the app context as dirty and should be closed. The app context will be recreated for subsequent tests



Further Reading

About Gordon

Technology enthusiast primarily focused on Java and Open Source projects. Spring Certified Professional and Trainer. http://twitter.com/gdickens http://linkedin.com/in/gordondickens http://github.com/gordonad
This entry was posted in JUnit, Spring, Testing and tagged , , , , , . Bookmark the permalink.

9 Responses to JUnit & Spring – What You Don’t Know

  1. nice tips. another one to add to the list is “@Resource”.

    It is not specific to Spring, but Spring fully supports it ( JSR 250: http://en.wikipedia.org/wiki/JSR_250 )

    It works somewhat like @Autowire, but it also supports JNDI resources + it is a one line shortcut to wire in by name:


    @Resource( name="cleverMoneyMakingBusinessService" )
    MoneyMakingBusinessService businessService;

    here is an example of the full test: https://github.com/anatoly-polinsky/money-making-project/blob/master/src/test/java/org/gitpod/startup/service/CleverMoneyMakingBusinessServiceIntegrationTest.java

    /Anatoly

  2. skill-guru says:

    Very helpful stuff Gordon. Thanks for settings this up.

  3. Pingback: Tweets that mention Technophile Blog » JUnit & Spring – What You Don’t Know -- Topsy.com

  4. Pingback: JUnit & Spring – What You Don’t Know

  5. Pingback: Coffee Notes: Spring & JUnit – What you Don’t Know « Christopher Grant

  6. developer says:

    We are currently developing a web project (spring, hibernate, maven). We have “actual version” and “test version” of classes for repositories and services, and we created a separate context xml for the test classes. The xml file for the test classes are the ones we are using at the moment while the actual classes are still in progress.

    The test version of repositories and services are not placed under the src/main/java folder, but in the src/test/java. And it seems that after running weblogic, an error comes out saying that the classes (test version) cannot be found

    Question:
    Can spring autowire only the classes under src/main at server runtime? Because autowiring classes under src/test works when running JUnit but throws an error when running the server

    Thanks in advance for the help =)

  7. Gordon says:

    You can autowire any classes that Spring finds in the context.

    Maven uses the src/test/java for the “test” lifecycle and executed with the Maven Surefire Plugin.

    Based on your specific use-case, you may want to build a parent (pom) project for both the production and test project builds. Create a child Maven project (directory) for production and another for test. However, the jar/war plugin packages only the src/main/java classes in the jar or war.

    Regards,
    Gordon Dickens

  8. Zo says:

    nice post, this is exactly what I was looking for. I have a question related to JUnit but it doesn’t really concern your post. I was wondering if it was possible to manage dependencies between classes without using a stub nor a mock. Thanks!

  9. Matthew Smith says:

    Hey Gordon, very helpful website! I really liked your Maven best practices posts. It helped me clean up a maven project at work.

    I have a comment on your best practices tip for creating app configs for each test class. Spring 3.1 included Context Caching. Once a context is loaded, that context will be cached and used for all further tests in a test suite. This tip will probably not save time any more.

    Still, great content! I really enjoy reading your posts. Thank you.

Leave a Reply

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


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>