I have a web application, that contains a configuration xml file for one of my application services that is exposed as spring bean. Also I have a standalone java application
I ended up using Spring MockServletContext class and injecting it directly to my service bean, before the test runs, as my service implemented ServletContextAware
:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/test-ctx.xml" } )
public class SomeServiceTest {
@Autowired
private MyServletContextAwareService myService;
@Before
public void before(){
//notice that I had to use relative path because the file is not available in the test project
MockServletContext mockServletContext = new MockServletContext("file:../<my web project name>/src/main/webapp");
myService.setServletContext(mockServletContext);
}
If I had several classes using Servlet Context, then the better solution would be to use WebApplicationContext instead the default one (currently provided by DelegatingSmartContextLoader), but it would require implementing custom ContextLoader class and passing its class name to @ContextConfiguration annotation.
alternative and somewhat cleaner solution which later came to my mind is to refactor the service and inject ServletContext
via @Autowired
instead of messing with ServletContextAware
, and provide the bean of corresponding type(effectively a MockServletContext
instance).
Possibly, in future the direct support of MockServletContext
from test classes will be added to Spring see SPR-5399 and SPR-5243.
UPDATE FOR SPRING 3.2
In Spring 3.2 initialization of the servlet context became as simple as adding one @WebAppConfiguration
annotation:
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration("file:../<my web project name>/src/main/webapp")
@ContextConfiguration(locations = { "/test-ctx.xml" } )
public class SomeServiceTest {
see details in the article
Definitely keep the file under WEB-INF/ folder if that's where it is supposed to live.
For your test classes that are being executed from the command line. Your can use getClassLoader().getResource() on a file that you know is in the root of your classpath (e.g. application.properties file). From there you know the structure of your project and where to find WEB-INF/ relative to the properties file. Since it returns a URL you can use it to figure out a path to the XML files you're looking for.
URL url = this.getClass().getClassLoader().getResource("application.properties");
System.out.println(url.getPath());
File file = new File(url.getFile());
System.out.println(file);
// now use the Files' path to obtain references to your WEB-INF folder
Hopefully you find this useful. I have had to make assumptions about how your test classes are runing etc.
Take a look at the File Class and it's getPath(), getAbsolutePath(), and getParent() methods that could be of use to you.
In a Maven project I had same problem. I had no servletContext and couldn't access static file in WEB-INF directory. I came across to a solution by adding entry to pom.xml which gave me access to the directory. It actually includes this path to the classpath.
PS: I was using Tomcat container
<project>
<build>
<resources>
<resource>
<directory>src/main/webapp/WEB-INF</directory>
</resource>
</resources>
</project>
It's a classpath resource, so put it on the classpath: $webapp/WEB-INF/classes
Maven projects will copy things in $module/src/main/resources to this location when packaging the webapp. (the former is a sourcepath, the latter - WEB-INF/classes - is always put on the classpath by the servlet container, per spec.)