我尝试创建某种集成测试环境,并在测试上下文框架没有为我的bean创建事务代理时遇到问题。我的代码:
JUnit类:FileServiceImplTest
@RunWith(SpringJUnit4ClassRunner.class)
@ContextHierarchy({
@ContextConfiguration(value = "file:src/main/webapp/WEB-INF/spring/applicationContext-db.xml"),
@ContextConfiguration(value = "file:src/main/webapp/WEB-INF/spring/applicationContext.xml")
})
public class FileServiceImplTest {
@Autowired
private FileService fileService;
@Test
public void testSaveFolder() {
FolderDTO rootFolder = new FolderDTO();
rootFolder.setName("ROOT");
rootFolder.setParentId(null);
rootFolder.setIdPath("/");
rootFolder.setPath("/");
fileService.saveFile(rootFolder);
List<AbstractFileDTO> rootFiles = fileService.getRootFiles();
assertEquals(1, rootFiles.size());
AbstractFileDTO abstractFileDTO = rootFiles.get(0);
assertEquals(rootFolder, abstractFileDTO);
}
}
测试上下文框架工作注入&#39; fileService&#39;提交了FileService bean本身,而不是事务代理。这是例外的原因:
org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
at org.springframework.orm.hibernate5.SpringSessionContext.currentSession(SpringSessionContext.java:132)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:697)
at org.sbezgin.p2016.db.dao.impl.FileDAOImpl.getSession(FileDAOImpl.java:69)
at org.sbezgin.p2016.db.dao.impl.FileDAOImpl.saveOrUpdateFile(FileDAOImpl.java:33)
at org.sbezgin.p2016.services.file.impl.FileServiceImpl.saveFile(FileServiceImpl.java:41)
at org.sbezgin.p2016.services.file.impl.FileServiceImplTest.testSaveFolder(FileServiceImplTest.java:35)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:254)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
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:309)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:193)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)
当我在tomcat下运行此代码时,一切正常,只有在运行测试期间才会出现问题。请帮忙解决这个问题。
我的其余代码: FileServiceImpl
@Transactional
public class FileServiceImpl implements FileService {
private FileDAO fileDAO;
private BeanTransformer beanTransformer;
@Override
public AbstractFileDTO getFileByID(long fileID) {
return null;
}
@Override
public FolderDTO getFolder(long folderID) {
return null;
}
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void saveFile(AbstractFileDTO file) {
Long id = file.getId();
if (id == null) {
AbstractFile fileEntity = (AbstractFile) beanTransformer.transformDTOToEntity(file);
User user = new User();
user.setId(1);
fileDAO.saveOrUpdateFile(user, fileEntity);
}
}
@Override
public void setPermission(long fileD, PermissionDTO perm) {
}
@Override
public void renameFile(long fileID, String newName) {
}
@Override
public void deleteFile(long fileID, boolean recursively) {
}
@Override
public List<AbstractFileDTO> getRootFiles() {
User user = new User();
user.setId(1);
List<AbstractFile> rootFiles = fileDAO.getRootFiles(user);
List<AbstractFileDTO> abstractFileDTOs = new ArrayList<>(rootFiles.size());
abstractFileDTOs.addAll(
rootFiles.stream().map(
rootFile -> (AbstractFileDTO) beanTransformer.transformEntityToDTO(rootFile)
).collect(Collectors.toList())
);
return abstractFileDTOs;
}
@Override
public List<AbstractFileDTO> getChildren(long folderID) {
return null;
}
@Override
public List<AbstractFileDTO> getFilesByType(String javaType) {
return null;
}
public FileDAO getFileDAO() {
return fileDAO;
}
public void setFileDAO(FileDAO fileDAO) {
this.fileDAO = fileDAO;
}
public BeanTransformer getBeanTransformer() {
return beanTransformer;
}
public void setBeanTransformer(BeanTransformer beanTransformer) {
this.beanTransformer = beanTransformer;
}
}
FileDAOImpl.java
public class FileDAOImpl implements FileDAO {
private SessionFactory sessionFactory;
@Override
public AbstractFile getFileByID(User user, long fileID) {
return null;
}
@Override
public Folder getFolder(User user, long folderID) {
return null;
}
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void saveOrUpdateFile(User user, AbstractFile file) {
Session session = getSession();
file.setClassName(file.getClass().getCanonicalName());
file.setOwnerID(user.getId());
session.save(file);
}
@Override
public void saveOrUpdateFiles(User user, List<AbstractFile> files) {
}
@Override
public void deleteFile(User user, long fileID, boolean recursively) {
}
@Override
public List<AbstractFile> getRootFiles(User user) {
Session session = getSession();
Query query = session.createQuery("from AbstractFile as file where file.ownerID = :ownerId and file.parentId is null ");
query.setParameter("ownerId", user.getId());
List list = query.list();
return list;
}
@Override
public List<AbstractFile> getChildren(User user, long folderID) {
return null;
}
@Override
public List<AbstractFile> getFilesByType(User user, String javaType) {
return null;
}
private Session getSession() {
return sessionFactory.getCurrentSession();
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
}
的applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<bean name="dozer" class="org.dozer.DozerBeanMapper" />
<bean name="beanTransformer" class="org.sbezgin.p2016.services.impl.BeanTransformerImpl">
<property name="dozerBeanMapper" ref="dozer"/>
<property name="beanMap">
<map>
<entry key="org.sbezgin.p2016.db.dto.file.FolderDTO" value="org.sbezgin.p2016.db.entity.file.Folder"/>
</map>
</property>
</bean>
<!-- services -->
<bean name="fileService" class="org.sbezgin.p2016.services.file.impl.FileServiceImpl">
<property name="fileDAO" ref="fileDAO" />
<property name="beanTransformer" ref="beanTransformer"/>
</bean>
<!-- dao -->
<bean name="fileDAO" class="org.sbezgin.p2016.db.dao.impl.FileDAOImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
</beans>
的applicationContext-db.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<context:property-placeholder location="WEB-INF/hibernate.properties" ignore-unresolvable="false"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan">
<list>
<value>org.sbezgin.p2016.db.entity</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql:false}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql:false}</prop>
<prop key="hibernate.id.new_generator_mappings">${hibernate.id.new_generator_mappings}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
hibernate.properties
jdbc.driverClassName = org.hsqldb.jdbcDriver
jdbc.url = jdbc:hsqldb:hsql://localhost:9001/xdb
jdbc.username = sa
jdbc.password =
hibernate.dialect = org.hibernate.dialect.HSQLDialect
hibernate.show_sql = true
hibernate.format_sql = true
hibernate.id.new_generator_mappings = false
hibernate.hbm2ddl.auto = create-drop
的pom.xml
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.0.7.Final</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer</artifactId>
<version>5.5.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<!-- TEST artifacts -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.2.4.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.2.8</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>p2016</finalName>
<plugins>
<plugin>
<!-- current version -->
<groupId>fr.avianey.mojo</groupId>
<artifactId>hsqldb-maven-plugin</artifactId>
<version>1.0.0</version>
<!--
default value for in memory jdbc:hsqldb:hsql://localhost/xdb
override only values you want to change
-->
<configuration>
<driver>org.hsqldb.jdbcDriver</driver>
<address>localhost</address>
<port>9001</port>
<name>xdb</name>
<username>sa</username>
<password></password>
<validationQuery>SELECT 1 FROM INFORMATION_SCHEMA.SYSTEM_USERS</validationQuery>
</configuration>
<!-- call start and stop -->
<executions>
<execution>
<id>start-hsqldb</id>
<phase>process-test-classes</phase>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>stop-hsqldb</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
答案 0 :(得分:1)
我发现我必须将@EnableTransactionManagement添加到我的配置中。在此之前,Spring没有运行SpringTransactionAnnotationParser并将代理事务方法添加到我的bean中。我只将它添加到一个测试中,因为它会使所有测试的运行方式与测试框架想要的不同(管理事务本身并自动将其回滚)
答案 1 :(得分:0)
基于Spring Framework的documentation:
在
TestContext
框架中,交易由管理TransactionalTestExecutionListener
默认配置, 即使你没有明确声明你的@TestExecutionListeners
考试班。但是,要启用对事务的支持,您必须这样做 在PlatformTransactionManager
中配置ApplicationContext
bean 通过@ContextConfiguration
语义加载。另外,你必须声明Spring的@Transactional
注释在类或方法级别为您的 测试
您确实在PlatformTransactionManager
中定义了applicationContext-db.xml
,但没有在@Transactional
类或FileServiceImplTest
方法中添加testSaveFolder
。在测试类或方法上添加@Transactional
。