Spring中Junit测试启动报错class path resource [xxx.xml] cannot be opened because it does not exist
文章目录问题分析解决问题本地开发项目时,直接将项目部署到idea配置的tomcat中能正常启动,但是使用Spring的junit测试时,启动报错class path resource [xxx.xml] cannot be opened because it does not exist。分析在测试类构造方法上获取当前测试环境的classpath路径然后去这个classpath路径看一下,发现确实
文章目录
问题
本地开发项目时,直接将项目部署到idea配置的tomcat中能正常启动,但是使用Spring的Junit测试时,启动报错class path resource [xxx.xml] cannot be opened because it does not exist。测试代码如下:
//@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class) // RunWith注解表示JUnit将不会跑其内置的测试,而是运行所引用的类中的所有测试
@ContextConfiguration(locations={"classpath:AppContext-spring.xml","classpath:AppContext-shiro.xml"/*,"classpath:AppContext-mvc.xml"*/}) //此注解用来加载配置ApplicationContext
@Slf4j
public class FunctionTest extends BaseUnit {
@Autowired
ManualDealMapper manualDealMapper;
@Test
public void test_selectVideo() {
PolicyInfo2 info2 = new PolicyInfo2();
info2.setIsManualDealt("0");
List<PolicyInfo2> list = manualDealMapper.selectVideo(info2, null, null, "asc");
System.out.println("list.size() = " + list.size());
}
}
注意:此时代码中没有开启@WebAppConfiguration
注意:遇到这种问题,最好先把项目的编译输出目录删掉,然后点击Gradle工具窗中的“Reload All Gradle Projects”按钮重新构建项目(而不是工具类的 build -> build project),因为有时重新构建一下就好,就是这么莫名其妙。
分析
在测试类构造方法上获取当前测试环境的classpath路径(注:不知道为啥一段时间后再一次这样做,得到的值变成了E:/xx/out/product/,也就没有问题了)
其实也就是我们在Gradle或者Idea中配置的路径:
然后去这个classpath路径看一下是不是真的没有这个xml配置文件,发现确实没有。说明确实是我们的配置文件没有被成功编译输出到classpath中。
最后发现原因是test模块中只有java包,缺少了resources包,而main模块中的resources包是不会被test模块编译的。
解决
方式一:手动处理test模块的编译输出目录
在每次进行junit测试之前手动将main模块编译输出目录中的resources包里的所有文件复制到test模块的编译输出目录(/out/test/classes)下,这样就能使得测试时classpath路径下有xml配置文件。
方式二:为test模块添加resources包(推荐)
可以将main模块中的resources包复制到test模块中,注意看看复制过来的resources包上是否标有“Test Resources Root”的小图标,若没有就选中它 --> 右键 --> “Mark Directory As ” --> “Test Resources Root”,这样的目录结构是符合maven-web项目的标准目录结构。然后点击操作栏的"build" --> “Build Project”,就能看到xml配置文件被编译输出到classpath路径了。如下图:
其实也可以不为test模块添加resources包,而是每次junit测试之前手动将main模块编译输出目录中的resources包复制到/out/test/目录下,即将/out/test目录结构手动改为跟上图一样。
方式二还有问题
但是再次启动测试还是报这个错,不过其实如果你细心的话,应该早就发现了是因为classpath是/out/test/classes目录,而我们的xml配置文件在/out/test/resources目录中(原因见下面引用),类加载器当然找不到它们啦,所以我们要做的是让他们也在classpath中!
maven/gradle 的plugin-war默认会从 src/main/java 搜寻打包源码,在 src/test/java 下搜寻测试源码。并且 src/main/resources 下的所有文件按都会被打包,所有 src/test/resources 下的文件 都会被添加到类路径用以执行测试。所有文件都输出到 build 下,打包的文件输出到 build/libs 下。
maven/gradle的plugin-war将项目目录结构定义的有别于程序包目录结构,是为了方便程序员在编写程序的时候更加直观的管理项目文件,因为程序包定义的目录结构不一定适合人们直观的对其进行操作。比如war包专门定义了一个Resource目录,方便用户集中管理资源文件和各种配置文件。
再解决方式二的问题
使得xml配置文件编译输出到/out/test/classes目录下,参考https://blog.csdn.net/sinat_38301574/article/details/80465693。
后来"最开始的场景"又莫名其妙的不报错了
再次 重新整理。。。
每次改project或moudle设置后,都先删除out目录,再点击Gradle工具窗中的“Reload All Gradle Projects”按钮方式来构建一下项目,再进行测试;
| test/resources包 | 加载mvc.xml | testCompile(org.glassfish.web:javax.el) | @WebAppConfiguration | 启动情况(若正常则记录@ContextConfiguration的类classLoader路径) | 分析 |
|---|---|---|---|---|---|
| × | × | × | × | E:/xx/out/production/resources/ | 不使用mvc.xml中注册的bean时用这种方式 |
| × | √ | × | × | HV000183:Unable to load ‘javax.el.ExpressionFactory’ | 因为我的mvc.xml配置了扫描有@EnableAutoConfiguration的类,自动配置会用到org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor,这个类会使用hibernate-validator,而validator依赖javax.el,servlet容器(tomcat)自带有实现,而junit测试没有 |
| × | √ | √ | × | No qualifying bean of type [javax.servlet.http.HttpServletRequest] found for dependency | 因为我的BaseController类中需要注入HttpServletRequest,Servlet容器(tomcat)是有HttpServletRequest和HttpServletResponse的实现的,而junit测试没有 |
| × | √ | √ | √ | E:/xx/out/production/resources/ | 要使用mvc.xml中注册的bean时用这种方式 |
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)