spring的@ContextConfiguration注解
近期项目由普通项目换成了gradle构建项目以及管理
问题描述:
在junit测试的时候出现: Failed to load ApplicationContext 具体如下
> Task :wrapper
BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed
> Task :cleanTest
> Task :compileJava UP-TO-DATE
> Task :processResources UP-TO-DATE
> Task :classes UP-TO-DATE
> Task :compileTestJava
> Task :processTestResources NO-SOURCE
> Task :testClasses
> Task :test FAILED
16:11:47,302 ERROR --- TestContextManager.prepareTestInstance(231) | Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@16d8ae4a] to prepare test instance [-路径-.TjTest@221c9715]
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:117)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:228)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:230)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:249)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:193)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:106)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:66)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:117)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:155)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:137)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
at java.lang.Thread.run(Thread.java:748)
解决经历:
出现这个问题,开始以为是gradle构建项目时 test包下的扫描问题,在网上查了一堆也没搞出个究竟,包括junit的各种可能原因,种种都试了都不行,一把辛酸一把泪啊!
最终发现了问题!
问题原因:
究其根本就是没有抓住问题的源头,反被一个小问题引出了其他问题迷惑了双眼。
@ContextConfiguration这个注解中属性值的问题。
下图是原来的配置:可以看到IDEA已经给 很清楚的提示(红色字体报错,如果正确会显示正常字体颜色),“cannot resolve file …”
也就是这个配置文件路径有问题,解析不了。都已经说了这么清楚了,你还去junit测试 ,那ApplicationContext能加载进来就见鬼了啊。
@ContextConfiguration 注解的用法详解
直接举例子吧:
首先是我的配置文件路径如下:
也就是在根目录之下
针对以上 “applicationContext.xml” 文件@ContextConfiguration可以如下使用:
@ContextConfiguration(value="/applicationContext.xml") //方法一
@ContextConfiguration(locations="/applicationContext.xml") //方法二
@ContextConfiguration("classpath:/applicationContext.xml") //方法三
@ContextConfiguration("/applicationContext.xml") //方法四
切记前边要加一个 “/” 代表根目录(不带双引号)
这是我亲测的几种都可以正常运行junit。
其实也不用去死记, 这个分开也就是两块;
- 一个是属性名(value、locations)
- 一个是 属性值(双引号里边的,就是文件路径)
单个文件一般直接在双引号里边写路径或者用value属性(切记要加“ / ” !!!)
如果有多个文件要加载可以使用多个文件时,可用{}括起来,并用逗号分隔,以下示例
@ContextConfiguration(locations = { "classpath*:/spring1.xml", "classpath*:/spring2.xml" })
或者用value
@ContextConfiguration(value = { "/spring1.xml", "/spring2.xml" })
或者不写属性名,(加不加"classpath:" 都可以)
@ContextConfiguration({ "classpath:/spring1.xml", "classpath:/spring2.xml" })
当然单个文件也可以用locations 如上述方法二。
总之双引号里边的 路径一定要写正确了!写错了idea会用红色字体标识无法解析
打开ContextConfiguration源码
关于属性名,可以直接打开这个注解
@AliasFor 意思是注解中的属性可以互相为别名进行使用
根据上述源码可以看到, 该属性可以使用 locations 、value 或者直接写值(不写属性名),重点是值(路径)一定要写对。
根据返回值可以得出以上三种方式都可以配置多个文件
总结
- 解决问题要抓源头,治标先治本。
- 一定要关注idea给的提示信息。
- 一个工具用好了是你的左膀右臂,用不好会成为你的绊脚石。