From 0fb66744182cbb2b075e081d87ac11f328cf8382 Mon Sep 17 00:00:00 2001 From: Adrian Maghear Date: Thu, 4 Jun 2020 16:29:55 +0200 Subject: [PATCH] [BAEL-3841] declarative caching testing --- spring-caching/pom.xml | 14 +++ .../springdatacaching/model/Book.java | 21 +++++ .../repositories/BookRepository.java | 15 ++++ spring-caching/src/main/resources/data.sql | 7 -- spring-caching/src/main/resources/schema.sql | 19 ---- .../BookRepositoryCachingIntegrationTest.java | 86 +++++++++++++++++++ .../BookRepositoryIntegrationTest.java | 58 +++++++++++++ 7 files changed, 194 insertions(+), 26 deletions(-) create mode 100644 spring-caching/src/main/java/com/baeldung/springdatacaching/model/Book.java create mode 100644 spring-caching/src/main/java/com/baeldung/springdatacaching/repositories/BookRepository.java delete mode 100644 spring-caching/src/main/resources/data.sql delete mode 100644 spring-caching/src/main/resources/schema.sql create mode 100644 spring-caching/src/test/java/com/baeldung/springdatacaching/repositories/BookRepositoryCachingIntegrationTest.java create mode 100644 spring-caching/src/test/java/com/baeldung/springdatacaching/repositories/BookRepositoryIntegrationTest.java diff --git a/spring-caching/pom.xml b/spring-caching/pom.xml index 80644f8a5f..5a320d3048 100644 --- a/spring-caching/pom.xml +++ b/spring-caching/pom.xml @@ -58,6 +58,20 @@ org.springframework.boot spring-boot-starter-jdbc + + org.projectlombok + lombok + 1.18.12 + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.data + spring-data-commons + 2.3.0.RELEASE + 3.5.2 diff --git a/spring-caching/src/main/java/com/baeldung/springdatacaching/model/Book.java b/spring-caching/src/main/java/com/baeldung/springdatacaching/model/Book.java new file mode 100644 index 0000000000..7de567f0db --- /dev/null +++ b/spring-caching/src/main/java/com/baeldung/springdatacaching/model/Book.java @@ -0,0 +1,21 @@ +package com.baeldung.springdatacaching.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.Entity; +import javax.persistence.Id; +import java.util.UUID; + +@Data +@Entity +@NoArgsConstructor +@AllArgsConstructor +public class Book { + + @Id + private UUID id; + private String title; + +} diff --git a/spring-caching/src/main/java/com/baeldung/springdatacaching/repositories/BookRepository.java b/spring-caching/src/main/java/com/baeldung/springdatacaching/repositories/BookRepository.java new file mode 100644 index 0000000000..d7f80b8b57 --- /dev/null +++ b/spring-caching/src/main/java/com/baeldung/springdatacaching/repositories/BookRepository.java @@ -0,0 +1,15 @@ +package com.baeldung.springdatacaching.repositories; + +import com.baeldung.springdatacaching.model.Book; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.repository.CrudRepository; + +import java.util.Optional; +import java.util.UUID; + +public interface BookRepository extends CrudRepository { + + @Cacheable(value = "books", unless="#a0=='Foundation'") + Optional findFirstByTitle(String title); + +} diff --git a/spring-caching/src/main/resources/data.sql b/spring-caching/src/main/resources/data.sql deleted file mode 100644 index e4165ae71f..0000000000 --- a/spring-caching/src/main/resources/data.sql +++ /dev/null @@ -1,7 +0,0 @@ -INSERT INTO CUSTOMER VALUES(1001,'BAELDUNG'); - -INSERT INTO ITEM VALUES(10001,'ITEM1',50.0); -INSERT INTO ITEM VALUES(10002,'ITEM2',100.0); - -INSERT INTO ORDERDETAIL VALUES(300001,1001,10001,2); -INSERT INTO ORDERDETAIL VALUES(300002,1001,10002,5); \ No newline at end of file diff --git a/spring-caching/src/main/resources/schema.sql b/spring-caching/src/main/resources/schema.sql deleted file mode 100644 index 5862499bc0..0000000000 --- a/spring-caching/src/main/resources/schema.sql +++ /dev/null @@ -1,19 +0,0 @@ -CREATE TABLE CUSTOMER( - CUSTOMERID INT PRIMARY KEY, - CUSTOMERNAME VARCHAR(250) NOT NULL -); - -CREATE TABLE ITEM( -ITEMID INT PRIMARY KEY, -ITEMDESC VARCHAR(250), -PRICE DOUBLE -); - -CREATE TABLE ORDERDETAIL( -ORDERID INT PRIMARY KEY, -CUSTOMERID INT NOT NULL, -ITEMID INT NOT NULL, -QUANTITY INT, -FOREIGN KEY (customerid) references CUSTOMER(customerid), -FOREIGN KEY (itemid) references ITEM(itemid) -); \ No newline at end of file diff --git a/spring-caching/src/test/java/com/baeldung/springdatacaching/repositories/BookRepositoryCachingIntegrationTest.java b/spring-caching/src/test/java/com/baeldung/springdatacaching/repositories/BookRepositoryCachingIntegrationTest.java new file mode 100644 index 0000000000..49ecc3a058 --- /dev/null +++ b/spring-caching/src/test/java/com/baeldung/springdatacaching/repositories/BookRepositoryCachingIntegrationTest.java @@ -0,0 +1,86 @@ +package com.baeldung.springdatacaching.repositories; + +import com.baeldung.springdatacaching.model.Book; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cache.concurrent.ConcurrentMapCacheManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.util.AopTestUtils; + +import java.util.UUID; + +import static java.util.Optional.of; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +@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"); + } + + } + + @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!")); + } + + @Test + void givenCachedBookWhenFindByTitleThenRepositoryShouldNotBeHit() { + assertEquals(of(DUNE), bookRepository.findFirstByTitle("Dune")); + verify(mock).findFirstByTitle("Dune"); + + assertEquals(of(DUNE), bookRepository.findFirstByTitle("Dune")); + assertEquals(of(DUNE), bookRepository.findFirstByTitle("Dune")); + + verifyNoMoreInteractions(mock); + } + + @Test + void givenNotCachedBookWhenFindByTitleThenRepositoryShouldBeHit() { + assertEquals(of(FOUNDATION), bookRepository.findFirstByTitle("Foundation")); + assertEquals(of(FOUNDATION), bookRepository.findFirstByTitle("Foundation")); + assertEquals(of(FOUNDATION), bookRepository.findFirstByTitle("Foundation")); + + verify(mock, times(3)).findFirstByTitle("Foundation"); + } + +} diff --git a/spring-caching/src/test/java/com/baeldung/springdatacaching/repositories/BookRepositoryIntegrationTest.java b/spring-caching/src/test/java/com/baeldung/springdatacaching/repositories/BookRepositoryIntegrationTest.java new file mode 100644 index 0000000000..56bc898bd0 --- /dev/null +++ b/spring-caching/src/test/java/com/baeldung/springdatacaching/repositories/BookRepositoryIntegrationTest.java @@ -0,0 +1,58 @@ +package com.baeldung.springdatacaching.repositories; + +import com.baeldung.caching.boot.CacheApplication; +import com.baeldung.springdatacaching.model.Book; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cache.CacheManager; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import java.util.Optional; +import java.util.UUID; + +import static java.util.Optional.empty; +import static java.util.Optional.ofNullable; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@ExtendWith(SpringExtension.class) +@EntityScan(basePackageClasses = Book.class) +@SpringBootTest(classes = CacheApplication.class) +@EnableJpaRepositories(basePackageClasses = BookRepository.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")); + } + + @Test + void givenBookThatShouldBeCachedWhenFindByTitleThenResultShouldBePutInCache() { + Optional dune = repository.findFirstByTitle("Dune"); + + assertEquals(dune, getCachedBook("Dune")); + } + + @Test + void givenBookThatShouldNotBeCachedWhenFindByTitleThenResultShouldNotBePutInCache() { + repository.findFirstByTitle("Foundation"); + + assertEquals(empty(), getCachedBook("Foundation")); + } + + private Optional getCachedBook(String title) { + return ofNullable(cacheManager.getCache("books")).map(c -> c.get(title, Book.class)); + } + +}