Hibernate 2 级数据缓存和集成/验收测试

Posted

技术标签:

【中文标题】Hibernate 2 级数据缓存和集成/验收测试【英文标题】:Hibernate 2nd level data cache and integration/acceptance testing 【发布时间】:2012-04-27 02:52:32 【问题描述】:

出于性能原因,我有一个启用了二级数据缓存的 JPA/Hibernate/Spring/Tomcat Web 应用程序。而且缓存做得很好!

我还有一个 Cucumber 测试套件,它将一些测试数据直接添加到应用程序的数据库中,然后执行一些 Selenium 步骤。当然它会失败,因为由于二级缓存,应用程序看不到更新。

我知道我可以为禁用缓存的测试进行特殊构建(通过传递一些用于 Maven 过滤或类似的布尔属性)但是有很多 @Cache 注释实体,因此禁用缓存会使应用程序失败,并出现“二级”异常缓存未启用”。

另一种方法是使用 ehcache 远程处理来清除缓存或将其配置为零对象生命周期或类似的。

我也可以仅使用应用程序 UI 创建测试数据,但这会给测试用例增加不必要的复杂性,因此我更喜欢在测试运行之前将它们写入数据库。

谁能分享他们启用二级数据缓存的集成测试应用程序的方法?

【问题讨论】:

【参考方案1】:

如果您需要使用单元测试来测试二级缓存,您必须确保在每次调用 dao 方法时关闭会话并打开它。否则,您将使用仅存在于一个/当前休眠会话范围内的一级缓存。

【讨论】:

【参考方案2】:

由于您是在谈论通过 Selenium 进行的功能测试,因此您应该将您的应用程序视为一个黑匣子,并在 Selenium 实际上是一个用户时对其进行测试。所以你需要通过网络接口传递数据,然后测试应用程序如何处理它并在之后显示它。

这种应用程序范围的功能测试的替代方案将是行为驱动开发,其中包含针对不同组件的测试。这里的组件是从你的控制器开始的一些流程,以 DAO 结尾(通常 DAO 在这样的测试中被模拟,这使得它们通过非常快,但不测试使用数据库)。在这种情况下,您有一组完整的环境测试和大量的 BDD 测试。

【讨论】:

不是全部,但我的一些 BDD 测试有以下步骤:创建测试数据,做 selenium 的事情,清理。同意黑盒,但是使用 UI 创建和清理数据有时非常困难,并且可能使测试相互依赖(如果与保存相关的 UI 被破坏,所有其他需要保存的测试也会被破坏) 是的,依赖测试会失败,但主要目的 - 失败,满足。如果您直接将数据填充到数据库中,那么它本质上不是验收测试,这不是最终用户使用应用程序的方式。并且这样的测试应该或多或少是粗粒度的。如果你需要更细粒度的,这对于 Selenium 来说可能不是一个好地方。【参考方案3】:

我需要为国家、地区等少数 bean 实现 只读缓存

为了检查它们是否真的被缓存了,我使用 spring 编写了一个集成测试。测试不太合适,它只是对我想要得到的东西的验证。您可以将此作为提示并实现您自己的提示。

您可以阅读here 了解如何使用 Spring 编写集成测试的文章。

@Configurable(autowire = Autowire.BY_NAME)
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations =  "classpath:applicationContext.xml" )
public class HibernateCachingTestIntg 

    @Autowired
    private ConfigurationDAO configurationDAO;

    @Autowired
    private CountryDAO countryDAO;

    @Test
    public void testGetCountries() 
        for (int i = 0; i < 5; i++) 
            StopWatch sw = new StopWatch("C");
            sw.start();
            countryDAO.listCountries();
            sw.stop();
            System.out.println(sw);
        

    

    @Test
    public void testGetRegionList() 

        for (int i = 0; i < 5; i++) 
            StopWatch sw = new StopWatch("R");
            sw.start();
            configurationDAO.getRegionList();
            sw.stop();
            System.out.println(sw);
        

    

这是输出:-

StopWatch 'C': running time (millis) = 217; [] took 217 = 100%
StopWatch 'C': running time (millis) = 15; [] took 15 = 100%
StopWatch 'C': running time (millis) = 16; [] took 16 = 100%
StopWatch 'C': running time (millis) = 15; [] took 15 = 100%
StopWatch 'C': running time (millis) = 16; [] took 16 = 100%

StopWatch 'R': running time (millis) = 201; [] took 201 = 100%
StopWatch 'R': running time (millis) = 15; [] took 15 = 100%
StopWatch 'R': running time (millis) = 0; [] took 0 = 0%
StopWatch 'R': running time (millis) = 16; [] took 16 = 100%
StopWatch 'R': running time (millis) = 15; [] took 15 = 100%

正如您在此处看到的,查询在第一次执行时需要更多时间,而在后面执行则需要更少时间。如果您打开查询记录器,您可以看到 SQL 只是第一次触发。

【讨论】:

谢谢。 Spring-test 工作正常,因为它在单个持久上下文中工作,但验收测试将数据插入到单独的上下文中。我的目的是用一些读写缓存实体而不是缓存本身来测试功能逻辑 文章链接已过期【参考方案4】:

虽然让验收测试独立于数据库是可取的,但它需要太多的重写,所以我目前决定只创建 org.hibernate.cache.Cache 和 org.hibernate.cache.CacheProvider 接口的非常简单的实现,它们什么都不做,什么都做作为一个始终为空的缓存。

测试版本用这个新的缓存替换了真正的缓存,这使得休眠注释和 BDD 步骤都很愉快。

【讨论】:

以上是关于Hibernate 2 级数据缓存和集成/验收测试的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate之一级缓存

如何知道/记录 Hibernate 2 级缓存是不是用于查询?

Infinispan/hibernate 2 级缓存更新不是事务性的?

HIbernate缓存

Hibernate 缓存介绍

Hibernate之缓存详解