diff --git a/src/test/java/com/jisungin/api/book/BookControllerTest.java b/src/test/java/com/jisungin/api/book/BookControllerTest.java index 31b4cc4..2c21e33 100644 --- a/src/test/java/com/jisungin/api/book/BookControllerTest.java +++ b/src/test/java/com/jisungin/api/book/BookControllerTest.java @@ -1,5 +1,7 @@ package com.jisungin.api.book; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; import static org.springframework.http.MediaType.APPLICATION_JSON; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; @@ -9,19 +11,18 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.jisungin.api.book.request.BookCreateRequest; -import com.jisungin.domain.book.Book; -import com.jisungin.domain.book.repository.BookRepository; +import com.jisungin.api.oauth.AuthContext; +import com.jisungin.application.book.BookService; +import com.jisungin.application.book.response.BookResponse; import java.time.LocalDateTime; -import org.junit.jupiter.api.AfterEach; 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.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.web.servlet.MockMvc; -@SpringBootTest -@AutoConfigureMockMvc +@WebMvcTest(BookController.class) public class BookControllerTest { @Autowired @@ -30,22 +31,20 @@ public class BookControllerTest { @Autowired private ObjectMapper objectMapper; - @Autowired - private BookRepository bookRepository; + @MockBean + private BookService bookService; - @AfterEach - void tearDown() { - bookRepository.deleteAllInBatch(); - } + @MockBean + private AuthContext context; @Test @DisplayName("책을 조회한다.") public void getBook() throws Exception { // given - Book book = bookRepository.save(create()); + when(bookService.getBook(any(String.class))).thenReturn(createResponse()); // when // then - mockMvc.perform(get("/v1/books/{isbn}", book.getIsbn()) + mockMvc.perform(get("/v1/books/{isbn}", "isbn") .accept(APPLICATION_JSON)) .andDo(print()) .andExpect(status().isOk()) @@ -54,22 +53,6 @@ public void getBook() throws Exception { .andExpect(jsonPath("$.message").value("OK")); } - @Test - @DisplayName("책 조회 시 일치하는 isbn이 존재해야 한다.") - public void getBookWithInvalidIsbn() throws Exception { - // given - String invalidIsbn = "0000000000"; - Book book = bookRepository.save(create()); - - // when // then - mockMvc.perform(get("/v1/books/{isbn}", invalidIsbn) - .accept(APPLICATION_JSON)) - .andDo(print()) - .andExpect(status().isNotFound()) - .andExpect(jsonPath("$.code").value("404")) - .andExpect(jsonPath("message").value("책을 찾을 수 없습니다.")); - } - @Test @DisplayName("신규 도서를 등록한다.") public void createBook() throws Exception { @@ -77,13 +60,15 @@ public void createBook() throws Exception { BookCreateRequest request = BookCreateRequest.builder() .title("도서 정보") .contents("도서 내용") - .isbn("도서 isbn") - .dateTime("2024-03-15T00:00:00.000+09:00") + .isbn("도서 ISBN") + .dateTime("2024-01-01T00:00:00.000+09:00") .authors(new String[]{"도서 저자1", "도서 저자2"}) .publisher("도서 출판사") .thumbnail("도서 썸네일") .build(); + when(bookService.createBook(request.toServiceRequest())).thenReturn(createResponse()); + // when // then mockMvc.perform(post("/v1/books") .content(objectMapper.writeValueAsString(request)) @@ -96,40 +81,13 @@ public void createBook() throws Exception { } @Test - @DisplayName("신규 도서 등록 시 isbn이 다른 책이어야 한다.") - public void createBookWithDuplicateIsbn() throws Exception { + @DisplayName("신규 책을 등록 시 책 제목 입력은 필수 값이다.") + public void createBookWithTitle() throws Exception { // given - Book book = create(); - bookRepository.save(book); - BookCreateRequest request = BookCreateRequest.builder() - .title("도서 정보") .contents("도서 내용") - .isbn("도서 isbn") - .dateTime("2024-03-15T00:00:00.000+09:00") - .authors(new String[]{"도서 저자1", "도서 저자2"}) - .publisher("도서 출판사") - .thumbnail("도서 썸네일") - .build(); - - // when // then - mockMvc.perform(post("/v1/books") - .content(objectMapper.writeValueAsString(request)) - .contentType(APPLICATION_JSON)) - .andDo(print()) - .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.code").value("400")) - .andExpect(jsonPath("$.message").value("이미 등록된 책 정보 입니다.")); - } - - @Test - @DisplayName("신규 도서 등록 시 책 제목은 필수이어야 한다.") - public void createBookWithNonTitle() throws Exception { - // given - BookCreateRequest request = BookCreateRequest.builder() - .contents("도서 내용") - .isbn("도서 isbn") - .dateTime("2024-03-15T00:00:00.000+09:00") + .isbn("도서 ISBN") + .dateTime("2024-01-01T00:00:00.000+09:00") .authors(new String[]{"도서 저자1", "도서 저자2"}) .publisher("도서 출판사") .thumbnail("도서 썸네일") @@ -146,13 +104,13 @@ public void createBookWithNonTitle() throws Exception { } @Test - @DisplayName("신규 도서 등록 시 책 내용은 필수이어야 한다.") - public void createBookWithNonContents() throws Exception { + @DisplayName("신규 책을 등록 시 책 내용 입력은 필수 값이다.") + public void createBookWithContent() throws Exception { // given BookCreateRequest request = BookCreateRequest.builder() .title("도서 정보") - .isbn("도서 isbn") - .dateTime("2024-03-15T00:00:00.000+09:00") + .isbn("도서 ISBN") + .dateTime("2024-01-01T00:00:00.000+09:00") .authors(new String[]{"도서 저자1", "도서 저자2"}) .publisher("도서 출판사") .thumbnail("도서 썸네일") @@ -169,13 +127,13 @@ public void createBookWithNonContents() throws Exception { } @Test - @DisplayName("신규 도서 등록 시 책 isbn 입력은 필수이어야 한다.") - public void createBookWithNonIsbn() throws Exception { + @DisplayName("신규 책 등록 시 책 ISBN 입력은 필수 값이다.") + public void createBookWithIsbn() throws Exception { // given BookCreateRequest request = BookCreateRequest.builder() .title("도서 정보") .contents("도서 내용") - .dateTime("2024-03-15T00:00:00.000+09:00") + .dateTime("2024-01-01T00:00:00.000+09:00") .authors(new String[]{"도서 저자1", "도서 저자2"}) .publisher("도서 출판사") .thumbnail("도서 썸네일") @@ -189,16 +147,17 @@ public void createBookWithNonIsbn() throws Exception { .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.code").value("400")) .andExpect(jsonPath("$.message").value("책 isbn 입력은 필수 입니다.")); + } @Test - @DisplayName("신규 도서 등록 시 책 출판일 입력은 필수이어야 한다.") - public void createBookWithNonDateTime() throws Exception { + @DisplayName("신규 책 등록 시 책 출판일 입력은 필수 값이다.") + public void createBookWithDateTime() throws Exception { // given BookCreateRequest request = BookCreateRequest.builder() .title("도서 정보") .contents("도서 내용") - .isbn("도서 isbn") + .isbn("도서 ISBN") .authors(new String[]{"도서 저자1", "도서 저자2"}) .publisher("도서 출판사") .thumbnail("도서 썸네일") @@ -212,17 +171,18 @@ public void createBookWithNonDateTime() throws Exception { .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.code").value("400")) .andExpect(jsonPath("$.message").value("책 출판일 입력은 필수 입니다.")); + } @Test - @DisplayName("신규 도서 등록 시 책 저자 입력은 필수이어야 한다.") + @DisplayName("신규 책 등록 시 책 저자 입력은 필수 값이다.") public void createBookWithAuthors() throws Exception { // given BookCreateRequest request = BookCreateRequest.builder() .title("도서 정보") .contents("도서 내용") - .isbn("도서 isbn") - .dateTime("2024-03-15T00:00:00.000+09:00") + .isbn("도서 ISBN") + .dateTime("2024-01-01T00:00:00.000+09:00") .publisher("도서 출판사") .thumbnail("도서 썸네일") .build(); @@ -238,14 +198,14 @@ public void createBookWithAuthors() throws Exception { } @Test - @DisplayName("신규 도서 등록 시 책 출판사 입력은 필수이어야 한다.") + @DisplayName("신규 책 등록 시 출판사 입력은 필수 값이다.") public void createBookWithPublisher() throws Exception { // given BookCreateRequest request = BookCreateRequest.builder() .title("도서 정보") .contents("도서 내용") - .isbn("도서 isbn") - .dateTime("2024-03-15T00:00:00.000+09:00") + .isbn("도서 ISBN") + .dateTime("2024-01-01T00:00:00.000+09:00") .authors(new String[]{"도서 저자1", "도서 저자2"}) .thumbnail("도서 썸네일") .build(); @@ -261,17 +221,14 @@ public void createBookWithPublisher() throws Exception { } @Test - @DisplayName("신규 도서 등록 시 책 썸네일 입력은 필수이어야 한다.") + @DisplayName("신규 책 등록 시 썸네일 입력은 필수 값이다.") public void createBookWithThumbnail() throws Exception { // given - Book book = create(); - bookRepository.save(book); - BookCreateRequest request = BookCreateRequest.builder() .title("도서 정보") .contents("도서 내용") - .isbn("도서 isbn") - .dateTime("2024-03-15T00:00:00.000+09:00") + .isbn("도서 ISBN") + .dateTime("2024-01-01T00:00:00.000+09:00") .authors(new String[]{"도서 저자1", "도서 저자2"}) .publisher("도서 출판사") .build(); @@ -286,16 +243,17 @@ public void createBookWithThumbnail() throws Exception { .andExpect(jsonPath("$.message").value("책 썸네일 입력은 필수 입니다.")); } - private static Book create() { - return Book.builder() - .title("도서 정보") - .content("도서 내용") - .imageUrl("도서 URL") - .isbn("도서 isbn") - .dateTime(LocalDateTime.now()) - .authors("도서 저자1, 도서 저자2") - .publisher("도서 출판사") - .thumbnail("도서 썸네일") + private static BookResponse createResponse() { + return BookResponse.builder() + .title("책 이름") + .content("책 설명") + .isbn("1111111111") + .authors("책 저자1, 책 저자2") + .publisher("책 출판사") + .imageUrl("책 이미지 URL") + .thumbnail("책 썸네일 URL") + .dateTime(LocalDateTime.of(2024, 1, 1, 0, 0)) + .ratingAverage(0.0) .build(); } diff --git a/src/test/java/com/jisungin/application/service/book/BookServiceTest.java b/src/test/java/com/jisungin/application/service/book/BookServiceTest.java index 847bbc3..02c8094 100644 --- a/src/test/java/com/jisungin/application/service/book/BookServiceTest.java +++ b/src/test/java/com/jisungin/application/service/book/BookServiceTest.java @@ -1,130 +1,139 @@ -//package com.jisungin.application.service.book; -// -//import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -//import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; -// -//import com.jisungin.application.book.BookService; -//import com.jisungin.application.book.request.BookCreateServiceRequest; -//import com.jisungin.application.book.response.BookResponse; -//import com.jisungin.domain.book.Book; -//import com.jisungin.domain.book.repository.BookRepository; -//import com.jisungin.exception.BusinessException; -//import java.time.LocalDateTime; -//import org.junit.jupiter.api.AfterEach; -//import org.junit.jupiter.api.DisplayName; -//import org.junit.jupiter.api.Test; -//import org.springframework.beans.factory.annotation.Autowired; -//import org.springframework.boot.test.context.SpringBootTest; -// -//@SpringBootTest -//public class BookServiceTest { -// -// @Autowired -// private BookRepository bookRepository; -// -// @Autowired -// private BookService bookService; -// -// @AfterEach -// void tearDown() { -// bookRepository.deleteAllInBatch(); -// } -// -// @Test -// @DisplayName("책을 조회한다.") -// public void getBook() { -// // given -// Book book = bookRepository.save(create()); -// -// // when -// BookResponse response = bookService.getBook(book.getIsbn()); -// -// // then -// assertThat(response.getDateTime()).isEqualTo(book.getDateTime()); -// assertThat(response.getAuthors()).hasSize(2) -// .contains("도서 저자1", "도서 저자2"); -// assertThat(response) -// .extracting("title", "content", "isbn", "publisher", "url", "thumbnail") -// .contains("도서 제목", "도서 내용", "123456789X", "도서 출판사", "도서 URL", "도서 썸네일"); -// } -// -// @Test -// @DisplayName("isbn이 일치하는 책이 없는 경우 예외가 발생한다.") -// public void getBookWithInvalidIsbn() { -// // given -// Book book = bookRepository.save(create()); -// String invalidIsbn = "0000000000"; -// -// // when // then -// assertThatThrownBy(() -> bookService.getBook(invalidIsbn)) -// .isInstanceOf(BusinessException.class) -// .hasMessage("책을 찾을 수 없습니다."); -// } -// -// @Test -// @DisplayName("도서 정보에 대한 책을 생성한다.") -// public void createBook() { -// // given -// LocalDateTime registeredDateTime = LocalDateTime.now(); -// -// BookCreateServiceRequest request = BookCreateServiceRequest.builder() -// .title("도서 제목") -// .contents("도서 내용") -// .isbn("123456789X") -// .dateTime(registeredDateTime) -// .authors("도서 저자1, 도서 저자2") -// .publisher("도서 출판사") -// .url("도서 URL") -// .thumbnail("도서 썸네일") -// .build(); -// -// // when -// BookResponse response = bookService.createBook(request); -// -// // then -// assertThat(response.getDateTime()).isEqualTo(registeredDateTime); -// assertThat(response.getAuthors()).hasSize(2) -// .contains("도서 저자1", "도서 저자2"); -// assertThat(response) -// .extracting("title", "content", "isbn", "publisher", "url", "thumbnail") -// .contains("도서 제목", "도서 내용", "123456789X", "도서 출판사", "도서 URL", "도서 썸네일"); -// } -// -// @Test -// @DisplayName("isbn이 일치하는 책을 생성하는 경우 예외가 발생한다.") -// public void createBookWithDuplicateIsbn() { -// // given -// Book book = create(); -// bookRepository.save(book); -// -// BookCreateServiceRequest request = BookCreateServiceRequest.builder() -// .title("도서 제목") -// .contents("도서 내용") -// .isbn("123456789X") -// .dateTime(LocalDateTime.now()) -// .authors("도서 저자1, 도서 저자2") -// .publisher("도서 출판사") -// .url("도서 URL") -// .thumbnail("도서 썸네일") -// .build(); -// -// // when // then -// assertThatThrownBy(() -> bookService.createBook(request)) -// .isInstanceOf(BusinessException.class) -// .hasMessage("이미 등록된 책 정보 입니다."); -// } -// -// private static Book create() { -// return Book.builder() -// .title("도서 제목") -// .content("도서 내용") -// .authors("도서 저자1, 도서 저자2") -// .isbn("123456789X") -// .dateTime(LocalDateTime.now()) -// .publisher("도서 출판사") -// .url("도서 URL") -// .thumbnail("도서 썸네일") -// .build(); -// } -// -//} +package com.jisungin.application.service.book; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; +import static org.mockito.Mockito.when; + +import com.jisungin.application.book.BookService; +import com.jisungin.application.book.request.BookCreateServiceRequest; +import com.jisungin.application.book.response.BookResponse; +import com.jisungin.domain.book.Book; +import com.jisungin.domain.book.repository.BookRepository; +import com.jisungin.exception.BusinessException; +import com.jisungin.infra.crawler.Crawler; +import com.jisungin.infra.crawler.CrawlingBook; +import java.time.LocalDateTime; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; + +@SpringBootTest +public class BookServiceTest { + + @Autowired + private BookService bookService; + + @Autowired + private BookRepository bookRepository; + + @MockBean + private Crawler crawler; + + @AfterEach + void tearDown() { + bookRepository.deleteAllInBatch(); + } + + @Test + @DisplayName("책을 조회한다.") + public void getBook() { + // given + Book book = bookRepository.save(create()); + + // when + BookResponse response = bookService.getBook(book.getIsbn()); + + // then + assertThat(response.getDateTime()).isEqualTo(book.getDateTime()); + assertThat(response.getAuthors()).hasSize(2) + .contains("도서 저자1", "도서 저자2"); + assertThat(response) + .extracting("title", "content", "isbn", "publisher", "imageUrl", "thumbnail") + .contains("도서 제목", "도서 내용", "123456789X", "도서 출판사", "도서 imageUrl", "도서 썸네일"); + } + + @Test + @DisplayName("존재하지 않는 책을 조회하면 예외가 발생한다.") + public void getBookWithInvalidIsbn() { + // given + String invalidIsbn = "0000000000"; + + // when // then + assertThatThrownBy(() -> bookService.getBook(invalidIsbn)) + .isInstanceOf(BusinessException.class) + .hasMessage("책을 찾을 수 없습니다."); + } + + @Test + @DisplayName("도서 정보에 대한 책을 생성한다.") + public void createBook() { + // given + LocalDateTime registeredDateTime = LocalDateTime.of(2024, 1, 1, 0, 0); + + BookCreateServiceRequest request = BookCreateServiceRequest.builder() + .title("도서 제목") + .contents("도서 내용") + .isbn("123456789X") + .dateTime(registeredDateTime) + .authors("도서 저자1, 도서 저자2") + .publisher("도서 출판사") + .imageUrl("도서 imageUrl") + .thumbnail("도서 썸네일") + .build(); + + when(crawler.crawlBook(request.getIsbn())) + .thenReturn(CrawlingBook.of("도서 imageUrl", "도서 내용")); + + // when + BookResponse response = bookService.createBook(request); + + // then + assertThat(response.getDateTime()).isEqualTo(request.getDateTime()); + assertThat(response.getAuthors()).hasSize(2) + .contains("도서 저자1", "도서 저자2"); + assertThat(response) + .extracting("title", "content", "isbn", "publisher", "imageUrl", "thumbnail") + .contains("도서 제목", "도서 내용", "123456789X", "도서 출판사", "도서 imageUrl", "도서 썸네일"); + } + + @Test + @DisplayName("이미 등록된 ISBN을 사용하여 책을 생성하는 경우 예외가 발생한다.") + public void createBookWithDuplicateIsbn() { + // given + Book book = create(); + bookRepository.save(book); + + BookCreateServiceRequest request = BookCreateServiceRequest.builder() + .title("도서 제목") + .contents("도서 내용") + .isbn(book.getIsbn()) + .dateTime(LocalDateTime.of(2024, 1, 1, 0, 0)) + .authors("도서 저자1, 도서 저자2") + .publisher("도서 출판사") + .imageUrl("도서 URL") + .thumbnail("도서 썸네일") + .build(); + + // when // then + assertThatThrownBy(() -> bookService.createBook(request)) + .isInstanceOf(BusinessException.class) + .hasMessage("이미 등록된 책 정보 입니다."); + } + + private static Book create() { + return Book.builder() + .title("도서 제목") + .content("도서 내용") + .authors("도서 저자1, 도서 저자2") + .isbn("123456789X") + .dateTime(LocalDateTime.of(2024, 1, 1, 0, 0)) + .publisher("도서 출판사") + .imageUrl("도서 imageUrl") + .thumbnail("도서 썸네일") + .build(); + } + +}