Spring 4.1 MVC项目中Spring JPA Repository测试问题排查
看起来你在传统Spring MVC(4.1版本)项目中测试JPA Repository时遇到了版本冲突和上下文加载的双重问题,我来帮你一步步梳理解决:
一、先搞定Spring版本冲突的根源
你碰到的Could not load TestContextBootstrapper异常,本质是Spring组件版本不匹配:spring-test 4.3依赖的org.springframework.core.annotation.AnnotatedElementUtils类有新方法,但你的spring-core还是4.1版本,根本没有这个方法,所以抛出NoSuchMethodError。
解决方法:统一所有Spring依赖版本
要么全量保持Spring 4.1,要么整体升级到4.3.x(更推荐,因为4.1早已停止维护)。在Maven的pom.xml里用<properties>统一管理版本,避免版本碎片化:
<properties> <spring.version>4.3.30.RELEASE</spring.version> <!-- 选一个4.3的稳定版本 --> </properties>
然后所有Spring相关依赖(spring-core、spring-context、spring-webmvc、spring-test、spring-orm等)都引用这个版本号,比如:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> <scope>test</scope> </dependency>
二、解决升级后"Application Context not found"的问题
升级到4.3后找不到上下文,是因为你测试类里的配置路径写错了:
Maven项目中,src/main/webapp/WEB-INF目录不在测试时的classpath范围内(默认classpath包含src/main/resources、src/test/resources),所以测试代码找不到classpath:WEB-INF/dispatcher-servlet.xml。
方案1:迁移配置文件到资源目录(最简便)
把dispatcher-servlet.xml从src/main/webapp/WEB-INF复制到src/main/resources下,然后修改测试类的注解:
@ContextConfiguration(locations={"classpath:dispatcher-servlet.xml"})
方案2:配置Maven插件,将WEB-INF纳入classpath
如果你不想移动配置文件,可以在pom.xml的<build>中添加资源插件配置,把WEB-INF下的配置文件复制到测试classpath:
<build> <resources> <resource> <directory>src/main/webapp/WEB-INF</directory> <includes> <include>*.xml</include> </includes> <targetPath>WEB-INF</targetPath> </resource> </resources> <testResources> <testResource> <directory>src/main/webapp/WEB-INF</directory> <includes> <include>*.xml</include> </includes> <targetPath>WEB-INF</targetPath> </testResource> </testResources> </build>
这样测试时就能通过原路径找到配置文件了。
三、测试类与代码的细节优化
解决完环境问题,还要检查代码里的小错误,避免测试失败:
1. 移除不必要的注解
如果你的测试只涉及数据层,不需要@WebAppConfiguration(这个注解是用于测试Web层,模拟Servlet上下文的),去掉它可以减少上下文加载的复杂度:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"classpath:dispatcher-servlet.xml"}) public class POSUserDaoTest { // ... 测试代码 }
2. 修复实体类的关联错误
你的POSUser实体中@OneToOne的mappedBy配置错了,mappedBy应该指定关联实体(UserInf)中对应POSUser的属性名,比如如果UserInf里有posUser字段,应该写成:
@OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "posUser") @MapsId private UserInf userInf;
如果是共享主键的关联,还要确保UserInf的@Id字段和POSUser的id对应配置正确。
3. 修复Repository的JPQL拼写错误
你POSUserDao里的JPQL语句用了usr.usrInf.id,但实体类里的属性是userInf,不是usrInf,会导致查询失败,改成:
return session.createQuery("FROM POSUser AS usr WHERE usr.userInf.id = :id", POSUser.class) .setParameter("id", user.getId()) .setMaxResults(1) .getSingleResult();
4. 检查BaseDao的SessionFactory注入
确保你的BaseDao正确注入了SessionFactory,比如:
public class BaseDao { @Autowired protected SessionFactory sessionFactory; // ... 其他通用方法 }
同时在dispatcher-servlet.xml中配置正确的SessionFactory Bean,包含数据源、实体扫描路径和Hibernate配置:
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="packagesToScan" value="com.yourproject.entity"/> <!-- 替换成你的实体类包路径 --> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop> <prop key="hibernate.show_sql">true</prop> <!-- 其他Hibernate配置 --> </props> </property> </bean>
四、最后验证测试
完成所有修改后,执行以下步骤确保测试正常运行:
- 执行
mvn clean install刷新Maven依赖,清除旧的编译文件 - 运行JUnit测试,检查Autowired的Bean是否正常注入,查询是否能返回预期结果
内容的提问来源于stack exchange,提问作者Saminda Peramuna

