[SPRING] 스프링 데이터 저장소에서 Spring의 선언적 캐싱 지원을 테스트하는 방법은 무엇입니까?
SPRING스프링 데이터 저장소에서 Spring의 선언적 캐싱 지원을 테스트하는 방법은 무엇입니까?
org.springframework.data.jpa.repository.JpaRepository를 확장 한 Spring 데이터 저장소 인 MemberRepository 인터페이스를 개발했습니다. MemberRepository에는 다음과 같은 메소드가 있습니다.
@Cacheable(CacheConfiguration.DATABASE_CACHE_NAME)
Member findByEmail(String email);
결과는 Spring 캐시 추상화 (ConcurrentMapCache가 지원)에 의해 캐시됩니다.
내가 가진 문제는 결과가 db에서 처음으로 검색되고 캐시에서 두 번째로 검색된다고 주장하는 통합 테스트 (hsqldb에 대해)를 작성하려고한다는 것입니다.
처음에는 jpa 인프라 스트럭처 (엔티티 관리자 등)를 조롱하던 중 엔티티 관리자가 두 번째 호출되지 않는다고 주장하지만 너무 어렵거나 복잡해 보입니다 (https://stackoverflow.com/a/23442457/536299 참조). ).
누군가가 @Cacheable 주석이 달린 Spring Data Repository 메소드의 캐싱 동작을 테스트하는 방법에 대한 조언을 제공해 줄 수 있습니까?
해결법
-
==============================
1.캐싱과 같은 기술적 측면을 테스트하려면 데이터베이스를 전혀 사용하지 마십시오. 여기에서 테스트 할 내용을 이해하는 것이 중요합니다. 매우 동일한 인수를 사용하여 호출에 대해 메소드 호출을 피할 수 있습니다. 데이터베이스를 다루는 리파지토리는이 주제와 완전히 직각 인 측면입니다.
캐싱과 같은 기술적 측면을 테스트하려면 데이터베이스를 전혀 사용하지 마십시오. 여기에서 테스트 할 내용을 이해하는 것이 중요합니다. 매우 동일한 인수를 사용하여 호출에 대해 메소드 호출을 피할 수 있습니다. 데이터베이스를 다루는 리파지토리는이 주제와 완전히 직각 인 측면입니다.
다음은 내가 권하는 것입니다.
@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)); } }
보시다시피, 우리는 여기서 약간의 테스트를 거칩니다.
-
==============================
2.올리버의 예를 사용하여 내 앱에서 캐시 동작을 테스트 해 보았습니다. 내 경우에는 캐시가 서비스 계층에 설정되어 있고 내 repo가 올바른 횟수만큼 호출되고 있는지 확인하고자합니다. 나는 mockito 대신 spock mock을 사용하고 있습니다. 처음에 테스트를 실행하면 캐시가 채워지고 다른 테스트가 실행된다는 것을 알게 될 때까지 내 테스트가 실패하는 이유를 알아 내려고 노력했습니다. 모든 테스트마다 캐시를 지운 다음 예상대로 작동하기 시작했습니다.
올리버의 예를 사용하여 내 앱에서 캐시 동작을 테스트 해 보았습니다. 내 경우에는 캐시가 서비스 계층에 설정되어 있고 내 repo가 올바른 횟수만큼 호출되고 있는지 확인하고자합니다. 나는 mockito 대신 spock mock을 사용하고 있습니다. 처음에 테스트를 실행하면 캐시가 채워지고 다른 테스트가 실행된다는 것을 알게 될 때까지 내 테스트가 실패하는 이유를 알아 내려고 노력했습니다. 모든 테스트마다 캐시를 지운 다음 예상대로 작동하기 시작했습니다.
여기 내가 끝까지 된 것은 :
@ContextConfiguration class FooBarServiceCacheTest extends Specification { @TestConfiguration @EnableCaching static class Config { def mockFactory = new DetachedMockFactory() def fooBarRepository = mockFactory.Mock(FooBarRepository) @Bean CacheManager cacheManager() { new ConcurrentMapCacheManager(FOOBARS) } @Bean FooBarRepository fooBarRepository() { fooBarRepository } @Bean FooBarService getFooBarService() { new FooBarService(fooBarRepository) } } @Autowired @Subject FooBarService fooBarService @Autowired FooBarRepository fooBarRepository @Autowired CacheManager cacheManager def "setup"(){ // we want to start each test with an new cache cacheManager.getCache(FOOBARS).clear() } def "should return cached foobars "() { given: final foobars = [new FooBar(), new FooBar()] when: fooBarService.getFooBars() fooBarService.getFooBars() final fooBars = fooBarService.getFooBars() then: 1 * fooBarRepository.findAll() >> foobars } def "should return new foobars after clearing cache"() { given: final foobars = [new FooBar(), new FooBar()] when: fooBarService.getFooBars() fooBarService.clearCache() final fooBars = fooBarService.getFooBars() then: 2 * fooBarRepository.findAll() >> foobars } }
from https://stackoverflow.com/questions/24221569/how-to-test-springs-declarative-caching-support-on-spring-data-repositories by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] Postman rest client에서 spring csrf 토큰을 보내려면 어떻게해야합니까? (0) | 2018.12.19 |
---|---|
[SPRING] 다중 데이터베이스 스키마를 사용하는 JPA (0) | 2018.12.19 |
[SPRING] 컨트롤러에서 BindingResult에서 오류 텍스트를 가져 오는 방법 (0) | 2018.12.19 |
[SPRING] Spring XML 설정에서 주어진 타입의 모든 빈을 수집하고 삽입하는 법 (0) | 2018.12.19 |
[SPRING] 스프링 배치 원격 청킹과 원격 파티셔닝의 차이점 (0) | 2018.12.19 |