Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

spring junit load application context for tests

I've got some XML files under my WEB-INF directory:

  • lyricsBaseApp-servlet.xml
  • hibernate.xml
  • dataSource.xml
  • beans.xml

the servlet xml imports other xml files:

<import resource="dataSource.xml"/> <import resource="hibernate.xml"/> <import resource="beans.xml"/> 

I would like my junit4 JukeboxTest class to include entire spring configuration. Using default filename I have created a JukeboxTest-content.xml file. And finally, I do not know what to put there...

I've tried:

<import resource="/WEB-INF/dataSource.xml"/> <import resource="/WEB-INF/hibernate.xml"/> <import resource="/WEB-INF/beans.xml"/> 

or

<import resource="classpath:./WEB-INF/dataSource.xml"/> <import resource="classpath:./WEB-INF/hibernate.xml"/> <import resource="classpath:./WEB-INF/beans.xml"/> 

and some other ideas but all failed. Could someone point me how to access those files and what way spring interprets those filepaths?

like image 573
ducin Avatar asked Feb 18 '13 22:02

ducin


People also ask

How can you access the application context in Spring integration test?

By default the ApplicationContext is loaded using the GenericXmlContextLoader which loads a context from XML Spring configuration files. You can then access beans from the ApplicationContext by annotating fields in your test class with @Autowired , @Resource , or @Inject .

How application context is loaded in Spring?

ApplicationContext is a corner stone of a Spring Boot application. It represents the Spring IoC container and is responsible for instantiating, configuring, and assembling the beans. The container gets its instructions on what objects to instantiate, configure, and assemble by reading configuration metadata.

What does failed to load application context mean?

However, sometimes in this situation, we may encounter the application context loading error “Failed to load ApplicationContext.” This error appears in the test classes because the application context isn't loaded in the test context.


1 Answers

Option 1 (should be preferred as it's the best practice):
Refactor your config files under WEB-INF and move the common parts (that you want to access also from integration tests) to src/main/resources/. Then write test specific configuration files in src/test/resources/ (if you only need to import several different config files from src/main to assemble your test context, then skip this, and use @ContextConfiguration preferably).

Option 2 (hack):
Use references like:

@ContextConfiguration("file:src/main/webapp/WEB-INF/dataSource.xml") 

Option 3 (hack):
If you have a Maven project, you can configure the maven-surefire-plugin (used in the test phase) to declare src/main/webapp as an additional classpath element during test execution.

The latter two options are considered as hack, because files under src/main/webapp are simply not supposed to be on the classpath.

Now the detailed explanation:

The reason why you can't refer to these files as classpath:/WEB-INF/*.xml is that they are indeed not on the classpath. It's important to understand how your webapp is packaged, and what exactly ends up on the classpath. Assuming a default Maven project structure:

  1. Java classes from src/main/java go to /WEB-INF/classes after compilation.
  2. Resources from src/main/resources go to /WEB-INF/classes as well.
  3. Project dependencies go to /WEB-INF/lib.
  4. Everything you have in src/main/webapp goes to / (root of the package). This means that all files from src/main/webapp/WEB-INF go to /WEB-INF, of course.

The most important thing to know is that the classpath will only contain /WEB-INF/classes and one entry for each jar in /WEB-INF/lib. Consequently, resources outside these two locations are completely invisible for the classloader. This is also true for the xml config files directly under /WEB-INF, which is why the reference classpath:/WEB-INF/dataSource.xml will never work.

You may ask yourself, how the hell are then these xml config files loaded by Spring if they are not reachable from the classpath? The answer is simple: When you start your webapp (as opposed to executing just unit/integration tests), it is running in a Servlet Container which provides access to the ServletContext (an actual class from the Servlet API), so it uses ServletContext.getResourceAsStream() to load these files. The key for understanding is the following quote from the javadoc of this method:

This method is different from java.lang.Class.getResourceAsStream, which uses a class loader. This method allows servlet containers to make a resource available to a servlet from any location, without using a class loader.

Sorry this become way too long, but that's the whole story...

like image 94
zagyi Avatar answered Sep 18 '22 21:09

zagyi