当前位置: 首页 > 面试题库 >

无法为测试上下文的@Transactional测试检索PlatformTransactionManager

乐正玺
2023-03-14
问题内容

尝试在事务之间测试Hibernate(版本4)EHCache的缓存功能时,它失败:Failed to retrieve PlatformTransactionManager for @Transactional test for test context

测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { ApplicationConfig.class, CachingConfig.class }, loader = AnnotationConfigContextLoader.class)
@PersistenceContext
@Transactional
public class EHCacheTest extends AbstractTransactionalJUnit4SpringContextTests {
    @Autowired
    private SessionFactory sessionFactory;
@Test
    public void testTransactionCaching(){
        Session session = sessionFactory.getCurrentSession();
        System.out.println(session.get(CustomerEntity.class, 1));
        Query query = session.createQuery("from CustomerEntity where CustomerEntity.customerId<10").setCacheable(true).setCacheRegion("customer");
        @SuppressWarnings("unchecked")
        List<CustomerEntity> customerEntities = query.list();
        System.out.println(customerEntities);

        TestTransaction.flagForCommit();
        TestTransaction.end();

        TestTransaction.start();

        Session sessionNew =  sessionFactory.getCurrentSession();
        System.out.println(sessionNew.get(CustomerEntity.class, 1));
        Query anotherQuery = sessionNew.createQuery("from CustomerEntity where CustomerEntity.customerId<10");
        anotherQuery.setCacheable(true).setCacheRegion("customer");
        @SuppressWarnings("unchecked")
        List<CustomerEntity> customerListfromCache = anotherQuery.list();
        System.out.println(customerListfromCache);

        TestTransaction.flagForCommit();
        TestTransaction.end();
    }
}

手动编程事务处理是通过Spring 4.x在文档中建议的方式实现的。

应用程序配置

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories (basePackages = { "com.hibernate.query.performance.persistence" }, transactionManagerRef = "jpaTransactionManager")
@EnableJpaAuditing
@PropertySource({ "classpath:persistence-postgresql.properties" })
@ComponentScan({ "com.hibernate.query.performance.persistence" })
public class ApplicationConfig {

    @Autowired
    private Environment env;

    public ApplicationConfig() {
        super();
    }

    @Bean
    public LocalSessionFactoryBean sessionFactory() {
        final LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(applicationDataSource());
        sessionFactory.setPackagesToScan(new String[] { "com.hibernate.query.performance.persistence.model" });
        sessionFactory.setHibernateProperties(hibernateProperties());

        return sessionFactory;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        final LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
        emf.setDataSource(applicationDataSource());
        emf.setPackagesToScan(new String[] { "com.hibernate.query.performance.persistence.model" });

        final JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        emf.setJpaVendorAdapter(vendorAdapter);
        emf.setJpaProperties(hibernateProperties());

        return emf;
    }

    @Bean
    public DataSource applicationDataSource() {
        final BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(Preconditions.checkNotNull(env.getProperty("jdbc.driverClassName")));
        dataSource.setUrl(Preconditions.checkNotNull(env.getProperty("jdbc.url")));
        dataSource.setUsername(Preconditions.checkNotNull(env.getProperty("jdbc.user")));
        dataSource.setPassword(Preconditions.checkNotNull(env.getProperty("jdbc.pass")));

        return dataSource;
    }

    @Bean
    public PlatformTransactionManager hibernateTransactionManager() { // TODO: Really need this?
        final HibernateTransactionManager transactionManager = new HibernateTransactionManager();
        transactionManager.setSessionFactory(sessionFactory().getObject());
        return transactionManager;
    }

    @Bean
    public PlatformTransactionManager jpaTransactionManager() { // TODO: Really need this?
        final JpaTransactionManager transactionManager = new JpaTransactionManager(); // http://stackoverflow.com/questions/26562787/hibernateexception-couldnt-obtain-transaction-synchronized-session-for-current
        transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
        return transactionManager;
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
        return new PersistenceExceptionTranslationPostProcessor();
    }

    private final Properties hibernateProperties() {
        final Properties hibernateProperties = new Properties();
        hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
        hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));

        hibernateProperties.setProperty("hibernate.show_sql", "true");
        hibernateProperties.setProperty("hibernate.format_sql", "true");
        // hibernateProperties.setProperty("hibernate.globally_quoted_identifiers", "true");
        hibernateProperties.setProperty("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.EhCacheRegionFactory");

        // Envers properties
        hibernateProperties.setProperty("org.hibernate.envers.audit_table_suffix", env.getProperty("envers.audit_table_suffix")); // TODO: Really need this?

        return hibernateProperties;
    }
}

缓存配置

