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

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

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

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

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

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

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

【问题讨论】:

    标签: java hibernate caching jpa selenium


    【解决方案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 步骤都很愉快。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-05-06
        • 2016-02-01
        • 2011-12-02
        • 2017-07-23
        • 2016-12-01
        • 1970-01-01
        • 2014-11-28
        • 2011-12-18
        相关资源
        最近更新 更多