diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..4f81299 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.configuration.updateBuildConfiguration": "automatic" +} diff --git a/src/main/java/ar/com/nanotaboada/java/samples/spring/boot/controllers/BooksController.java b/src/main/java/ar/com/nanotaboada/java/samples/spring/boot/controllers/BooksController.java index 33c1267..1369397 100644 --- a/src/main/java/ar/com/nanotaboada/java/samples/spring/boot/controllers/BooksController.java +++ b/src/main/java/ar/com/nanotaboada/java/samples/spring/boot/controllers/BooksController.java @@ -1,6 +1,7 @@ package ar.com.nanotaboada.java.samples.spring.boot.controllers; import java.net.URI; +import java.util.List; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -63,6 +64,12 @@ public ResponseEntity getBook(@PathVariable String isbn) { } } + @GetMapping("/books") + public ResponseEntity> getAllBooks() { + List books = service.retrieveAll(); + return new ResponseEntity<>(books, HttpStatus.OK); + } + /* -------------------------------------------------------------------------------------------- * HTTP PUT * ----------------------------------------------------------------------------------------- */ @@ -96,4 +103,4 @@ public ResponseEntity deleteBook(@PathVariable String isbn) { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } } -} \ No newline at end of file +} diff --git a/src/main/java/ar/com/nanotaboada/java/samples/spring/boot/services/BooksService.java b/src/main/java/ar/com/nanotaboada/java/samples/spring/boot/services/BooksService.java index 440564b..a9023e1 100644 --- a/src/main/java/ar/com/nanotaboada/java/samples/spring/boot/services/BooksService.java +++ b/src/main/java/ar/com/nanotaboada/java/samples/spring/boot/services/BooksService.java @@ -2,6 +2,10 @@ import jakarta.validation.Validator; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + import org.modelmapper.ModelMapper; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; @@ -54,6 +58,15 @@ public BookDTO retrieveByIsbn(String isbn) { return bookDTO; } + @Cacheable(value = "books") + public List retrieveAll() { + List books = StreamSupport.stream(repository.findAll().spliterator(), false) + .collect(Collectors.toList()); + return books.stream() + .map(book -> mapper.map(book, BookDTO.class)) + .collect(Collectors.toList()); + } + /* -------------------------------------------------------------------------------------------- * Update * ----------------------------------------------------------------------------------------- */ diff --git a/src/test/java/ar/com/nanotaboada/java/samples/spring/boot/test/BookDTOsBuilder.java b/src/test/java/ar/com/nanotaboada/java/samples/spring/boot/test/BookDTOsBuilder.java index 3b0b614..a3c8639 100644 --- a/src/test/java/ar/com/nanotaboada/java/samples/spring/boot/test/BookDTOsBuilder.java +++ b/src/test/java/ar/com/nanotaboada/java/samples/spring/boot/test/BookDTOsBuilder.java @@ -1,42 +1,149 @@ package ar.com.nanotaboada.java.samples.spring.boot.test; import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; import ar.com.nanotaboada.java.samples.spring.boot.models.BookDTO; public class BookDTOsBuilder { public static BookDTO buildOneValid() { - BookDTO bookDto = new BookDTO(); - bookDto.setIsbn("978-1484200773"); - bookDto.setTitle("Pro Git"); - bookDto.setSubtitle("Everything you neeed to know about Git"); - bookDto.setAuthor("Scott Chacon and Ben Straub"); - bookDto.setPublisher("lulu.com; First Edition"); - bookDto.setPublished(LocalDate.of(2014, 11, 18)); - bookDto.setPages(458); - bookDto.setDescription(""" + BookDTO bookDTO = new BookDTO(); + bookDTO.setIsbn("978-1484200773"); + bookDTO.setTitle("Pro Git"); + bookDTO.setSubtitle("Everything you neeed to know about Git"); + bookDTO.setAuthor("Scott Chacon and Ben Straub"); + bookDTO.setPublisher("lulu.com; First Edition"); + bookDTO.setPublished(LocalDate.of(2014, 11, 18)); + bookDTO.setPages(458); + bookDTO.setDescription( + """ Pro Git (Second Edition) is your fully-updated guide to Git and its \ usage in the modern world. Git has come a long way since it was first developed by \ Linus Torvalds for Linux kernel development. It has taken the open source world by \ storm since its inception in 2005, and this book teaches you how to use it like a \ - pro.\ - """); - bookDto.setWebsite("https://git-scm.com/book/en/v2"); - return bookDto; + pro."""); + bookDTO.setWebsite("https://git-scm.com/book/en/v2"); + return bookDTO; } public static BookDTO buildOneInvalid() { - BookDTO bookDto = new BookDTO(); - bookDto.setIsbn("978-1234567890"); // Invalid (invalid ISBN) - bookDto.setTitle("Title"); - bookDto.setSubtitle("Sub Title"); - bookDto.setAuthor("Author"); - bookDto.setPublisher("Publisher"); - bookDto.setPublished(LocalDate.now()); // Invalid (must be a past date) - bookDto.setPages(123); - bookDto.setDescription("Description"); - bookDto.setWebsite("https://domain.com/"); - return bookDto; + BookDTO bookDTO = new BookDTO(); + bookDTO.setIsbn("978-1234567890"); // Invalid (invalid ISBN) + bookDTO.setTitle("Title"); + bookDTO.setSubtitle("Sub Title"); + bookDTO.setAuthor("Author"); + bookDTO.setPublisher("Publisher"); + bookDTO.setPublished(LocalDate.now()); // Invalid (must be a past date) + bookDTO.setPages(123); + bookDTO.setDescription("Description"); + bookDTO.setWebsite("https://domain.com/"); + return bookDTO; + } + + public static List buildManyValid() { + ArrayList bookDTOs = new ArrayList<>(); + BookDTO bookDTO9781838986698 = new BookDTO(); + bookDTO9781838986698.setIsbn("9781838986698"); + bookDTO9781838986698.setTitle("The Java Workshop"); + bookDTO9781838986698.setSubtitle("Learn object-oriented programming and kickstart your career in software development"); + bookDTO9781838986698.setAuthor("David Cuartielles, Andreas Göransson, Eric Foster-Johnson"); + bookDTO9781838986698.setPublisher("Packt Publishing"); + bookDTO9781838986698.setPublished(LocalDate.of(2019, 10, 31)); + bookDTO9781838986698.setPages(606); + bookDTO9781838986698.setDescription( + """ + Java is a versatile, popular programming language used across a wide range of \ + industries. Learning how to write effective Java code can take your career to \ + the next level, and The Java Workshop will help you do just that. This book is \ + designed to take the pain out of Java coding and teach you everything you need \ + to know to be productive in building real-world software. The Workshop starts by \ + showing you how to use classes, methods, and the built-in Collections API to \ + manipulate data structures effortlessly. You'll dive right into learning about \ + object-oriented programming by creating classes and interfaces and making use of \ + inheritance and polymorphism. After learning how to handle exceptions, you'll \ + study the modules, packages, and libraries that help you organize your code. As \ + you progress, you'll discover how to connect to external databases and web \ + servers, work with regular expressions, and write unit tests to validate your \ + code. You'll also be introduced to functional programming and see how to \ + implement it using lambda functions. By the end of this Workshop, you'll be \ + well-versed with key Java concepts and have the knowledge and confidence to \ + tackle your own ambitious projects with Java."""); + bookDTO9781838986698.setWebsite("https://www.packtpub.com/free-ebook/the-java-workshop/9781838986698"); + bookDTOs.add(bookDTO9781838986698); + BookDTO bookDTO9781789613476 = new BookDTO(); + bookDTO9781789613476.setIsbn("9781789613476"); + bookDTO9781789613476.setTitle("Hands-On Microservices with Spring Boot and Spring Cloud"); + bookDTO9781789613476.setSubtitle("Build and deploy Java microservices using Spring Cloud, Istio, and Kubernetes"); + bookDTO9781789613476.setAuthor("Magnus Larsson"); + bookDTO9781789613476.setPublisher("Packt Publishing"); + bookDTO9781789613476.setPublished(LocalDate.of(2019, 9, 20)); + bookDTO9781789613476.setPages(668); + bookDTO9781789613476.setDescription( + """ + Microservices architecture allows developers to build and maintain applications \ + with ease, and enterprises are rapidly adopting it to build software using \ + Spring Boot as their default framework. With this book, you'll learn how to \ + efficiently build and deploy microservices using Spring Boot. This microservices \ + book will take you through tried and tested approaches to building distributed \ + systems and implementing microservices architecture in your organization. \ + Starting with a set of simple cooperating microservices developed using Spring \ + Boot, you'll learn how you can add functionalities such as persistence, make \ + your microservices reactive, and describe their APIs using Swagger/OpenAPI. As \ + you advance, you'll understand how to add different services from Spring Cloud \ + to your microservice system. The book also demonstrates how to deploy your \ + microservices using Kubernetes and manage them with Istio for improved security \ + and traffic management. Finally, you'll explore centralized log management using \ + the EFK stack and monitor microservices using Prometheus and Grafana. By the end \ + of this book, you'll be able to build microservices that are scalable and robust \ + using Spring Boot and Spring Cloud."""); + bookDTO9781789613476.setWebsite("https://www.packtpub.com/free-ebook/hands-on-microservices-with-spring-boot-and-spring-cloud/9781789613476"); + bookDTOs.add(bookDTO9781789613476); + BookDTO bookDTO9781838555726 = new BookDTO(); + bookDTO9781838555726.setIsbn("9781838555726"); + bookDTO9781838555726.setTitle("Mastering Kotlin"); + bookDTO9781838555726.setSubtitle("Learn advanced Kotlin programming techniques to build apps for Android, iOS, and the web"); + bookDTO9781838555726.setAuthor("Nate Ebel"); + bookDTO9781838555726.setPublisher("Packt Publishing"); + bookDTO9781838555726.setPublished(LocalDate.of(2019, 10, 11)); + bookDTO9781838555726.setPages(434); + bookDTO9781838555726.setDescription( + """ + Using Kotlin without taking advantage of its power and interoperability is like \ + owning a sports car and never taking it out of the garage. While documentation \ + and introductory resources can help you learn the basics of Kotlin, the fact \ + that it's a new language means that there are limited learning resources and \ + code bases available in comparison to Java and other established languages. This \ + Kotlin book will show you how to leverage software designs and concepts that \ + have made Java the most dominant enterprise programming language. You'll \ + understand how Kotlin is a modern approach to object-oriented programming (OOP). \ + This book will take you through the vast array of features that Kotlin provides \ + over other languages. These features include seamless interoperability with \ + Java, efficient syntax, built-in functional programming constructs, and support \ + for creating your own DSL. Finally, you will gain an understanding of \ + implementing practical design patterns and best practices to help you master the \ + Kotlin language. By the end of the book, you'll have obtained an advanced \ + understanding of Kotlin in order to be able to build production-grade \ + applications."""); + bookDTO9781838555726.setWebsite("https://www.packtpub.com/free-ebook/mastering-kotlin/9781838555726"); + bookDTOs.add(bookDTO9781838555726); + BookDTO bookDTO9781484242216 = new BookDTO(); + bookDTO9781484242216.setIsbn("9781484242216"); + bookDTO9781484242216.setTitle("Rethinking Productivity in Software Engineering"); + bookDTO9781484242216.setAuthor("Caitlin Sadowski, Thomas Zimmermann"); + bookDTO9781484242216.setPublisher("Apress"); + bookDTO9781484242216.setPublished(LocalDate.of(2019, 5, 7)); + bookDTO9781484242216.setPages(301); + bookDTO9781484242216.setDescription( + """ + Get the most out of this foundational reference and improve the productivity of \ + your software teams. This open access book collects the wisdom of the 2017 \ + "Dagstuhl" seminar on productivity in software engineering, a meeting of \ + community leaders, who came together with the goal of rethinking traditional \ + definitions and measures of productivity."""); + bookDTO9781484242216.setWebsite("https://link.springer.com/book/10.1007/978-1-4842-4221-6"); + bookDTOs.add(bookDTO9781484242216); + return bookDTOs; } } diff --git a/src/test/java/ar/com/nanotaboada/java/samples/spring/boot/test/BooksBuilder.java b/src/test/java/ar/com/nanotaboada/java/samples/spring/boot/test/BooksBuilder.java index 5b45d8d..ddcdd42 100644 --- a/src/test/java/ar/com/nanotaboada/java/samples/spring/boot/test/BooksBuilder.java +++ b/src/test/java/ar/com/nanotaboada/java/samples/spring/boot/test/BooksBuilder.java @@ -1,6 +1,8 @@ package ar.com.nanotaboada.java.samples.spring.boot.test; import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; import ar.com.nanotaboada.java.samples.spring.boot.models.Book; @@ -39,4 +41,109 @@ public static Book buildOneInvalid() { book.setWebsite("https://domain.com/"); return book; } + + public static List buildManyValid() { + ArrayList books = new ArrayList<>(); + Book book9781838986698 = new Book(); + book9781838986698.setIsbn("9781838986698"); + book9781838986698.setTitle("The Java Workshop"); + book9781838986698.setSubtitle("Learn object-oriented programming and kickstart your career in software development"); + book9781838986698.setAuthor("David Cuartielles, Andreas Göransson, Eric Foster-Johnson"); + book9781838986698.setPublisher("Packt Publishing"); + book9781838986698.setPublished(LocalDate.of(2019, 10, 31)); + book9781838986698.setPages(606); + book9781838986698.setDescription( + """ + Java is a versatile, popular programming language used across a wide range of \ + industries. Learning how to write effective Java code can take your career to \ + the next level, and The Java Workshop will help you do just that. This book is \ + designed to take the pain out of Java coding and teach you everything you need \ + to know to be productive in building real-world software. The Workshop starts by \ + showing you how to use classes, methods, and the built-in Collections API to \ + manipulate data structures effortlessly. You'll dive right into learning about \ + object-oriented programming by creating classes and interfaces and making use of \ + inheritance and polymorphism. After learning how to handle exceptions, you'll \ + study the modules, packages, and libraries that help you organize your code. As \ + you progress, you'll discover how to connect to external databases and web \ + servers, work with regular expressions, and write unit tests to validate your \ + code. You'll also be introduced to functional programming and see how to \ + implement it using lambda functions. By the end of this Workshop, you'll be \ + well-versed with key Java concepts and have the knowledge and confidence to \ + tackle your own ambitious projects with Java."""); + book9781838986698.setWebsite("https://www.packtpub.com/free-ebook/the-java-workshop/9781838986698"); + books.add(book9781838986698); + Book book9781789613476 = new Book(); + book9781789613476.setIsbn("9781789613476"); + book9781789613476.setTitle("Hands-On Microservices with Spring Boot and Spring Cloud"); + book9781789613476.setSubtitle("Build and deploy Java microservices using Spring Cloud, Istio, and Kubernetes"); + book9781789613476.setAuthor("Magnus Larsson"); + book9781789613476.setPublisher("Packt Publishing"); + book9781789613476.setPublished(LocalDate.of(2019, 9, 20)); + book9781789613476.setPages(668); + book9781789613476.setDescription( + """ + Microservices architecture allows developers to build and maintain applications \ + with ease, and enterprises are rapidly adopting it to build software using \ + Spring Boot as their default framework. With this book, you'll learn how to \ + efficiently build and deploy microservices using Spring Boot. This microservices \ + book will take you through tried and tested approaches to building distributed \ + systems and implementing microservices architecture in your organization. \ + Starting with a set of simple cooperating microservices developed using Spring \ + Boot, you'll learn how you can add functionalities such as persistence, make \ + your microservices reactive, and describe their APIs using Swagger/OpenAPI. As \ + you advance, you'll understand how to add different services from Spring Cloud \ + to your microservice system. The book also demonstrates how to deploy your \ + microservices using Kubernetes and manage them with Istio for improved security \ + and traffic management. Finally, you'll explore centralized log management using \ + the EFK stack and monitor microservices using Prometheus and Grafana. By the end \ + of this book, you'll be able to build microservices that are scalable and robust \ + using Spring Boot and Spring Cloud."""); + book9781789613476.setWebsite("https://www.packtpub.com/free-ebook/hands-on-microservices-with-spring-boot-and-spring-cloud/9781789613476"); + books.add(book9781789613476); + Book book9781838555726 = new Book(); + book9781838555726.setIsbn("9781838555726"); + book9781838555726.setTitle("Mastering Kotlin"); + book9781838555726.setSubtitle("Learn advanced Kotlin programming techniques to build apps for Android, iOS, and the web"); + book9781838555726.setAuthor("Nate Ebel"); + book9781838555726.setPublisher("Packt Publishing"); + book9781838555726.setPublished(LocalDate.of(2019, 10, 11)); + book9781838555726.setPages(434); + book9781838555726.setDescription( + """ + Using Kotlin without taking advantage of its power and interoperability is like \ + owning a sports car and never taking it out of the garage. While documentation \ + and introductory resources can help you learn the basics of Kotlin, the fact \ + that it's a new language means that there are limited learning resources and \ + code bases available in comparison to Java and other established languages. This \ + Kotlin book will show you how to leverage software designs and concepts that \ + have made Java the most dominant enterprise programming language. You'll \ + understand how Kotlin is a modern approach to object-oriented programming (OOP). \ + This book will take you through the vast array of features that Kotlin provides \ + over other languages. These features include seamless interoperability with \ + Java, efficient syntax, built-in functional programming constructs, and support \ + for creating your own DSL. Finally, you will gain an understanding of \ + implementing practical design patterns and best practices to help you master the \ + Kotlin language. By the end of the book, you'll have obtained an advanced \ + understanding of Kotlin in order to be able to build production-grade \ + applications."""); + book9781838555726.setWebsite("https://www.packtpub.com/free-ebook/mastering-kotlin/9781838555726"); + books.add(book9781838555726); + Book book9781484242216 = new Book(); + book9781484242216.setIsbn("9781484242216"); + book9781484242216.setTitle("Rethinking Productivity in Software Engineering"); + book9781484242216.setAuthor("Caitlin Sadowski, Thomas Zimmermann"); + book9781484242216.setPublisher("Apress"); + book9781484242216.setPublished(LocalDate.of(2019, 5, 7)); + book9781484242216.setPages(301); + book9781484242216.setDescription( + """ + Get the most out of this foundational reference and improve the productivity of \ + your software teams. This open access book collects the wisdom of the 2017 \ + "Dagstuhl" seminar on productivity in software engineering, a meeting of \ + community leaders, who came together with the goal of rethinking traditional \ + definitions and measures of productivity."""); + book9781484242216.setWebsite("https://link.springer.com/book/10.1007/978-1-4842-4221-6"); + books.add(book9781484242216); + return books; + } } diff --git a/src/test/java/ar/com/nanotaboada/java/samples/spring/boot/test/controllers/BooksControllerTests.java b/src/test/java/ar/com/nanotaboada/java/samples/spring/boot/test/controllers/BooksControllerTests.java index 6e5cfb4..d303966 100644 --- a/src/test/java/ar/com/nanotaboada/java/samples/spring/boot/test/controllers/BooksControllerTests.java +++ b/src/test/java/ar/com/nanotaboada/java/samples/spring/boot/test/controllers/BooksControllerTests.java @@ -6,6 +6,8 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import java.util.List; + import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -20,6 +22,7 @@ import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import ar.com.nanotaboada.java.samples.spring.boot.controllers.BooksController; @@ -89,6 +92,7 @@ void givenHttpPostVerb_whenRequestBodyContainsNewValidBook_thenShouldReturnStatu .perform(request) .andReturn() .getResponse(); + response.setContentType("application/json;charset=UTF-8"); // Assert assertThat(response.getStatus()).isEqualTo(HttpStatus.CREATED.value()); assertThat(response.getHeader(HttpHeaders.LOCATION)).isNotNull(); @@ -132,22 +136,23 @@ void givenHttpPostVerb_whenRequestBodyContainsInvalidBook_thenShouldReturnStatus void givenHttpGetVerb_whenRequestParameterIdentifiesExistingBook_thenShouldReturnStatusOkAndTheBook() throws Exception { // Arrange - BookDTO expected = BookDTOsBuilder.buildOneValid(); + BookDTO bookDTO = BookDTOsBuilder.buildOneValid(); Mockito .when(service.retrieveByIsbn(anyString())) - .thenReturn(expected); // Existing + .thenReturn(bookDTO); // Existing MockHttpServletRequestBuilder request = MockMvcRequestBuilders - .get("/book/{isbn}", expected.getIsbn()); + .get("/book/{isbn}", bookDTO.getIsbn()); // Act MockHttpServletResponse response = mockMvc .perform(request) .andReturn() .getResponse(); + response.setContentType("application/json;charset=UTF-8"); String content = response.getContentAsString(); BookDTO actual = new ObjectMapper().readValue(content, BookDTO.class); // Assert assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value()); - assertThat(actual).usingRecursiveComparison().isEqualTo(expected); + assertThat(actual).usingRecursiveComparison().isEqualTo(bookDTO); verify(service, times(1)).retrieveByIsbn(anyString()); } @@ -155,7 +160,7 @@ void givenHttpGetVerb_whenRequestParameterIdentifiesExistingBook_thenShouldRetur void givenHttpGetVerb_whenRequestParameterDoesNotIdentifyAnExistingBook_thenShouldReturnStatusNotFound() throws Exception { // Arrange - String isbn = BookDTOsBuilder.buildOneValid().getIsbn(); + String isbn = "9781484242216"; Mockito .when(service.retrieveByIsbn(anyString())) .thenReturn(null); // New @@ -171,6 +176,30 @@ void givenHttpGetVerb_whenRequestParameterDoesNotIdentifyAnExistingBook_thenShou verify(service, times(1)).retrieveByIsbn(anyString()); } + @Test + void givenHttpGetVerb_whenRequestPathIsBooks_thenShouldReturnStatusOkAndCollectionOfBooks() + throws Exception { + // Arrange + List expected = BookDTOsBuilder.buildManyValid(); + Mockito + .when(service.retrieveAll()) + .thenReturn(expected); + MockHttpServletRequestBuilder request = MockMvcRequestBuilders + .get("/books"); + // Act + MockHttpServletResponse response = mockMvc + .perform(request) + .andReturn() + .getResponse(); + response.setContentType("application/json;charset=UTF-8"); + String content = response.getContentAsString(); + List actual = new ObjectMapper().readValue(content, new TypeReference>() {}); + // Assert + assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value()); + assertThat(actual).usingRecursiveComparison().isEqualTo(expected); + verify(service, times(1)).retrieveAll(); + } + /* -------------------------------------------------------------------------------------------- * HTTP PUT * ----------------------------------------------------------------------------------------- */ diff --git a/src/test/java/ar/com/nanotaboada/java/samples/spring/boot/test/services/BooksServiceTests.java b/src/test/java/ar/com/nanotaboada/java/samples/spring/boot/test/services/BooksServiceTests.java index d3e71d0..87b9678 100644 --- a/src/test/java/ar/com/nanotaboada/java/samples/spring/boot/test/services/BooksServiceTests.java +++ b/src/test/java/ar/com/nanotaboada/java/samples/spring/boot/test/services/BooksServiceTests.java @@ -8,6 +8,7 @@ import static org.mockito.Mockito.verify; import java.util.HashSet; +import java.util.List; import java.util.Optional; import java.util.Set; @@ -40,7 +41,7 @@ public class BooksServiceTests { @Mock private Validator validator; - + @Mock private ModelMapper mapper; @@ -85,7 +86,7 @@ void givenCreate_whenBookIsValidButAlreadyExistsInRepository_thenShouldNeverSave boolean result = false; BookDTO bookDTO = BookDTOsBuilder.buildOneValid(); Book book = BooksBuilder.buildOneValid(); - Set> errors = new HashSet>(); // isEmpty(); + Set> errors = new HashSet>(); Mockito .when(mapper.map(bookDTO, Book.class)) .thenReturn(book); @@ -99,6 +100,7 @@ void givenCreate_whenBookIsValidButAlreadyExistsInRepository_thenShouldNeverSave result = service.create(bookDTO); // Assert verify(mapper, times(1)).map(bookDTO, Book.class); + assertThat(errors).isEmpty(); verify(repository, never()).save(any(Book.class)); assertThat(result).isFalse(); } @@ -109,7 +111,7 @@ void givenCreate_whenBookIsValidAndDoesNotExistInRepository_thenShouldSaveBookIn boolean result = false; BookDTO bookDTO = BookDTOsBuilder.buildOneValid(); Book book = BooksBuilder.buildOneValid(); - Set> errors = new HashSet>(); // isEmpty(); + Set> errors = new HashSet>(); Mockito .when(mapper.map(bookDTO, Book.class)) .thenReturn(book); @@ -123,6 +125,7 @@ void givenCreate_whenBookIsValidAndDoesNotExistInRepository_thenShouldSaveBookIn result = service.create(bookDTO); // Assert verify(mapper, times(1)).map(bookDTO, Book.class); + assertThat(errors).isEmpty(); verify(repository, times(1)).save(any(Book.class)); assertThat(result).isTrue(); } @@ -134,37 +137,60 @@ void givenCreate_whenBookIsValidAndDoesNotExistInRepository_thenShouldSaveBookIn @Test void givenRetrieveByIsbn_whenIsbnIsFoundInRepository_thenShouldReturnBook() { // Arrange - BookDTO expected = BookDTOsBuilder.buildOneValid(); - Book existing = BooksBuilder.buildOneValid(); + BookDTO bookDTO = BookDTOsBuilder.buildOneValid(); + Book book = BooksBuilder.buildOneValid(); Mockito .when(repository.findByIsbn(anyString())) - .thenReturn(Optional.of(existing)); + .thenReturn(Optional.of(book)); Mockito - .when(mapper.map(existing, BookDTO.class)) - .thenReturn(expected); + .when(mapper.map(book, BookDTO.class)) + .thenReturn(bookDTO); // Act - BookDTO actual = service.retrieveByIsbn(expected.getIsbn()); + BookDTO result = service.retrieveByIsbn(bookDTO.getIsbn()); // Assert - verify(mapper, times(1)).map(existing, BookDTO.class); - assertThat(actual).usingRecursiveComparison().isEqualTo(expected); + verify(mapper, times(1)).map(book, BookDTO.class); + assertThat(result).usingRecursiveComparison().isEqualTo(bookDTO); verify(repository, times(1)).findByIsbn(anyString()); } @Test void givenRetrieveByIsbn_whenIsbnIsNotFoundInRepository_thenShouldReturnNull() { // Arrange - BookDTO expected = BookDTOsBuilder.buildOneValid(); + String isbn = "9781484242216"; Mockito .when(repository.findByIsbn(anyString())) .thenReturn(Optional.empty()); // Act - BookDTO actual = service.retrieveByIsbn(expected.getIsbn()); + BookDTO result = service.retrieveByIsbn(isbn); // Assert - assertThat(actual).isNull(); + assertThat(result).isNull(); verify(mapper, never()).map(any(Book.class), any(BookDTO.class)); verify(repository, times(1)).findByIsbn(anyString()); } + @Test + void givenRetrieveAll_whenRepositoryHasCollectionOfBooks_thenShouldReturnAllBooks() { + // Arrange + List expected = BookDTOsBuilder.buildManyValid(); + List existing = BooksBuilder.buildManyValid(); + Mockito + .when(repository.findAll()) + .thenReturn(existing); + for (int index = 0; index < existing.size(); index++) { + Mockito + .when(mapper.map(existing.get(index), BookDTO.class)) + .thenReturn(expected.get(index)); + } + // Act + List actual = service.retrieveAll(); + // Assert + assertThat(actual).usingRecursiveComparison().isEqualTo(expected); + for (Book book : existing) { + verify(mapper, times(1)).map(book, BookDTO.class); + } + verify(repository, times(1)).findAll(); + } + /* -------------------------------------------------------------------------------------------- * Update * ----------------------------------------------------------------------------------------- */ @@ -203,7 +229,7 @@ void givenUpdate_whenBookIsValidAndExistInRepository_thenShouldSaveBookIntoRepos boolean result = false; BookDTO bookDTO = BookDTOsBuilder.buildOneValid(); Book book = BooksBuilder.buildOneValid(); - Set> errors = new HashSet>(); // isEmpty(); + Set> errors = new HashSet>(); Mockito .when(mapper.map(bookDTO, Book.class)) .thenReturn(book); @@ -217,6 +243,7 @@ void givenUpdate_whenBookIsValidAndExistInRepository_thenShouldSaveBookIntoRepos result = service.update(bookDTO); // Assert verify(mapper, times(1)).map(bookDTO, Book.class); + assertThat(errors).isEmpty(); verify(repository, times(1)).save(any(Book.class)); assertThat(result).isTrue(); } @@ -227,7 +254,7 @@ void givenUpdate_whenBookIsValidButDoesNotExistInRepository_thenShouldNeverSaveB boolean result = false; BookDTO bookDTO = BookDTOsBuilder.buildOneValid(); Book book = BooksBuilder.buildOneValid(); - Set> errors = new HashSet>(); // isEmpty(); + Set> errors = new HashSet>(); Mockito .when(mapper.map(bookDTO, Book.class)) .thenReturn(book); @@ -241,6 +268,7 @@ void givenUpdate_whenBookIsValidButDoesNotExistInRepository_thenShouldNeverSaveB result = service.update(bookDTO); // Assert verify(mapper, times(1)).map(bookDTO, Book.class); + assertThat(errors).isEmpty(); verify(repository, never()).save(any(Book.class)); assertThat(result).isFalse(); }