diff --git a/src/test/java/eatda/controller/BaseControllerTest.java b/src/test/java/eatda/controller/BaseControllerTest.java index 6d0b3174..651d8e7b 100644 --- a/src/test/java/eatda/controller/BaseControllerTest.java +++ b/src/test/java/eatda/controller/BaseControllerTest.java @@ -17,10 +17,12 @@ import eatda.fixture.CheerGenerator; import eatda.fixture.MemberGenerator; import eatda.fixture.StoreGenerator; +import eatda.fixture.StoryGenerator; +import eatda.repository.article.ArticleRepository; import eatda.repository.member.MemberRepository; import eatda.repository.store.CheerRepository; import eatda.repository.store.StoreRepository; -import eatda.service.story.StoryService; +import eatda.repository.story.StoryRepository; import eatda.storage.image.ImageStorage; import io.restassured.RestAssured; import io.restassured.builder.RequestSpecBuilder; @@ -63,6 +65,9 @@ public class BaseControllerTest { @Autowired protected ArticleGenerator articleGenerator; + @Autowired + protected StoryGenerator storyGenerator; + @Autowired protected MemberRepository memberRepository; @@ -72,6 +77,12 @@ public class BaseControllerTest { @Autowired protected CheerRepository cheerRepository; + @Autowired + protected ArticleRepository articleRepository; + + @Autowired + protected StoryRepository storyRepository; + @Autowired protected JwtManager jwtManager; @@ -84,9 +95,6 @@ public class BaseControllerTest { @MockitoBean private ImageStorage imageStorage; - @MockitoBean - protected StoryService storyService; // TODO 실 객체로 변환 - @LocalServerPort private int port; diff --git a/src/test/java/eatda/controller/story/StoryControllerTest.java b/src/test/java/eatda/controller/story/StoryControllerTest.java index b4ca8ce7..259da87a 100644 --- a/src/test/java/eatda/controller/story/StoryControllerTest.java +++ b/src/test/java/eatda/controller/story/StoryControllerTest.java @@ -1,33 +1,21 @@ package eatda.controller.story; import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.equalTo; import static org.junit.jupiter.api.Assertions.assertAll; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; import eatda.controller.BaseControllerTest; -import eatda.controller.story.StoriesDetailResponse.StoryDetailResponse; +import eatda.domain.member.Member; +import eatda.domain.story.Story; import eatda.exception.BusinessErrorCode; -import eatda.exception.BusinessException; +import eatda.exception.ErrorResponse; import eatda.util.ImageUtils; import eatda.util.MappingUtils; -import io.restassured.response.Response; -import java.util.List; -import org.junit.jupiter.api.BeforeEach; +import java.time.LocalDateTime; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; public class StoryControllerTest extends BaseControllerTest { - @BeforeEach - void setUpMock() { - doReturn(new StoryRegisterResponse(1L)) - .when(storyService) - .registerStory(any(), any(), any()); - } - @Nested class RegisterStory { @@ -35,21 +23,18 @@ class RegisterStory { void 스토리를_등록할_수_있다() { StoryRegisterRequest request = new StoryRegisterRequest("농민백암순대", "123", "여기 진짜 맛있어요!"); - doReturn(new StoryRegisterResponse(123L)) - .when(storyService) - .registerStory(any(), any(), any()); - - Response response = given() + StoryRegisterResponse response = given() .contentType("multipart/form-data") .header("Authorization", accessToken()) .multiPart("request", "request.json", MappingUtils.toJsonBytes(request), "application/json") .multiPart("image", ImageUtils.getTestImage(), "image/png") .when() - .post("/api/stories"); - - response.then() + .post("/api/stories") + .then() .statusCode(201) - .body("storyId", equalTo(123)); + .extract().as(StoryRegisterResponse.class); + + assertThat(response.storyId()).isNotZero(); } } @@ -58,14 +43,10 @@ class GetStories { @Test void 스토리_목록을_조회할_수_있다() { - StoriesResponse mockResponse = new StoriesResponse(List.of( - new StoriesResponse.StoryPreview(1L, "https://s3.bucket.com/story/dummy/1.jpg"), - new StoriesResponse.StoryPreview(2L, "https://s3.bucket.com/story/dummy/2.jpg") - )); - - doReturn(mockResponse) - .when(storyService) - .getPagedStoryPreviews(5); + Member member = memberGenerator.generateRegisteredMember("test", "test@kakao.com", "812", "01081231234"); + LocalDateTime createdAt = LocalDateTime.of(2025, 8, 5, 12, 0, 0); + Story story1 = storyGenerator.generate(member, "123456", "진또곱창집", createdAt); + Story story2 = storyGenerator.generate(member, "654321", "또진곱창집", createdAt.plusHours(1)); StoriesResponse response = given() .queryParam("size", 5) @@ -76,9 +57,8 @@ class GetStories { assertAll( () -> assertThat(response.stories()).hasSize(2), - () -> assertThat(response.stories().getFirst().storyId()).isEqualTo(1L), - () -> assertThat(response.stories().getFirst().imageUrl()).isEqualTo( - "https://s3.bucket.com/story/dummy/1.jpg") + () -> assertThat(response.stories().get(0).storyId()).isEqualTo(story2.getId()), + () -> assertThat(response.stories().get(1).storyId()).isEqualTo(story1.getId()) ); } } @@ -88,23 +68,11 @@ class GetStory { @Test void 해당_스토리를_상세_조회할_수_있다() { - long storyId = 1L; - - doReturn(new StoryResponse( - 5L, - "123456", - "한식", - "진또곱창집", - "성동구", - "성수동", - "곱창은 여기", - "https://s3.bucket.com/story1.jpg", - 1L, - "커찬" - )).when(storyService).getStory(storyId); + Member member = memberGenerator.generateRegisteredMember("test", "test@kakao.com", "812", "01081231234"); + Story story = storyGenerator.generate(member, "123456", "진또곱창집", "서울시 성동구 성수동 123-45", "곱창은 여기"); StoryResponse response = given() - .pathParam("storyId", storyId) + .pathParam("storyId", story.getId()) .when() .get("/api/stories/{storyId}") .then() @@ -112,16 +80,14 @@ class GetStory { .extract().as(StoryResponse.class); assertAll( - () -> assertThat(response.storeId()).isEqualTo(5L), + () -> assertThat(response.storeId()).isNull(), () -> assertThat(response.storeKakaoId()).isEqualTo("123456"), - () -> assertThat(response.category()).isEqualTo("한식"), () -> assertThat(response.storeName()).isEqualTo("진또곱창집"), () -> assertThat(response.storeDistrict()).isEqualTo("성동구"), () -> assertThat(response.storeNeighborhood()).isEqualTo("성수동"), () -> assertThat(response.description()).isEqualTo("곱창은 여기"), - () -> assertThat(response.imageUrl()).isEqualTo("https://s3.bucket.com/story1.jpg"), - () -> assertThat(response.memberId()).isEqualTo(1L), - () -> assertThat(response.memberNickname()).isEqualTo("커찬") + () -> assertThat(response.memberId()).isEqualTo(member.getId()), + () -> assertThat(response.memberNickname()).isEqualTo("test") ); } @@ -129,15 +95,16 @@ class GetStory { void 존재하지_않는_스토리를_조회하면_404_응답한다() { long nonexistentId = 999L; - doThrow(new BusinessException(BusinessErrorCode.STORY_NOT_FOUND)) - .when(storyService).getStory(nonexistentId); - - given().pathParam("storyId", nonexistentId) + ErrorResponse response = given().pathParam("storyId", nonexistentId) .when().get("/api/stories/{storyId}") .then() .statusCode(404) - .body("errorCode", equalTo(BusinessErrorCode.STORY_NOT_FOUND.getCode())) - .body("message", equalTo(BusinessErrorCode.STORY_NOT_FOUND.getMessage())); + .extract().as(ErrorResponse.class); + + assertAll( + () -> assertThat(response.errorCode()).isEqualTo(BusinessErrorCode.STORY_NOT_FOUND.getCode()), + () -> assertThat(response.message()).isEqualTo(BusinessErrorCode.STORY_NOT_FOUND.getMessage()) + ); } } @@ -147,14 +114,10 @@ class GetPagedStoryDetailsByKakaoId { @Test void 카카오ID로_스토리_목록을_조회할_수_있다() { String kakaoId = "123456"; - List mockDetails = List.of( - new StoryDetailResponse(1L, "https://s3.bucket.com/story/dummy/1.jpg", 5L, "커찬"), - new StoryDetailResponse(2L, "https://s3.bucket.com/story/dummy/2.jpg", 2L, "지민") - ); - - doReturn(new StoriesDetailResponse(mockDetails)) - .when(storyService) - .getPagedStoryDetails(kakaoId, 5); + LocalDateTime startAt = LocalDateTime.of(2025, 8, 5, 12, 0, 0); + Member member = memberGenerator.generateRegisteredMember("test", "test@kakao.com", "812", "01081231234"); + Story story1 = storyGenerator.generate(member, kakaoId, "진또곱창집", startAt); + Story story2 = storyGenerator.generate(member, kakaoId, "진또곱창집", startAt.plusHours(1)); StoriesDetailResponse response = given() .pathParam("kakaoId", kakaoId) @@ -166,11 +129,12 @@ class GetPagedStoryDetailsByKakaoId { assertAll( () -> assertThat(response.stories()).hasSize(2), - () -> assertThat(response.stories().getFirst().storyId()).isEqualTo(1L), - () -> assertThat(response.stories().getFirst().imageUrl()).isEqualTo( - "https://s3.bucket.com/story/dummy/1.jpg"), - () -> assertThat(response.stories().getFirst().memberId()).isEqualTo(5L), - () -> assertThat(response.stories().getFirst().memberNickname()).isEqualTo("커찬") + () -> assertThat(response.stories().getFirst().storyId()).isEqualTo(story2.getId()), + () -> assertThat(response.stories().getFirst().memberId()).isEqualTo(member.getId()), + () -> assertThat(response.stories().getFirst().memberNickname()).isEqualTo(member.getNickname()), + () -> assertThat(response.stories().get(1).storyId()).isEqualTo(story1.getId()), + () -> assertThat(response.stories().get(1).memberId()).isEqualTo(member.getId()), + () -> assertThat(response.stories().get(1).memberNickname()).isEqualTo(member.getNickname()) ); } } diff --git a/src/test/java/eatda/fixture/StoryGenerator.java b/src/test/java/eatda/fixture/StoryGenerator.java new file mode 100644 index 00000000..d60c4c1b --- /dev/null +++ b/src/test/java/eatda/fixture/StoryGenerator.java @@ -0,0 +1,56 @@ +package eatda.fixture; + +import eatda.domain.ImageKey; +import eatda.domain.member.Member; +import eatda.domain.store.StoreCategory; +import eatda.domain.story.Story; +import eatda.repository.story.StoryRepository; +import eatda.util.DomainUtils; +import java.time.LocalDateTime; +import org.springframework.stereotype.Component; + +@Component +public class StoryGenerator { + + private static final StoreCategory DEFAULT_CATEGORY = StoreCategory.OTHER; + private static final String DEFAULT_DESCRIPTION = "이곳은 정말 맛있어요!"; + private static final String DEFAULT_ROAD_ADDRESS = "서울시 강남구 준비로 11길 123"; + private static final String DEFAULT_LOT_NUMBER_ADDRESS = "서울시 강남구 역삼동 123-45"; + private static final ImageKey DEFAULT_IMAGE_KEY = new ImageKey("default-story-image.jpg"); + + private final StoryRepository storyRepository; + + public StoryGenerator(StoryRepository storyRepository) { + this.storyRepository = storyRepository; + } + + public Story generate(Member member, String kakaoId, String storeName) { + Story story = create(member, kakaoId, storeName, DEFAULT_LOT_NUMBER_ADDRESS, DEFAULT_DESCRIPTION); + return storyRepository.save(story); + } + + public Story generate(Member member, String kakaoId, String storeName, LocalDateTime createdAt) { + Story story = create(member, kakaoId, storeName, DEFAULT_LOT_NUMBER_ADDRESS, DEFAULT_DESCRIPTION); + DomainUtils.setCreatedAt(story, createdAt); + return storyRepository.save(story); + } + + public Story generate(Member member, String kakaoId, String storeName, String lotNumberAddress, + String description) { + Story story = create(member, kakaoId, storeName, lotNumberAddress, description); + return storyRepository.save(story); + } + + private Story create(Member member, String kakaoId, String storeName, String lotNumberAddress, String description) { + return Story.builder() + .member(member) + .storeKakaoId(kakaoId) + .storeCategory(DEFAULT_CATEGORY) + .storeName(storeName) + .storeRoadAddress(DEFAULT_ROAD_ADDRESS) + .storeLotNumberAddress(lotNumberAddress) + .description(description) + .imageKey(DEFAULT_IMAGE_KEY) + .build(); + } +}