본문 바로가기

Web/spring

[Spring] Testing @Cacheable on Spring Data Repositories

728x90

 

 

 

Caching in Spring Mechanism

 

 

 

 

 

Simple Model

@Entity
public class Book {

    @Id
    private UUID id;
    private String title;

}

 

 

 

repository interface that has a @Cacheable method

public interface BookRepository extends CrudRepository<Book, UUID> {
    @Cacheable(value = "books", unless = "#a0=='Foundation'")
    Optional<Book> findFirstByTitle(String title);
}

unless < 제외 조건 (필수는 아님)

 

#title " 대신 SpEL 표현식 "#a0" 에 유의할 것

프록시가 매개변수 이름을 유지하지 않기 때문에 #root.arg[0], p0 또는 a0 표기법을 사용함

 

 

 

Testing

The goal of our tests is to make sure the caching mechanism works. Therefore, we don't intend to cover the Spring Data repository implementation or the persistence aspects.

 

 

Spring Boot Test

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = CacheApplication.class)
public class BookRepositoryIntegrationTest {

    @Autowired
    CacheManager cacheManager;

    @Autowired
    BookRepository repository;

    @BeforeEach
    void setUp() {
        repository.save(new Book(UUID.randomUUID(), "Dune"));
        repository.save(new Book(UUID.randomUUID(), "Foundation"));
    }

    private Optional<Book> getCachedBook(String title) {
        return ofNullable(cacheManager.getCache("books")).map(c -> c.get(title, Book.class));
    }

 

 

Book 요청 후 Cache에 배치되는지 확인해본다

 

@Test
void givenBookThatShouldBeCached_whenFindByTitle_thenResultShouldBePutInCache() {
	Optional<Book> dune = repository.findFirstByTitle("Dune");
	assertEquals(dune, getCachedBook("Dune"));
  }

 

that some books are not placed in the cache:

    @Test
    void givenBookThatShouldNotBeCached_whenFindByTitle_thenResultShouldNotBePutInCache() {
        repository.findFirstByTitle("Foundation");

        assertEquals(empty(), getCachedBook("Foundation"));
    }

Spring에서 제공하는 CacheManager를 사용 하고  repository.findFirstByTitle 작업 후 CacheManager가 @Cacheable 규칙 에 따라 책을 포함하는지(또는 포함하지 않는지) 확인한다

 

 

 

 

Plain Spring

@Configuration that provides the mock implementation for our BookRepository:

@ContextConfiguration
@ExtendWith(SpringExtension.class)
public class BookRepositoryCachingIntegrationTest {

    private static final Book DUNE = new Book(UUID.randomUUID(), "Dune");
    private static final Book FOUNDATION = new Book(UUID.randomUUID(), "Foundation");

    private BookRepository mock;

    @Autowired
    private BookRepository bookRepository;

    @EnableCaching
    @Configuration
    public static class CachingTestConfig {

        @Bean
        public BookRepository bookRepositoryMockImplementation() {
            return mock(BookRepository.class);
        }

        @Bean
        public CacheManager cacheManager() {
            return new ConcurrentMapCacheManager("books");
        }

    }

BookRepository 는  a proxy around our mock. 이다, Mockito 유효성 검사를 위해 AopTestUtils.getTargetObject를통해 실제 모의를 검색한다

CachingTestConfig가 한 번만 로드되기 때문에 테스트 사이에 재설정(mock) 해야한다

 

 

 @BeforeEach
    void setUp() {
        mock = AopTestUtils.getTargetObject(bookRepository);

        reset(mock);

        when(mock.findFirstByTitle(eq("Foundation")))
                .thenReturn(of(FOUNDATION));

        when(mock.findFirstByTitle(eq("Dune")))
                .thenReturn(of(DUNE))
                .thenThrow(new RuntimeException("Book should be cached!"));
    }

 

 

 

 

after a book is placed in the cache, there are no more interactions with the repository implementation when later trying to retrieve that book

책이 캐싱된 후 책을 검색할 때 repository 를 사용하는지 테스트 한다

    @Test
    void givenCachedBook_whenFindByTitle_thenRepositoryShouldNotBeHit() {
        assertEquals(of(DUNE), bookRepository.findFirstByTitle("Dune"));
        verify(mock).findFirstByTitle("Dune");

        assertEquals(of(DUNE), bookRepository.findFirstByTitle("Dune"));
        assertEquals(of(DUNE), bookRepository.findFirstByTitle("Dune"));

        verifyNoMoreInteractions(mock);
    }

that for non-cached books, we invoke the repository every time:

캐싱이 없는 경우에는 repository를 계속 호출하는지 확인한다

    @Test
    void givenNotCachedBook_whenFindByTitle_thenRepositoryShouldBeHit() {
        assertEquals(of(FOUNDATION), bookRepository.findFirstByTitle("Foundation"));
        assertEquals(of(FOUNDATION), bookRepository.findFirstByTitle("Foundation"));
        assertEquals(of(FOUNDATION), bookRepository.findFirstByTitle("Foundation"));

        verify(mock, times(3)).findFirstByTitle("Foundation");
    }
728x90

'Web > spring' 카테고리의 다른 글

[Spring] Assertions in JUnit 4 and JUnit 5  (0) 2023.04.25
[Spring] A Spring Custom Annotation for a Better DAO  (0) 2023.04.24
[Spring Test]  (0) 2023.04.22
[JPA Repository] supported keyword  (0) 2023.04.20
[Spring] stereotype  (0) 2023.04.15