0

我正在尝试创建某种集成测试环境,并在测试上下文框架没有为我的 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);

    }

}

测试上下文框架注入到 FileService bean 本身的“fileService”中,而不是事务代理。这是例外的原因:

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;
    }
}

文件DAOImpl.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;
    }
}

应用程序上下文.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>
4

2 回答 2

1

我发现我必须将 @EnableTransactionManagement 添加到我的配置中。在此之前,Spring 没有运行 SpringTransactionAnnotationParser 并将代理事务方法添加到我的 bean。我只将它添加到一个测试中,因为它会使所有测试的运行方式与测试框架想要的不同(管理事务本身并自动回滚)

于 2016-05-18T00:09:13.050 回答
0

基于 Spring Framework 的文档

TestContext框架中,事务 TransactionalTestExecutionListener由默认配置的 管理,即使您没有@TestExecutionListeners在测试类上显式声明。但是,要启用对事务的支持,您必须在 通过语义加载的PlatformTransactionManagerbean 中配置一个 bean 。此外,您必须 在测试的类或方法级别声明 Spring 的注解。ApplicationContext@ContextConfiguration@Transactional

您确实在您的类或方法中定义了 a PlatformTransactionManagerapplicationContext-db.xml但没有@Transactional在您的FileServiceImplTest类或testSaveFolder方法中添加 a 。@Transactional在您的测试类或方法上添加。

于 2016-02-18T16:43:56.847 回答