当前位置: 首页 > 知识库问答 >
问题:

如何在Spring数据存储库上测试Spring的声明式缓存支持?

娄建义
2023-03-14
@Cacheable(CacheConfiguration.DATABASE_CACHE_NAME)
Member findByEmail(String email);

我最初想嘲弄一下jpa基础结构(实体管理器等),并以某种方式断言实体管理器不是第二次调用的,但它似乎太难/太累赘了(参见https://stackoverflow.com/A/23442457/536299)。

那么,有人能提供建议,如何测试用@cacheable注释的Spring数据存储库方法的缓存行为吗?

共有1个答案

傅皓君
2023-03-14

如果您想测试像缓存这样的技术方面,完全不要使用数据库。了解您想在这里测试什么是很重要的。您希望确保使用相同参数的调用避免方法调用。数据库前面的存储库是本主题的一个完全正交的方面。

以下是我的建议:

  1. 设置配置声明式缓存的集成测试(或从生产配置中导入必要的位和片段。
  2. 配置存储库的模拟实例。
  3. 编写一个测试用例来设置模拟的预期行为,调用方法并相应地验证输出。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class CachingIntegrationTest {

  // Your repository interface
  interface MyRepo extends Repository<Object, Long> {

    @Cacheable("sample")
    Object findByEmail(String email);
  }

  @Configuration
  @EnableCaching
  static class Config {

    // Simulating your caching configuration
    @Bean
    CacheManager cacheManager() {
      return new ConcurrentMapCacheManager("sample");
    }

    // A repository mock instead of the real proxy
    @Bean
    MyRepo myRepo() {
      return Mockito.mock(MyRepo.class);
    }
  }

  @Autowired CacheManager manager;
  @Autowired MyRepo repo;

  @Test
  public void methodInvocationShouldBeCached() {

    Object first = new Object();
    Object second = new Object();

    // Set up the mock to return *different* objects for the first and second call
    Mockito.when(repo.findByEmail(Mockito.any(String.class))).thenReturn(first, second);

    // First invocation returns object returned by the method
    Object result = repo.findByEmail("foo");
    assertThat(result, is(first));

    // Second invocation should return cached value, *not* second (as set up above)
    result = repo.findByEmail("foo");
    assertThat(result, is(first));

    // Verify repository method was invoked once
    Mockito.verify(repo, Mockito.times(1)).findByEmail("foo");
    assertThat(manager.getCache("sample").get("foo"), is(notNullValue()));

    // Third invocation with different key is triggers the second invocation of the repo method
    result = repo.findByEmail("bar");
    assertThat(result, is(second));
  }
}

正如您所看到的,我们在这里做了一些过度测试:

  1. 最相关的检查,我认为是第二个调用返回第一个对象。这就是缓存的意义所在。使用相同键的前两次调用返回相同的对象,而使用不同键的第三次调用将导致对存储库的第二次实际调用。
  2. 我们通过检查缓存实际上有第一个键的值来加强测试用例。甚至可以扩展它来检查实际值。另一方面,我也认为最好避免这样做,因为您倾向于测试机制的更多内部内容,而不是应用程序级别的行为。
  1. 测试容器行为不需要任何基础结构。
  2. 设置测试用例很简单,也很简单。
  3. 设计良好的组件使您能够编写简单的测试用例,并且在测试中需要较少的集成部分工作。
 类似资料:
  • 问题内容: 我已经开发了一个Spring Data仓库,扩展了接口有一个方法: 结果由Spring缓存抽象(由)支持缓存。 我的问题是,我想要写一个集成测试(针对HSQLDB)断言结果被从数据库第一次检索,并从缓存中的第二次。 我最初想到模拟jpa基础结构(实体管理器等),并以某种方式断言第二次不调用实体管理器,但似乎太难/麻烦了)。 然后有人可以提供有关如何测试带有注释的Spring Data

  • 我试图测试Spring数据JPA存储库(扩展)的Spring缓存支持(如本文所述),但我的配置确实有问题。 下面是我的测试: 通过运行上面的测试,我注意到类型的对象作为键传递给,而null作为值传递给: 下面是堆栈跟踪:

  • 我想要一个在Spring数据的帮助下创建的存储库(例如)。我不熟悉spring-data(但不熟悉spring),我使用本教程。我选择的处理数据库的技术是JPA2.1和Hibernate。问题是我不知道如何为这样的存储库编写单元测试。 让我们以方法为例。由于我正在进行测试--首先,我应该为它编写一个单元测试--这就是我遇到三个问题的地方: > 首先,如何将的模拟注入到不存在的接口实现中?Sprin

  • 我需要使用spring@Cacheable注释缓存对MongoDB的调用: 不幸的是,使用@Cacheable注释接口中的任何方法都会导致以下异常: 我正在寻找一种方法来缓存对DB的调用(这相当昂贵)。有什么想法吗?

  • 它是否将其存储在缓存中?我有一个应用程序,但应用程序中没有任何地方。属性是提到的db详细信息。我可以通过邮递员存储数据和查询它。