From 891bf5b9b10c9fb385c58ee143724912dcb810c3 Mon Sep 17 00:00:00 2001 From: Andrii Honchar Date: Sat, 3 Jan 2026 20:19:13 +0200 Subject: [PATCH 1/8] added configuration file for custom container and application properties to test section --- pom.xml | 25 ++++++++++++++ .../springm/store/config/CustomContainer.java | 33 +++++++++++++++++++ src/test/resources/application.properties | 11 ++----- 3 files changed, 61 insertions(+), 8 deletions(-) create mode 100644 src/test/java/com/springm/store/config/CustomContainer.java diff --git a/pom.xml b/pom.xml index f7c1ebe..e94c47e 100644 --- a/pom.xml +++ b/pom.xml @@ -24,6 +24,7 @@ checkstyle.xml 1.5.5.Final 0.2.0 + 1.21.3 @@ -147,8 +148,32 @@ spring-boot-docker-compose + + org.testcontainers + junit-jupiter + test + + + + org.testcontainers + mysql + test + + + + + + org.testcontainers + testcontainers-bom + ${testcontainers.version} + pom + import + + + + diff --git a/src/test/java/com/springm/store/config/CustomContainer.java b/src/test/java/com/springm/store/config/CustomContainer.java new file mode 100644 index 0000000..227edba --- /dev/null +++ b/src/test/java/com/springm/store/config/CustomContainer.java @@ -0,0 +1,33 @@ +package com.springm.store.config; + +import org.testcontainers.containers.MySQLContainer; + +public class CustomContainer extends MySQLContainer { + private static final String DB_IMAGE = "mysql:9.5.0"; + + private static CustomContainer container; + + private CustomContainer() { + super(DB_IMAGE); + } + + public static synchronized CustomContainer getInstance() { + if (container == null) { + container = new CustomContainer(); + } + return container; + } + + @Override + public void start() { + super.start(); + System.setProperty("TEST_DB_URL", container.getJdbcUrl()); + System.setProperty("TEST_DB_USERNAME", container.getUsername()); + System.setProperty("TEST_DB_PASSWORD", container.getPassword()); + } + + @Override + public void stop() { + super.stop(); + } +} diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties index 6ad9bb5..e3221ed 100644 --- a/src/test/resources/application.properties +++ b/src/test/resources/application.properties @@ -1,8 +1,3 @@ -spring.datasource.url=jdbc:h2:mem:testdb -spring.datasource.driverClassName=org.h2.Driver -spring.datasource.username=sa -spring.datasource.password=password -spring.jpa.database-platform=org.hibernate.dialect.H2Dialect - -jwt.expiration=500000 -jwt.secret=imustspendmoretimeonmateacademytillendofthe2025 +spring.datasource.url=jdbc:tc:mysql:9.5.0:///book_store_test +spring.datasource.username=test +spring.datasource.password=test \ No newline at end of file From ae26a47c04699c69f0c940ee29382c018b07932b Mon Sep 17 00:00:00 2001 From: Andrii Honchar Date: Wed, 7 Jan 2026 12:11:10 +0200 Subject: [PATCH 2/8] all tests for BookService --- pom.xml | 4 +- .../store/repository/BookRepositoryTest.java | 70 +++++++ .../store/service/BookServiceTest.java | 190 ++++++++++++++++++ src/test/resources/application-test.yml | 4 + src/test/resources/application.properties | 8 +- .../books/add-two-items-to-books-table.sql | 2 + .../books/delete-items-from-books-table.sql | 1 + 7 files changed, 275 insertions(+), 4 deletions(-) create mode 100644 src/test/java/com/springm/store/repository/BookRepositoryTest.java create mode 100644 src/test/java/com/springm/store/service/BookServiceTest.java create mode 100644 src/test/resources/application-test.yml create mode 100644 src/test/resources/database/books/add-two-items-to-books-table.sql create mode 100644 src/test/resources/database/books/delete-items-from-books-table.sql diff --git a/pom.xml b/pom.xml index e94c47e..434e501 100644 --- a/pom.xml +++ b/pom.xml @@ -202,8 +202,8 @@ org.apache.maven.plugins maven-compiler-plugin - ${java.version} - ${java.version} + 19 + 19 org.projectlombok diff --git a/src/test/java/com/springm/store/repository/BookRepositoryTest.java b/src/test/java/com/springm/store/repository/BookRepositoryTest.java new file mode 100644 index 0000000..522e114 --- /dev/null +++ b/src/test/java/com/springm/store/repository/BookRepositoryTest.java @@ -0,0 +1,70 @@ +package com.springm.store.repository; + +import com.springm.store.model.Book; +import com.springm.store.model.Category; +import com.springm.store.repository.book.BookRepository; +import com.springm.store.repository.category.CategoryRepository; +import java.math.BigDecimal; +import java.util.List; +import java.util.Set; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.testcontainers.junit.jupiter.Testcontainers; + +@DataJpaTest +@Testcontainers +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +class BookRepositoryTest { + + @Autowired + private BookRepository bookRepository; + + @Autowired + private CategoryRepository categoryRepository; + + @Test + @DisplayName("Find all books that belongs to category with ID: 1") + void findAllByCategoryId_EqualsOne_ReturnsListWithOneBook() { + Category category = new Category(); + category.setName("Fantastic"); + category.setDescription("Fantastic books"); + categoryRepository.save(category); + + Book book = new Book(); + book.setTitle("Harry Potter"); + book.setAuthor("J. K. Rowling"); + book.setPrice(BigDecimal.TEN); + book.setIsbn("978-0547928213"); + book.setDescription("Such a good book about a boy that survived"); + book.setCoverImage("harryPotter.png"); + book.setCategories(Set.of(category)); + bookRepository.save(book); + + List actual = bookRepository.findAllByCategories_Id(1L); + + Assertions.assertEquals(1, actual.size()); + } + + @Test + @DisplayName("Returns empty list, when tries to find by non-existing category.") + void findAllByCategoryId_EqualsNonExistingId_ReturnsEmptyList() { + Book book = new Book(); + book.setTitle("Harry Potter"); + book.setAuthor("J. K. Rowling"); + book.setPrice(BigDecimal.TEN); + book.setIsbn("978-0547928213"); + book.setDescription("Such a good book about a boy that survived"); + book.setCoverImage("harryPotter.png"); + book.setCategories(Set.of()); + bookRepository.save(book); + + List actual = bookRepository.findAllByCategories_Id(2L); + + Assertions.assertEquals(0, actual.size()); + } + +} diff --git a/src/test/java/com/springm/store/service/BookServiceTest.java b/src/test/java/com/springm/store/service/BookServiceTest.java new file mode 100644 index 0000000..c23ac9d --- /dev/null +++ b/src/test/java/com/springm/store/service/BookServiceTest.java @@ -0,0 +1,190 @@ +package com.springm.store.service; + +import com.springm.store.dto.book.BookDto; +import com.springm.store.dto.book.CreateBookRequestDto; +import com.springm.store.mapper.BookMapper; +import com.springm.store.model.Book; +import com.springm.store.model.Category; +import com.springm.store.repository.book.BookRepository; +import com.springm.store.repository.book.BookSpecificationBuilder; +import com.springm.store.repository.category.CategoryRepository; +import com.springm.store.service.impl.BookServiceImpl; +import java.math.BigDecimal; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +import org.testcontainers.junit.jupiter.Testcontainers; + +@SpringBootTest +@Testcontainers +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +class BookServiceTest { + @Autowired + private BookServiceImpl bookService; + + @MockitoBean + private BookRepository bookRepository; + + @MockitoBean + private CategoryRepository categoryRepository; + + @MockitoBean + private BookMapper bookMapper; + + @MockitoBean + private BookSpecificationBuilder bookSpecificationBuilder; + + @Test + @DisplayName("Save book with valid input") + void save_ValidInput_Success() { + Category category = new Category(); + category.setId(1L); + category.setName("Poetry"); + + Mockito.when(categoryRepository.findById(1L)) + .thenReturn(Optional.of(category)); + + CreateBookRequestDto requestDto = new CreateBookRequestDto(); + requestDto.setTitle("Kobzar"); + requestDto.setAuthor("Taras Shevchenko"); + requestDto.setPrice(BigDecimal.valueOf(24)); + requestDto.setCategoryIds(Set.of(1L)); + + Book bookEntity = new Book(); + bookEntity.setTitle("Kobzar"); + bookEntity.setAuthor("Taras Shevchenko"); + bookEntity.setPrice(BigDecimal.valueOf(24)); + + BookDto bookDto = new BookDto(); + bookDto.setTitle("Kobzar"); + bookDto.setAuthor("Taras Shevchenko"); + bookDto.setPrice(BigDecimal.valueOf(24)); + bookDto.setCategoryIds(Set.of(1L)); + + Mockito.when(bookMapper.toModel(Mockito.any(CreateBookRequestDto.class))) + .thenReturn(bookEntity); + + Mockito.when(bookRepository.save(Mockito.any(Book.class))) + .thenReturn(bookEntity); + + Mockito.when(bookMapper.toDto(Mockito.any(Book.class))) + .thenReturn(bookDto); + BookDto actual = bookService.save(requestDto); + + Assertions.assertNotNull(actual); + Assertions.assertEquals("Kobzar", actual.getTitle()); + Assertions.assertEquals("Taras Shevchenko", actual.getAuthor()); + Assertions.assertEquals(BigDecimal.valueOf(24), actual.getPrice()); + + } + + @Test + @DisplayName("Find book by id, returns BookDto") + void findById_ValidInput_Success() { + + Book bookEntity = new Book(); + bookEntity.setId(1L); + bookEntity.setTitle("Kobzar"); + bookEntity.setAuthor("Taras Shevchenko"); + + BookDto bookDto = new BookDto(); + bookDto.setId(1L); + bookDto.setTitle("Kobzar"); + bookDto.setAuthor("Taras Shevchenko"); + + Mockito.when(bookRepository.findById(1L)) + .thenReturn(Optional.of(bookEntity)); + + Mockito.when(bookMapper.toDto(bookEntity)) + .thenReturn(bookDto); + + BookDto actual = bookService.findById(1L); + + Assertions.assertNotNull(actual); + Assertions.assertEquals(1L, actual.getId()); + Assertions.assertEquals("Kobzar", actual.getTitle()); + Assertions.assertEquals("Taras Shevchenko", actual.getAuthor()); + } + + @Test + @DisplayName("Find all books") + void findAll_Pageable_ReturnsAllBooks() { + Pageable pageable = PageRequest.of(0, 1); + + Book book = new Book(); + book.setId(1L); + + Page bookPage = + new PageImpl<>(List.of(book), pageable, 2); + + Mockito.when(bookRepository.findAll(pageable)) + .thenReturn(bookPage); + + Mockito.when(bookMapper.toDto(book)) + .thenReturn(new BookDto()); + + Page result = bookService.findAll(pageable); + + Assertions.assertEquals(1, result.getContent().size()); + Assertions.assertEquals(2, result.getTotalElements()); + } + + @Test + @DisplayName("Updates book with valid id and input dto") + void updateBookById_ValidInput_Success() { + Book bookEntity = new Book(); + bookEntity.setId(1L); + bookEntity.setTitle("Harry Potter"); + bookEntity.setAuthor("J. K. Rowling"); + + + Mockito.when(bookRepository.findById(1L)) + .thenReturn(Optional.of(bookEntity)); + + CreateBookRequestDto changedBookDto = new CreateBookRequestDto(); + changedBookDto.setTitle("The World of Ice and Fire"); + changedBookDto.setAuthor("George R. R. Martin"); + + + BookDto bookDto = new BookDto(); + bookDto.setId(1L); + bookDto.setTitle("The World of Ice and Fire"); + bookDto.setAuthor("George R. R. Martin"); + + + Mockito.when(bookMapper.toDto(bookEntity)) + .thenReturn(bookDto); + + BookDto actual = bookService.updateBookById(1L, changedBookDto); + + Assertions.assertEquals(1L, actual.getId()); + Assertions.assertEquals("The World of Ice and Fire", actual.getTitle()); + Assertions.assertEquals("George R. R. Martin", actual.getAuthor()); + } + + @Test + @DisplayName("Deletes books with valid id") + void deleteBookById_ValidInput_Success() { + Mockito.doNothing() + .when(bookRepository) + .deleteById(1L); + + bookService.deleteBookById(1L); + + Mockito.verify(bookRepository) + .deleteById(1L); + } + +} diff --git a/src/test/resources/application-test.yml b/src/test/resources/application-test.yml new file mode 100644 index 0000000..4446ada --- /dev/null +++ b/src/test/resources/application-test.yml @@ -0,0 +1,4 @@ +spring: + autoconfigure: + exclude: + - org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties index e3221ed..60e01a1 100644 --- a/src/test/resources/application.properties +++ b/src/test/resources/application.properties @@ -1,3 +1,7 @@ -spring.datasource.url=jdbc:tc:mysql:9.5.0:///book_store_test +spring.datasource.url=jdbc:tc:mysql:8.0:///test spring.datasource.username=test -spring.datasource.password=test \ No newline at end of file +spring.datasource.password=test +spring.jpa.hibernate.ddl-auto=create + +jwt.expiration=36000 +jwt.secret=sdawaedsadwad12312dsadczxczu6t@312 diff --git a/src/test/resources/database/books/add-two-items-to-books-table.sql b/src/test/resources/database/books/add-two-items-to-books-table.sql new file mode 100644 index 0000000..67a638a --- /dev/null +++ b/src/test/resources/database/books/add-two-items-to-books-table.sql @@ -0,0 +1,2 @@ +insert into books (id, title, author, isbn, price) values (1, 'Kobzar', 'Taras Shevchenko', '978-1909156548', 49.99); +insert into books (id, title, author, isbn, price) values (2, 'Harry Potter', 'J. K. Rowling', '978-1408855652', 39.99); \ No newline at end of file diff --git a/src/test/resources/database/books/delete-items-from-books-table.sql b/src/test/resources/database/books/delete-items-from-books-table.sql new file mode 100644 index 0000000..2a9c0db --- /dev/null +++ b/src/test/resources/database/books/delete-items-from-books-table.sql @@ -0,0 +1 @@ +delete from books; \ No newline at end of file From ceb249b0444710f0fb066d9adf55a0e68847e407 Mon Sep 17 00:00:00 2001 From: Andrii Honchar Date: Wed, 7 Jan 2026 13:50:17 +0200 Subject: [PATCH 3/8] added CategoryServiceTest --- .../store/controller/CategoryController.java | 2 +- .../store/service/CategoryService.java | 2 +- .../service/impl/CategoryServiceImpl.java | 6 +- .../store/service/BookServiceTest.java | 29 +++-- .../store/service/CategoryServiceTest.java | 122 ++++++++++++++++++ src/test/resources/application.properties | 2 +- 6 files changed, 143 insertions(+), 20 deletions(-) create mode 100644 src/test/java/com/springm/store/service/CategoryServiceTest.java diff --git a/src/main/java/com/springm/store/controller/CategoryController.java b/src/main/java/com/springm/store/controller/CategoryController.java index b15ebd5..6715dd4 100644 --- a/src/main/java/com/springm/store/controller/CategoryController.java +++ b/src/main/java/com/springm/store/controller/CategoryController.java @@ -56,7 +56,7 @@ public ResponseEntity> getAll() { @Operation(summary = "Get a category by ID", description = "Get a category with specified ID") public ResponseEntity getCategoryById(@PathVariable Long id) { return new ResponseEntity( - categoryService.getById(id), + categoryService.findById(id), HttpStatus.OK ); } diff --git a/src/main/java/com/springm/store/service/CategoryService.java b/src/main/java/com/springm/store/service/CategoryService.java index 9529d59..3779cda 100644 --- a/src/main/java/com/springm/store/service/CategoryService.java +++ b/src/main/java/com/springm/store/service/CategoryService.java @@ -8,7 +8,7 @@ public interface CategoryService { List findAll(); - CategoryDto getById(Long id); + CategoryDto findById(Long id); CategoryDto save(CreateCategoryRequestDto createCategoryRequestDto); diff --git a/src/main/java/com/springm/store/service/impl/CategoryServiceImpl.java b/src/main/java/com/springm/store/service/impl/CategoryServiceImpl.java index 7550201..ecf2d67 100644 --- a/src/main/java/com/springm/store/service/impl/CategoryServiceImpl.java +++ b/src/main/java/com/springm/store/service/impl/CategoryServiceImpl.java @@ -31,7 +31,7 @@ public List findAll() { } @Override - public CategoryDto getById(Long id) { + public CategoryDto findById(Long id) { Category category = categoryRepository.findById(id) .orElseThrow( () -> new EntityNotFoundException("Category with id [" @@ -50,8 +50,8 @@ public CategoryDto save(CreateCategoryRequestDto createCategoryRequestDto) { public CategoryDto update(Long id, CreateCategoryRequestDto changedCategoryDto) { Category existingCategory = categoryRepository.findById(id) .orElseThrow( - () -> new EntityNotFoundException("Category with id: " - + id + " not found!")); + () -> new EntityNotFoundException("Category with id [" + + id + "] not found!")); categoryMapper.updateCategoryFromDto(changedCategoryDto, existingCategory); categoryRepository.save(existingCategory); diff --git a/src/test/java/com/springm/store/service/BookServiceTest.java b/src/test/java/com/springm/store/service/BookServiceTest.java index c23ac9d..81c57c3 100644 --- a/src/test/java/com/springm/store/service/BookServiceTest.java +++ b/src/test/java/com/springm/store/service/BookServiceTest.java @@ -13,7 +13,6 @@ import java.util.List; import java.util.Optional; import java.util.Set; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -26,6 +25,8 @@ import org.springframework.data.domain.Pageable; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.testcontainers.junit.jupiter.Testcontainers; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; @SpringBootTest @Testcontainers @@ -83,10 +84,10 @@ void save_ValidInput_Success() { .thenReturn(bookDto); BookDto actual = bookService.save(requestDto); - Assertions.assertNotNull(actual); - Assertions.assertEquals("Kobzar", actual.getTitle()); - Assertions.assertEquals("Taras Shevchenko", actual.getAuthor()); - Assertions.assertEquals(BigDecimal.valueOf(24), actual.getPrice()); + assertNotNull(actual); + assertEquals("Kobzar", actual.getTitle()); + assertEquals("Taras Shevchenko", actual.getAuthor()); + assertEquals(BigDecimal.valueOf(24), actual.getPrice()); } @@ -112,10 +113,10 @@ void findById_ValidInput_Success() { BookDto actual = bookService.findById(1L); - Assertions.assertNotNull(actual); - Assertions.assertEquals(1L, actual.getId()); - Assertions.assertEquals("Kobzar", actual.getTitle()); - Assertions.assertEquals("Taras Shevchenko", actual.getAuthor()); + assertNotNull(actual); + assertEquals(1L, actual.getId()); + assertEquals("Kobzar", actual.getTitle()); + assertEquals("Taras Shevchenko", actual.getAuthor()); } @Test @@ -137,8 +138,8 @@ void findAll_Pageable_ReturnsAllBooks() { Page result = bookService.findAll(pageable); - Assertions.assertEquals(1, result.getContent().size()); - Assertions.assertEquals(2, result.getTotalElements()); + assertEquals(1, result.getContent().size()); + assertEquals(2, result.getTotalElements()); } @Test @@ -169,9 +170,9 @@ void updateBookById_ValidInput_Success() { BookDto actual = bookService.updateBookById(1L, changedBookDto); - Assertions.assertEquals(1L, actual.getId()); - Assertions.assertEquals("The World of Ice and Fire", actual.getTitle()); - Assertions.assertEquals("George R. R. Martin", actual.getAuthor()); + assertEquals(1L, actual.getId()); + assertEquals("The World of Ice and Fire", actual.getTitle()); + assertEquals("George R. R. Martin", actual.getAuthor()); } @Test diff --git a/src/test/java/com/springm/store/service/CategoryServiceTest.java b/src/test/java/com/springm/store/service/CategoryServiceTest.java new file mode 100644 index 0000000..da2168d --- /dev/null +++ b/src/test/java/com/springm/store/service/CategoryServiceTest.java @@ -0,0 +1,122 @@ +package com.springm.store.service; + +import com.springm.store.dto.category.CategoryDto; +import com.springm.store.dto.category.CreateCategoryRequestDto; +import com.springm.store.mapper.CategoryMapper; +import com.springm.store.model.Category; +import com.springm.store.repository.category.CategoryRepository; +import com.springm.store.service.impl.CategoryServiceImpl; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +import org.testcontainers.junit.jupiter.Testcontainers; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@SpringBootTest +@Testcontainers +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +class CategoryServiceTest { + @Autowired + private CategoryServiceImpl categoryService; + + @Autowired + private CategoryMapper categoryMapper; + + @MockitoBean + private CategoryRepository categoryRepository; + + @Test + @DisplayName("Saves category with valid input") + void save_ValidInput_Success() { + CreateCategoryRequestDto categoryRequestDto = new CreateCategoryRequestDto(); + categoryRequestDto.setName("Poetry"); + + Category category = new Category(); + category.setId(0L); + category.setName("Poetry"); + + Mockito.when(categoryRepository.save(Mockito.any(Category.class))).thenReturn(category); + + CategoryDto actual = categoryService.save(categoryRequestDto); + + assertNotNull(actual); + assertEquals(0L, actual.getId()); + assertEquals("Poetry", actual.getName()); + } + + @Test + @DisplayName("Find category by id, returns CategoryDto") + void findById_ValidInput_Success() { + Category category = new Category(); + category.setId(1L); + category.setName("Fiction"); + + Mockito.when(categoryRepository.findById(1L)).thenReturn(Optional.of(category)); + + CategoryDto actual = categoryService.findById(1L); + + assertNotNull(actual); + assertEquals(1L, actual.getId()); + assertEquals("Fiction", actual.getName()); + } + + @Test + @DisplayName("Returns all categories that created") + void findAll_ReturnsAllCategories() { + Category category1 = new Category(); + category1.setId(1L); + category1.setName("Poetry"); + + Category category2 = new Category(); + category2.setId(2L); + category2.setName("Fiction"); + + List categories = List.of(category1, category2); + + Mockito.when(categoryRepository.findAll()).thenReturn(categories); + + + List actualList = categoryService.findAll(); + + assertEquals(2, actualList.size()); + assertEquals("Poetry", actualList.get(0).getName()); + assertEquals("Fiction", actualList.get(1).getName()); + } + + @Test + @DisplayName("Receives category id that must be updated and new name and description for replace") + void update_ValidInput_Success() { + Category category = new Category(); + category.setId(1L); + category.setName("Fiction"); + + Mockito.when(categoryRepository.findById(1L)).thenReturn(Optional.of(category)); + + CreateCategoryRequestDto categoryRequestDto = new CreateCategoryRequestDto(); + categoryRequestDto.setName("History"); + + CategoryDto actual = categoryService.update(1L, categoryRequestDto); + + assertNotNull(actual); + assertEquals(1L, actual.getId()); + assertEquals("History", actual.getName()); + } + + @Test + @DisplayName("Deletes category by id") + void deleteById_ValidInput_Success() { + Mockito.doNothing().when(categoryRepository).deleteById(1L); + + categoryService.deleteById(1L); + + Mockito.verify(categoryRepository).deleteById(1L); + } + +} diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties index 60e01a1..3c86135 100644 --- a/src/test/resources/application.properties +++ b/src/test/resources/application.properties @@ -1,7 +1,7 @@ spring.datasource.url=jdbc:tc:mysql:8.0:///test spring.datasource.username=test spring.datasource.password=test -spring.jpa.hibernate.ddl-auto=create +spring.jpa.hibernate.ddl-auto=create-drop jwt.expiration=36000 jwt.secret=sdawaedsadwad12312dsadczxczu6t@312 From 22cb76f5316018804eb2c4ffcb96e134adb7077a Mon Sep 17 00:00:00 2001 From: Andrii Honchar Date: Thu, 8 Jan 2026 12:03:45 +0200 Subject: [PATCH 4/8] added BookControllerTest and decreased minimum title length for books --- pom.xml | 24 +++ .../store/validation/book/TitleValidator.java | 2 +- .../store/controller/BookControllerTest.java | 172 ++++++++++++++++++ .../store/service/BookServiceTest.java | 11 +- .../store/service/CategoryServiceTest.java | 3 - .../books/add-items-to-categories-table.sql | 2 + .../books/add-three-items-to-books-table.sql | 3 + .../books/add-two-items-to-books-table.sql | 2 - .../books/assign-categories-for-books.sql | 5 + .../database/books/clear-all-tables.sql | 5 + .../books/delete-items-from-books-table.sql | 1 - 11 files changed, 217 insertions(+), 13 deletions(-) create mode 100644 src/test/java/com/springm/store/controller/BookControllerTest.java create mode 100644 src/test/resources/database/books/add-items-to-categories-table.sql create mode 100644 src/test/resources/database/books/add-three-items-to-books-table.sql delete mode 100644 src/test/resources/database/books/add-two-items-to-books-table.sql create mode 100644 src/test/resources/database/books/assign-categories-for-books.sql create mode 100644 src/test/resources/database/books/clear-all-tables.sql delete mode 100644 src/test/resources/database/books/delete-items-from-books-table.sql diff --git a/pom.xml b/pom.xml index 434e501..0c8ef70 100644 --- a/pom.xml +++ b/pom.xml @@ -160,6 +160,19 @@ test + + org.springframework.security + spring-security-test + 7.0.2 + test + + + + org.mockito + mockito-core + 5.20.0 + test + @@ -234,6 +247,17 @@ liquibase-maven-plugin ${liquibase.version} + + + org.apache.maven.plugins + maven-surefire-plugin + 3.2.5 + + + -javaagent:${settings.localRepository}/org/mockito/mockito-core/5.20.0/mockito-core-5.20.0.jar + + + diff --git a/src/main/java/com/springm/store/validation/book/TitleValidator.java b/src/main/java/com/springm/store/validation/book/TitleValidator.java index d490208..fbd33ba 100644 --- a/src/main/java/com/springm/store/validation/book/TitleValidator.java +++ b/src/main/java/com/springm/store/validation/book/TitleValidator.java @@ -4,7 +4,7 @@ import jakarta.validation.ConstraintValidatorContext; public class TitleValidator implements ConstraintValidator { - private static final int MINIMUM_TITLE_LENGTH = 8; + private static final int MINIMUM_TITLE_LENGTH = 4; @Override public boolean isValid(String title, ConstraintValidatorContext constraintValidatorContext) { diff --git a/src/test/java/com/springm/store/controller/BookControllerTest.java b/src/test/java/com/springm/store/controller/BookControllerTest.java new file mode 100644 index 0000000..e35f091 --- /dev/null +++ b/src/test/java/com/springm/store/controller/BookControllerTest.java @@ -0,0 +1,172 @@ +package com.springm.store.controller; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.springm.store.dto.book.BookDto; +import com.springm.store.dto.book.CreateBookRequestDto; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.testcontainers.shaded.org.apache.commons.lang3.builder.EqualsBuilder; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@AutoConfigureMockMvc +@Sql(scripts = "classpath:database/books/add-items-to-categories-table.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) +@Sql(scripts = "classpath:database/books/add-three-items-to-books-table.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) +@Sql(scripts = "classpath:database/books/assign-categories-for-books.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) +@Sql(scripts = "classpath:database/books/clear-all-tables.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) +class BookControllerTest { + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @WithMockUser(username = "admin", roles = {"ADMIN"}) + @Test + @DisplayName("Add a new book") + void createBook_ValidRequestDto_Success() throws Exception { + + CreateBookRequestDto bookRequestDto = new CreateBookRequestDto(); + bookRequestDto.setTitle("Dune"); + bookRequestDto.setAuthor("Frank Gerbert"); + bookRequestDto.setIsbn("978-0316597011"); + bookRequestDto.setPrice(BigDecimal.valueOf(35.32)); + bookRequestDto.setCategoryIds(Set.of(1L)); + + BookDto expected = new BookDto(); + expected.setTitle(bookRequestDto.getTitle()); + expected.setAuthor(bookRequestDto.getAuthor()); + expected.setIsbn(bookRequestDto.getIsbn()); + expected.setPrice(bookRequestDto.getPrice()); + expected.setCategoryIds(bookRequestDto.getCategoryIds()); + + String jsonRequest = objectMapper.writeValueAsString(bookRequestDto); + + MvcResult result = mockMvc.perform( + post("/books") + .content(jsonRequest) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + ) + .andExpect(status().isCreated()) + .andReturn(); + + BookDto actual = objectMapper.readValue(result.getResponse().getContentAsString(), BookDto.class); + + assertTrue( + EqualsBuilder.reflectionEquals(expected, actual, "id") + ); + } + + @WithMockUser(username = "admin", roles = {"ADMIN"}) + @Test + @DisplayName("Find all available books") + void findAll_ValidItems_ShouldReturnAllBooks() throws Exception { + MvcResult result = mockMvc.perform(get("/books") + .param("page", "0") + .param("size", "4") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + String jsonResponse = result.getResponse().getContentAsString(); + assertTrue(jsonResponse.contains("Kobzar")); + assertTrue(jsonResponse.contains("Harry Potter")); + assertTrue(jsonResponse.contains("The Witcher")); + + Map responseMap = objectMapper.readValue(jsonResponse, new TypeReference<>() { + }); + Assertions.assertEquals(3, responseMap.get("totalElements")); + Assertions.assertEquals(3, ((List) responseMap.get("content")).size()); + } + + @WithMockUser(username = "admin", roles = {"ADMIN"}) + @Test + @DisplayName("Returns book with right id") + void getBookById_ValidItems_ShouldReturnBook() throws Exception { + MvcResult result = mockMvc.perform( + get("/books/1") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + String jsonResponse = result.getResponse().getContentAsString(); + + assertTrue(jsonResponse.contains("Kobzar")); + assertTrue(jsonResponse.contains("Taras Shevchenko")); + assertTrue(jsonResponse.contains("978-1909156548")); + } + + @WithMockUser(username = "admin", roles = {"ADMIN"}) + @Test + @DisplayName("Updates book by id") + void updateBookById_ValidInput_Success() throws Exception { + CreateBookRequestDto bookRequestDto = new CreateBookRequestDto(); + bookRequestDto.setTitle("The World of Ice and Fire"); + bookRequestDto.setAuthor("George R. R. Martin"); + bookRequestDto.setIsbn("978-0316597101"); + bookRequestDto.setPrice(BigDecimal.valueOf(69.99)); + bookRequestDto.setCategoryIds(Set.of(1L, 2L)); + + String jsonRequest = objectMapper.writeValueAsString(bookRequestDto); + + MvcResult result = mockMvc.perform( + put("/books/2") + .content(jsonRequest) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + BookDto actual = objectMapper.readValue( + result.getResponse().getContentAsString(), + BookDto.class + ); + + BookDto expected = new BookDto(); + expected.setId(2L); + expected.setTitle(bookRequestDto.getTitle()); + expected.setAuthor(bookRequestDto.getAuthor()); + expected.setIsbn(bookRequestDto.getIsbn()); + expected.setPrice(bookRequestDto.getPrice()); + expected.setCategoryIds(bookRequestDto.getCategoryIds()); + + assertNotNull(actual); + assertEquals(expected.getId(), actual.getId()); + assertEquals(expected.getAuthor(), actual.getAuthor()); + assertEquals(expected.getTitle(), actual.getTitle()); + assertEquals(expected.getPrice(), actual.getPrice()); + assertEquals(expected.getCategoryIds(), actual.getCategoryIds()); + } + + @WithMockUser(username = "admin", roles = {"ADMIN"}) + @Test + @DisplayName("Deletes book by id") + void deleteBookById_ValidInput_Success() throws Exception { + mockMvc.perform( + delete("/books/3") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isNoContent()); + } +} diff --git a/src/test/java/com/springm/store/service/BookServiceTest.java b/src/test/java/com/springm/store/service/BookServiceTest.java index 81c57c3..a44ed63 100644 --- a/src/test/java/com/springm/store/service/BookServiceTest.java +++ b/src/test/java/com/springm/store/service/BookServiceTest.java @@ -25,6 +25,7 @@ import org.springframework.data.domain.Pageable; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.shaded.org.apache.commons.lang3.builder.EqualsBuilder; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -84,10 +85,7 @@ void save_ValidInput_Success() { .thenReturn(bookDto); BookDto actual = bookService.save(requestDto); - assertNotNull(actual); - assertEquals("Kobzar", actual.getTitle()); - assertEquals("Taras Shevchenko", actual.getAuthor()); - assertEquals(BigDecimal.valueOf(24), actual.getPrice()); + EqualsBuilder.reflectionEquals(bookEntity, actual, "id"); } @@ -114,7 +112,7 @@ void findById_ValidInput_Success() { BookDto actual = bookService.findById(1L); assertNotNull(actual); - assertEquals(1L, actual.getId()); + assertNotNull(actual.getId()); assertEquals("Kobzar", actual.getTitle()); assertEquals("Taras Shevchenko", actual.getAuthor()); } @@ -170,7 +168,8 @@ void updateBookById_ValidInput_Success() { BookDto actual = bookService.updateBookById(1L, changedBookDto); - assertEquals(1L, actual.getId()); + assertNotNull(actual); + assertNotNull(actual.getId()); assertEquals("The World of Ice and Fire", actual.getTitle()); assertEquals("George R. R. Martin", actual.getAuthor()); } diff --git a/src/test/java/com/springm/store/service/CategoryServiceTest.java b/src/test/java/com/springm/store/service/CategoryServiceTest.java index da2168d..f6b1337 100644 --- a/src/test/java/com/springm/store/service/CategoryServiceTest.java +++ b/src/test/java/com/springm/store/service/CategoryServiceTest.java @@ -47,7 +47,6 @@ void save_ValidInput_Success() { CategoryDto actual = categoryService.save(categoryRequestDto); assertNotNull(actual); - assertEquals(0L, actual.getId()); assertEquals("Poetry", actual.getName()); } @@ -63,7 +62,6 @@ void findById_ValidInput_Success() { CategoryDto actual = categoryService.findById(1L); assertNotNull(actual); - assertEquals(1L, actual.getId()); assertEquals("Fiction", actual.getName()); } @@ -105,7 +103,6 @@ void update_ValidInput_Success() { CategoryDto actual = categoryService.update(1L, categoryRequestDto); assertNotNull(actual); - assertEquals(1L, actual.getId()); assertEquals("History", actual.getName()); } diff --git a/src/test/resources/database/books/add-items-to-categories-table.sql b/src/test/resources/database/books/add-items-to-categories-table.sql new file mode 100644 index 0000000..12050b1 --- /dev/null +++ b/src/test/resources/database/books/add-items-to-categories-table.sql @@ -0,0 +1,2 @@ +insert into categories (id, name, is_deleted) values (1, 'Fantasy', 0); +insert into categories (id, name, is_deleted) values (2, 'Classic', 0); \ No newline at end of file diff --git a/src/test/resources/database/books/add-three-items-to-books-table.sql b/src/test/resources/database/books/add-three-items-to-books-table.sql new file mode 100644 index 0000000..af6a9c4 --- /dev/null +++ b/src/test/resources/database/books/add-three-items-to-books-table.sql @@ -0,0 +1,3 @@ +insert into books (id, title, author, isbn, price, is_deleted) values (1, 'Kobzar', 'Taras Shevchenko', '978-1909156548', 49.99, 0); +insert into books (id, title, author, isbn, price, is_deleted) values (2, 'Harry Potter', 'J. K. Rowling', '978-1408855652', 39.99, 0); +insert into books (id, title, author, isbn, price, is_deleted) values (3, 'The Witcher', 'Andrzej Sapkowski', '978-0316597739', 29.99, 0); diff --git a/src/test/resources/database/books/add-two-items-to-books-table.sql b/src/test/resources/database/books/add-two-items-to-books-table.sql deleted file mode 100644 index 67a638a..0000000 --- a/src/test/resources/database/books/add-two-items-to-books-table.sql +++ /dev/null @@ -1,2 +0,0 @@ -insert into books (id, title, author, isbn, price) values (1, 'Kobzar', 'Taras Shevchenko', '978-1909156548', 49.99); -insert into books (id, title, author, isbn, price) values (2, 'Harry Potter', 'J. K. Rowling', '978-1408855652', 39.99); \ No newline at end of file diff --git a/src/test/resources/database/books/assign-categories-for-books.sql b/src/test/resources/database/books/assign-categories-for-books.sql new file mode 100644 index 0000000..f58b632 --- /dev/null +++ b/src/test/resources/database/books/assign-categories-for-books.sql @@ -0,0 +1,5 @@ +insert into books_categories (book_id, category_id) values (1, 1); +insert into books_categories (book_id, category_id) values (2, 1); +insert into books_categories (book_id, category_id) values (2, 2); +insert into books_categories (book_id, category_id) values (3, 1); +insert into books_categories (book_id, category_id) values (3, 2); diff --git a/src/test/resources/database/books/clear-all-tables.sql b/src/test/resources/database/books/clear-all-tables.sql new file mode 100644 index 0000000..8352479 --- /dev/null +++ b/src/test/resources/database/books/clear-all-tables.sql @@ -0,0 +1,5 @@ +delete from books_categories; + +delete from categories; + +delete from books; diff --git a/src/test/resources/database/books/delete-items-from-books-table.sql b/src/test/resources/database/books/delete-items-from-books-table.sql deleted file mode 100644 index 2a9c0db..0000000 --- a/src/test/resources/database/books/delete-items-from-books-table.sql +++ /dev/null @@ -1 +0,0 @@ -delete from books; \ No newline at end of file From eb648a5cf8ce0629d2fb6ec5fc006c6e3bd86451 Mon Sep 17 00:00:00 2001 From: Andrii Honchar Date: Thu, 8 Jan 2026 12:40:25 +0200 Subject: [PATCH 5/8] added CategoryControllerTest --- .../store/controller/CategoryController.java | 2 +- .../controller/CategoryControllerTest.java | 171 ++++++++++++++++++ .../add-five-items-to-categories-table.sql | 5 + 3 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/springm/store/controller/CategoryControllerTest.java create mode 100644 src/test/resources/database/books/categories/add-five-items-to-categories-table.sql diff --git a/src/main/java/com/springm/store/controller/CategoryController.java b/src/main/java/com/springm/store/controller/CategoryController.java index 6715dd4..9cebb69 100644 --- a/src/main/java/com/springm/store/controller/CategoryController.java +++ b/src/main/java/com/springm/store/controller/CategoryController.java @@ -44,7 +44,7 @@ public ResponseEntity createCategory( @GetMapping @PreAuthorize("hasAnyRole('USER', 'ADMIN')") @Operation(summary = "Get all categories", description = "Fetch all categories") - public ResponseEntity> getAll() { + public ResponseEntity> getAllCategories() { return new ResponseEntity>( categoryService.findAll(), HttpStatus.OK diff --git a/src/test/java/com/springm/store/controller/CategoryControllerTest.java b/src/test/java/com/springm/store/controller/CategoryControllerTest.java new file mode 100644 index 0000000..73b3648 --- /dev/null +++ b/src/test/java/com/springm/store/controller/CategoryControllerTest.java @@ -0,0 +1,171 @@ +package com.springm.store.controller; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.springm.store.dto.category.CategoryDto; +import com.springm.store.dto.category.CreateCategoryRequestDto; +import java.util.List; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.testcontainers.shaded.org.apache.commons.lang3.builder.EqualsBuilder; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@AutoConfigureMockMvc +@WithMockUser(username = "admin", roles = {"ADMIN"}) +@Sql(scripts = "classpath:database/books/categories/add-five-items-to-categories-table.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) +@Sql(scripts = "classpath:database/books/add-three-items-to-books-table.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) +@Sql(scripts = "classpath:database/books/assign-categories-for-books.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) +@Sql(scripts = "classpath:database/books/clear-all-tables.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) +class CategoryControllerTest { + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @Test + @DisplayName("Create category") + void createCategory_ValidInput_Success() throws Exception { + CreateCategoryRequestDto categoryRequestDto = new CreateCategoryRequestDto(); + categoryRequestDto.setName("Novels"); + categoryRequestDto.setDescription("novels"); + + CategoryDto expected = new CategoryDto(); + expected.setName(categoryRequestDto.getName()); + expected.setDescription(categoryRequestDto.getDescription()); + + String jsonRequest = objectMapper.writeValueAsString(categoryRequestDto); + + MvcResult result = mockMvc.perform( + post("/categories") + .content(jsonRequest) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isCreated()) + .andReturn(); + + CategoryDto actual = objectMapper.readValue(result.getResponse().getContentAsString(), CategoryDto.class); + + Assertions.assertTrue(EqualsBuilder.reflectionEquals(expected, actual, "id")); + } + + @Test + @DisplayName("Get all existing categories") + void getAllCategories_ValidItems_ShouldReturnAllCategories() throws Exception { + MvcResult result = mockMvc.perform(get("/categories") + .param("page", "0") + .param("size", "5") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + String jsonResponse = result.getResponse().getContentAsString(); + assertTrue(jsonResponse.contains("Fantasy")); + assertTrue(jsonResponse.contains("Classic")); + assertTrue(jsonResponse.contains("Poetry")); + assertTrue(jsonResponse.contains("History")); + assertTrue(jsonResponse.contains("Fantastic")); + + List categoryDtos = objectMapper.readValue( + jsonResponse, + new TypeReference>() {} + ); + Assertions.assertEquals(5, categoryDtos.size()); + } + + @Test + @DisplayName("Return category by id") + void getCategoryById_ValidId_Success() throws Exception { + MvcResult result = mockMvc.perform( + get("/categories/4") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + String jsonResponse = result.getResponse().getContentAsString(); + + assertTrue(jsonResponse.contains("History")); + } + + @Test + @DisplayName("Update category by id") + void updateCategory_ValidInput_Success() throws Exception { + CreateCategoryRequestDto categoryRequestDto = new CreateCategoryRequestDto(); + categoryRequestDto.setName("Military"); + categoryRequestDto.setName("Category about military things"); + + String jsonRequest = objectMapper.writeValueAsString(categoryRequestDto); + + MvcResult result = mockMvc.perform( + put("/categories/3") + .content(jsonRequest) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isNoContent()) + .andReturn(); + + CategoryDto actual = objectMapper.readValue( + result.getResponse().getContentAsString(), + CategoryDto.class + ); + + CategoryDto expected = new CategoryDto(); + expected.setId(3L); + expected.setName(categoryRequestDto.getName()); + expected.setDescription(categoryRequestDto.getDescription()); + + assertNotNull(actual); + assertEquals(expected.getId(), actual.getId()); + assertEquals(expected.getName(), actual.getName()); + assertEquals(expected.getDescription(), actual.getDescription()); + } + + @Test + @DisplayName("Delete category by id") + void deleteCategoryById_ValidId_Success() throws Exception { + mockMvc.perform( + delete("/categories/2") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isNoContent()); + } + + @Test + @DisplayName("Get all books that belong to specific category") + void getBooksByCategoryId_ValidInput_Success() throws Exception { + MvcResult result = mockMvc.perform( + get("/categories/1/books") + .param("page", "0") + .param("size", "5") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + String jsonResponse = result.getResponse().getContentAsString(); + + List actual = objectMapper.readValue( + jsonResponse, + new TypeReference>() {} + ); + + assertEquals(3, actual.size()); + } + + +} diff --git a/src/test/resources/database/books/categories/add-five-items-to-categories-table.sql b/src/test/resources/database/books/categories/add-five-items-to-categories-table.sql new file mode 100644 index 0000000..9f8a2dc --- /dev/null +++ b/src/test/resources/database/books/categories/add-five-items-to-categories-table.sql @@ -0,0 +1,5 @@ +insert into categories (id, name, is_deleted) values (1, 'Fantasy', 0); +insert into categories (id, name, is_deleted) values (2, 'Classic', 0); +insert into categories (id, name, is_deleted) values (3, 'Poetry', 0); +insert into categories (id, name, is_deleted) values (4, 'History', 0); +insert into categories (id, name, is_deleted) values (5, 'Fantastic', 0); \ No newline at end of file From 44bd91214f6a759845e9d059fac76cdcc2e13d74 Mon Sep 17 00:00:00 2001 From: Andrii Honchar Date: Thu, 8 Jan 2026 12:44:34 +0200 Subject: [PATCH 6/8] little fixes --- .../com/springm/store/controller/BookControllerTest.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/test/java/com/springm/store/controller/BookControllerTest.java b/src/test/java/com/springm/store/controller/BookControllerTest.java index e35f091..06fcef3 100644 --- a/src/test/java/com/springm/store/controller/BookControllerTest.java +++ b/src/test/java/com/springm/store/controller/BookControllerTest.java @@ -31,6 +31,7 @@ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @AutoConfigureMockMvc +@WithMockUser(username = "admin", roles = {"ADMIN"}) @Sql(scripts = "classpath:database/books/add-items-to-categories-table.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = "classpath:database/books/add-three-items-to-books-table.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = "classpath:database/books/assign-categories-for-books.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @@ -42,7 +43,6 @@ class BookControllerTest { @Autowired private ObjectMapper objectMapper; - @WithMockUser(username = "admin", roles = {"ADMIN"}) @Test @DisplayName("Add a new book") void createBook_ValidRequestDto_Success() throws Exception { @@ -79,7 +79,6 @@ void createBook_ValidRequestDto_Success() throws Exception { ); } - @WithMockUser(username = "admin", roles = {"ADMIN"}) @Test @DisplayName("Find all available books") void findAll_ValidItems_ShouldReturnAllBooks() throws Exception { @@ -101,7 +100,6 @@ void findAll_ValidItems_ShouldReturnAllBooks() throws Exception { Assertions.assertEquals(3, ((List) responseMap.get("content")).size()); } - @WithMockUser(username = "admin", roles = {"ADMIN"}) @Test @DisplayName("Returns book with right id") void getBookById_ValidItems_ShouldReturnBook() throws Exception { @@ -118,7 +116,6 @@ void getBookById_ValidItems_ShouldReturnBook() throws Exception { assertTrue(jsonResponse.contains("978-1909156548")); } - @WithMockUser(username = "admin", roles = {"ADMIN"}) @Test @DisplayName("Updates book by id") void updateBookById_ValidInput_Success() throws Exception { @@ -160,7 +157,6 @@ void updateBookById_ValidInput_Success() throws Exception { assertEquals(expected.getCategoryIds(), actual.getCategoryIds()); } - @WithMockUser(username = "admin", roles = {"ADMIN"}) @Test @DisplayName("Deletes book by id") void deleteBookById_ValidInput_Success() throws Exception { From af835d25bd35ca97058ddbe83ce52060a81af976 Mon Sep 17 00:00:00 2001 From: Andrii Honchar Date: Sat, 10 Jan 2026 12:11:25 +0200 Subject: [PATCH 7/8] fixes due to mentor's advice --- .../store/controller/BookControllerTest.java | 28 ++++++++------ .../controller/CategoryControllerTest.java | 38 +++++++++---------- .../store/repository/BookRepositoryTest.java | 6 +-- .../store/service/BookServiceTest.java | 1 + .../store/service/CategoryServiceTest.java | 1 - 5 files changed, 40 insertions(+), 34 deletions(-) diff --git a/src/test/java/com/springm/store/controller/BookControllerTest.java b/src/test/java/com/springm/store/controller/BookControllerTest.java index 06fcef3..bac95ec 100644 --- a/src/test/java/com/springm/store/controller/BookControllerTest.java +++ b/src/test/java/com/springm/store/controller/BookControllerTest.java @@ -8,7 +8,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -32,9 +31,9 @@ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @AutoConfigureMockMvc @WithMockUser(username = "admin", roles = {"ADMIN"}) -@Sql(scripts = "classpath:database/books/add-items-to-categories-table.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) -@Sql(scripts = "classpath:database/books/add-three-items-to-books-table.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) -@Sql(scripts = "classpath:database/books/assign-categories-for-books.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) +@Sql(scripts = {"classpath:database/books/add-items-to-categories-table.sql", + "classpath:database/books/add-three-items-to-books-table.sql", + "classpath:database/books/assign-categories-for-books.sql"}) @Sql(scripts = "classpath:database/books/clear-all-tables.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) class BookControllerTest { @Autowired @@ -90,14 +89,21 @@ void findAll_ValidItems_ShouldReturnAllBooks() throws Exception { .andReturn(); String jsonResponse = result.getResponse().getContentAsString(); - assertTrue(jsonResponse.contains("Kobzar")); - assertTrue(jsonResponse.contains("Harry Potter")); - assertTrue(jsonResponse.contains("The Witcher")); - Map responseMap = objectMapper.readValue(jsonResponse, new TypeReference<>() { - }); - Assertions.assertEquals(3, responseMap.get("totalElements")); - Assertions.assertEquals(3, ((List) responseMap.get("content")).size()); + Map responseMap = objectMapper.readValue( + jsonResponse, + new TypeReference<>() { + }); + List actualDtos = objectMapper.convertValue( + responseMap.get("content"), + new TypeReference>() { + } + ); + assertEquals("Kobzar", actualDtos.get(0).getTitle()); + assertEquals("Harry Potter", actualDtos.get(1).getTitle()); + assertEquals("The Witcher", actualDtos.get(2).getTitle()); + assertEquals(3, responseMap.get("totalElements")); + assertEquals(3, ((List) responseMap.get("content")).size()); } @Test diff --git a/src/test/java/com/springm/store/controller/CategoryControllerTest.java b/src/test/java/com/springm/store/controller/CategoryControllerTest.java index 73b3648..8b80cc8 100644 --- a/src/test/java/com/springm/store/controller/CategoryControllerTest.java +++ b/src/test/java/com/springm/store/controller/CategoryControllerTest.java @@ -5,7 +5,6 @@ import com.springm.store.dto.category.CategoryDto; import com.springm.store.dto.category.CreateCategoryRequestDto; import java.util.List; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -29,9 +28,9 @@ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @AutoConfigureMockMvc @WithMockUser(username = "admin", roles = {"ADMIN"}) -@Sql(scripts = "classpath:database/books/categories/add-five-items-to-categories-table.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) -@Sql(scripts = "classpath:database/books/add-three-items-to-books-table.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) -@Sql(scripts = "classpath:database/books/assign-categories-for-books.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) +@Sql(scripts = {"classpath:database/books/categories/add-five-items-to-categories-table.sql", + "classpath:database/books/add-three-items-to-books-table.sql", + "classpath:database/books/assign-categories-for-books.sql"}) @Sql(scripts = "classpath:database/books/clear-all-tables.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) class CategoryControllerTest { @Autowired @@ -63,7 +62,7 @@ void createCategory_ValidInput_Success() throws Exception { CategoryDto actual = objectMapper.readValue(result.getResponse().getContentAsString(), CategoryDto.class); - Assertions.assertTrue(EqualsBuilder.reflectionEquals(expected, actual, "id")); + assertTrue(EqualsBuilder.reflectionEquals(expected, actual, "id")); } @Test @@ -77,17 +76,18 @@ void getAllCategories_ValidItems_ShouldReturnAllCategories() throws Exception { .andReturn(); String jsonResponse = result.getResponse().getContentAsString(); - assertTrue(jsonResponse.contains("Fantasy")); - assertTrue(jsonResponse.contains("Classic")); - assertTrue(jsonResponse.contains("Poetry")); - assertTrue(jsonResponse.contains("History")); - assertTrue(jsonResponse.contains("Fantastic")); - List categoryDtos = objectMapper.readValue( + List actualDtos = objectMapper.readValue( jsonResponse, - new TypeReference>() {} + new TypeReference>() { + } ); - Assertions.assertEquals(5, categoryDtos.size()); + assertEquals(5, actualDtos.size()); + assertEquals("Fantasy", actualDtos.get(0).getName()); + assertEquals("Classic", actualDtos.get(1).getName()); + assertEquals("Poetry", actualDtos.get(2).getName()); + assertEquals("History", actualDtos.get(3).getName()); + assertEquals("Fantastic", actualDtos.get(4).getName()); } @Test @@ -150,10 +150,10 @@ void deleteCategoryById_ValidId_Success() throws Exception { @DisplayName("Get all books that belong to specific category") void getBooksByCategoryId_ValidInput_Success() throws Exception { MvcResult result = mockMvc.perform( - get("/categories/1/books") - .param("page", "0") - .param("size", "5") - .accept(MediaType.APPLICATION_JSON)) + get("/categories/1/books") + .param("page", "0") + .param("size", "5") + .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andReturn(); @@ -161,11 +161,11 @@ void getBooksByCategoryId_ValidInput_Success() throws Exception { List actual = objectMapper.readValue( jsonResponse, - new TypeReference>() {} + new TypeReference>() { + } ); assertEquals(3, actual.size()); } - } diff --git a/src/test/java/com/springm/store/repository/BookRepositoryTest.java b/src/test/java/com/springm/store/repository/BookRepositoryTest.java index 522e114..a0ead05 100644 --- a/src/test/java/com/springm/store/repository/BookRepositoryTest.java +++ b/src/test/java/com/springm/store/repository/BookRepositoryTest.java @@ -7,13 +7,13 @@ import java.math.BigDecimal; import java.util.List; import java.util.Set; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.testcontainers.junit.jupiter.Testcontainers; +import static org.junit.jupiter.api.Assertions.assertEquals; @DataJpaTest @Testcontainers @@ -46,7 +46,7 @@ void findAllByCategoryId_EqualsOne_ReturnsListWithOneBook() { List actual = bookRepository.findAllByCategories_Id(1L); - Assertions.assertEquals(1, actual.size()); + assertEquals(1, actual.size()); } @Test @@ -64,7 +64,7 @@ void findAllByCategoryId_EqualsNonExistingId_ReturnsEmptyList() { List actual = bookRepository.findAllByCategories_Id(2L); - Assertions.assertEquals(0, actual.size()); + assertEquals(0, actual.size()); } } diff --git a/src/test/java/com/springm/store/service/BookServiceTest.java b/src/test/java/com/springm/store/service/BookServiceTest.java index a44ed63..a117d9a 100644 --- a/src/test/java/com/springm/store/service/BookServiceTest.java +++ b/src/test/java/com/springm/store/service/BookServiceTest.java @@ -28,6 +28,7 @@ import org.testcontainers.shaded.org.apache.commons.lang3.builder.EqualsBuilder; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; @SpringBootTest @Testcontainers diff --git a/src/test/java/com/springm/store/service/CategoryServiceTest.java b/src/test/java/com/springm/store/service/CategoryServiceTest.java index f6b1337..e76c496 100644 --- a/src/test/java/com/springm/store/service/CategoryServiceTest.java +++ b/src/test/java/com/springm/store/service/CategoryServiceTest.java @@ -80,7 +80,6 @@ void findAll_ReturnsAllCategories() { Mockito.when(categoryRepository.findAll()).thenReturn(categories); - List actualList = categoryService.findAll(); assertEquals(2, actualList.size()); From d623b0146fa6e2249658af139c0c3912be0b6485 Mon Sep 17 00:00:00 2001 From: Andrii Honchar Date: Wed, 14 Jan 2026 14:55:30 +0200 Subject: [PATCH 8/8] fixes due to comments --- .../store/controller/BookControllerTest.java | 28 ++++----- .../controller/CategoryControllerTest.java | 23 +++---- .../store/service/BookServiceTest.java | 60 +++++++++---------- .../store/service/CategoryServiceTest.java | 48 +++++++++------ 4 files changed, 78 insertions(+), 81 deletions(-) diff --git a/src/test/java/com/springm/store/controller/BookControllerTest.java b/src/test/java/com/springm/store/controller/BookControllerTest.java index bac95ec..377ac22 100644 --- a/src/test/java/com/springm/store/controller/BookControllerTest.java +++ b/src/test/java/com/springm/store/controller/BookControllerTest.java @@ -18,15 +18,15 @@ import org.springframework.test.context.jdbc.Sql; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; -import org.testcontainers.shaded.org.apache.commons.lang3.builder.EqualsBuilder; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.testcontainers.shaded.org.apache.commons.lang3.builder.EqualsBuilder.reflectionEquals; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @AutoConfigureMockMvc @@ -74,7 +74,7 @@ void createBook_ValidRequestDto_Success() throws Exception { BookDto actual = objectMapper.readValue(result.getResponse().getContentAsString(), BookDto.class); assertTrue( - EqualsBuilder.reflectionEquals(expected, actual, "id") + reflectionEquals(expected, actual, "id") ); } @@ -87,23 +87,24 @@ void findAll_ValidItems_ShouldReturnAllBooks() throws Exception { .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andReturn(); - + int expectedElementsCount = 3; String jsonResponse = result.getResponse().getContentAsString(); Map responseMap = objectMapper.readValue( jsonResponse, new TypeReference<>() { }); - List actualDtos = objectMapper.convertValue( + List actualList = objectMapper.convertValue( responseMap.get("content"), new TypeReference>() { } ); - assertEquals("Kobzar", actualDtos.get(0).getTitle()); - assertEquals("Harry Potter", actualDtos.get(1).getTitle()); - assertEquals("The Witcher", actualDtos.get(2).getTitle()); - assertEquals(3, responseMap.get("totalElements")); - assertEquals(3, ((List) responseMap.get("content")).size()); + + assertThat(actualList) + .extracting(BookDto::getTitle) + .containsExactly("Kobzar", "Harry Potter", "The Witcher"); + assertEquals(expectedElementsCount, responseMap.get("totalElements")); + assertEquals(expectedElementsCount, ((List) responseMap.get("content")).size()); } @Test @@ -155,12 +156,7 @@ void updateBookById_ValidInput_Success() throws Exception { expected.setPrice(bookRequestDto.getPrice()); expected.setCategoryIds(bookRequestDto.getCategoryIds()); - assertNotNull(actual); - assertEquals(expected.getId(), actual.getId()); - assertEquals(expected.getAuthor(), actual.getAuthor()); - assertEquals(expected.getTitle(), actual.getTitle()); - assertEquals(expected.getPrice(), actual.getPrice()); - assertEquals(expected.getCategoryIds(), actual.getCategoryIds()); + assertTrue(reflectionEquals(expected, actual, "id")); } @Test diff --git a/src/test/java/com/springm/store/controller/CategoryControllerTest.java b/src/test/java/com/springm/store/controller/CategoryControllerTest.java index 8b80cc8..c9a2e70 100644 --- a/src/test/java/com/springm/store/controller/CategoryControllerTest.java +++ b/src/test/java/com/springm/store/controller/CategoryControllerTest.java @@ -15,15 +15,15 @@ import org.springframework.test.context.jdbc.Sql; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; -import org.testcontainers.shaded.org.apache.commons.lang3.builder.EqualsBuilder; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.testcontainers.shaded.org.apache.commons.lang3.builder.EqualsBuilder.reflectionEquals; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @AutoConfigureMockMvc @@ -62,7 +62,7 @@ void createCategory_ValidInput_Success() throws Exception { CategoryDto actual = objectMapper.readValue(result.getResponse().getContentAsString(), CategoryDto.class); - assertTrue(EqualsBuilder.reflectionEquals(expected, actual, "id")); + assertTrue(reflectionEquals(expected, actual, "id")); } @Test @@ -77,17 +77,15 @@ void getAllCategories_ValidItems_ShouldReturnAllCategories() throws Exception { String jsonResponse = result.getResponse().getContentAsString(); - List actualDtos = objectMapper.readValue( + List actualList = objectMapper.readValue( jsonResponse, new TypeReference>() { } ); - assertEquals(5, actualDtos.size()); - assertEquals("Fantasy", actualDtos.get(0).getName()); - assertEquals("Classic", actualDtos.get(1).getName()); - assertEquals("Poetry", actualDtos.get(2).getName()); - assertEquals("History", actualDtos.get(3).getName()); - assertEquals("Fantastic", actualDtos.get(4).getName()); + assertThat(actualList) + .extracting(CategoryDto::getName) + .containsExactly("Fantasy", "Classic", + "Poetry", "History", "Fantastic"); } @Test @@ -109,7 +107,7 @@ void getCategoryById_ValidId_Success() throws Exception { void updateCategory_ValidInput_Success() throws Exception { CreateCategoryRequestDto categoryRequestDto = new CreateCategoryRequestDto(); categoryRequestDto.setName("Military"); - categoryRequestDto.setName("Category about military things"); + categoryRequestDto.setDescription("Category about military things"); String jsonRequest = objectMapper.writeValueAsString(categoryRequestDto); @@ -131,10 +129,7 @@ void updateCategory_ValidInput_Success() throws Exception { expected.setName(categoryRequestDto.getName()); expected.setDescription(categoryRequestDto.getDescription()); - assertNotNull(actual); - assertEquals(expected.getId(), actual.getId()); assertEquals(expected.getName(), actual.getName()); - assertEquals(expected.getDescription(), actual.getDescription()); } @Test diff --git a/src/test/java/com/springm/store/service/BookServiceTest.java b/src/test/java/com/springm/store/service/BookServiceTest.java index a117d9a..3d48cc6 100644 --- a/src/test/java/com/springm/store/service/BookServiceTest.java +++ b/src/test/java/com/springm/store/service/BookServiceTest.java @@ -15,7 +15,6 @@ import java.util.Set; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.context.SpringBootTest; @@ -25,10 +24,13 @@ import org.springframework.data.domain.Pageable; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.testcontainers.junit.jupiter.Testcontainers; -import org.testcontainers.shaded.org.apache.commons.lang3.builder.EqualsBuilder; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.testcontainers.shaded.org.apache.commons.lang3.builder.EqualsBuilder.reflectionEquals; @SpringBootTest @Testcontainers @@ -56,7 +58,7 @@ void save_ValidInput_Success() { category.setId(1L); category.setName("Poetry"); - Mockito.when(categoryRepository.findById(1L)) + when(categoryRepository.findById(1L)) .thenReturn(Optional.of(category)); CreateBookRequestDto requestDto = new CreateBookRequestDto(); @@ -69,24 +71,25 @@ void save_ValidInput_Success() { bookEntity.setTitle("Kobzar"); bookEntity.setAuthor("Taras Shevchenko"); bookEntity.setPrice(BigDecimal.valueOf(24)); + bookEntity.setCategories(Set.of(category)); - BookDto bookDto = new BookDto(); - bookDto.setTitle("Kobzar"); - bookDto.setAuthor("Taras Shevchenko"); - bookDto.setPrice(BigDecimal.valueOf(24)); - bookDto.setCategoryIds(Set.of(1L)); + BookDto expected = new BookDto(); + expected.setTitle(bookEntity.getTitle()); + expected.setAuthor(bookEntity.getAuthor()); + expected.setPrice(bookEntity.getPrice()); + expected.setCategoryIds(requestDto.getCategoryIds()); - Mockito.when(bookMapper.toModel(Mockito.any(CreateBookRequestDto.class))) + when(bookMapper.toModel(any(CreateBookRequestDto.class))) .thenReturn(bookEntity); - Mockito.when(bookRepository.save(Mockito.any(Book.class))) + when(bookRepository.save(any(Book.class))) .thenReturn(bookEntity); - Mockito.when(bookMapper.toDto(Mockito.any(Book.class))) - .thenReturn(bookDto); + when(bookMapper.toDto(any(Book.class))) + .thenReturn(expected); BookDto actual = bookService.save(requestDto); - EqualsBuilder.reflectionEquals(bookEntity, actual, "id"); + assertTrue(reflectionEquals(expected, actual, "id")); } @@ -104,18 +107,15 @@ void findById_ValidInput_Success() { bookDto.setTitle("Kobzar"); bookDto.setAuthor("Taras Shevchenko"); - Mockito.when(bookRepository.findById(1L)) + when(bookRepository.findById(1L)) .thenReturn(Optional.of(bookEntity)); - Mockito.when(bookMapper.toDto(bookEntity)) + when(bookMapper.toDto(bookEntity)) .thenReturn(bookDto); BookDto actual = bookService.findById(1L); - assertNotNull(actual); - assertNotNull(actual.getId()); - assertEquals("Kobzar", actual.getTitle()); - assertEquals("Taras Shevchenko", actual.getAuthor()); + assertTrue(reflectionEquals(bookDto, actual, "id")); } @Test @@ -129,10 +129,10 @@ void findAll_Pageable_ReturnsAllBooks() { Page bookPage = new PageImpl<>(List.of(book), pageable, 2); - Mockito.when(bookRepository.findAll(pageable)) + when(bookRepository.findAll(pageable)) .thenReturn(bookPage); - Mockito.when(bookMapper.toDto(book)) + when(bookMapper.toDto(book)) .thenReturn(new BookDto()); Page result = bookService.findAll(pageable); @@ -149,42 +149,36 @@ void updateBookById_ValidInput_Success() { bookEntity.setTitle("Harry Potter"); bookEntity.setAuthor("J. K. Rowling"); - - Mockito.when(bookRepository.findById(1L)) + when(bookRepository.findById(1L)) .thenReturn(Optional.of(bookEntity)); CreateBookRequestDto changedBookDto = new CreateBookRequestDto(); changedBookDto.setTitle("The World of Ice and Fire"); changedBookDto.setAuthor("George R. R. Martin"); - BookDto bookDto = new BookDto(); bookDto.setId(1L); bookDto.setTitle("The World of Ice and Fire"); bookDto.setAuthor("George R. R. Martin"); - - Mockito.when(bookMapper.toDto(bookEntity)) + when(bookMapper.toDto(bookEntity)) .thenReturn(bookDto); BookDto actual = bookService.updateBookById(1L, changedBookDto); - assertNotNull(actual); - assertNotNull(actual.getId()); - assertEquals("The World of Ice and Fire", actual.getTitle()); - assertEquals("George R. R. Martin", actual.getAuthor()); + assertTrue(reflectionEquals(bookDto, actual, "id")); } @Test @DisplayName("Deletes books with valid id") void deleteBookById_ValidInput_Success() { - Mockito.doNothing() + doNothing() .when(bookRepository) .deleteById(1L); bookService.deleteBookById(1L); - Mockito.verify(bookRepository) + verify(bookRepository) .deleteById(1L); } diff --git a/src/test/java/com/springm/store/service/CategoryServiceTest.java b/src/test/java/com/springm/store/service/CategoryServiceTest.java index e76c496..abfb884 100644 --- a/src/test/java/com/springm/store/service/CategoryServiceTest.java +++ b/src/test/java/com/springm/store/service/CategoryServiceTest.java @@ -10,14 +10,18 @@ import java.util.Optional; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.testcontainers.junit.jupiter.Testcontainers; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.testcontainers.shaded.org.apache.commons.lang3.builder.EqualsBuilder.reflectionEquals; @SpringBootTest @Testcontainers @@ -42,12 +46,15 @@ void save_ValidInput_Success() { category.setId(0L); category.setName("Poetry"); - Mockito.when(categoryRepository.save(Mockito.any(Category.class))).thenReturn(category); + CategoryDto expected = new CategoryDto(); + expected.setId(1L); + expected.setName("Poetry"); + + when(categoryRepository.save(any(Category.class))).thenReturn(category); CategoryDto actual = categoryService.save(categoryRequestDto); - assertNotNull(actual); - assertEquals("Poetry", actual.getName()); + assertTrue(reflectionEquals(expected, actual, "id")); } @Test @@ -57,12 +64,15 @@ void findById_ValidInput_Success() { category.setId(1L); category.setName("Fiction"); - Mockito.when(categoryRepository.findById(1L)).thenReturn(Optional.of(category)); + when(categoryRepository.findById(1L)).thenReturn(Optional.of(category)); + + CategoryDto expected = new CategoryDto(); + expected.setId(1L); + expected.setName("Fiction"); CategoryDto actual = categoryService.findById(1L); - assertNotNull(actual); - assertEquals("Fiction", actual.getName()); + assertTrue(reflectionEquals(expected, actual, "id")); } @Test @@ -78,13 +88,13 @@ void findAll_ReturnsAllCategories() { List categories = List.of(category1, category2); - Mockito.when(categoryRepository.findAll()).thenReturn(categories); + when(categoryRepository.findAll()).thenReturn(categories); List actualList = categoryService.findAll(); - assertEquals(2, actualList.size()); - assertEquals("Poetry", actualList.get(0).getName()); - assertEquals("Fiction", actualList.get(1).getName()); + assertThat(actualList) + .extracting(CategoryDto::getName) + .containsExactly("Poetry", "Fiction"); } @Test @@ -94,25 +104,27 @@ void update_ValidInput_Success() { category.setId(1L); category.setName("Fiction"); - Mockito.when(categoryRepository.findById(1L)).thenReturn(Optional.of(category)); + when(categoryRepository.findById(1L)).thenReturn(Optional.of(category)); CreateCategoryRequestDto categoryRequestDto = new CreateCategoryRequestDto(); categoryRequestDto.setName("History"); + CategoryDto expected = new CategoryDto(); + expected.setName("History"); + CategoryDto actual = categoryService.update(1L, categoryRequestDto); - assertNotNull(actual); - assertEquals("History", actual.getName()); + assertTrue(reflectionEquals(expected, actual, "id")); } @Test @DisplayName("Deletes category by id") void deleteById_ValidInput_Success() { - Mockito.doNothing().when(categoryRepository).deleteById(1L); + doNothing().when(categoryRepository).deleteById(1L); categoryService.deleteById(1L); - Mockito.verify(categoryRepository).deleteById(1L); + verify(categoryRepository).deleteById(1L); } }