-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
307 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 2 additions & 0 deletions
2
module-application/app-api/src/main/java/shop/jtoon/webtoon/request/GetEpisodesReq.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,10 @@ | ||
package shop.jtoon.webtoon.request; | ||
|
||
import lombok.Getter; | ||
import lombok.experimental.SuperBuilder; | ||
import shop.jtoon.type.CustomPageRequest; | ||
|
||
@Getter | ||
@SuperBuilder | ||
public class GetEpisodesReq extends CustomPageRequest { | ||
} |
202 changes: 202 additions & 0 deletions
202
...-application/app-api/src/test/java/shop/jtoon/webtoon/application/EpisodeServiceTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
package shop.jtoon.webtoon.application; | ||
|
||
import static org.assertj.core.api.Assertions.*; | ||
import static org.mockito.ArgumentMatchers.*; | ||
import static org.mockito.BDDMockito.*; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Optional; | ||
|
||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
import org.mockito.InjectMocks; | ||
import org.mockito.Mock; | ||
import org.mockito.junit.jupiter.MockitoExtension; | ||
import org.springframework.mock.web.MockMultipartFile; | ||
|
||
import shop.jtoon.dto.UploadImageDto; | ||
import shop.jtoon.entity.Episode; | ||
import shop.jtoon.entity.Member; | ||
import shop.jtoon.entity.PurchasedEpisode; | ||
import shop.jtoon.entity.Webtoon; | ||
import shop.jtoon.exception.DuplicatedException; | ||
import shop.jtoon.exception.InvalidRequestException; | ||
import shop.jtoon.exception.NotFoundException; | ||
import shop.jtoon.member.application.MemberService; | ||
import shop.jtoon.payment.application.MemberCookieService; | ||
import shop.jtoon.repository.EpisodeRepository; | ||
import shop.jtoon.repository.EpisodeSearchRepository; | ||
import shop.jtoon.repository.PurchasedEpisodeRepository; | ||
import shop.jtoon.response.EpisodeInfoRes; | ||
import shop.jtoon.response.EpisodeItemRes; | ||
import shop.jtoon.service.S3Service; | ||
import shop.jtoon.webtoon.factory.CreatorFactory; | ||
import shop.jtoon.webtoon.request.CreateEpisodeReq; | ||
import shop.jtoon.webtoon.request.GetEpisodesReq; | ||
|
||
@ExtendWith(MockitoExtension.class) | ||
class EpisodeServiceTest { | ||
|
||
@InjectMocks | ||
private EpisodeService episodeService; | ||
|
||
@Mock | ||
private MemberService memberService; | ||
|
||
@Mock | ||
private MemberCookieService memberCookieService; | ||
|
||
@Mock | ||
private WebtoonService webtoonService; | ||
|
||
@Mock | ||
private S3Service s3Service; | ||
|
||
@Mock | ||
private EpisodeRepository episodeRepository; | ||
|
||
@Mock | ||
private EpisodeSearchRepository episodeSearchRepository; | ||
|
||
@Mock | ||
private PurchasedEpisodeRepository purchasedEpisodeRepository; | ||
|
||
private Member member; | ||
private Webtoon webtoon; | ||
|
||
@BeforeEach | ||
void beforeEach() { | ||
member = spy(CreatorFactory.createMember()); | ||
lenient().when(member.getId()).thenReturn(1L); | ||
webtoon = spy(CreatorFactory.createWebtoon(member)); | ||
lenient().when(webtoon.getId()).thenReturn(1L); | ||
} | ||
|
||
@DisplayName("createEpisode - 회차 생성 성공, - Void") | ||
@Test | ||
void createEpisode_Void() { | ||
// Given | ||
CreateEpisodeReq request = CreatorFactory.createEpisodeReq(); | ||
MockMultipartFile image = CreatorFactory.createMultipartFile(); | ||
given(webtoonService.getWebtoonById(webtoon.getId())).willReturn(webtoon); | ||
given(s3Service.uploadImage(any(UploadImageDto.class))).willReturn("https://webtoons/episodes/image"); | ||
|
||
// When | ||
episodeService.createEpisode(member.getId(), webtoon.getId(), image, image, request); | ||
|
||
// Then | ||
verify(episodeRepository).save(any(Episode.class)); | ||
} | ||
|
||
@DisplayName("createEpisode - 회차 번호 중복, - DuplicatedException") | ||
@Test | ||
void createEpisode_DuplicatedException() { | ||
// Given | ||
CreateEpisodeReq request = CreatorFactory.createEpisodeReq(); | ||
MockMultipartFile image = CreatorFactory.createMultipartFile(); | ||
given(webtoonService.getWebtoonById(webtoon.getId())).willReturn(webtoon); | ||
given(episodeRepository.existsByWebtoonAndNo(any(Webtoon.class), anyInt())).willReturn(true); | ||
|
||
// When, Then | ||
assertThatThrownBy(() -> episodeService.createEpisode(member.getId(), webtoon.getId(), image, image, request)) | ||
.isInstanceOf(DuplicatedException.class) | ||
.hasMessage("이미 존재하는 회차 번호입니다."); | ||
} | ||
|
||
@DisplayName("createEpisode - 회차 생성 실패 시 이미지 삭제 서비스 호출, - InvalidRequestException") | ||
@Test | ||
void createEpisode_InvalidRequestException() { | ||
// Given | ||
CreateEpisodeReq request = CreatorFactory.createEpisodeReq(); | ||
MockMultipartFile image = CreatorFactory.createMultipartFile(); | ||
given(webtoonService.getWebtoonById(webtoon.getId())).willReturn(webtoon); | ||
given(s3Service.uploadImage(any(UploadImageDto.class))).willReturn("https://webtoons/episodes/image"); | ||
given(episodeRepository.save(any(Episode.class))).willThrow(new RuntimeException()); | ||
|
||
// When, Then | ||
assertThatThrownBy(() -> episodeService.createEpisode(member.getId(), webtoon.getId(), image, image, request)) | ||
.isInstanceOf(InvalidRequestException.class) | ||
.hasMessage("회차 생성에 실패했습니다."); | ||
verify(s3Service, times(2)).deleteImage(anyString()); | ||
} | ||
|
||
@DisplayName("getEpisodes - 조회할 회차 리스트가 없을 때, - Empty List") | ||
@Test | ||
void getEpisodes_EmptyList() { | ||
// Given | ||
GetEpisodesReq request = CreatorFactory.createGetEpisodesReq(); | ||
List<Episode> episodes = new ArrayList<>(); | ||
given(episodeSearchRepository.getEpisodes(webtoon.getId(), request.getSize(), request.getOffset())) | ||
.willReturn(episodes); | ||
|
||
// When | ||
List<EpisodeItemRes> actual = episodeService.getEpisodes(webtoon.getId(), request); | ||
|
||
// Then | ||
assertThat(actual).isEmpty(); | ||
} | ||
|
||
@DisplayName("getEpisodes - 회차 리스트 조회 성공, - List<EpisodeItemRes>") | ||
@Test | ||
void getEpisodes_EpisodeItemResList() { | ||
// Given | ||
GetEpisodesReq request = CreatorFactory.createGetEpisodesReq(); | ||
List<Episode> episodes = new ArrayList<>(); | ||
episodes.add(CreatorFactory.createEpisode(webtoon, 1)); | ||
episodes.add(CreatorFactory.createEpisode(webtoon, 2)); | ||
given(episodeSearchRepository.getEpisodes(webtoon.getId(), request.getSize(), request.getOffset())) | ||
.willReturn(episodes); | ||
|
||
// When | ||
List<EpisodeItemRes> actual = episodeService.getEpisodes(webtoon.getId(), request); | ||
|
||
// Then | ||
assertThat(actual).hasSize(episodes.size()); | ||
} | ||
|
||
@DisplayName("getEpisode - 회차 정보가 존재하지 않을 때, - NotFoundException") | ||
@Test | ||
void getEpisode_NotFoundException() { | ||
// Given | ||
given(episodeRepository.findById(anyLong())).willReturn(Optional.empty()); | ||
|
||
// When, Then | ||
assertThatThrownBy(() -> episodeService.getEpisode(1L)) | ||
.isInstanceOf(NotFoundException.class) | ||
.hasMessage("존재하지 않는 회차입니다."); | ||
} | ||
|
||
@DisplayName("getEpisode - 회차 정보 조회 성공, - EpisodeInfoRes") | ||
@Test | ||
void getEpisode_EpisodeInfoRes() { | ||
// Given | ||
Episode episode = CreatorFactory.createEpisode(webtoon, 1); | ||
given(episodeRepository.findById(anyLong())).willReturn(Optional.of(episode)); | ||
|
||
// When | ||
EpisodeInfoRes actual = episodeService.getEpisode(1L); | ||
|
||
// Then | ||
assertThat(actual.mainUrl()).isEqualTo("https://webtoons/episodes/main"); | ||
} | ||
|
||
@DisplayName("purchaseEpisode - 회차 구매 성공, - Void") | ||
@Test | ||
void purchaseEpisode_Void() { | ||
// Given | ||
Episode episode = spy(CreatorFactory.createEpisode(webtoon, 1)); | ||
given(episode.getId()).willReturn(1L); | ||
given(memberService.findById(member.getId())).willReturn(member); | ||
given(episodeRepository.findById(anyLong())).willReturn(Optional.of(episode)); | ||
|
||
// When | ||
episodeService.purchaseEpisode(member.getId(), episode.getId()); | ||
|
||
// Then | ||
verify(memberCookieService).useCookie(episode.getCookieCount(), member); | ||
verify(purchasedEpisodeRepository).save(any(PurchasedEpisode.class)); | ||
} | ||
} |
86 changes: 86 additions & 0 deletions
86
module-application/app-api/src/test/java/shop/jtoon/webtoon/factory/CreatorFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package shop.jtoon.webtoon.factory; | ||
|
||
import java.io.IOException; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.nio.file.Paths; | ||
import java.time.LocalDateTime; | ||
|
||
import org.springframework.mock.web.MockMultipartFile; | ||
|
||
import shop.jtoon.entity.Episode; | ||
import shop.jtoon.entity.Gender; | ||
import shop.jtoon.entity.LoginType; | ||
import shop.jtoon.entity.Member; | ||
import shop.jtoon.entity.Role; | ||
import shop.jtoon.entity.Webtoon; | ||
import shop.jtoon.entity.enums.AgeLimit; | ||
import shop.jtoon.webtoon.request.CreateEpisodeReq; | ||
import shop.jtoon.webtoon.request.GetEpisodesReq; | ||
|
||
public class CreatorFactory { | ||
|
||
public static Member createMember() { | ||
return Member.builder() | ||
.email("test@gmail.com") | ||
.password("Test123!") | ||
.name("홍길동") | ||
.nickname("길동") | ||
.gender(Gender.MALE) | ||
.phone("01012345678") | ||
.role(Role.USER) | ||
.loginType(LoginType.LOCAL) | ||
.build(); | ||
} | ||
|
||
public static Webtoon createWebtoon(Member member) { | ||
return Webtoon.builder() | ||
.title("웹툰 제목") | ||
.description("웹툰 설명") | ||
.ageLimit(AgeLimit.ALL) | ||
.thumbnailUrl("https://webtoons/thumbnail") | ||
.cookieCount(3) | ||
.author(member) | ||
.build(); | ||
} | ||
|
||
public static Episode createEpisode(Webtoon webtoon, int no) { | ||
return Episode.builder() | ||
.no(no) | ||
.title("회차 제목") | ||
.mainUrl("https://webtoons/episodes/main") | ||
.thumbnailUrl("https://webtoons/episodes/thumbnail") | ||
.hasComment(true) | ||
.openedAt(LocalDateTime.of(2023, 9, 20, 0, 0, 0)) | ||
.webtoon(webtoon) | ||
.build(); | ||
} | ||
|
||
public static CreateEpisodeReq createEpisodeReq() { | ||
return CreateEpisodeReq.builder() | ||
.no(1) | ||
.title("회차 제목") | ||
.hasComment(true) | ||
.openedAt(LocalDateTime.of(2023, 9, 20, 0, 0, 0)) | ||
.build(); | ||
} | ||
|
||
public static GetEpisodesReq createGetEpisodesReq() { | ||
return GetEpisodesReq.builder().build(); | ||
} | ||
|
||
public static MockMultipartFile createMultipartFile() { | ||
Path path = Paths.get("src/test/resources/test.png"); | ||
|
||
try { | ||
return new MockMultipartFile( | ||
"image", | ||
"test.png", | ||
"image/png", | ||
Files.readAllBytes(path) | ||
); | ||
} catch (IOException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters