Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions src/test/java/eatda/controller/BaseControllerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -63,6 +65,9 @@ public class BaseControllerTest {
@Autowired
protected ArticleGenerator articleGenerator;

@Autowired
protected StoryGenerator storyGenerator;

@Autowired
protected MemberRepository memberRepository;

Expand All @@ -72,6 +77,12 @@ public class BaseControllerTest {
@Autowired
protected CheerRepository cheerRepository;

@Autowired
protected ArticleRepository articleRepository;

@Autowired
protected StoryRepository storyRepository;

@Autowired
protected JwtManager jwtManager;

Expand All @@ -84,9 +95,6 @@ public class BaseControllerTest {
@MockitoBean
private ImageStorage imageStorage;

@MockitoBean
protected StoryService storyService; // TODO 실 객체로 변환

@LocalServerPort
private int port;

Expand Down
114 changes: 39 additions & 75 deletions src/test/java/eatda/controller/story/StoryControllerTest.java
Original file line number Diff line number Diff line change
@@ -1,55 +1,40 @@
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 {

@Test
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();
}
}

Expand All @@ -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", "[email protected]", "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)
Expand All @@ -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())
);
}
}
Expand All @@ -88,56 +68,43 @@ 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", "[email protected]", "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()
.statusCode(200)
.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")
);
}

@Test
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())
);
}
}

Expand All @@ -147,14 +114,10 @@ class GetPagedStoryDetailsByKakaoId {
@Test
void 카카오ID로_스토리_목록을_조회할_수_있다() {
String kakaoId = "123456";
List<StoryDetailResponse> 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", "[email protected]", "812", "01081231234");
Story story1 = storyGenerator.generate(member, kakaoId, "진또곱창집", startAt);
Story story2 = storyGenerator.generate(member, kakaoId, "진또곱창집", startAt.plusHours(1));

StoriesDetailResponse response = given()
.pathParam("kakaoId", kakaoId)
Expand All @@ -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())
);
}
}
Expand Down
56 changes: 56 additions & 0 deletions src/test/java/eatda/fixture/StoryGenerator.java
Original file line number Diff line number Diff line change
@@ -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();
}
}