@Configuration
@EnableCaching
public class CachingConfig implements CachingConfigurer {
    @Bean(destroyMethod="shutdown")
    public net.sf.ehcache.CacheManager ehCacheManager() {
        CacheConfiguration cacheConfiguration = new CacheConfiguration();
        cacheConfiguration.setName("myCacheName");
        cacheConfiguration.setMemoryStoreEvictionPolicy("LRU");
        cacheConfiguration.setMaxElementsInMemory(1000);

        net.sf.ehcache.config.Configuration config = new net.sf.ehcache.config.Configuration();
        config.addCache(cacheConfiguration);

        return net.sf.ehcache.CacheManager.create(config);
    }

    @Bean
    @Override
    public CacheManager cacheManager() {
        return new EhCacheCacheManager(ehCacheManager());
    }

    @Override
    public CacheResolver cacheResolver() {
        return null;
    }

    @Bean
    @Override
    public KeyGenerator keyGenerator() {
        return new SimpleKeyGenerator();
    }

    @Override
    public CacheErrorHandler errorHandler() {
        return null;
    }
}

错误

java.lang.IllegalStateException: Failed to retrieve PlatformTransactionManager for @Transactional test for test context [DefaultTestContext@d8355a8 testClass = EHCacheTest, testInstance = com.hibernate.query.performance.EHCacheTest@3532ec19, testMethod = testTransactionCaching@EHCacheTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@59fa1d9b testClass = EHCacheTest, locations = '{}', classes = '{class com.hibernate.query.performance.config.ApplicationConfig, class com.hibernate.query.performance.config.CachingConfig}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextLoader = 'org.springframework.test.context.support.AnnotationConfigContextLoader', parent = [null]]].

如何使其运作?

更新:

通过添加(不确定是否@TestExecutionListeners确实需要)来使其工作:

@Transactional(transactionManager = "hibernateTransactionManager")
@TestExecutionListeners({})

问题答案:

如果未明确指定,则@Transactional需要在应用程序上下文中使用名称为transactionManager的bean。使用@Transaction批注值属性指定要与测试一起使用的事务管理器

例如,如果您想使用hibernateTransactionManager,请指定为

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { ApplicationConfig.class, CachingConfig.class }, loader = AnnotationConfigContextLoader.class)
@PersistenceContext
@Transactional("hibernateTransactionManager")
public class EHCacheTest extends AbstractTransactionalJUnit4SpringContextTests {
}

否则,将您要使用的事务管理器重命名为默认名称transactionManager

@Bean
    public PlatformTransactionManager transactionManager() { // TODO: Really need this?
        final HibernateTransactionManager transactionManager = new HibernateTransactionManager();
        transactionManager.setSessionFactory(sessionFactory().getObject());
        return transactionManager;
    }


 类似资料:
  • 22.13.5.测试检测 测试任务检测哪些类是通过检查编译测试类的测试类。默认情况下它会扫描所有.calss文件.可以自定义包含/排除哪些类需不要要被扫描.所使用不同的测试框架(JUnit/ TestNG)时测试类检测使用不同的标准。 当使用JUnit,我们扫描的JUnit3和JUnit4的测试类。如果任一下列条件匹配,类被认为是一个JUnit测试类: 类或父类集成自TestCase或Groovy

  • 问题内容: 是否可以像使用JUnit一样(使用getName()或rules)检索当前正在运行的测试名称? PS我不想使用基于堆栈跟踪的一些自写工具。 问题答案: 根据位于http://testng.org/doc/documentation- main.html的 TestNG文档, 您可以实现可能有助于您解决问题的侦听器。 查看5.16节的TestNG侦听器,尤其是IInvokedMethod

  • SpringWeb应用程序的事务JUnit测试失败。 具体地说:如果我分别使用maven执行每个测试,它们将运行: 如果我执行 我在其中一个测试中发现JPA错误: 如果我设置surefire插件为每个测试重新创建整个JVM,它们也会运行,这当然需要花费大量的时间。 应用程序设置: Spring,与Spring Roo(因此proxyMode=asjectJ!) Eclipselink作为JPA提供

  • 您好,我有一个将人员添加到团队的方法。我想为此方法编写一个测试,但我是junit/mockito测试的新手,所以我有很多问题:这是我的添加方法: 这两个实体(人员/团队)之间存在关系,这是我的测试代码,但它不起作用: 模拟组合:

  • 我在Android Studio3.0.1和Kotlin中运行时遇到了一些问题(我在以前的Android Studios和Java中没有遇到这样的问题)。我在包中创建了这个(非常简单的)类[reference],它如下所示: 当我尝试运行测试时,有两个问题。首先,它希望在控制台中运行测试,而不打开仿真器或将apk包部署到设备(因为这只是一个正常的本地单元测试)。此外,我还会收到以下错误消息: 找不

  • 我们有一个基于Spring的JUnit测试类,它利用一个内部测试上下文配置类 最近,服务类中引入了新的功能,相关测试应添加到ServiceTest中。但是,这也需要创建不同的测试上下文配置类(现有配置类的内部结构相当复杂,如果可能的话,将其更改为既服务于旧测试又服务于新测试似乎非常困难) 有没有一种方法可以实现一个测试类中的某些测试方法将使用一个配置类,而其他方法将使用另一个?似乎只适用于类级别,