Vladimir Kishlaly
Vladimir Kishlaly

Reputation: 1942

Testing with Spring and Maven: applicationContext

Seems that question old as world, but I still can't find out the solution..

I'm trying to run simple test:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"/applicationContext.xml", "/PersonsPopulateTest-context.xml"})
@Transactional
public class PersonsPopulateTest {

Files are at:

src
   main
      resources
           applicationContext.xml

and

src        
   test
      resources
          PersonsPopulateTest-context.xml 

So after building these files are at target/classes and target/test-classes

But mvn test command still says: Failed to load ApplicationContext

What official docs say:

@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from "/applicationContext.xml" and "/applicationContext-test.xml"
// in the root of the classpath
@ContextConfiguration(locations={"/applicationContext.xml", "/applicationContext-test.xml"})
public class MyTest {
    // class body...
}

Where did I go wrong?

Thanks, Vlaidimir

UPDATE. surefire-reports:

java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:157)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:321)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:290)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:53)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:123)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:104)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:164)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:110)
at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:175)
at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcessWhenForked(SurefireStarter.java:107)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:68)
Caused by: java.lang.IllegalArgumentException: Can not load an ApplicationContext with a NULL 'contextLoader'. Consider annotating your test class with @ContextConfiguration.
at org.springframework.util.Assert.notNull(Assert.java:112)
at org.springframework.test.context.TestContext.loadApplicationContext(TestContext.java:117)
at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:148)
... 30 more

Upvotes: 35

Views: 99086

Answers (10)

user3300845
user3300845

Reputation: 127

Within your integration test class, try add

@Test
public void contextLoads(){
}

Upvotes: 0

Ambarish Hazarnis
Ambarish Hazarnis

Reputation: 186

I faced the same problem. For me the test was running successfully via eclipse. However, when I ran mvn test, it was giving me error: Failed to load ApplicationContext

Fix: Added the src/test/resources directory to classpath of surefire plugin as-

<plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.10</version>
            <configuration>
                <additionalClasspathElements>
                    <additionalClasspathElement>${project.basedir}/src/test/resources</additionalClasspathElement>
                </additionalClasspathElements>      
            </configuration>

Adding classpath to SureFire

Hope it helps.

Upvotes: 1

Vladimir Tsvetkov
Vladimir Tsvetkov

Reputation: 3013

I think Maven simply didn't include the XML file from main/resources.

You could try to specify explicitly what to include in the pom.xml.

Let me know if the following configuration has worked:

    <!-- Add this directly after the <build>-opening tag -->
    <resources>
        <resource>
            <filtering>true</filtering>
            <directory>src/test/resources</directory>
            <includes>
                <include>**/*.properties</include>
            </includes>
            <excludes>
                <exclude>**/*local.properties</exclude>
            </excludes>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
        </resource>
    </resources>

This is something I use in your case. You can edit this if you don't have properties files to be included.

Upvotes: 11

lekant
lekant

Reputation: 1002

For some reason, I had the same issue and it worked when I ran maven test with the JDK6 instead of JDK8 (in my case this is a legacy application)

If it helps anyone.

Upvotes: 1

Tony Vu
Tony Vu

Reputation: 4371

I think best practice is to put your application context file for testing PersonsPopulateTest-context.xml under src/test/resources. This file will be copied into target/test-classes and you can refer to it in your test class as below:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:**/PersonsPopulateTest-context.xml"})
@Transactional
public class PersonsPopulateTest {

}

If you still want to refer to applicationContext.xml under src/main/resources, then you have to include it as follow:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"file:src/main/resources/applicationContext.xml"})
@Transactional
public class PersonsPopulateTest {

}

It worked for me.

Upvotes: 3

Borja
Borja

Reputation: 3610

your application context must be included in classpath and put * :

@ContextConfiguration(locations = { "classpath:*/application-context.xml" })

Upvotes: 4

Alexander Volkov
Alexander Volkov

Reputation: 8407

UPDATED: Actually in my case the problem was in Compile on Save option enabled. I use Netbeans, and the option was set to For test execution only. This value compiles changed files and replaces resources with new files. However, due to usage of application resources additionally to test resources, For test execution only produces incorrectly generated resources in target folder.

Changing Compile on Save=For test execution only

to Compile on Save=Disable fixes the problem.

The text below is also correct, but sometimes does not work. It was working only till I restarted Netbeans IDE. However, the details of the reason of the problem are correct, hence, I prefer to leave the test.


OLD: In my situation I have appContext-test.xml in src/main/resources. When I change any code and launch one unit test (not all of them) it recompiles and correctly executed. But if I launch same unit test again it is failed with the java.lang.IllegalStateException: Failed to load ApplicationContext.

I have changed pom.xml from

<build>
    <resources>
        <resource>
            <directory>${project.basedir}/src/main/resources</directory>
            <filtering>true</filtering>
        </resource>
    </resources>
    <testResources>
        <testResource>
            <directory>${project.basedir}/src/test/java/resources</directory>
            <filtering>true</filtering>
        </testResource>
    </testResources>
</build>

to

<build>
    <resources>
        <resource>
            <directory>${project.basedir}/src/main/resources</directory>
            <filtering>true</filtering>
        </resource>
    </resources>
    <testResources>
        <testResource>
            <directory>${project.basedir}/src/main/resources</directory>
            <filtering>true</filtering>
        </testResource>
        <testResource>
            <directory>${project.basedir}/src/test/java/resources</directory>
            <filtering>true</filtering>
        </testResource>
    </testResources>
</build>

and now all work fine.

The error was due to appContext-test.xml uses src/main/resources/my.properties file with a lot of variables like

database.url = ${database.url}
database.username = ${database.username}
database.password = ${database.password}

that are filled during a build. However, if you skip src/main/resources in testResource, then my.properties is added to target/classes/my.properties as is, i.g. without a substitution. This file of course breaks the context.

PS: You can remove ${project.basedir}/ - it is my custom thing.

Upvotes: 0

Volodymyr Sorokin
Volodymyr Sorokin

Reputation: 1745

I had the same problem, all files were successfully copied to target/classes and target/test-classes, still spring could not find them.

Problem disappeared when I explicitly specified versions for maven-surefire-plugin and maven-resources-plugin in pom

Upvotes: 0

Daniela
Daniela

Reputation: 21

<!-- Add this directly after the <build>-opening tag in the your pom-->
            <testResources>
                <testResource>
                    <directory>src/test/resources</directory>
                    <filtering>true</filtering>
                    <includes>
                        <include>**/*.xml</include>
                        <include>**/*.properties</include>
                    </includes>
                </testResource>
            </testResources>

Upvotes: 2

Ahamed Mustafa M
Ahamed Mustafa M

Reputation: 3139

My test context file is under src\test\resources\spring folder. I managed to load the context with

@ContextConfiguration(locations={"classpath:**/test-context.xml"})

But reference (in test-context.xml) to the application-context.xml which is under src\main\resources\spring folder failed

I managed to load the application-context by creating a ClassPathXmlApplicationContext in the test class with

ClassPathXmlApplicationContext appContext=new ClassPathXmlApplicationContext(new String[]{"classpath:spring/application-context.xml","classpath:spring/model-context.xml"});

Let me know if this helps or might create any other issues.

Upvotes: 9

Related Questions