From 1304ac8e55d0630c4ee3a3ccda19de68429aaa10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=A4=80=ED=98=B8?= Date: Thu, 25 Apr 2024 22:13:31 +0900 Subject: [PATCH] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=84=B0=EB=A7=81=20(#458)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test: 시간 제어 구성 및 Activity Fixture 추가 * test: 로그인 테스트 최적화 * test: bus API 테스트 수정 * test: community 테스트 수정 * test: dept 테스트 수정 * test: dining test 수정 * test: land test 수정 * test: member test 수정 * test: notification test 수정 * test: owner test 수정 * test: ownerShop test 수정 * test: shop test 수정 * test: lecture test 수정 * test: track test 수정 * test: version test 수정 * test: log 제거 * test: SuppressWarnings 추가 * test: 라인 포맷팅 * test: ExtractableResponse var로 대체 * test: objectMapper static으로 변경 * chore: admin 패키지 위치 수정 * test: log 제거 * test: 불필요한 설정 제거 --- .../admin/land/controller/AdminLandApi.java | 5 +- .../land/controller/AdminLandController.java | 8 +- .../admin/land/dto/AdminLandResponse.java | 7 +- .../admin/land/dto/AdminLandsResponse.java | 8 +- .../land/repository/AdminLandRepository.java | 2 +- .../admin/land/service/AdminLandService.java | 6 +- .../koin/domain/activity/model/Activity.java | 10 +- .../domain/bus/dto/BusTimetableResponse.java | 3 + .../repository/ExpressBusCacheRepository.java | 2 +- .../koin/domain/bus/service/BusService.java | 4 +- .../domain/bus/util/CityBusOpenApiClient.java | 2 +- .../bus/util/ExpressBusOpenApiClient.java | 7 +- .../koin/domain/community/model/Board.java | 12 +- .../community/service/CommunityService.java | 2 +- .../koin/domain/coop/dto/SoldOutRequest.java | 4 +- .../koin/domain/member/model/TechStack.java | 8 +- .../ownershop/service/OwnerShopService.java | 2 - .../domain/shop/dto/MenuDetailResponse.java | 3 +- .../koin/domain/shop/model/EventArticle.java | 8 +- .../domain/shop/model/EventArticleImage.java | 9 +- .../koin/domain/shop/model/Menu.java | 6 +- .../koin/domain/shop/model/Shop.java | 10 +- .../koin/domain/user/model/Student.java | 10 +- .../koin/domain/user/model/User.java | 23 +- .../koin/global/config/ClockConfig.java | 2 + .../koin/global/config/JpaConfiguration.java | 2 + .../in/koreatech/koin/AcceptanceTest.java | 22 +- .../koreatech/koin/KoinApplicationTest.java | 5 + .../koin/acceptance/ActivityApiTest.java | 187 ++- .../koin/acceptance/AuthApiTest.java | 100 +- .../koreatech/koin/acceptance/BusApiTest.java | 347 ++--- .../koin/acceptance/CommunityApiTest.java | 616 ++++---- .../koin/acceptance/DeptApiTest.java | 36 +- .../koin/acceptance/DiningApiTest.java | 525 ++----- .../koin/acceptance/LandApiTest.java | 240 +-- .../koin/acceptance/MemberApiTest.java | 134 +- .../koin/acceptance/NotificationApiTest.java | 162 +- .../koin/acceptance/OwnerApiTest.java | 258 +--- .../koin/acceptance/OwnerShopApiTest.java | 1242 +++++---------- .../koin/acceptance/ShopApiTest.java | 1376 +++++------------ .../koin/acceptance/TimetableApiTest.java | 1042 +++++-------- .../koin/acceptance/TrackApiTest.java | 195 ++- .../koin/acceptance/UserApiTest.java | 482 ++---- .../koin/acceptance/VersionApiTest.java | 45 +- .../acceptance/AdminLandApiTest.java | 11 +- .../koin/config/TestJpaConfiguration.java | 10 + .../koreatech/koin/config/TestTimeConfig.java | 28 + .../koin/fixture/ActivityFixture.java | 70 + .../koin/fixture/ArticleFixture.java | 165 ++ .../koreatech/koin/fixture/BoardFixture.java | 106 ++ .../in/koreatech/koin/fixture/BusFixture.java | 60 + .../koreatech/koin/fixture/DiningFixture.java | 79 + .../koin/fixture/EventArticleFixture.java | 90 ++ .../koreatech/koin/fixture/LandFixture.java | 65 + .../koin/fixture/LectureFixture.java | 97 ++ .../koreatech/koin/fixture/MemberFixture.java | 52 + .../koin/fixture/MenuCategoryFixture.java | 54 + .../koreatech/koin/fixture/MenuFixture.java | 114 ++ .../koin/fixture/SemesterFixture.java | 25 + .../koin/fixture/ShopCategoryFixture.java | 37 + .../koreatech/koin/fixture/ShopFixture.java | 281 ++++ .../koin/fixture/TechStackFixture.java | 28 + .../koin/fixture/TimeTableFixture.java | 107 ++ .../koreatech/koin/fixture/TrackFixture.java | 40 + .../koreatech/koin/fixture/UserFixture.java | 316 ++++ .../domain/upload/UploadServiceTest.java | 10 +- .../koin/support/JsonAssertions.java | 23 +- src/test/resources/application.yml | 10 +- 68 files changed, 4285 insertions(+), 4772 deletions(-) rename src/main/java/in/koreatech/koin/{domain => }/admin/land/controller/AdminLandApi.java (87%) rename src/main/java/in/koreatech/koin/{domain => }/admin/land/controller/AdminLandController.java (73%) rename src/main/java/in/koreatech/koin/{domain => }/admin/land/dto/AdminLandResponse.java (89%) rename src/main/java/in/koreatech/koin/{domain => }/admin/land/dto/AdminLandsResponse.java (88%) rename src/main/java/in/koreatech/koin/{domain => }/admin/land/repository/AdminLandRepository.java (88%) rename src/main/java/in/koreatech/koin/{domain => }/admin/land/service/AdminLandService.java (85%) rename src/test/java/in/koreatech/koin/{ => admin}/acceptance/AdminLandApiTest.java (84%) create mode 100644 src/test/java/in/koreatech/koin/config/TestJpaConfiguration.java create mode 100644 src/test/java/in/koreatech/koin/config/TestTimeConfig.java create mode 100644 src/test/java/in/koreatech/koin/fixture/ActivityFixture.java create mode 100644 src/test/java/in/koreatech/koin/fixture/ArticleFixture.java create mode 100644 src/test/java/in/koreatech/koin/fixture/BoardFixture.java create mode 100644 src/test/java/in/koreatech/koin/fixture/BusFixture.java create mode 100644 src/test/java/in/koreatech/koin/fixture/DiningFixture.java create mode 100644 src/test/java/in/koreatech/koin/fixture/EventArticleFixture.java create mode 100644 src/test/java/in/koreatech/koin/fixture/LandFixture.java create mode 100644 src/test/java/in/koreatech/koin/fixture/LectureFixture.java create mode 100644 src/test/java/in/koreatech/koin/fixture/MemberFixture.java create mode 100644 src/test/java/in/koreatech/koin/fixture/MenuCategoryFixture.java create mode 100644 src/test/java/in/koreatech/koin/fixture/MenuFixture.java create mode 100644 src/test/java/in/koreatech/koin/fixture/SemesterFixture.java create mode 100644 src/test/java/in/koreatech/koin/fixture/ShopCategoryFixture.java create mode 100644 src/test/java/in/koreatech/koin/fixture/ShopFixture.java create mode 100644 src/test/java/in/koreatech/koin/fixture/TechStackFixture.java create mode 100644 src/test/java/in/koreatech/koin/fixture/TimeTableFixture.java create mode 100644 src/test/java/in/koreatech/koin/fixture/TrackFixture.java create mode 100644 src/test/java/in/koreatech/koin/fixture/UserFixture.java diff --git a/src/main/java/in/koreatech/koin/domain/admin/land/controller/AdminLandApi.java b/src/main/java/in/koreatech/koin/admin/land/controller/AdminLandApi.java similarity index 87% rename from src/main/java/in/koreatech/koin/domain/admin/land/controller/AdminLandApi.java rename to src/main/java/in/koreatech/koin/admin/land/controller/AdminLandApi.java index 2eba3f59c..03ee22a26 100644 --- a/src/main/java/in/koreatech/koin/domain/admin/land/controller/AdminLandApi.java +++ b/src/main/java/in/koreatech/koin/admin/land/controller/AdminLandApi.java @@ -1,11 +1,10 @@ -package in.koreatech.koin.domain.admin.land.controller; +package in.koreatech.koin.admin.land.controller; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; -import in.koreatech.koin.domain.admin.land.dto.AdminLandsResponse; -import in.koreatech.koin.domain.land.dto.LandsGroupResponse; +import in.koreatech.koin.admin.land.dto.AdminLandsResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/src/main/java/in/koreatech/koin/domain/admin/land/controller/AdminLandController.java b/src/main/java/in/koreatech/koin/admin/land/controller/AdminLandController.java similarity index 73% rename from src/main/java/in/koreatech/koin/domain/admin/land/controller/AdminLandController.java rename to src/main/java/in/koreatech/koin/admin/land/controller/AdminLandController.java index 7a0ca35bb..6fa564ce9 100644 --- a/src/main/java/in/koreatech/koin/domain/admin/land/controller/AdminLandController.java +++ b/src/main/java/in/koreatech/koin/admin/land/controller/AdminLandController.java @@ -1,14 +1,12 @@ -package in.koreatech.koin.domain.admin.land.controller; +package in.koreatech.koin.admin.land.controller; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import in.koreatech.koin.domain.admin.land.dto.AdminLandsResponse; -import in.koreatech.koin.domain.admin.land.service.AdminLandService; -import in.koreatech.koin.domain.land.dto.LandsGroupResponse; +import in.koreatech.koin.admin.land.dto.AdminLandsResponse; +import in.koreatech.koin.admin.land.service.AdminLandService; import lombok.RequiredArgsConstructor; @RestController diff --git a/src/main/java/in/koreatech/koin/domain/admin/land/dto/AdminLandResponse.java b/src/main/java/in/koreatech/koin/admin/land/dto/AdminLandResponse.java similarity index 89% rename from src/main/java/in/koreatech/koin/domain/admin/land/dto/AdminLandResponse.java rename to src/main/java/in/koreatech/koin/admin/land/dto/AdminLandResponse.java index c26f18f53..0c5e1d1cc 100644 --- a/src/main/java/in/koreatech/koin/domain/admin/land/dto/AdminLandResponse.java +++ b/src/main/java/in/koreatech/koin/admin/land/dto/AdminLandResponse.java @@ -1,9 +1,8 @@ -package in.koreatech.koin.domain.admin.land.dto; +package in.koreatech.koin.admin.land.dto; -import static com.fasterxml.jackson.databind.PropertyNamingStrategies.*; +import static com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; -import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; import in.koreatech.koin.domain.land.model.Land; @@ -26,7 +25,7 @@ public record AdminLandResponse( @Schema(description = "전세", example = "3500") String charterFee, - @Schema(description = "삭제(soft delete) 여부", example = "false", required = true) + @Schema(description = "삭제(soft delete) 여부", example = "false", requiredMode = REQUIRED) Boolean isDeleted ) { public static AdminLandResponse from(Land land) { diff --git a/src/main/java/in/koreatech/koin/domain/admin/land/dto/AdminLandsResponse.java b/src/main/java/in/koreatech/koin/admin/land/dto/AdminLandsResponse.java similarity index 88% rename from src/main/java/in/koreatech/koin/domain/admin/land/dto/AdminLandsResponse.java rename to src/main/java/in/koreatech/koin/admin/land/dto/AdminLandsResponse.java index 96f07f7d1..5d2676a99 100644 --- a/src/main/java/in/koreatech/koin/domain/admin/land/dto/AdminLandsResponse.java +++ b/src/main/java/in/koreatech/koin/admin/land/dto/AdminLandsResponse.java @@ -1,14 +1,12 @@ -package in.koreatech.koin.domain.admin.land.dto; +package in.koreatech.koin.admin.land.dto; -import static com.fasterxml.jackson.databind.PropertyNamingStrategies.*; +import static com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; import java.util.List; -import java.util.stream.Collectors; import org.springframework.data.domain.Page; -import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; import in.koreatech.koin.domain.land.model.Land; @@ -42,7 +40,7 @@ public static AdminLandsResponse of(Page pagedResult, Criteria criteria) { pagedResult.getContent() .stream() .map(AdminLandResponse::from) - .collect(Collectors.toList()) + .toList() ); } } diff --git a/src/main/java/in/koreatech/koin/domain/admin/land/repository/AdminLandRepository.java b/src/main/java/in/koreatech/koin/admin/land/repository/AdminLandRepository.java similarity index 88% rename from src/main/java/in/koreatech/koin/domain/admin/land/repository/AdminLandRepository.java rename to src/main/java/in/koreatech/koin/admin/land/repository/AdminLandRepository.java index 870c1d1ec..cce5c009d 100644 --- a/src/main/java/in/koreatech/koin/domain/admin/land/repository/AdminLandRepository.java +++ b/src/main/java/in/koreatech/koin/admin/land/repository/AdminLandRepository.java @@ -1,4 +1,4 @@ -package in.koreatech.koin.domain.admin.land.repository; +package in.koreatech.koin.admin.land.repository; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; diff --git a/src/main/java/in/koreatech/koin/domain/admin/land/service/AdminLandService.java b/src/main/java/in/koreatech/koin/admin/land/service/AdminLandService.java similarity index 85% rename from src/main/java/in/koreatech/koin/domain/admin/land/service/AdminLandService.java rename to src/main/java/in/koreatech/koin/admin/land/service/AdminLandService.java index 2446eef95..fee191da6 100644 --- a/src/main/java/in/koreatech/koin/domain/admin/land/service/AdminLandService.java +++ b/src/main/java/in/koreatech/koin/admin/land/service/AdminLandService.java @@ -1,4 +1,4 @@ -package in.koreatech.koin.domain.admin.land.service; +package in.koreatech.koin.admin.land.service; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -6,8 +6,8 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import in.koreatech.koin.domain.admin.land.dto.AdminLandsResponse; -import in.koreatech.koin.domain.admin.land.repository.AdminLandRepository; +import in.koreatech.koin.admin.land.dto.AdminLandsResponse; +import in.koreatech.koin.admin.land.repository.AdminLandRepository; import in.koreatech.koin.domain.land.model.Land; import in.koreatech.koin.global.model.Criteria; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/in/koreatech/koin/domain/activity/model/Activity.java b/src/main/java/in/koreatech/koin/domain/activity/model/Activity.java index bb615f806..7d6f1eacd 100644 --- a/src/main/java/in/koreatech/koin/domain/activity/model/Activity.java +++ b/src/main/java/in/koreatech/koin/domain/activity/model/Activity.java @@ -42,9 +42,13 @@ public class Activity extends BaseEntity { private boolean isDeleted = false; @Builder - private Activity(Integer id, String title, String description, String imageUrls, LocalDate date, - boolean isDeleted) { - this.id = id; + private Activity( + String title, + String description, + String imageUrls, + LocalDate date, + boolean isDeleted + ) { this.title = title; this.description = description; this.imageUrls = imageUrls; diff --git a/src/main/java/in/koreatech/koin/domain/bus/dto/BusTimetableResponse.java b/src/main/java/in/koreatech/koin/domain/bus/dto/BusTimetableResponse.java index 3505aa276..6ffd599d4 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/dto/BusTimetableResponse.java +++ b/src/main/java/in/koreatech/koin/domain/bus/dto/BusTimetableResponse.java @@ -6,6 +6,7 @@ import java.time.LocalDateTime; import java.util.List; +import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.databind.annotation.JsonNaming; import in.koreatech.koin.domain.bus.model.BusTimetable; @@ -25,6 +26,8 @@ public record BusTimetableResponse( List busTimetable, @Schema(description = "업데이트 시각", example = "2024-04-20 18:00:00", requiredMode = NOT_REQUIRED) + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime updatedAt ) { + } diff --git a/src/main/java/in/koreatech/koin/domain/bus/repository/ExpressBusCacheRepository.java b/src/main/java/in/koreatech/koin/domain/bus/repository/ExpressBusCacheRepository.java index 2c9c9fcb3..476f3188e 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/repository/ExpressBusCacheRepository.java +++ b/src/main/java/in/koreatech/koin/domain/bus/repository/ExpressBusCacheRepository.java @@ -20,5 +20,5 @@ default ExpressBusCache getById(String busRoute) { List findAll(); - Boolean existsById(String id); + boolean existsById(String id); } diff --git a/src/main/java/in/koreatech/koin/domain/bus/service/BusService.java b/src/main/java/in/koreatech/koin/domain/bus/service/BusService.java index 8fce726cc..c1d28d3be 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/service/BusService.java +++ b/src/main/java/in/koreatech/koin/domain/bus/service/BusService.java @@ -183,14 +183,14 @@ public List getBusTimetable(BusType busType, String dire } public BusTimetableResponse getBusTimetableWithUpdatedAt(BusType busType, String direction, String region){ - List BusTimetables = getBusTimetable(busType, direction, region); + List busTimetables = getBusTimetable(busType, direction, region); if (busType.equals(BusType.COMMUTING)){ busType = BusType.SHUTTLE; } VersionResponse version = versionService.getVersion(busType.name().toLowerCase() + "_bus_timetable"); - return new BusTimetableResponse(BusTimetables, version.updatedAt()); + return new BusTimetableResponse(busTimetables, version.updatedAt()); } public List getBusCourses() { diff --git a/src/main/java/in/koreatech/koin/domain/bus/util/CityBusOpenApiClient.java b/src/main/java/in/koreatech/koin/domain/bus/util/CityBusOpenApiClient.java index 19df15fad..299ae3529 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/util/CityBusOpenApiClient.java +++ b/src/main/java/in/koreatech/koin/domain/bus/util/CityBusOpenApiClient.java @@ -76,7 +76,7 @@ public CityBusOpenApiClient( public List getBusRemainTime(String nodeId) { Version version = versionRepository.getByType(VersionType.CITY); - if (isCacheExpired(version, clock)) { + if (isCacheExpired(version, clock) || cityBusCacheRepository.findById(nodeId).isEmpty()) { storeRemainTimeByOpenApi(); } return getCityBusArrivalInfoByCache(nodeId); diff --git a/src/main/java/in/koreatech/koin/domain/bus/util/ExpressBusOpenApiClient.java b/src/main/java/in/koreatech/koin/domain/bus/util/ExpressBusOpenApiClient.java index c2082bf3c..213c9c43d 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/util/ExpressBusOpenApiClient.java +++ b/src/main/java/in/koreatech/koin/domain/bus/util/ExpressBusOpenApiClient.java @@ -104,7 +104,7 @@ public List getBusRemainTime(BusStation depart, BusStation if (!expressBusCacheRepository.existsById(busCacheId)) { storeRemainTimeByOpenApi(depart.name().toLowerCase(), arrival.name().toLowerCase()); } - return getStoredRemainTime(depart.name().toLowerCase(), arrival.name().toLowerCase()); + return getStoredRemainTime(busCacheId); } private void storeRemainTimeByOpenApi(String departName, String arrivalName) { @@ -139,7 +139,7 @@ private void storeRemainTimeByOpenApi(String departName, String arrivalName) { private JsonObject getBusApiResponse(String departName, String arrivalName) { try { URL url = getBusApiURL(departName, arrivalName); - HttpURLConnection conn = (HttpURLConnection)url.openConnection(); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setRequestProperty("Content-type", "application/json"); BufferedReader reader; @@ -202,8 +202,7 @@ private List extractBusArrivalInfo(JsonObject jsonObje } } - private List getStoredRemainTime(String departName, String arrivalName) { - String busCacheId = ExpressBusCache.generateId(new ExpressBusRoute(departName, arrivalName)); + private List getStoredRemainTime(String busCacheId) { ExpressBusCache expressBusCache = expressBusCacheRepository.getById(busCacheId); if (Objects.isNull(expressBusCache)) { return Collections.emptyList(); diff --git a/src/main/java/in/koreatech/koin/domain/community/model/Board.java b/src/main/java/in/koreatech/koin/domain/community/model/Board.java index 977e5fff0..fc60d0008 100644 --- a/src/main/java/in/koreatech/koin/domain/community/model/Board.java +++ b/src/main/java/in/koreatech/koin/domain/community/model/Board.java @@ -69,8 +69,16 @@ public List getChildren() { } @Builder - private Board(String tag, String name, boolean isAnonymous, Integer articleCount, boolean isDeleted, - boolean isNotice, Integer parentId, Integer seq) { + private Board( + String tag, + String name, + boolean isAnonymous, + Integer articleCount, + boolean isDeleted, + boolean isNotice, + Integer parentId, + Integer seq + ) { this.tag = tag; this.name = name; this.isAnonymous = isAnonymous; diff --git a/src/main/java/in/koreatech/koin/domain/community/service/CommunityService.java b/src/main/java/in/koreatech/koin/domain/community/service/CommunityService.java index e0f77947d..eb5c3fdda 100644 --- a/src/main/java/in/koreatech/koin/domain/community/service/CommunityService.java +++ b/src/main/java/in/koreatech/koin/domain/community/service/CommunityService.java @@ -18,11 +18,11 @@ import in.koreatech.koin.domain.community.model.ArticleViewLog; import in.koreatech.koin.domain.community.model.Board; import in.koreatech.koin.domain.community.model.BoardTag; -import in.koreatech.koin.global.model.Criteria; import in.koreatech.koin.domain.community.repository.ArticleRepository; import in.koreatech.koin.domain.community.repository.ArticleViewLogRepository; import in.koreatech.koin.domain.community.repository.BoardRepository; import in.koreatech.koin.domain.user.repository.UserRepository; +import in.koreatech.koin.global.model.Criteria; import lombok.RequiredArgsConstructor; @Service diff --git a/src/main/java/in/koreatech/koin/domain/coop/dto/SoldOutRequest.java b/src/main/java/in/koreatech/koin/domain/coop/dto/SoldOutRequest.java index f4b645b82..7ccf47822 100644 --- a/src/main/java/in/koreatech/koin/domain/coop/dto/SoldOutRequest.java +++ b/src/main/java/in/koreatech/koin/domain/coop/dto/SoldOutRequest.java @@ -1,14 +1,14 @@ package in.koreatech.koin.domain.coop.dto; +import static com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; -import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; -@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class) +@JsonNaming(value = SnakeCaseStrategy.class) public record SoldOutRequest( @Schema(description = "메뉴 고유 ID", example = "1", requiredMode = REQUIRED) @NotNull(message = "메뉴 ID는 필수입니다.") diff --git a/src/main/java/in/koreatech/koin/domain/member/model/TechStack.java b/src/main/java/in/koreatech/koin/domain/member/model/TechStack.java index 865eecd82..b09379ad9 100644 --- a/src/main/java/in/koreatech/koin/domain/member/model/TechStack.java +++ b/src/main/java/in/koreatech/koin/domain/member/model/TechStack.java @@ -45,11 +45,15 @@ public class TechStack extends BaseEntity { private boolean isDeleted = false; @Builder - private TechStack(String imageUrl, String name, String description, Integer trackId, boolean isDeleted) { + private TechStack( + String imageUrl, + String name, + String description, + Integer trackId + ) { this.imageUrl = imageUrl; this.name = name; this.description = description; this.trackId = trackId; - this.isDeleted = isDeleted; } } diff --git a/src/main/java/in/koreatech/koin/domain/ownershop/service/OwnerShopService.java b/src/main/java/in/koreatech/koin/domain/ownershop/service/OwnerShopService.java index f9d281214..2172a7ab1 100644 --- a/src/main/java/in/koreatech/koin/domain/ownershop/service/OwnerShopService.java +++ b/src/main/java/in/koreatech/koin/domain/ownershop/service/OwnerShopService.java @@ -2,7 +2,6 @@ import java.time.Clock; import java.time.LocalDate; -import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -273,7 +272,6 @@ public void createEvent(Integer ownerId, Integer shopId, CreateEventRequest shop Shop shop = getOwnerShopById(shopId, ownerId); EventArticle eventArticle = EventArticle.builder() .shop(shop) - .thumbnailImages(new ArrayList<>()) .startDate(shopEventRequest.startDate()) .endDate(shopEventRequest.endDate()) .title(shopEventRequest.title()) diff --git a/src/main/java/in/koreatech/koin/domain/shop/dto/MenuDetailResponse.java b/src/main/java/in/koreatech/koin/domain/shop/dto/MenuDetailResponse.java index 8e10a2794..1ce94bade 100644 --- a/src/main/java/in/koreatech/koin/domain/shop/dto/MenuDetailResponse.java +++ b/src/main/java/in/koreatech/koin/domain/shop/dto/MenuDetailResponse.java @@ -89,7 +89,8 @@ public static MenuDetailResponse createForMultipleOption(Menu menu, List thumbnailImages = new ArrayList<>(); /** @@ -123,7 +122,6 @@ private EventArticle( String title, String content, User user, - List thumbnailImages, Integer hit, String ip, LocalDate startDate, @@ -133,7 +131,6 @@ private EventArticle( this.title = title; this.content = content; this.user = user; - this.thumbnailImages = thumbnailImages; this.hit = hit; this.ip = ip; this.startDate = startDate; @@ -152,7 +149,6 @@ public void modifyArticle( this.content = content; this.startDate = startDate; this.endDate = endDate; - this.thumbnailImages.forEach(entityManager::remove); this.thumbnailImages.clear(); entityManager.flush(); for (String imageUrl : thumbnailImages) { diff --git a/src/main/java/in/koreatech/koin/domain/shop/model/EventArticleImage.java b/src/main/java/in/koreatech/koin/domain/shop/model/EventArticleImage.java index f44598b8f..52880cc66 100644 --- a/src/main/java/in/koreatech/koin/domain/shop/model/EventArticleImage.java +++ b/src/main/java/in/koreatech/koin/domain/shop/model/EventArticleImage.java @@ -1,12 +1,12 @@ package in.koreatech.koin.domain.shop.model; -import static jakarta.persistence.FetchType.LAZY; import static jakarta.persistence.GenerationType.IDENTITY; import static lombok.AccessLevel.PROTECTED; import in.koreatech.koin.global.domain.BaseEntity; import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; @@ -28,7 +28,7 @@ public class EventArticleImage extends BaseEntity { @GeneratedValue(strategy = IDENTITY) private Integer id; - @ManyToOne(fetch = LAZY) + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "event_id", nullable = false) private EventArticle eventArticle; @@ -38,7 +38,10 @@ public class EventArticleImage extends BaseEntity { private String thumbnailImage; @Builder - private EventArticleImage(EventArticle eventArticle, String thumbnailImage) { + private EventArticleImage( + EventArticle eventArticle, + String thumbnailImage + ) { this.eventArticle = eventArticle; this.thumbnailImage = thumbnailImage; } diff --git a/src/main/java/in/koreatech/koin/domain/shop/model/Menu.java b/src/main/java/in/koreatech/koin/domain/shop/model/Menu.java index 745d50926..481990e50 100644 --- a/src/main/java/in/koreatech/koin/domain/shop/model/Menu.java +++ b/src/main/java/in/koreatech/koin/domain/shop/model/Menu.java @@ -62,7 +62,11 @@ public class Menu extends BaseEntity { private List menuImages = new ArrayList<>(); @Builder - private Menu(Integer shopId, String name, String description) { + private Menu( + Integer shopId, + String name, + String description + ) { this.shopId = shopId; this.name = name; this.description = description; diff --git a/src/main/java/in/koreatech/koin/domain/shop/model/Shop.java b/src/main/java/in/koreatech/koin/domain/shop/model/Shop.java index c74d656ef..845eb0acc 100644 --- a/src/main/java/in/koreatech/koin/domain/shop/model/Shop.java +++ b/src/main/java/in/koreatech/koin/domain/shop/model/Shop.java @@ -132,11 +132,7 @@ private Shop( boolean isDeleted, boolean isEvent, String remarks, - Integer hit, - List shopCategories, - List shopOpens, - List shopImages, - List menuCategories + Integer hit ) { this.owner = owner; this.name = name; @@ -153,10 +149,6 @@ private Shop( this.isEvent = isEvent; this.remarks = remarks; this.hit = hit; - this.shopCategories = shopCategories; - this.shopOpens = shopOpens; - this.shopImages = shopImages; - this.menuCategories = menuCategories; } public void modifyShop( diff --git a/src/main/java/in/koreatech/koin/domain/user/model/Student.java b/src/main/java/in/koreatech/koin/domain/user/model/Student.java index a23ce3f75..31e48cc5f 100644 --- a/src/main/java/in/koreatech/koin/domain/user/model/Student.java +++ b/src/main/java/in/koreatech/koin/domain/user/model/Student.java @@ -48,8 +48,14 @@ public class Student { private User user; @Builder - private Student(String anonymousNickname, String studentNumber, String department, - UserIdentity userIdentity, boolean isGraduated, User user) { + private Student( + String anonymousNickname, + String studentNumber, + String department, + UserIdentity userIdentity, + boolean isGraduated, + User user + ) { this.anonymousNickname = anonymousNickname; this.studentNumber = studentNumber; this.department = department; diff --git a/src/main/java/in/koreatech/koin/domain/user/model/User.java b/src/main/java/in/koreatech/koin/domain/user/model/User.java index eedc86c1a..d86501cc6 100644 --- a/src/main/java/in/koreatech/koin/domain/user/model/User.java +++ b/src/main/java/in/koreatech/koin/domain/user/model/User.java @@ -102,11 +102,24 @@ public class User extends BaseEntity { private String deviceToken; @Builder - private User(String password, String nickname, String name, String phoneNumber, UserType userType, - String email, UserGender gender, boolean isAuthed, LocalDateTime lastLoggedAt, String profileImageUrl, - Boolean isDeleted, String authToken, LocalDateTime authExpiredAt, String resetToken, - LocalDateTime resetExpiredAt, - String deviceToken) { + private User( + String password, + String nickname, + String name, + String phoneNumber, + UserType userType, + String email, + UserGender gender, + boolean isAuthed, + LocalDateTime lastLoggedAt, + String profileImageUrl, + Boolean isDeleted, + String authToken, + LocalDateTime authExpiredAt, + String resetToken, + LocalDateTime resetExpiredAt, + String deviceToken + ) { this.password = password; this.nickname = nickname; this.name = name; diff --git a/src/main/java/in/koreatech/koin/global/config/ClockConfig.java b/src/main/java/in/koreatech/koin/global/config/ClockConfig.java index ae4211a0e..adb22d795 100644 --- a/src/main/java/in/koreatech/koin/global/config/ClockConfig.java +++ b/src/main/java/in/koreatech/koin/global/config/ClockConfig.java @@ -4,8 +4,10 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; @Configuration +@Profile("!test") public class ClockConfig { @Bean diff --git a/src/main/java/in/koreatech/koin/global/config/JpaConfiguration.java b/src/main/java/in/koreatech/koin/global/config/JpaConfiguration.java index aa1acd063..46ebc0cba 100644 --- a/src/main/java/in/koreatech/koin/global/config/JpaConfiguration.java +++ b/src/main/java/in/koreatech/koin/global/config/JpaConfiguration.java @@ -1,10 +1,12 @@ package in.koreatech.koin.global.config; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; @Configuration @EnableJpaAuditing +@Profile("!test") public class JpaConfiguration { } diff --git a/src/test/java/in/koreatech/koin/AcceptanceTest.java b/src/test/java/in/koreatech/koin/AcceptanceTest.java index 7f98d24c6..f828c6b31 100644 --- a/src/test/java/in/koreatech/koin/AcceptanceTest.java +++ b/src/test/java/in/koreatech/koin/AcceptanceTest.java @@ -11,8 +11,6 @@ import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.context.annotation.Import; -import org.springframework.data.auditing.AuditingHandler; -import org.springframework.data.auditing.DateTimeProvider; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.DynamicPropertyRegistry; import org.springframework.test.context.DynamicPropertySource; @@ -21,6 +19,8 @@ import org.testcontainers.junit.jupiter.Container; import org.testcontainers.utility.DockerImageName; +import in.koreatech.koin.config.TestJpaConfiguration; +import in.koreatech.koin.config.TestTimeConfig; import in.koreatech.koin.domain.bus.util.CityBusOpenApiClient; import in.koreatech.koin.domain.coop.model.CoopEventListener; import in.koreatech.koin.domain.owner.model.OwnerEventListener; @@ -28,9 +28,10 @@ import in.koreatech.koin.domain.user.model.StudentEventListener; import in.koreatech.koin.support.DBInitializer; import io.restassured.RestAssured; +import jakarta.persistence.EntityManager; @SpringBootTest(webEnvironment = RANDOM_PORT) -@Import(DBInitializer.class) +@Import({DBInitializer.class, TestJpaConfiguration.class, TestTimeConfig.class}) @ActiveProfiles("test") public abstract class AcceptanceTest { @@ -40,18 +41,9 @@ public abstract class AcceptanceTest { @LocalServerPort protected int port; - @MockBean - protected Clock clock; - - @MockBean - protected DateTimeProvider dateTimeProvider; - @SpyBean protected CityBusOpenApiClient cityBusOpenApiClient; - @SpyBean - protected AuditingHandler handler; - @MockBean protected OwnerEventListener ownerEventListener; @@ -67,6 +59,12 @@ public abstract class AcceptanceTest { @Autowired private DBInitializer dataInitializer; + @Autowired + protected EntityManager entityManager; + + @Autowired + protected Clock clock; + @Container protected static MySQLContainer mySqlContainer; diff --git a/src/test/java/in/koreatech/koin/KoinApplicationTest.java b/src/test/java/in/koreatech/koin/KoinApplicationTest.java index c4a59d21a..b9d1c1877 100644 --- a/src/test/java/in/koreatech/koin/KoinApplicationTest.java +++ b/src/test/java/in/koreatech/koin/KoinApplicationTest.java @@ -2,10 +2,15 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; import org.springframework.test.context.ActiveProfiles; +import in.koreatech.koin.config.TestJpaConfiguration; +import in.koreatech.koin.config.TestTimeConfig; + @SpringBootTest @ActiveProfiles("test") +@Import({TestJpaConfiguration.class, TestTimeConfig.class}) class KoinApplicationTest { @Test diff --git a/src/test/java/in/koreatech/koin/acceptance/ActivityApiTest.java b/src/test/java/in/koreatech/koin/acceptance/ActivityApiTest.java index 319449262..1d372c434 100644 --- a/src/test/java/in/koreatech/koin/acceptance/ActivityApiTest.java +++ b/src/test/java/in/koreatech/koin/acceptance/ActivityApiTest.java @@ -2,28 +2,26 @@ import java.time.LocalDate; -import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import in.koreatech.koin.AcceptanceTest; -import in.koreatech.koin.domain.activity.model.Activity; -import in.koreatech.koin.domain.activity.repository.ActivityRepository; +import in.koreatech.koin.fixture.ActivityFixture; +import in.koreatech.koin.support.JsonAssertions; import io.restassured.RestAssured; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; +@SuppressWarnings("NonAsciiCharacters") class ActivityApiTest extends AcceptanceTest { @Autowired - private ActivityRepository activityRepository; + protected ActivityFixture activityFixture; @Test @DisplayName("BCSD Lab 활동 내역을 조회한다.") void getActivities() { - Activity request1 = Activity.builder() + activityFixture.builder() .title("BCSD/KAP 통합") .description("BCSD와 KAP가 통합되었습니다.") .imageUrls("https://test.com.png") @@ -31,7 +29,7 @@ void getActivities() { .isDeleted(false) .build(); - Activity request2 = Activity.builder() + activityFixture.builder() .title("19-3기 모집") .description("BCSD Lab과 함께 성장해나갈 인재를 모집했습니다.") .imageUrls(""" @@ -42,7 +40,7 @@ void getActivities() { .isDeleted(false) .build(); - Activity request3 = Activity.builder() + activityFixture.builder() .title("코인 시간표 기능 추가") .description("더 편리한 서비스 제공을 위해 시간표 기능을 추가했습니다") .imageUrls("https://test4.com.png") @@ -50,15 +48,7 @@ void getActivities() { .isDeleted(false) .build(); - Activity activity1 = activityRepository.save(request1); - Activity activity2 = activityRepository.save(request2); - Activity activity3 = activityRepository.save(request3); - - LocalDate expectedDate1 = request1.getDate(); - LocalDate expectedDate2 = request2.getDate(); - LocalDate expectedDate3 = request3.getDate(); - - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .param("year", 2019) @@ -67,40 +57,44 @@ void getActivities() { .statusCode(HttpStatus.OK.value()) .extract(); - SoftAssertions.assertSoftly( - softly -> { - // activity2 - softly.assertThat(response.body().jsonPath().getList("Activities").size()).isEqualTo(2); - softly.assertThat(response.body().jsonPath().getInt("Activities[0].id")).isEqualTo(activity2.getId()); - softly.assertThat(response.body().jsonPath().getString("Activities[0].title")) - .isEqualTo(activity2.getTitle()); - softly.assertThat(response.body().jsonPath().getString("Activities[0].description")) - .isEqualTo(activity2.getDescription()); - softly.assertThat(response.body().jsonPath().getList("Activities[0].image_urls")).hasSize(2); - LocalDate actualDate = LocalDate.parse(response.body().jsonPath().getString("Activities[0].date")); - softly.assertThat(actualDate).isEqualTo(expectedDate2); - softly.assertThat(response.body().jsonPath().getBoolean("Activities[0].is_deleted")) - .isEqualTo(activity2.isDeleted()); - - //activity3 - softly.assertThat(response.body().jsonPath().getInt("Activities[1].id")).isEqualTo(activity3.getId()); - softly.assertThat(response.body().jsonPath().getString("Activities[1].title")) - .isEqualTo(activity3.getTitle()); - softly.assertThat(response.body().jsonPath().getString("Activities[1].description")) - .isEqualTo(activity3.getDescription()); - softly.assertThat(response.body().jsonPath().getList("Activities[1].image_urls")).hasSize(1); - LocalDate actualDate2 = LocalDate.parse(response.body().jsonPath().getString("Activities[1].date")); - softly.assertThat(actualDate2).isEqualTo(expectedDate3); - softly.assertThat(response.body().jsonPath().getBoolean("Activities[1].is_deleted")) - .isEqualTo(activity3.isDeleted()); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + { + "Activities": [ + { + "date": "2019-07-29", + "is_deleted": false, + "updated_at": "2024-01-15 12:00:00", + "created_at": "2024-01-15 12:00:00", + "description": "BCSD Lab과 함께 성장해나갈 인재를 모집했습니다.", + "image_urls": [ + "https://test2.com.png", + "https://test3.com.png" + ], + "id": 2, + "title": "19-3기 모집" + }, + { + "date": "2019-08-20", + "is_deleted": false, + "updated_at": "2024-01-15 12:00:00", + "created_at": "2024-01-15 12:00:00", + "description": "더 편리한 서비스 제공을 위해 시간표 기능을 추가했습니다", + "image_urls": [ + "https://test4.com.png" + ], + "id": 3, + "title": "코인 시간표 기능 추가" + } + ] + } + """); } @Test @DisplayName("BCSD Lab 활동 내역을 조회한다. - 파라미터가 없는 경우 전체조회") void getActivitiesWithoutYear() { - Activity request1 = Activity.builder() + activityFixture.builder() .title("BCSD/KAP 통합") .description("BCSD와 KAP가 통합되었습니다.") .imageUrls("https://test.com.png") @@ -108,7 +102,7 @@ void getActivitiesWithoutYear() { .isDeleted(false) .build(); - Activity request2 = Activity.builder() + activityFixture.builder() .title("19-3기 모집") .description("BCSD Lab과 함께 성장해나갈 인재를 모집했습니다.") .imageUrls(""" @@ -119,7 +113,7 @@ void getActivitiesWithoutYear() { .isDeleted(false) .build(); - Activity request3 = Activity.builder() + activityFixture.builder() .title("코인 시간표 기능 추가") .description("더 편리한 서비스 제공을 위해 시간표 기능을 추가했습니다") .imageUrls("https://test4.com.png") @@ -127,15 +121,7 @@ void getActivitiesWithoutYear() { .isDeleted(false) .build(); - Activity activity1 = activityRepository.save(request1); - Activity activity2 = activityRepository.save(request2); - Activity activity3 = activityRepository.save(request3); - - LocalDate expectedDate1 = request1.getDate(); // LocalDate 객체 - LocalDate expectedDate2 = request2.getDate(); // LocalDate 객체 - LocalDate expectedDate3 = request3.getDate(); // LocalDate 객체 - - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .get("/activities") @@ -143,46 +129,49 @@ void getActivitiesWithoutYear() { .statusCode(HttpStatus.OK.value()) .extract(); - SoftAssertions.assertSoftly( - softly -> { - // activity1 - softly.assertThat(response.body().jsonPath().getList("Activities").size()).isEqualTo(3); - softly.assertThat(response.body().jsonPath().getInt("Activities[0].id")).isEqualTo(activity1.getId()); - softly.assertThat(response.body().jsonPath().getString("Activities[0].title")) - .isEqualTo(activity1.getTitle()); - softly.assertThat(response.body().jsonPath().getString("Activities[0].description")) - .isEqualTo(activity1.getDescription()); - softly.assertThat(response.body().jsonPath().getList("Activities[0].image_urls")).hasSize(1); - LocalDate actualDate = LocalDate.parse(response.body().jsonPath().getString("Activities[0].date")); - softly.assertThat(actualDate).isEqualTo(expectedDate1); - softly.assertThat(response.body().jsonPath().getBoolean("Activities[0].is_deleted")) - .isEqualTo(activity1.isDeleted()); - - // activity2 - softly.assertThat(response.body().jsonPath().getList("Activities").size()).isEqualTo(3); - softly.assertThat(response.body().jsonPath().getInt("Activities[1].id")).isEqualTo(activity2.getId()); - softly.assertThat(response.body().jsonPath().getString("Activities[1].title")) - .isEqualTo(activity2.getTitle()); - softly.assertThat(response.body().jsonPath().getString("Activities[1].description")) - .isEqualTo(activity2.getDescription()); - softly.assertThat(response.body().jsonPath().getList("Activities[1].image_urls")).hasSize(2); - LocalDate actualDate2 = LocalDate.parse(response.body().jsonPath().getString("Activities[1].date")); - softly.assertThat(actualDate2).isEqualTo(expectedDate2); - softly.assertThat(response.body().jsonPath().getBoolean("Activities[1].is_deleted")) - .isEqualTo(activity2.isDeleted()); - - //activity3 - softly.assertThat(response.body().jsonPath().getInt("Activities[2].id")).isEqualTo(activity3.getId()); - softly.assertThat(response.body().jsonPath().getString("Activities[2].title")) - .isEqualTo(activity3.getTitle()); - softly.assertThat(response.body().jsonPath().getString("Activities[2].description")) - .isEqualTo(activity3.getDescription()); - softly.assertThat(response.body().jsonPath().getList("Activities[2].image_urls")).hasSize(1); - LocalDate actualDate3 = LocalDate.parse(response.body().jsonPath().getString("Activities[2].date")); - softly.assertThat(actualDate3).isEqualTo(expectedDate3); - softly.assertThat(response.body().jsonPath().getBoolean("Activities[2].is_deleted")) - .isEqualTo(activity2.isDeleted()); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + { + "Activities": [ + { + "date": "2018-09-12", + "is_deleted": false, + "updated_at": "2024-01-15 12:00:00", + "created_at": "2024-01-15 12:00:00", + "description": "BCSD와 KAP가 통합되었습니다.", + "image_urls": [ + "https://test.com.png" + ], + "id": 1, + "title": "BCSD/KAP 통합" + }, + { + "date": "2019-07-29", + "is_deleted": false, + "updated_at": "2024-01-15 12:00:00", + "created_at": "2024-01-15 12:00:00", + "description": "BCSD Lab과 함께 성장해나갈 인재를 모집했습니다.", + "image_urls": [ + "https://test2.com.png", + "https://test3.com.png" + ], + "id": 2, + "title": "19-3기 모집" + }, + { + "date": "2019-08-20", + "is_deleted": false, + "updated_at": "2024-01-15 12:00:00", + "created_at": "2024-01-15 12:00:00", + "description": "더 편리한 서비스 제공을 위해 시간표 기능을 추가했습니다", + "image_urls": [ + "https://test4.com.png" + ], + "id": 3, + "title": "코인 시간표 기능 추가" + } + ] + } + """); } } diff --git a/src/test/java/in/koreatech/koin/acceptance/AuthApiTest.java b/src/test/java/in/koreatech/koin/acceptance/AuthApiTest.java index f1b162a18..1446494e9 100644 --- a/src/test/java/in/koreatech/koin/acceptance/AuthApiTest.java +++ b/src/test/java/in/koreatech/koin/acceptance/AuthApiTest.java @@ -1,44 +1,40 @@ package in.koreatech.koin.acceptance; -import java.util.Map; -import java.util.Optional; +import static in.koreatech.koin.domain.user.model.UserType.STUDENT; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; -import org.springframework.security.crypto.password.PasswordEncoder; import in.koreatech.koin.AcceptanceTest; import in.koreatech.koin.domain.user.model.User; import in.koreatech.koin.domain.user.model.UserToken; -import static in.koreatech.koin.domain.user.model.UserType.STUDENT; import in.koreatech.koin.domain.user.repository.UserRepository; import in.koreatech.koin.domain.user.repository.UserTokenRepository; +import in.koreatech.koin.fixture.UserFixture; +import in.koreatech.koin.support.JsonAssertions; import io.restassured.RestAssured; import io.restassured.http.ContentType; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; -import static org.assertj.core.api.SoftAssertions.assertSoftly; +@SuppressWarnings("NonAsciiCharacters") class AuthApiTest extends AcceptanceTest { @Autowired - private UserRepository userRepository; + private UserFixture userFixture; @Autowired - private UserTokenRepository tokenRepository; + private UserRepository userRepository; @Autowired - private PasswordEncoder passwordEncoder; + private UserTokenRepository tokenRepository; @Test @DisplayName("사용자가 로그인을 수행한다") void userLoginSuccess() { - String password = passwordEncoder.encode("1234"); - User user = User.builder() - .password(password) + User user = userFixture.builder() + .password("1234") .nickname("주노") .name("최준호") .phoneNumber("010-1234-5678") @@ -48,9 +44,7 @@ void userLoginSuccess() { .isDeleted(false) .build(); - userRepository.save(user); - - ExtractableResponse response = RestAssured + var response = RestAssured .given() .body(""" { @@ -68,24 +62,25 @@ void userLoginSuccess() { User userResult = userRepository.findById(user.getId()).get(); UserToken token = tokenRepository.findById(userResult.getId()).get(); - assertSoftly( - softly -> { - softly.assertThat(response.jsonPath().getString("token")).isNotNull(); - softly.assertThat(response.jsonPath().getString("refresh_token")).isNotNull(); - softly.assertThat(response.jsonPath().getString("refresh_token")) - .isEqualTo(token.getRefreshToken()); - softly.assertThat(response.jsonPath().getString("user_type")).isEqualTo("STUDENT"); - softly.assertThat(userResult.getLastLoggedAt()).isNotNull(); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(String.format(""" + { + "token": "%s", + "refresh_token": "%s", + "user_type": "%s" + } + """, + response.jsonPath().getString("token"), + token.getRefreshToken(), + user.getUserType().name() + )); } @Test @DisplayName("사용자가 로그인 이후 로그아웃을 수행한다") - void userLogoutSuccess() { - String password = passwordEncoder.encode("1234"); - User user = User.builder() - .password(password) + void userLogoutSuccessg() { + User user = userFixture.builder() + .password("1234") .nickname("주노") .name("최준호") .phoneNumber("010-1234-5678") @@ -95,9 +90,7 @@ void userLogoutSuccess() { .isDeleted(false) .build(); - userRepository.save(user); - - ExtractableResponse response = RestAssured + var response = RestAssured .given() .body(""" { @@ -121,17 +114,14 @@ void userLogoutSuccess() { .statusCode(HttpStatus.OK.value()) .extract(); - Optional token = tokenRepository.findById(user.getId()); - - Assertions.assertThat(token).isEmpty(); + Assertions.assertThat(tokenRepository.findById(user.getId())).isEmpty(); } @Test @DisplayName("사용자가 로그인 이후 refreshToken을 재발급한다") void userRefreshToken() { - String password = passwordEncoder.encode("1234"); - User user = User.builder() - .password(password) + User user = userFixture.builder() + .password("1234") .nickname("주노") .name("최준호") .phoneNumber("010-1234-5678") @@ -141,9 +131,7 @@ void userRefreshToken() { .isDeleted(false) .build(); - userRepository.save(user); - - ExtractableResponse response = RestAssured + var loginResponse = RestAssured .given() .body(""" { @@ -158,10 +146,14 @@ void userRefreshToken() { .statusCode(HttpStatus.CREATED.value()) .extract(); - RestAssured + var response = RestAssured .given() - .body( - Map.of("refresh_token", response.jsonPath().getString("refresh_token")) + .body(String.format(""" + { + "refresh_token": "%s" + } + """, + loginResponse.jsonPath().getString("refresh_token")) ) .contentType(ContentType.JSON) .when() @@ -172,13 +164,15 @@ void userRefreshToken() { UserToken token = tokenRepository.findById(user.getId()).get(); - assertSoftly( - softly -> { - softly.assertThat(response.jsonPath().getString("token")).isNotNull(); - softly.assertThat(response.jsonPath().getString("refresh_token")).isNotNull(); - softly.assertThat(response.jsonPath().getString("refresh_token")) - .isEqualTo(token.getRefreshToken()); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(String.format(""" + { + "token": "%s", + "refresh_token": "%s" + } + """, + response.jsonPath().getString("token"), + token.getRefreshToken() + )); } } diff --git a/src/test/java/in/koreatech/koin/acceptance/BusApiTest.java b/src/test/java/in/koreatech/koin/acceptance/BusApiTest.java index 266317100..0e2276707 100644 --- a/src/test/java/in/koreatech/koin/acceptance/BusApiTest.java +++ b/src/test/java/in/koreatech/koin/acceptance/BusApiTest.java @@ -1,20 +1,16 @@ package in.koreatech.koin.acceptance; -import static in.koreatech.koin.domain.version.model.VersionType.CITY; import static java.time.format.DateTimeFormatter.ofPattern; import static org.assertj.core.api.SoftAssertions.assertSoftly; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; -import java.time.Clock; -import java.time.Instant; import java.time.LocalTime; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.List; -import java.util.Optional; import org.assertj.core.api.SoftAssertions; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -23,7 +19,6 @@ import in.koreatech.koin.AcceptanceTest; import in.koreatech.koin.domain.bus.dto.SingleBusTimeResponse; -import in.koreatech.koin.domain.bus.model.BusRemainTime; import in.koreatech.koin.domain.bus.model.city.CityBusArrival; import in.koreatech.koin.domain.bus.model.city.CityBusCache; import in.koreatech.koin.domain.bus.model.city.CityBusCacheInfo; @@ -33,23 +28,20 @@ import in.koreatech.koin.domain.bus.model.express.ExpressBusCache; import in.koreatech.koin.domain.bus.model.express.ExpressBusCacheInfo; import in.koreatech.koin.domain.bus.model.express.ExpressBusRoute; -import in.koreatech.koin.domain.bus.model.mongo.BusCourse; -import in.koreatech.koin.domain.bus.model.mongo.Route; -import in.koreatech.koin.domain.bus.repository.BusRepository; import in.koreatech.koin.domain.bus.repository.CityBusCacheRepository; import in.koreatech.koin.domain.bus.repository.ExpressBusCacheRepository; import in.koreatech.koin.domain.version.model.Version; +import in.koreatech.koin.domain.version.model.VersionType; import in.koreatech.koin.domain.version.repository.VersionRepository; -import in.koreatech.koin.domain.version.service.VersionService; +import in.koreatech.koin.fixture.BusFixture; import in.koreatech.koin.support.JsonAssertions; import io.restassured.RestAssured; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; +@SuppressWarnings("NonAsciiCharacters") class BusApiTest extends AcceptanceTest { @Autowired - private BusRepository busRepository; + private BusFixture busFixture; @Autowired private VersionRepository versionRepository; @@ -60,122 +52,104 @@ class BusApiTest extends AcceptanceTest { @Autowired private ExpressBusCacheRepository expressBusCacheRepository; - @Autowired - private VersionService versionService; - - private final Instant UPDATED_AT = ZonedDateTime.parse( - "2024-02-21 18:00:00 KST", - ofPattern("yyyy-MM-dd " + "HH:mm:ss z") - ) - .toInstant(); - @BeforeEach void setup() { - when(clock.instant()).thenReturn(UPDATED_AT); - when(clock.getZone()).thenReturn(Clock.systemDefaultZone().getZone()); - handler.setDateTimeProvider(dateTimeProvider); - - final String arrivalTime = "18:10"; - BusCourse busCourse = BusCourse.builder() - .busType("shuttle") - .region("천안") - .direction("from") - .routes( - List.of( - Route.builder() - .routeName("주중") - .runningDays(List.of("MON", "TUE", "WED", "THU", "FRI")) - .arrivalInfos( - List.of( - Route.ArrivalNode.builder() - .nodeName("한기대") - .arrivalTime(arrivalTime) - .build(), - Route.ArrivalNode.builder() - .nodeName("신계초,운전리,연춘리") - .arrivalTime("정차") - .build(), - Route.ArrivalNode.builder() - .nodeName("천안역(학화호두과자)") - .arrivalTime("18:50") - .build(), - Route.ArrivalNode.builder() - .nodeName("터미널(신세계 앞 횡단보도)") - .arrivalTime("18:55") - .build() - ) - ) - .build() - ) - ) - .build(); - busRepository.save(busCourse); - } - - @AfterEach - void end() { - handler.setDateTimeProvider(null); + busFixture.버스_시간표_등록(); + when(cityBusOpenApiClient.getOpenApiResponse(any())).thenReturn(""" + { + "response": { + "header": { + "resultCode": "00", + "resultMsg": "NORMAL SERVICE." + }, + "body": { + "items": { + "item": [ + { + "arrprevstationcnt": 3, + "arrtime": 600, + "nodeid": "CAB285000686", + "nodenm": "종합터미널", + "routeid": "CAB285000003", + "routeno": 400, + "routetp": "일반버스", + "vehicletp": "저상버스" + }, + { + "arrprevstationcnt": 10, + "arrtime": 800, + "nodeid": "CAB285000686", + "nodenm": "종합터미널", + "routeid": "CAB285000024", + "routeno": 405, + "routetp": "일반버스", + "vehicletp": "일반차량" + }, + { + "arrprevstationcnt": 10, + "arrtime": 700, + "nodeid": "CAB285000686", + "nodenm": "종합터미널", + "routeid": "CAB285000024", + "routeno": 200, + "routetp": "일반버스", + "vehicletp": "일반차량" + } + ] + }, + "numOfRows": 30, + "pageNo": 1, + "totalCount": 3 + } + } + } + """); } @Test @DisplayName("다음 셔틀버스까지 남은 시간을 조회한다.") void getNextShuttleBusRemainTime() { - final String arrivalTime = "18:10"; - - BusType busType = BusType.from("shuttle"); - BusStation depart = BusStation.from("koreatech"); - BusStation arrival = BusStation.from("terminal"); - - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() - .param("bus_type", busType.name().toLowerCase()) - .param("depart", depart.name()) - .param("arrival", arrival.name()) + .param("bus_type", "shuttle") + .param("depart", "koreatech") + .param("arrival", "terminal") .get("/bus") .then() .statusCode(HttpStatus.OK.value()) .extract(); - SoftAssertions.assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getString("bus_type")) - .isEqualTo(busType.name().toLowerCase()); - softly.assertThat((Long)response.body().jsonPath().get("now_bus.bus_number")).isNull(); - softly.assertThat(response.body().jsonPath().getLong("now_bus.remain_time")).isEqualTo( - BusRemainTime.from(arrivalTime).getRemainSeconds(clock)); - softly.assertThat((Long)response.body().jsonPath().get("next_bus.bus_number")).isNull(); - softly.assertThat((Long)response.body().jsonPath().get("next_bus.remain_time")).isNull(); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + { + "bus_type": "shuttle", + "now_bus": { + "bus_number": null, + "remain_time": 22200 + }, + "next_bus": null + } + """); } @Test - @DisplayName("다음 시내버스까지 남은 시간을 조회한다. - Redis") + @DisplayName("다음 시내버스까지 남은 시간을 조회한다. - Redis 캐시 히트") void getNextCityBusRemainTimeRedis() { final long remainTime = 600L; final long busNumber = 400; + BusType busType = BusType.CITY; + BusStation depart = BusStation.TERMINAL; + BusStation arrival = BusStation.KOREATECH; - when(dateTimeProvider.getNow()).thenReturn(Optional.of(UPDATED_AT)); - - BusType busType = BusType.from("city"); - BusStation depart = BusStation.from("terminal"); - BusStation arrival = BusStation.from("koreatech"); BusDirection direction = BusStation.getDirection(depart, arrival); - Version version = versionRepository.save( Version.builder() - .version("20240_1711255839") - .type("city_bus_timetable") + .version("test_version") + .type(VersionType.CITY.getValue()) .build() ); - Instant requestedAt = ZonedDateTime.parse("2024-02-21 18:00:30 KST", ofPattern("yyyy-MM-dd " + "HH:mm:ss z")) - .toInstant(); - - when(clock.instant()).thenReturn(requestedAt); - when(dateTimeProvider.getNow()).thenReturn(Optional.of(requestedAt)); - cityBusCacheRepository.save( CityBusCache.of( depart.getNodeId(direction), @@ -189,7 +163,7 @@ void getNextCityBusRemainTimeRedis() { ) ); - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .param("bus_type", busType.name().toLowerCase()) @@ -200,121 +174,45 @@ void getNextCityBusRemainTimeRedis() { .statusCode(HttpStatus.OK.value()) .extract(); - assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getString("bus_type")) - .isEqualTo(busType.name().toLowerCase()); - softly.assertThat((Long)response.body().jsonPath().getLong("now_bus.bus_number")).isEqualTo(busNumber); - softly.assertThat((Long)response.body().jsonPath().getLong("now_bus.remain_time")) - .isEqualTo( - BusRemainTime.of(remainTime, version.getUpdatedAt().toLocalTime()).getRemainSeconds(clock)); - softly.assertThat(response.body().jsonPath().getObject("next_bus.bus_number", Long.class)).isNull(); - softly.assertThat(response.body().jsonPath().getObject("next_bus.remain_time", Long.class)).isNull(); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + { + "bus_type": "city", + "now_bus": { + "bus_number": 400, + "remain_time": 600 + }, + "next_bus": null + } + """); } @Test @DisplayName("다음 시내버스까지 남은 시간을 조회한다. - OpenApi") void getNextCityBusRemainTimeOpenApi() { - when(dateTimeProvider.getNow()).thenReturn(Optional.of(UPDATED_AT)); - - BusType busType = BusType.from("city"); - BusStation depart = BusStation.from("terminal"); - BusStation arrival = BusStation.from("koreatech"); - BusDirection direction = BusStation.getDirection(depart, arrival); - versionRepository.save( Version.builder() - .version("20240_1711255839") + .version("test_version") .type("city_bus_timetable") .build() ); - Instant requestedAt = ZonedDateTime.parse("2024-02-21 21:00:00 KST", ofPattern("yyyy-MM-dd " + "HH:mm:ss z")) - .toInstant(); - - when(clock.instant()).thenReturn(requestedAt); - when(dateTimeProvider.getNow()).thenReturn(Optional.of(requestedAt)); - - String busApiReturnValue = """ - { - "response": { - "header": { - "resultCode": "00", - "resultMsg": "NORMAL SERVICE." - }, - "body": { - "items": { - "item": [ - { - "arrprevstationcnt": 3, - "arrtime": 600, - "nodeid": "CAB285000686", - "nodenm": "종합터미널", - "routeid": "CAB285000003", - "routeno": 400, - "routetp": "일반버스", - "vehicletp": "저상버스" - }, - { - "arrprevstationcnt": 10, - "arrtime": 800, - "nodeid": "CAB285000686", - "nodenm": "종합터미널", - "routeid": "CAB285000024", - "routeno": 405, - "routetp": "일반버스", - "vehicletp": "일반차량" - }, - { - "arrprevstationcnt": 10, - "arrtime": 700, - "nodeid": "CAB285000686", - "nodenm": "종합터미널", - "routeid": "CAB285000024", - "routeno": 200, - "routetp": "일반버스", - "vehicletp": "일반차량" - } - ] - }, - "numOfRows": 30, - "pageNo": 1, - "totalCount": 3 - } - } - } - """; - - String nodeId = depart.getNodeId(direction); - when(cityBusOpenApiClient.getOpenApiResponse(nodeId)).thenReturn(busApiReturnValue); - - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() - .param("bus_type", busType.name().toLowerCase()) - .param("depart", depart.name()) - .param("arrival", arrival.name()) + .param("bus_type", "city") + .param("depart", "terminal") + .param("arrival", "koreatech") .get("/bus") .then() .statusCode(HttpStatus.OK.value()) .extract(); - Version version = versionRepository.getByType(CITY); - assertSoftly( softly -> { - softly.assertThat(response.body().jsonPath().getString("bus_type")) - .isEqualTo(busType.name().toLowerCase()); + softly.assertThat(response.body().jsonPath().getString("bus_type")).isEqualTo("city"); softly.assertThat((Long)response.body().jsonPath().getLong("now_bus.bus_number")).isEqualTo(400); - softly.assertThat((Long)response.body().jsonPath().getLong("now_bus.remain_time")) - .isEqualTo( - BusRemainTime.of(600L, version.getUpdatedAt().toLocalTime()).getRemainSeconds(clock)); softly.assertThat((Long)response.body().jsonPath().getLong("next_bus.bus_number")).isEqualTo(405); - softly.assertThat((Long)response.body().jsonPath().getLong("next_bus.remain_time")) - .isEqualTo( - BusRemainTime.of(800L, version.getUpdatedAt().toLocalTime()).getRemainSeconds(clock)); } ); } @@ -343,20 +241,16 @@ void getBusCourses() { @Test @DisplayName("다음 셔틀버스까지 남은 시간을 조회한다.") void getSearchTimetable() { - when(dateTimeProvider.getNow()).thenReturn(Optional.of(UPDATED_AT)); versionRepository.save( Version.builder() - .version("20240_1711255839") - .type("express_bus_timetable") + .version("test_version") + .type(VersionType.EXPRESS.getValue()) .build() ); - ZonedDateTime requestedAt = ZonedDateTime.parse("2024-02-21 18:05:00 KST", + ZonedDateTime requestedAt = ZonedDateTime.parse("2024-01-15 12:05:00 KST", ofPattern("yyyy-MM-dd " + "HH:mm:ss z")); - when(clock.instant()).thenReturn(requestedAt.toInstant()); - when(dateTimeProvider.getNow()).thenReturn(Optional.of(requestedAt.toInstant())); - final String arrivalTime = "18:10"; BusStation depart = BusStation.from("koreatech"); @@ -384,7 +278,7 @@ void getSearchTimetable() { ); expressBusCacheRepository.save(expressBusCache); - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .param("date", requestedAt.toLocalDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))) @@ -411,14 +305,7 @@ void getSearchTimetable() { @Test @DisplayName("시내버스 시간표를 조회한다 - 지원하지 않음") void getCityBusTimetable() { - when(dateTimeProvider.getNow()).thenReturn(Optional.of(UPDATED_AT)); - Instant requestedAt = ZonedDateTime.parse("2024-02-21 21:00:00 KST", ofPattern("yyyy-MM-dd " + "HH:mm:ss z")) - .toInstant(); - - when(clock.instant()).thenReturn(requestedAt); - when(dateTimeProvider.getNow()).thenReturn(Optional.of(requestedAt)); - - ExtractableResponse response = RestAssured + RestAssured .given() .when() .param("bus_type", "city") @@ -433,16 +320,12 @@ void getCityBusTimetable() { @Test @DisplayName("셔틀버스 시간표를 조회한다.") void getShuttleBusTimetable() { - BusType busType = BusType.from("shuttle"); - String direction = "from"; - String region = "천안"; - - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() - .param("bus_type", busType.name().toLowerCase()) - .param("direction", direction) - .param("region", region) + .param("bus_type", "shuttle") + .param("direction", "from") + .param("region", "천안") .get("/bus/timetable") .then() .statusCode(HttpStatus.OK.value()) @@ -452,8 +335,8 @@ void getShuttleBusTimetable() { .isEqualTo(""" [ { - "routeName": "주중", - "arrivalInfo": [ + "route_name": "주중", + "arrival_info": [ { "nodeName": "한기대", "arrivalTime": "18:10" @@ -465,7 +348,8 @@ void getShuttleBusTimetable() { { "nodeName": "천안역(학화호두과자)", "arrivalTime": "18:50" - },{ + }, + { "nodeName": "터미널(신세계 앞 횡단보도)", "arrivalTime": "18:55" } @@ -478,11 +362,9 @@ void getShuttleBusTimetable() { @Test @DisplayName("셔틀버스 시간표를 조회한다(업데이트 시각 포함).") void getShuttleBusTimetableWithUpdatedAt() { - when(dateTimeProvider.getNow()).thenReturn(Optional.of(UPDATED_AT)); - Version version = Version.builder() - .version("20240_1712920946") - .type("shuttle_bus_timetable") + .version("test_version") + .type(VersionType.SHUTTLE.getValue()) .build(); versionRepository.save(version); @@ -490,7 +372,7 @@ void getShuttleBusTimetableWithUpdatedAt() { String direction = "from"; String region = "천안"; - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .param("bus_type", busType.name().toLowerCase()) @@ -502,7 +384,7 @@ void getShuttleBusTimetableWithUpdatedAt() { .extract(); JsonAssertions.assertThat(response.asPrettyString()) - .isEqualTo(String.format(""" + .isEqualTo(""" { "bus_timetable": [ { @@ -519,15 +401,16 @@ void getShuttleBusTimetableWithUpdatedAt() { { "nodeName": "천안역(학화호두과자)", "arrivalTime": "18:50" - },{ + }, + { "nodeName": "터미널(신세계 앞 횡단보도)", "arrivalTime": "18:55" } ] } ], - "updated_at": %s + "updated_at": "2024-01-15 12:00:00" } - """, version.getUpdatedAt())); + """); } } diff --git a/src/test/java/in/koreatech/koin/acceptance/CommunityApiTest.java b/src/test/java/in/koreatech/koin/acceptance/CommunityApiTest.java index 0c8647008..c90527adc 100644 --- a/src/test/java/in/koreatech/koin/acceptance/CommunityApiTest.java +++ b/src/test/java/in/koreatech/koin/acceptance/CommunityApiTest.java @@ -1,10 +1,6 @@ package in.koreatech.koin.acceptance; -import static in.koreatech.koin.domain.user.model.UserType.STUDENT; -import static org.assertj.core.api.SoftAssertions.assertSoftly; - -import java.util.ArrayList; -import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -17,113 +13,42 @@ import in.koreatech.koin.domain.community.model.Board; import in.koreatech.koin.domain.community.model.Comment; import in.koreatech.koin.domain.community.repository.ArticleRepository; -import in.koreatech.koin.domain.community.repository.BoardRepository; import in.koreatech.koin.domain.community.repository.CommentRepository; import in.koreatech.koin.domain.user.model.Student; -import in.koreatech.koin.domain.user.model.User; -import in.koreatech.koin.domain.user.model.UserGender; -import in.koreatech.koin.domain.user.model.UserIdentity; -import in.koreatech.koin.domain.user.repository.StudentRepository; -import in.koreatech.koin.global.auth.JwtProvider; +import in.koreatech.koin.fixture.ArticleFixture; +import in.koreatech.koin.fixture.BoardFixture; +import in.koreatech.koin.fixture.UserFixture; +import in.koreatech.koin.support.JsonAssertions; import io.restassured.RestAssured; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; +@SuppressWarnings("NonAsciiCharacters") class CommunityApiTest extends AcceptanceTest { @Autowired private ArticleRepository articleRepository; - @Autowired - private BoardRepository boardRepository; - @Autowired private CommentRepository commentRepository; @Autowired - private StudentRepository studentRepository; + private UserFixture userFixture; @Autowired - private JwtProvider jwtProvider; + private ArticleFixture articleFixture; - private final long PAGE_NUMBER = 1; - private final long PAGE_LIMIT = 1; - private final long ARTICLE_COUNT = 2L; + @Autowired + private BoardFixture boardFixture; - private Board board; - private Article article1, article2; - private Student student; + Student student; + Board board; + Article article1, article2; @BeforeEach void givenBeforeEach() { - Student studentRequest = Student.builder() - .studentNumber("202020136070") - .anonymousNickname("익명") - .department("컴퓨터공학부") - .userIdentity(UserIdentity.UNDERGRADUATE) - .isGraduated(false) - .user( - User.builder() - .password("0000") - .nickname("BCSD") - .name("송선권") - .phoneNumber("010-1234-5678") - .userType(STUDENT) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build() - ) - .build(); - student = studentRepository.save(studentRequest); - - Board boardRequest = Board.builder() - .tag("FA001") - .name("자유게시판") - .isAnonymous(false) - .articleCount(338) - .isDeleted(false) - .isNotice(false) - .parentId(null) - .seq(1) - .build(); - board = boardRepository.save(boardRequest); - - Article article1Request = Article.builder() - .board(board) - .title("Article 1") - .content("

내용

") - .user(student.getUser()) - .nickname("BCSD") - .hit(14) - .ip("123.21.234.321") - .isSolved(false) - .isDeleted(false) - .commentCount((byte)2) - .meta(null) - .isNotice(false) - .noticeArticleId(null) - .build(); - article1 = articleRepository.save(article1Request); - - Article article2Request = Article.builder() - .board(board) - .title("Article 2") - .content("

CONTENT

") - .user(student.getUser()) - .nickname("BCSD") - .hit(14) - .ip("123.14.321.213") - .isSolved(false) - .isDeleted(false) - .commentCount((byte)2) - .meta(null) - .isNotice(false) - .noticeArticleId(null) - .build(); - - article2 = articleRepository.save(article2Request); + student = userFixture.준호_학생(); + board = boardFixture.자유게시판(); + article1 = articleFixture.자유글_1(student.getUser(), board); + article2 = articleFixture.자유글_2(student.getUser(), board); } @Test @@ -137,11 +62,10 @@ void getArticle() { .nickname("BCSD") .isDeleted(false) .build(); - - Comment comment = commentRepository.save(request); + commentRepository.save(request); // when then - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .get("/articles/{articleId}", article1.getId()) @@ -149,57 +73,58 @@ void getArticle() { .statusCode(HttpStatus.OK.value()) .extract(); - article1.updateContentSummary(); - assertSoftly( - softly -> { - softly.assertThat(response.jsonPath().getInt("id")).isEqualTo(article1.getId()); - softly.assertThat(response.jsonPath().getInt("board_id")).isEqualTo(article1.getBoard().getId()); - softly.assertThat(response.jsonPath().getString("title")).isEqualTo(article1.getTitle()); - softly.assertThat(response.jsonPath().getString("content")).isEqualTo(article1.getContent()); - softly.assertThat(response.jsonPath().getString("nickname")).isEqualTo(article1.getNickname()); - softly.assertThat(response.jsonPath().getInt("hit")).isEqualTo(article1.getHit()); - softly.assertThat(response.jsonPath().getBoolean("is_solved")).isEqualTo(article1.isSolved()); - softly.assertThat(response.jsonPath().getByte("comment_count")).isEqualTo(article1.getCommentCount()); - softly.assertThat(response.jsonPath().getBoolean("is_notice")).isEqualTo(article1.isNotice()); - softly.assertThat(response.jsonPath().getString("contentSummary")) - .isEqualTo(article1.getContentSummary()); - - softly.assertThat(response.jsonPath().getInt("board.id")).isEqualTo(board.getId()); - softly.assertThat(response.jsonPath().getString("board.tag")).isEqualTo(board.getTag()); - softly.assertThat(response.jsonPath().getString("board.name")).isEqualTo(board.getName()); - softly.assertThat(response.jsonPath().getBoolean("board.is_anonymous")) - .isEqualTo(board.getIsAnonymous()); - softly.assertThat(response.jsonPath().getInt("board.article_count")) - .isEqualTo(board.getArticleCount()); - softly.assertThat(response.jsonPath().getBoolean("board.is_deleted")).isEqualTo(board.isDeleted()); - softly.assertThat(response.jsonPath().getBoolean("board.is_notice")).isEqualTo(board.isNotice()); - softly.assertThat(response.jsonPath().getString("board.parent_id")).isEqualTo(board.getParentId()); - softly.assertThat(response.jsonPath().getInt("board.seq")).isEqualTo(board.getSeq()); - softly.assertThat(response.jsonPath().getString("board.children")) - .isEqualTo(board.getChildren().isEmpty() ? null : board.getChildren()); - - softly.assertThat(response.jsonPath().getInt("comments[0].id")).isEqualTo(comment.getId()); - softly.assertThat(response.jsonPath().getInt("comments[0].article_id")) - .isEqualTo(comment.getArticle().getId()); - softly.assertThat(response.jsonPath().getString("comments[0].content")).isEqualTo(comment.getContent()); - softly.assertThat(response.jsonPath().getInt("comments[0].user_id")).isEqualTo(comment.getUserId()); - softly.assertThat(response.jsonPath().getString("comments[0].nickname")) - .isEqualTo(comment.getNickname()); - softly.assertThat(response.jsonPath().getBoolean("comments[0].is_deleted")) - .isEqualTo(comment.getIsDeleted()); - softly.assertThat(response.jsonPath().getBoolean("comments[0].grantEdit")) - .isEqualTo(comment.isGrantEdit()); - softly.assertThat(response.jsonPath().getBoolean("comments[0].grantDelete")) - .isEqualTo(comment.isGrantDelete()); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + { + "contentSummary": "내용", + "id": 1, + "board_id": 1, + "title": "자유 글의 제목입니다", + "content": "

내용

", + "nickname": "준호", + "is_solved": false, + "is_notice": false, + "hit": 1, + "comment_count": 0, + "board": { + "id": 1, + "tag": "FA001", + "name": "자유게시판", + "is_anonymous": false, + "article_count": 0, + "is_deleted": false, + "is_notice": false, + "parent_id": null, + "seq": 1, + "children": null, + "created_at": "2024-01-15 12:00:00", + "updated_at": "2024-01-15 12:00:00" + }, + "comments": [ + { + "grantEdit": false, + "grantDelete": false, + "id": 1, + "article_id": 1, + "content": "댓글", + "user_id": 1, + "nickname": "BCSD", + "is_deleted": false, + "created_at": "2024-01-15 12:00:00", + "updated_at": "2024-01-15 12:00:00" + } + ], + "created_at": "2024-01-15 12:00:00", + "updated_at": "2024-01-15 12:00:00" + } + """); } @Test @DisplayName("특정 게시글을 단일 조회한다. - 댓글 작성자가 본인이면 수정 및 제거 권한이 부여된다.") void getArticleAuthorizationComment() { // given - String token = jwtProvider.createToken(student.getUser()); + String token = userFixture.getToken(student.getUser()); Comment request = Comment.builder() .article(article1) @@ -213,7 +138,7 @@ void getArticleAuthorizationComment() { comment.updateAuthority(student.getUser().getId()); // when then - ExtractableResponse response = RestAssured + var response = RestAssured .given() .header("Authorization", "Bearer " + token) .when() @@ -222,193 +147,209 @@ void getArticleAuthorizationComment() { .statusCode(HttpStatus.OK.value()) .extract(); - article1.updateContentSummary(); - assertSoftly( - softly -> { - softly.assertThat(response.jsonPath().getBoolean("comments[0].grantEdit")) - .isEqualTo(comment.isGrantEdit()); - softly.assertThat(response.jsonPath().getBoolean("comments[0].grantDelete")) - .isEqualTo(comment.isGrantDelete()); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + { + "contentSummary": "내용", + "id": 1, + "board_id": 1, + "title": "자유 글의 제목입니다", + "content": "

내용

", + "nickname": "준호", + "is_solved": false, + "is_notice": false, + "hit": 2, + "comment_count": 0, + "board": { + "id": 1, + "tag": "FA001", + "name": "자유게시판", + "is_anonymous": false, + "article_count": 0, + "is_deleted": false, + "is_notice": false, + "parent_id": null, + "seq": 1, + "children": null, + "created_at": "2024-01-15 12:00:00", + "updated_at": "2024-01-15 12:00:00" + }, + "comments": [ + { + "grantEdit": true, + "grantDelete": true, + "id": 1, + "article_id": 1, + "content": "댓글", + "user_id": 1, + "nickname": "BCSD", + "is_deleted": false, + "created_at": "2024-01-15 12:00:00", + "updated_at": "2024-01-15 12:00:00" + } + ], + "created_at": "2024-01-15 12:00:00", + "updated_at": "2024-01-15 12:00:00" + } + """); } @Test @DisplayName("게시글들을 페이지네이션하여 조회한다.") void getArticlesByPagination() { - // given - // when then - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .param("boardId", board.getId()) - .param("page", PAGE_NUMBER) - .param("limit", PAGE_LIMIT) + .param("page", 1) + .param("limit", 10) .get("/articles") .then() .statusCode(HttpStatus.OK.value()) .extract(); - article2.updateContentSummary(); - assertSoftly( - softly -> { - softly.assertThat(response.jsonPath().getInt("board.id")).isEqualTo(board.getId()); - softly.assertThat(response.jsonPath().getString("board.tag")).isEqualTo(board.getTag()); - softly.assertThat(response.jsonPath().getString("board.name")).isEqualTo(board.getName()); - softly.assertThat(response.jsonPath().getBoolean("board.is_anonymous")) - .isEqualTo(board.getIsAnonymous()); - softly.assertThat(response.jsonPath().getInt("board.article_count")) - .isEqualTo(board.getArticleCount()); - softly.assertThat(response.jsonPath().getBoolean("board.is_deleted")).isEqualTo(board.isDeleted()); - softly.assertThat(response.jsonPath().getBoolean("board.is_notice")).isEqualTo(board.isNotice()); - softly.assertThat(response.jsonPath().getString("board.parent_id")).isEqualTo(board.getParentId()); - softly.assertThat(response.jsonPath().getInt("board.seq")).isEqualTo(board.getSeq()); - softly.assertThat(response.jsonPath().getString("board.children")) - .isEqualTo(board.getChildren().isEmpty() ? null : board.getChildren()); - - softly.assertThat(response.jsonPath().getInt("articles[0].id")).isEqualTo(article2.getId()); - softly.assertThat(response.jsonPath().getInt("articles[0].board_id")) - .isEqualTo(article2.getBoard().getId()); - softly.assertThat(response.jsonPath().getString("articles[0].title")).isEqualTo(article2.getTitle()); - softly.assertThat(response.jsonPath().getString("articles[0].content")) - .isEqualTo(article2.getContent()); - softly.assertThat(response.jsonPath().getInt("articles[0].user_id")) - .isEqualTo(article2.getUser().getId()); - softly.assertThat(response.jsonPath().getString("articles[0].nickname")) - .isEqualTo(article2.getNickname()); - softly.assertThat(response.jsonPath().getInt("articles[0].hit")).isEqualTo(article2.getHit()); - softly.assertThat(response.jsonPath().getString("articles[0].ip")).isEqualTo(article2.getIp()); - softly.assertThat(response.jsonPath().getBoolean("articles[0].is_solved")) - .isEqualTo(article2.isSolved()); - softly.assertThat(response.jsonPath().getBoolean("articles[0].is_deleted")) - .isEqualTo(article2.isDeleted()); - softly.assertThat(response.jsonPath().getByte("articles[0].comment_count")) - .isEqualTo(article2.getCommentCount()); - softly.assertThat(response.jsonPath().getString("articles[0].meta")).isEqualTo(article2.getMeta()); - softly.assertThat(response.jsonPath().getBoolean("articles[0].is_notice")) - .isEqualTo(article2.isNotice()); - softly.assertThat(response.jsonPath().getString("articles[0].notice_article_id")) - .isEqualTo(article2.getNoticeArticleId()); - softly.assertThat(response.jsonPath().getString("articles[0].summary")) - .isEqualTo(article2.getSummary()); - softly.assertThat(response.jsonPath().getString("articles[0].contentSummary")) - .isEqualTo(article2.getContentSummary()); - - softly.assertThat(response.jsonPath().getInt("totalPage")).isEqualTo(ARTICLE_COUNT / PAGE_LIMIT); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + { + "articles": [ + { + "contentSummary": "내용222", + "id": 2, + "board_id": 1, + "title": "자유 글2의 제목입니다", + "content": "

내용222

", + "user_id": 1, + "nickname": "준호", + "hit": 1, + "ip": "127.0.0.1", + "is_solved": false, + "is_deleted": false, + "comment_count": 0, + "meta": null, + "is_notice": false, + "notice_article_id": null, + "summary": null, + "created_at": "2024-01-15 12:00:00", + "updated_at": "2024-01-15 12:00:00" + }, + { + "contentSummary": "내용", + "id": 1, + "board_id": 1, + "title": "자유 글의 제목입니다", + "content": "

내용

", + "user_id": 1, + "nickname": "준호", + "hit": 1, + "ip": "123.21.234.321", + "is_solved": false, + "is_deleted": false, + "comment_count": 0, + "meta": null, + "is_notice": false, + "notice_article_id": null, + "summary": null, + "created_at": "2024-01-15 12:00:00", + "updated_at": "2024-01-15 12:00:00" + } + ], + "board": { + "id": 1, + "tag": "FA001", + "name": "자유게시판", + "is_anonymous": false, + "article_count": 0, + "is_deleted": false, + "is_notice": false, + "parent_id": null, + "seq": 1, + "children": null, + "created_at": "2024-01-15 12:00:00", + "updated_at": "2024-01-15 12:00:00" + }, + "totalPage": 1 + } + """); } @Test @DisplayName("게시글들을 페이지네이션하여 조회한다. - 페이지가 0이면 1 페이지 조회") void getArticlesByPagination_0Page() { - // given - final long PAGE_NUMBER_ZERO = 0L; - // when then - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .param("boardId", board.getId()) - .param("page", PAGE_NUMBER_ZERO) - .param("limit", PAGE_LIMIT) + .param("page", 0L) + .param("limit", 1) .get("/articles") .then() .statusCode(HttpStatus.OK.value()) .extract(); - assertSoftly( - softly -> { - softly.assertThat(response.jsonPath().getInt("articles[0].id")).isEqualTo(article2.getId()); - } - ); + assertThat(response.jsonPath().getInt("articles[0].id")).isEqualTo(article2.getId()); } @Test @DisplayName("게시글들을 페이지네이션하여 조회한다. - 페이지가 음수이면 1 페이지 조회") void getArticlesByPagination_lessThan0Pages() { - // given - final long PAGE_NUMBER_MINUS = -10L; - // when then - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .param("boardId", board.getId()) - .param("page", PAGE_NUMBER_MINUS) - .param("limit", PAGE_LIMIT) + .param("page", -10L) + .param("limit", 1) .get("/articles") .then() .statusCode(HttpStatus.OK.value()) .extract(); - assertSoftly( - softly -> { - softly.assertThat(response.jsonPath().getInt("articles[0].id")).isEqualTo(article2.getId()); - } - ); + assertThat(response.jsonPath().getInt("articles[0].id")).isEqualTo(article2.getId()); } @Test @DisplayName("게시글들을 페이지네이션하여 조회한다. - limit가 0 이면 한 번에 1 게시글 조회") void getArticlesByPagination_1imit() { - // given - final long PAGE_LIMIT_ZERO = 0L; - // when then - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .param("boardId", board.getId()) - .param("page", PAGE_NUMBER) - .param("limit", PAGE_LIMIT_ZERO) + .param("page", 1) + .param("limit", 0L) .get("/articles") .then() .statusCode(HttpStatus.OK.value()) .extract(); - assertSoftly( - softly -> { - softly.assertThat(response.jsonPath().getInt("totalPage")).isEqualTo(ARTICLE_COUNT / PAGE_LIMIT); - } - ); + assertThat(response.jsonPath().getList("articles")).hasSize(1); } @Test @DisplayName("게시글들을 페이지네이션하여 조회한다. - limit가 음수이면 한 번에 1 게시글 조회") void getArticlesByPagination_lessThan0Limit() { - // given - final long PAGE_LIMIT_ZERO = -10L; - // when then - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .param("boardId", board.getId()) - .param("page", PAGE_NUMBER) - .param("limit", PAGE_LIMIT_ZERO) + .param("page", 1) + .param("limit", -10L) .get("/articles") .then() .statusCode(HttpStatus.OK.value()) .extract(); - assertSoftly( - softly -> { - softly.assertThat(response.jsonPath().getInt("totalPage")).isEqualTo(ARTICLE_COUNT / PAGE_LIMIT); - } - ); + assertThat(response.jsonPath().getList("articles")).hasSize(1); } @Test @DisplayName("게시글들을 페이지네이션하여 조회한다. - limit가 50 이상이면 한 번에 50 게시글 조회") void getArticlesByPagination_over50Limit() { // given - final long PAGE_LIMIT_ZERO = 100L; - final long MAX_PAGE_LIMIT = 50L; - final long ADD_ARTICLE_COUNT = 60L; - - for (int i = 0; i < ADD_ARTICLE_COUNT; i++) { + for (int i = 0; i < 60; i++) { Article article = Article.builder() .board(board) .title("제목") @@ -428,34 +369,25 @@ void getArticlesByPagination_over50Limit() { } // when then - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .param("boardId", board.getId()) - .param("page", PAGE_NUMBER) - .param("limit", PAGE_LIMIT_ZERO) + .param("page", 1) + .param("limit", 100L) .get("/articles") .then() .statusCode(HttpStatus.OK.value()) .extract(); - assertSoftly( - softly -> { - softly.assertThat(response.jsonPath().getInt("totalPage")) - .isEqualTo((long)Math.ceil(((double)ARTICLE_COUNT + ADD_ARTICLE_COUNT) / MAX_PAGE_LIMIT)); - } - ); + assertThat(response.jsonPath().getList("articles")).hasSize(50); } @Test @DisplayName("게시글들을 페이지네이션하여 조회한다. - 페이지, limit가 주어지지 않으면 1 페이지 10 게시글 조회") void getArticlesByPagination_default() { // given - final long DEFAULT_LIMIT = 10L; - final long ADD_ARTICLE_COUNT = 10L; - final long FINAL_ARTICLE_ID = ARTICLE_COUNT + ADD_ARTICLE_COUNT; - - for (int i = 0; i < ADD_ARTICLE_COUNT; i++) { + for (int i = 0; i < 10; i++) { Article article = Article.builder() .board(board) .title("제목") @@ -475,7 +407,7 @@ void getArticlesByPagination_default() { } // when then - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .param("boardId", board.getId()) @@ -484,71 +416,53 @@ void getArticlesByPagination_default() { .statusCode(HttpStatus.OK.value()) .extract(); - assertSoftly( - softly -> { - softly.assertThat(response.jsonPath().getInt("articles[0].id")).isEqualTo(FINAL_ARTICLE_ID); - softly.assertThat(response.jsonPath().getInt("totalPage")) - .isEqualTo((long)Math.ceil(((double)ARTICLE_COUNT + ADD_ARTICLE_COUNT) / DEFAULT_LIMIT)); - } - ); + assertThat(response.jsonPath().getList("articles")).hasSize(10); + } @Test @DisplayName("게시글들을 페이지네이션하여 조회한다. - 요청된 페이지에 게시글이 존재하지 않으면 빈 게시글 배열을 반환한다.") void getArticlesByPagination_overMaxPageNotFound() { - // given - final long PAGE_NUMBER = 10000L; - // when then - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .param("boardId", board.getId()) - .param("page", PAGE_NUMBER) - .param("limit", PAGE_LIMIT) + .param("page", 10000L) + .param("limit", 1) .get("/articles") .then() .statusCode(HttpStatus.OK.value()) .extract(); - assertSoftly( - softly -> { - softly.assertThat(response.jsonPath().getList("articles")).hasSize(0); - } - ); + assertThat(response.jsonPath().getList("articles")).isEmpty(); } @Test @DisplayName("인기많은 게시글 목록을 조회한다.") void getHotArticles() { // given - final int ARTICLE_COUNT = 30; - final int HOT_ARTICLE_LIMIT = 10; - List
articles = new ArrayList<>(); - - for (int i = 1; i <= ARTICLE_COUNT; i++) { - articles.add( - Article.builder() - .board(board) - .title(String.format("Article %d", i)) - .content("

내용

") - .user(student.getUser()) - .nickname("BCSD") - .hit(i) - .ip("123.21.234.321") - .isSolved(false) - .isDeleted(false) - .commentCount((byte)2) - .meta(null) - .isNotice(false) - .noticeArticleId(null) - .build() + for (int i = 5; i <= 7; i++) { + articleRepository.save(Article.builder() + .board(board) + .title(String.format("Article %d", i)) + .content("

내용

") + .user(student.getUser()) + .nickname("BCSD") + .hit(i) + .ip("123.21.234.321") + .isSolved(false) + .isDeleted(false) + .commentCount((byte)2) + .meta(null) + .isNotice(false) + .noticeArticleId(null) + .build() ); - articleRepository.save(articles.get(i - 1)); } // when then - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .get("/articles/hot/list") @@ -556,41 +470,55 @@ void getHotArticles() { .statusCode(HttpStatus.OK.value()) .extract(); - assertSoftly( - softly -> { - softly.assertThat(response.jsonPath().getList("").size()).isEqualTo(HOT_ARTICLE_LIMIT); - - softly.assertThat(response.jsonPath().getInt("[0].id")) - .isEqualTo(articles.get(ARTICLE_COUNT - 1).getId()); - softly.assertThat(response.jsonPath().getInt("[0].board_id")).isEqualTo(board.getId()); - softly.assertThat(response.jsonPath().getString("[0].title")) - .isEqualTo(articles.get(ARTICLE_COUNT - 1).getTitle()); - softly.assertThat(response.jsonPath().getString("[0].contentSummary")) - .isEqualTo(articles.get(ARTICLE_COUNT - 1).getContentSummary()); - softly.assertThat(response.jsonPath().getByte("[0].comment_count")) - .isEqualTo((byte)articles.get(ARTICLE_COUNT - 1).getCommentCount()); - softly.assertThat(response.jsonPath().getInt("[0].hit")) - .isEqualTo(articles.get(ARTICLE_COUNT - 1).getHit()); - - softly.assertThat(response.jsonPath().getInt("[1].id")) - .isEqualTo(articles.get(ARTICLE_COUNT - 2).getId()); - softly.assertThat(response.jsonPath().getInt("[2].id")) - .isEqualTo(articles.get(ARTICLE_COUNT - 3).getId()); - softly.assertThat(response.jsonPath().getInt("[3].id")) - .isEqualTo(articles.get(ARTICLE_COUNT - 4).getId()); - softly.assertThat(response.jsonPath().getInt("[4].id")) - .isEqualTo(articles.get(ARTICLE_COUNT - 5).getId()); - softly.assertThat(response.jsonPath().getInt("[5].id")) - .isEqualTo(articles.get(ARTICLE_COUNT - 6).getId()); - softly.assertThat(response.jsonPath().getInt("[6].id")) - .isEqualTo(articles.get(ARTICLE_COUNT - 7).getId()); - softly.assertThat(response.jsonPath().getInt("[7].id")) - .isEqualTo(articles.get(ARTICLE_COUNT - 8).getId()); - softly.assertThat(response.jsonPath().getInt("[8].id")) - .isEqualTo(articles.get(ARTICLE_COUNT - 9).getId()); - softly.assertThat(response.jsonPath().getInt("[9].id")) - .isEqualTo(articles.get(ARTICLE_COUNT - 10).getId()); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + [ + { + "contentSummary": "내용", + "id": 5, + "board_id": 1, + "title": "Article 7", + "comment_count": 2, + "hit": 7, + "created_at": "2024-01-15 12:00:00" + }, + { + "contentSummary": "내용", + "id": 4, + "board_id": 1, + "title": "Article 6", + "comment_count": 2, + "hit": 6, + "created_at": "2024-01-15 12:00:00" + }, + { + "contentSummary": "내용", + "id": 3, + "board_id": 1, + "title": "Article 5", + "comment_count": 2, + "hit": 5, + "created_at": "2024-01-15 12:00:00" + }, + { + "contentSummary": "내용222", + "id": 2, + "board_id": 1, + "title": "자유 글2의 제목입니다", + "comment_count": 0, + "hit": 1, + "created_at": "2024-01-15 12:00:00" + }, + { + "contentSummary": "내용", + "id": 1, + "board_id": 1, + "title": "자유 글의 제목입니다", + "comment_count": 0, + "hit": 1, + "created_at": "2024-01-15 12:00:00" + } + ] + """); } } diff --git a/src/test/java/in/koreatech/koin/acceptance/DeptApiTest.java b/src/test/java/in/koreatech/koin/acceptance/DeptApiTest.java index f8358f765..55ff3c7e1 100644 --- a/src/test/java/in/koreatech/koin/acceptance/DeptApiTest.java +++ b/src/test/java/in/koreatech/koin/acceptance/DeptApiTest.java @@ -1,6 +1,6 @@ package in.koreatech.koin.acceptance; -import static org.assertj.core.api.SoftAssertions.assertSoftly; +import static org.assertj.core.api.Assertions.assertThat; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -8,10 +8,10 @@ import in.koreatech.koin.AcceptanceTest; import in.koreatech.koin.domain.dept.model.Dept; +import in.koreatech.koin.support.JsonAssertions; import io.restassured.RestAssured; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; +@SuppressWarnings("NonAsciiCharacters") class DeptApiTest extends AcceptanceTest { @Test @@ -21,7 +21,7 @@ void findDeptNameByDeptNumber() { Dept dept = Dept.COMPUTER_SCIENCE; // when then - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .param("dept_num", dept.getNumbers().get(0)) @@ -30,12 +30,14 @@ void findDeptNameByDeptNumber() { .statusCode(HttpStatus.OK.value()) .extract(); - assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getString("dept_num")).isEqualTo(dept.getNumbers().get(0)); - softly.assertThat(response.body().jsonPath().getString("name")).isEqualTo(dept.getName()); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + { + "dept_num": "35", + "name": "컴퓨터공학부" + } + """ + ); } @Test @@ -45,7 +47,7 @@ void findAllDepts() { final int DEPT_SIZE = Dept.values().length - 1; //when then - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .get("/depts") @@ -53,16 +55,6 @@ void findAllDepts() { .statusCode(HttpStatus.OK.value()) .extract(); - assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getList(".").size()) - .isEqualTo(DEPT_SIZE); - for (int i = 0; i < DEPT_SIZE; i++) { - softly.assertThat(response.body().jsonPath().getString(String.format("[%d].name", i))).isNotEmpty(); - softly.assertThat(response.body().jsonPath().getString(String.format("[%d].curriculum_link", i))) - .isNotEmpty(); - } - } - ); + assertThat(response.body().jsonPath().getList(".")).hasSize(DEPT_SIZE); } } diff --git a/src/test/java/in/koreatech/koin/acceptance/DiningApiTest.java b/src/test/java/in/koreatech/koin/acceptance/DiningApiTest.java index 40d2e9825..c3e61ff2b 100644 --- a/src/test/java/in/koreatech/koin/acceptance/DiningApiTest.java +++ b/src/test/java/in/koreatech/koin/acceptance/DiningApiTest.java @@ -1,22 +1,12 @@ package in.koreatech.koin.acceptance; -import static in.koreatech.koin.domain.user.model.UserType.COOP; -import static in.koreatech.koin.domain.user.model.UserType.STUDENT; -import static in.koreatech.koin.global.domain.notification.model.NotificationSubscribeType.DINING_SOLD_OUT; import static io.restassured.RestAssured.given; -import static java.time.format.DateTimeFormatter.ofPattern; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import java.time.Clock; import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.util.List; -import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -24,72 +14,32 @@ import in.koreatech.koin.AcceptanceTest; import in.koreatech.koin.domain.coop.dto.DiningImageRequest; -import in.koreatech.koin.domain.coop.dto.SoldOutRequest; import in.koreatech.koin.domain.dining.model.Dining; import in.koreatech.koin.domain.dining.repository.DiningRepository; import in.koreatech.koin.domain.user.model.User; -import in.koreatech.koin.domain.user.model.UserGender; -import in.koreatech.koin.domain.user.repository.UserRepository; -import in.koreatech.koin.global.auth.JwtProvider; -import in.koreatech.koin.global.domain.notification.model.NotificationSubscribe; -import in.koreatech.koin.global.domain.notification.repository.NotificationSubscribeRepository; +import in.koreatech.koin.fixture.DiningFixture; +import in.koreatech.koin.fixture.UserFixture; +import in.koreatech.koin.support.JsonAssertions; +import io.restassured.RestAssured; import io.restassured.http.ContentType; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; +@SuppressWarnings("NonAsciiCharacters") class DiningApiTest extends AcceptanceTest { @Autowired private DiningRepository diningRepository; @Autowired - private JwtProvider jwtProvider; + private UserFixture userFixture; @Autowired - private UserRepository userRepository; - - @Autowired - private NotificationSubscribeRepository notificationSubscribeRepository; + private DiningFixture diningFixture; @Test @DisplayName("특정 날짜의 모든 식단들을 조회한다.") void findDinings() { - Dining request1 = Dining.builder() - .date(LocalDate.parse("2024-03-11")) - .type("LUNCH") - .place("A코스") - .priceCard(6000) - .priceCash(6000) - .kcal(881) - .menu(""" - ["병아리콩밥", "(탕)소고기육개장", "땡초부추전", "누룽지탕"]""") - .build(); - - Dining request2 = Dining.builder() - .date(LocalDate.parse("2024-03-01")) - .type("LUNCH") - .place("2캠퍼스") - .priceCard(6000) - .priceCash(6000) - .kcal(881) - .menu(""" - ["혼합잡곡밥", "가쓰오장국", "땡초부추전", "누룽지탕"]""") - .build(); - - Dining request3 = Dining.builder() - .date(LocalDate.parse("2024-03-11")) - .type("LUNCH") - .place("능수관") - .priceCard(6000) - .priceCash(6000) - .kcal(300) - .menu(""" - ["참치김치볶음밥", "유부된장국", "땡초부추전", "누룽지탕"]""") - .build(); - - Dining dining1 = diningRepository.save(request1); - Dining dining2 = diningRepository.save(request2); - Dining dining3 = diningRepository.save(request3); + diningFixture.능수관_점심(LocalDate.parse("2024-03-11")); + diningFixture.캠퍼스2_점심(LocalDate.parse("2024-03-11")); var response = given() .when() @@ -98,70 +48,57 @@ void findDinings() { .statusCode(HttpStatus.OK.value()) .extract(); - List menus1 = List.of("병아리콩밥", "(탕)소고기육개장", "땡초부추전", "누룽지탕"); - List menus2 = List.of("참치김치볶음밥", "유부된장국", "땡초부추전", "누룽지탕"); - - SoftAssertions.assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getList(".").size()).isEqualTo(2); - - softly.assertThat(response.body().jsonPath().getInt("[0].id")).isEqualTo(dining1.getId()); - softly.assertThat(response.body().jsonPath().getString("[0].date")) - .isEqualTo(dining1.getDate().format(ofPattern("yyyy-MM-dd"))); - softly.assertThat(response.body().jsonPath().getString("[0].type")).isEqualTo(dining1.getType()); - softly.assertThat(response.body().jsonPath().getString("[0].place")).isEqualTo(dining1.getPlace()); - softly.assertThat(response.body().jsonPath().getInt("[0].price_card")) - .isEqualTo(dining1.getPriceCard()); - softly.assertThat(response.body().jsonPath().getInt("[0].price_cash")) - .isEqualTo(dining1.getPriceCash()); - softly.assertThat(response.body().jsonPath().getInt("[0].kcal")).isEqualTo(dining1.getKcal()); - softly.assertThat(response.body().jsonPath().getString("[0].created_at")) - .contains(dining1.getUpdatedAt().format(ofPattern("yyyy-MM-dd"))); - softly.assertThat(response.body().jsonPath().getString("[0].updated_at")) - .contains(dining1.getUpdatedAt().format(ofPattern("yyyy-MM-dd"))); - softly.assertThat(response.body().jsonPath().getList("[0].menu", String.class)) - .containsExactlyInAnyOrderElementsOf(menus1); - softly.assertThat((LocalDateTime)response.body().jsonPath().get("[0].is_changed")) - .isEqualTo(dining1.getIsChanged()); - - softly.assertThat(response.body().jsonPath().getInt("[1].id")).isEqualTo(dining3.getId()); - softly.assertThat(response.body().jsonPath().getString("[1].date")) - .isEqualTo(dining3.getDate().format(ofPattern("yyyy-MM-dd"))); - softly.assertThat(response.body().jsonPath().getString("[1].type")).isEqualTo(dining3.getType()); - softly.assertThat(response.body().jsonPath().getString("[1].place")).isEqualTo(dining3.getPlace()); - softly.assertThat(response.body().jsonPath().getInt("[1].price_card")) - .isEqualTo(dining3.getPriceCard()); - softly.assertThat(response.body().jsonPath().getInt("[1].price_cash")) - .isEqualTo(dining3.getPriceCash()); - softly.assertThat(response.body().jsonPath().getInt("[1].kcal")).isEqualTo(dining3.getKcal()); - softly.assertThat(response.body().jsonPath().getString("[1].created_at")) - .contains(dining3.getUpdatedAt().format(ofPattern("yyyy-MM-dd"))); - softly.assertThat(response.body().jsonPath().getString("[1].updated_at")) - .contains(dining3.getUpdatedAt().format(ofPattern("yyyy-MM-dd"))); - softly.assertThat(response.body().jsonPath().getList("[1].menu", String.class)) - .containsExactlyInAnyOrderElementsOf(menus2); - softly.assertThat((LocalDateTime)response.body().jsonPath().get("[1].is_changed")) - .isEqualTo(dining3.getIsChanged()); - - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + [ + { + "id": 2, + "date": "2024-03-11", + "type": "LUNCH", + "place": "2캠퍼스", + "price_card": 6000, + "price_cash": 6000, + "kcal": 881, + "menu": [ + "혼합잡곡밥", + "가쓰오장국", + "땡초부추전", + "누룽지탕" + ], + "image_url": null, + "created_at": "2024-01-15 12:00:00", + "updated_at": "2024-01-15 12:00:00", + "soldout_at": null, + "changed_at": null + }, + { + "id": 1, + "date": "2024-03-11", + "type": "LUNCH", + "place": "능수관", + "price_card": 6000, + "price_cash": 6000, + "kcal": 300, + "menu": [ + "참치김치볶음밥", + "유부된장국", + "땡초부추전", + "누룽지탕" + ], + "image_url": null, + "created_at": "2024-01-15 12:00:00", + "updated_at": "2024-01-15 12:00:00", + "soldout_at": null, + "changed_at": null + } + ] + """); } @Test @DisplayName("잘못된 형식의 날짜로 조회한다. - 날짜의 형식이 잘못되었다면 400") void invalidFormatDate() { - Dining request = Dining.builder() - .date(LocalDate.parse("2024-03-11")) - .type("LUNCH") - .place("A코스") - .priceCard(6000) - .priceCash(6000) - .kcal(881) - .menu(""" - ["병아리콩밥", "(탕)소고기육개장", "땡초부추전", "누룽지탕"]""") - .build(); - - Dining dining = diningRepository.save(request); + diningFixture.능수관_점심(LocalDate.parse("2024-03-11")); given() .when() @@ -174,36 +111,8 @@ void invalidFormatDate() { @Test @DisplayName("날짜가 비어있다. - 오늘 날짜를 받아 조회한다.") void nullDate() { - when(clock.instant()).thenReturn( - ZonedDateTime.parse("2024-03-16 18:00:00 KST", ofPattern("yyyy-MM-dd " + "HH:mm:ss z")).toInstant()); - when(clock.getZone()).thenReturn(Clock.systemDefaultZone().getZone()); - - Dining request1 = Dining.builder() - .date(LocalDate.parse("2024-03-16")) - .type("LUNCH") - .place("A코스") - .priceCard(6000) - .priceCash(6000) - .kcal(881) - .menu(""" - ["병아리콩밥", "(탕)소고기육개장", "땡초부추전", "고구마순들깨볶음", "총각김치"]""") - .build(); - - Dining request2 = Dining.builder() - .date(LocalDate.parse("2024-03-13")) - .type("LUNCH") - .place("2캠퍼스") - .priceCard(6000) - .priceCash(6000) - .kcal(881) - .menu(""" - ["혼합잡곡밥", "가쓰오장국", "땡초부추전", "누룽지탕"]""") - .build(); - - Dining dining1 = diningRepository.save(request1); - Dining dining2 = diningRepository.save(request2); - - List menus = List.of("병아리콩밥", "(탕)소고기육개장", "땡초부추전", "고구마순들깨볶음", "총각김치"); + diningFixture.A코스_점심(LocalDate.parse("2024-01-15")); + diningFixture.캠퍼스2_점심(LocalDate.parse("2024-01-15")); var response = given() .when() @@ -212,138 +121,94 @@ void nullDate() { .statusCode(HttpStatus.OK.value()) .extract(); - SoftAssertions.assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getList(".").size()).isEqualTo(1); - - softly.assertThat(response.body().jsonPath().getInt("[0].id")).isEqualTo(dining1.getId()); - softly.assertThat(response.body().jsonPath().getString("[0].date")) - .isEqualTo(dining1.getDate().format(ofPattern("yyyy-MM-dd"))); - softly.assertThat(response.body().jsonPath().getString("[0].type")).isEqualTo(dining1.getType()); - softly.assertThat(response.body().jsonPath().getString("[0].place")).isEqualTo(dining1.getPlace()); - softly.assertThat(response.body().jsonPath().getInt("[0].price_card")) - .isEqualTo(dining1.getPriceCard()); - softly.assertThat(response.body().jsonPath().getInt("[0].price_cash")) - .isEqualTo(dining1.getPriceCash()); - softly.assertThat(response.body().jsonPath().getInt("[0].kcal")).isEqualTo(dining1.getKcal()); - softly.assertThat(response.body().jsonPath().getString("[0].created_at")) - .contains(dining1.getUpdatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); - softly.assertThat(response.body().jsonPath().getString("[0].updated_at")) - .contains(dining1.getUpdatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); - softly.assertThat(response.body().jsonPath().getList("[0].menu", String.class)) - .containsExactlyInAnyOrderElementsOf(menus); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + [ + { + "id": 2, + "date": "2024-01-15", + "type": "LUNCH", + "place": "2캠퍼스", + "price_card": 6000, + "price_cash": 6000, + "kcal": 881, + "menu": [ + "혼합잡곡밥", + "가쓰오장국", + "땡초부추전", + "누룽지탕" + ], + "image_url": null, + "created_at": "2024-01-15 12:00:00", + "updated_at": "2024-01-15 12:00:00", + "soldout_at": null, + "changed_at": null + }, + { + "id": 1, + "date": "2024-01-15", + "type": "LUNCH", + "place": "A코스", + "price_card": 6000, + "price_cash": 6000, + "kcal": 881, + "menu": [ + "병아리콩밥", + "(탕)소고기육개장", + "땡초부추전", + "누룽지탕" + ], + "image_url": null, + "created_at": "2024-01-15 12:00:00", + "updated_at": "2024-01-15 12:00:00", + "soldout_at": null, + "changed_at": null + } + ] + """); } @Test @DisplayName("영양사 권한으로 품절 요청을 보내고 메뉴를 변경한다.") void requestSoldOut() { - User user = User.builder() - .password("1234") - .nickname("준기") - .name("허준기") - .phoneNumber("010-1234-5678") - .userType(COOP) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build(); - userRepository.save(user); - - String token = jwtProvider.createToken(user); - - when(clock.instant()).thenReturn(ZonedDateTime.parse( - "2024-04-04 18:00:00 KST", - ofPattern("yyyy-MM-dd " + "HH:mm:ss z") - ) - .toInstant()); - when(clock.getZone()).thenReturn(Clock.systemDefaultZone().getZone()); + User user = userFixture.준기_영양사(); + String token = userFixture.getToken(user); + diningFixture.A코스_점심(LocalDate.parse("2024-03-11")); + Dining menu2 = diningFixture.B코스_점심(LocalDate.parse("2024-03-11")); - Dining dining1 = Dining.builder() - .date(LocalDate.parse("2024-03-11")) - .type("LUNCH") - .place("A코스") - .priceCard(6000) - .priceCash(6000) - .kcal(881) - .menu(""" - ["병아리콩밥", "(탕)소고기육개장", "땡초부추전", "누룽지탕"]""") - .isChanged(LocalDateTime.now(clock)) - .build(); - - Dining dining2 = Dining.builder() - .date(LocalDate.parse("2024-03-11")) - .type("LUNCH") - .place("B코스") - .priceCard(6000) - .priceCash(6000) - .kcal(881) - .menu(""" - ["병아리", "소고기", "땡초", "탕"]""") - .build(); - - diningRepository.save(dining1); - diningRepository.save(dining2); - SoldOutRequest soldOutRequest = new SoldOutRequest(2, true); - - ExtractableResponse response = given() + RestAssured.given() .contentType(ContentType.JSON) .header("Authorization", "Bearer " + token) - .body(soldOutRequest) + .body(String.format(""" + { + "menu_id": "%s", + "sold_out": %s + } + """, menu2.getId(), true) + ) .when() .patch("/coop/dining/soldout") .then() .statusCode(HttpStatus.OK.value()) .extract(); - - SoftAssertions.assertSoftly( - softly -> { - softly.assertThat(diningRepository.getById(1).getIsChanged()).isEqualTo(LocalDateTime.now(clock)); - - softly.assertThat(diningRepository.getById(2).getSoldOut()).isEqualTo(LocalDateTime.now(clock)); - softly.assertThat(diningRepository.getById(2).getIsChanged()).isNull(); - } - ); } @Test @DisplayName("권한이 없는 사용자가 품절 요청을 보낸다") void requestSoldOutNoAuth() { - User user = User.builder() - .password("1234") - .nickname("준기") - .name("허준기") - .phoneNumber("010-1234-5678") - .userType(STUDENT) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build(); - userRepository.save(user); + User user = userFixture.준호_학생().getUser(); + String token = userFixture.getToken(user); + Dining menu = diningFixture.A코스_점심(LocalDate.parse("2024-03-11")); - String token = jwtProvider.createToken(user); - - Dining dining1 = Dining.builder() - .date(LocalDate.parse("2024-03-11")) - .type("LUNCH") - .place("A코스") - .priceCard(6000) - .priceCash(6000) - .kcal(881) - .menu(""" - ["병아리콩밥", "(탕)소고기육개장", "땡초부추전", "누룽지탕"]""") - .build(); - - diningRepository.save(dining1); - SoldOutRequest soldOutRequest = new SoldOutRequest(1, true); - - ExtractableResponse response = given() + var response = given() .contentType(ContentType.JSON) .header("Authorization", "Bearer " + token) - .body(soldOutRequest) + .body(String.format(""" + { + "menu_id": "%s", + "sold_out": %s + } + """, menu.getId(), true)) .when() .patch("/coop/dining/soldout") .then() @@ -354,91 +219,50 @@ void requestSoldOutNoAuth() { @Test @DisplayName("영양사님 권한으로 식단 이미지를 업로드한다. - 이미지 URL이 DB에 저장된다.") void ImageUpload() { - User coop = User.builder() - .password("1234") - .nickname("춘식") - .name("황현식") - .phoneNumber("010-1234-5678") - .userType(COOP) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build(); - userRepository.save(coop); - - String token = jwtProvider.createToken(coop); - - Dining request = Dining.builder() - .date(LocalDate.parse("2024-03-11")) - .type("LUNCH") - .place("A코스") - .priceCard(6000) - .priceCash(6000) - .kcal(881) - .menu(""" - ["병아리콩밥", "(탕)소고기육개장", "땡초부추전", "누룽지탕"]""") - .build(); - - Dining dining = diningRepository.save(request); - - DiningImageRequest imageUrl = new DiningImageRequest(1, "https://stage.koreatech.in/image.jpg"); + User user = userFixture.준기_영양사(); + String token = userFixture.getToken(user); + Dining menu = diningFixture.A코스_점심(LocalDate.parse("2024-03-11")); + String imageUrl = "https://stage.koreatech.in/image.jpg"; given() - .body(imageUrl) .contentType(ContentType.JSON) .header("Authorization", "Bearer " + token) + .body(String.format(""" + { + "menu_id": "%s", + "image_url": "%s" + } + """, menu.getId(), imageUrl) + ) .when() .patch("/coop/dining/image") .then() .statusCode(HttpStatus.OK.value()) .extract(); - SoftAssertions.assertSoftly( - softly -> - softly.assertThat(diningRepository.getById(request.getId()).getImageUrl()) - .isEqualTo(imageUrl.imageUrl()) - ); + Dining result = diningRepository.getById(menu.getId()); + assertThat(result.getImageUrl()).isEqualTo(imageUrl); } @Test @DisplayName("허용되지 않은 권한으로 식단 이미지를 업로드한다. - 권한 오류.") void ImageUploadWithNoAuth() { - User user = User.builder() - .password("1234") - .nickname("춘식") - .name("황현식") - .phoneNumber("010-1234-5678") - .userType(STUDENT) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build(); - - userRepository.save(user); - - String token = jwtProvider.createToken(user); - - Dining request = Dining.builder() - .date(LocalDate.parse("2024-03-11")) - .type("LUNCH") - .place("A코스") - .priceCard(6000) - .priceCash(6000) - .kcal(881) - .menu(""" - ["병아리콩밥", "(탕)소고기육개장", "땡초부추전", "누룽지탕"]""") - .build(); - - Dining dining = diningRepository.save(request); + User user = userFixture.현수_사장님().getUser(); + String token = userFixture.getToken(user); + Dining menu = diningFixture.A코스_점심(LocalDate.parse("2024-03-11")); DiningImageRequest imageUrl = new DiningImageRequest(1, "https://stage.koreatech.in/image.jpg"); given() - .body(imageUrl) .contentType(ContentType.JSON) .header("Authorization", "Bearer " + token) + .body(String.format(""" + { + "menu_id": "%s", + "image_url": "%s" + } + """, menu.getId(), imageUrl) + ) .when() .patch("/coop/dining/image") .then() @@ -449,54 +273,19 @@ void ImageUploadWithNoAuth() { @Test @DisplayName("품절 이벤트가 발생한다.") void checkSoldOutEventListener() { - when(clock.instant()).thenReturn(ZonedDateTime.parse( - "2024-04-04 18:00:00 KST", - ofPattern("yyyy-MM-dd " + "HH:mm:ss z") - ) - .toInstant()); - when(clock.getZone()).thenReturn(Clock.systemDefaultZone().getZone()); - - User user = User.builder() - .password("1234") - .nickname("준기") - .name("허준기") - .phoneNumber("010-1234-5678") - .userType(COOP) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build(); - - userRepository.save(user); - - String token = jwtProvider.createToken(user); - - notificationSubscribeRepository.save(NotificationSubscribe.builder() - .user(user) - .subscribeType(DINING_SOLD_OUT) - .build()); - - Dining dining = Dining.builder() - .date(LocalDate.parse("2024-04-04")) - .type("LUNCH") - .place("A코스") - .priceCard(6000) - .priceCash(6000) - .kcal(881) - .menu(""" - ["병아리콩밥", "(탕)소고기육개장", "땡초부추전", "누룽지탕"]""") - .isChanged(LocalDateTime.now(clock)) - .build(); - - diningRepository.save(dining); - - SoldOutRequest soldOutRequest = new SoldOutRequest(1, true); + User user = userFixture.준기_영양사(); + String token = userFixture.getToken(user); + Dining menu = diningFixture.A코스_점심(LocalDate.parse("2024-03-11")); given() .contentType(ContentType.JSON) .header("Authorization", "Bearer " + token) - .body(soldOutRequest) + .body(String.format(""" + { + "menu_id": "%s", + "sold_out": %s + } + """, menu.getId(), true)) .when() .patch("/coop/dining/soldout") .then() diff --git a/src/test/java/in/koreatech/koin/acceptance/LandApiTest.java b/src/test/java/in/koreatech/koin/acceptance/LandApiTest.java index 7579c110c..cc146ea71 100644 --- a/src/test/java/in/koreatech/koin/acceptance/LandApiTest.java +++ b/src/test/java/in/koreatech/koin/acceptance/LandApiTest.java @@ -1,11 +1,5 @@ package in.koreatech.koin.acceptance; -import static org.assertj.core.api.SoftAssertions.assertSoftly; - -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.time.format.DateTimeFormatter; - import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -13,42 +7,23 @@ import in.koreatech.koin.AcceptanceTest; import in.koreatech.koin.domain.land.model.Land; -import in.koreatech.koin.domain.land.repository.LandRepository; +import in.koreatech.koin.fixture.LandFixture; +import in.koreatech.koin.support.JsonAssertions; import io.restassured.RestAssured; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; +@SuppressWarnings("NonAsciiCharacters") class LandApiTest extends AcceptanceTest { @Autowired - private LandRepository landRepository; + private LandFixture landFixture; @Test @DisplayName("복덕방 리스트를 조회한다.") void getLands() { - Land request = Land.builder() - .internalName("복덕방") - .name("복덕방") - .roomType("원룸") - .latitude("37.555") - .longitude("126.555") - .monthlyFee("100") - .charterFee("1000") - .build(); - Land request2 = Land.builder() - .internalName("복덕방2") - .name("복덕방2") - .roomType("원룸2") - .latitude("37.5552") - .longitude("126.5552") - .monthlyFee("102") - .charterFee("1002") - .build(); - - Land land = landRepository.save(request); - Land land2 = landRepository.save(request2); + landFixture.신안빌(); + landFixture.에듀윌(); - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .get("/lands") @@ -56,68 +31,41 @@ void getLands() { .statusCode(HttpStatus.OK.value()) .extract(); - assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getList("lands").size()).isEqualTo(2); - softly.assertThat(response.body().jsonPath().getInt("lands[0].id")).isEqualTo(land.getId()); - softly.assertThat(response.body().jsonPath().getString("lands[0].internal_name")) - .isEqualTo(land.getInternalName()); - softly.assertThat(response.body().jsonPath().getString("lands[0].name")).isEqualTo(land.getName()); - softly.assertThat(response.body().jsonPath().getString("lands[0].room_type")) - .isEqualTo(land.getRoomType()); - softly.assertThat(response.body().jsonPath().getString("lands[0].latitude")) - .isEqualTo(land.getLatitude()); - softly.assertThat(response.body().jsonPath().getString("lands[0].longitude")) - .isEqualTo(land.getLongitude()); - softly.assertThat(response.body().jsonPath().getString("lands[0].monthly_fee")) - .isEqualTo(land.getMonthlyFee()); - softly.assertThat(response.body().jsonPath().getString("lands[0].charter_fee")) - .isEqualTo(land.getCharterFee()); - - softly.assertThat(response.body().jsonPath().getInt("lands[1].id")).isEqualTo(land2.getId()); - softly.assertThat(response.body().jsonPath().getString("lands[1].internal_name")) - .isEqualTo(land2.getInternalName()); - softly.assertThat(response.body().jsonPath().getString("lands[1].name")).isEqualTo(land2.getName()); - softly.assertThat(response.body().jsonPath().getString("lands[1].room_type")) - .isEqualTo(land2.getRoomType()); - softly.assertThat(response.body().jsonPath().getString("lands[1].latitude")) - .isEqualTo(land2.getLatitude()); - softly.assertThat(response.body().jsonPath().getString("lands[1].longitude")) - .isEqualTo(land2.getLongitude()); - softly.assertThat(response.body().jsonPath().getString("lands[1].monthly_fee")) - .isEqualTo(land2.getMonthlyFee()); - softly.assertThat(response.body().jsonPath().getString("lands[1].charter_fee")) - .isEqualTo(land2.getCharterFee()); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + { + "lands": [ + { + "internal_name": "신", + "monthly_fee": "100", + "latitude": "37.555", + "charter_fee": "1000", + "name": "신안빌", + "id": 1, + "longitude": "126.555", + "room_type": "원룸" + }, + { + "internal_name": "에", + "monthly_fee": "100", + "latitude": "37.555", + "charter_fee": "1000", + "name": "에듀윌", + "id": 2, + "longitude": "126.555", + "room_type": "원룸" + } + ] + } + """); } @Test @DisplayName("복덕방을 단일 조회한다.") void getLand() { - Land request = Land.builder() - .internalName("복덕방") - .name("복덕방") - .roomType("원룸") - .latitude("37.555") - .longitude("126.555") - .floor(1) - .monthlyFee("100") - .charterFee("1000") - .deposit("1000") - .managementFee("100") - .phone("010-1234-5678") - .address("서울시 강남구") - .size("100.0") - .imageUrls(""" - ["https://example1.test.com/image.jpeg", - "https://example2.test.com/image.jpeg"] - """) - .build(); - - Land land = landRepository.save(request); + Land land = landFixture.에듀윌(); - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .get("/lands/{id}", land.getId()) @@ -125,77 +73,49 @@ void getLand() { .statusCode(HttpStatus.OK.value()) .extract(); - assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getBoolean("opt_electronic_door_locks")) - .isEqualTo(land.isOptElectronicDoorLocks()); - softly.assertThat(response.body().jsonPath().getBoolean("opt_tv")).isEqualTo(land.isOptTv()); - softly.assertThat(response.body().jsonPath().getString("monthly_fee")) - .isEqualTo(land.getMonthlyFee()); - softly.assertThat(response.body().jsonPath().getBoolean("opt_elevator")) - .isEqualTo(land.isOptElevator()); - softly.assertThat(response.body().jsonPath().getBoolean("opt_water_purifier")) - .isEqualTo(land.isOptWaterPurifier()); - softly.assertThat(response.body().jsonPath().getBoolean("opt_washer")) - .isEqualTo(land.isOptWasher()); - softly.assertThat(response.body().jsonPath().getString("latitude")) - .isEqualTo(land.getLatitude()); - softly.assertThat(response.body().jsonPath().getString("charter_fee")) - .isEqualTo(land.getCharterFee()); - softly.assertThat(response.body().jsonPath().getBoolean("opt_veranda")) - .isEqualTo(land.isOptVeranda()); - softly.assertThat(response.body().jsonPath().getString("created_at")) - .contains(land.getCreatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); - softly.assertThat(response.body().jsonPath().getString("description")) - .isEqualTo(land.getDescription()); - softly.assertThat(response.body().jsonPath().getBoolean("opt_gas_range")) - .isEqualTo(land.isOptGasRange()); - softly.assertThat(response.body().jsonPath().getBoolean("opt_induction")) - .isEqualTo(land.isOptInduction()); - softly.assertThat(response.body().jsonPath().getString("internal_name")) - .isEqualTo(land.getInternalName()); - softly.assertThat(response.body().jsonPath().getBoolean("is_deleted")) - .isEqualTo(land.isDeleted()); - softly.assertThat(response.body().jsonPath().getString("updated_at")) - .contains(land.getUpdatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); - softly.assertThat(response.body().jsonPath().getBoolean("opt_bidet")) - .isEqualTo(land.isOptBidet()); - softly.assertThat(response.body().jsonPath().getBoolean("opt_shoe_closet")) - .isEqualTo(land.isOptShoeCloset()); - softly.assertThat(response.body().jsonPath().getBoolean("opt_refrigerator")) - .isEqualTo(land.isOptRefrigerator()); - softly.assertThat(response.body().jsonPath().getInt("id")).isEqualTo(land.getId()); - softly.assertThat(response.body().jsonPath().getInt("floor")).isEqualTo(land.getFloor()); - softly.assertThat(response.body().jsonPath().getString("management_fee")) - .isEqualTo(land.getManagementFee()); - softly.assertThat(response.body().jsonPath().getBoolean("opt_desk")) - .isEqualTo(land.isOptDesk()); - softly.assertThat(response.body().jsonPath().getBoolean("opt_closet")) - .isEqualTo(land.isOptCloset()); - softly.assertThat(response.body().jsonPath().getString("longitude")) - .isEqualTo(land.getLongitude()); - softly.assertThat(response.body().jsonPath().getString("address")) - .isEqualTo(land.getAddress()); - softly.assertThat(response.body().jsonPath().getBoolean("opt_bed")) - .isEqualTo(land.isOptBed()); - softly.assertThat(response.body().jsonPath().getString("size")) - .isEqualTo(land.getSize()); - softly.assertThat(response.body().jsonPath().getString("phone")) - .isEqualTo(land.getPhone()); - softly.assertThat(response.body().jsonPath().getBoolean("opt_air_conditioner")) - .isEqualTo(land.isOptAirConditioner()); - softly.assertThat(response.body().jsonPath().getString("name")) - .isEqualTo(land.getName()); - softly.assertThat(response.body().jsonPath().getString("deposit")) - .isEqualTo(land.getDeposit()); - softly.assertThat(response.body().jsonPath().getBoolean("opt_microwave")) - .isEqualTo(land.isOptMicrowave()); - softly.assertThat(response.body().jsonPath().getString("permalink")) - .isEqualTo(URLEncoder.encode(land.getInternalName(), StandardCharsets.UTF_8)); - softly.assertThat(response.body().jsonPath().getString("room_type")) - .isEqualTo(land.getRoomType()); - softly.assertThat(response.body().jsonPath().getList("image_urls")).hasSize(2); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + { + "opt_electronic_door_locks": false, + "opt_tv": false, + "monthly_fee": "100", + "opt_elevator": false, + "opt_water_purifier": false, + "opt_washer": false, + "latitude": "37.555", + "charter_fee": "1000", + "opt_veranda": false, + "created_at": "2024-01-15 12:00:00", + "description": null, + "image_urls": [ + "https://example1.test.com/image.jpeg", + "https://example2.test.com/image.jpeg" + ], + "opt_gas_range": false, + "opt_induction": false, + "internal_name": "에", + "is_deleted": false, + "updated_at": "2024-01-15 12:00:00", + "opt_bidet": false, + "opt_shoe_closet": false, + "opt_refrigerator": false, + "id": 1, + "floor": 1, + "management_fee": "100", + "opt_desk": false, + "opt_closet": false, + "longitude": "126.555", + "address": "천안시 동남구 강남구", + "opt_bed": false, + "size": "100.0", + "phone": "010-1133-5555", + "opt_air_conditioner": false, + "name": "에듀윌", + "deposit": "1000", + "opt_microwave": false, + "permalink": "%EC%97%90", + "room_type": "원룸" + } + """); } } diff --git a/src/test/java/in/koreatech/koin/acceptance/MemberApiTest.java b/src/test/java/in/koreatech/koin/acceptance/MemberApiTest.java index b9c5f2d74..9e621a021 100644 --- a/src/test/java/in/koreatech/koin/acceptance/MemberApiTest.java +++ b/src/test/java/in/koreatech/koin/acceptance/MemberApiTest.java @@ -1,6 +1,6 @@ package in.koreatech.koin.acceptance; -import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -9,35 +9,41 @@ import in.koreatech.koin.AcceptanceTest; import in.koreatech.koin.domain.member.model.Member; import in.koreatech.koin.domain.member.model.Track; -import in.koreatech.koin.domain.member.repository.MemberRepository; import in.koreatech.koin.domain.member.repository.TrackRepository; +import in.koreatech.koin.fixture.MemberFixture; +import in.koreatech.koin.support.JsonAssertions; import io.restassured.RestAssured; +@SuppressWarnings("NonAsciiCharacters") class MemberApiTest extends AcceptanceTest { @Autowired - private MemberRepository memberRepository; + private TrackRepository trackRepository; @Autowired - private TrackRepository trackRepository; + private MemberFixture memberFixture; + + Track backend; + Track frontend; + + @BeforeEach + void setUp() { + backend = trackRepository.save( + Track.builder() + .name("BackEnd") + .build() + ); + frontend = trackRepository.save( + Track.builder() + .name("FrontEnd") + .build() + ); + } @Test @DisplayName("BCSDLab 회원의 정보를 조회한다") void getMember() { - Track track = Track.builder().name("BackEnd").build(); - trackRepository.save(track); - - Member member = Member.builder() - .isDeleted(false) - .studentNumber("2019136135") - .imageUrl("https://imagetest.com/juno.jpg") - .name("최준호") - .position("Regular") - .track(track) - .email("juno@gmail.com") - .build(); - - var saved = memberRepository.save(member); + Member member = memberFixture.최준호(backend); var response = RestAssured .given() @@ -47,7 +53,7 @@ void getMember() { .statusCode(HttpStatus.OK.value()) .extract(); - Assertions.assertThat(response.asPrettyString()) + JsonAssertions.assertThat(response.asPrettyString()) .isEqualTo(String.format(""" { "id": %d, @@ -55,13 +61,13 @@ void getMember() { "student_number": "2019136135", "track": "BackEnd", "position": "Regular", - "email": "juno@gmail.com", + "email": "testjuno@gmail.com", "image_url": "https://imagetest.com/juno.jpg", "is_deleted": false, "created_at": "%s", "updated_at": "%s" }""", - saved.getId(), + member.getId(), response.jsonPath().getString("created_at"), response.jsonPath().getString("updated_at") )); @@ -70,31 +76,8 @@ void getMember() { @Test @DisplayName("BCSDLab 회원들의 정보를 조회한다") void getMembers() { - Track track = Track.builder().name("BackEnd").build(); - trackRepository.save(track); - - Member member = Member.builder() - .isDeleted(false) - .studentNumber("2019136064") - .imageUrl("https://imagetest.com/asdf.jpg") - .name("박한수") - .position("Regular") - .track(track) - .email("hsp@gmail.com") - .build(); - - Member member2 = Member.builder() - .isDeleted(false) - .studentNumber("2019136135") - .imageUrl("https://imagetest.com/juno.jpg") - .name("최준호") - .position("Regular") - .track(track) - .email("juno@gmail.com") - .build(); - - var saved = memberRepository.save(member); - var saved2 = memberRepository.save(member2); + memberFixture.최준호(backend); + memberFixture.박한수(frontend); var response = RestAssured .given() @@ -104,38 +87,35 @@ void getMembers() { .statusCode(HttpStatus.OK.value()) .extract(); - Assertions.assertThat(response.asPrettyString()) + JsonAssertions.assertThat(response.asPrettyString()) .isEqualTo(""" - [ - { - "id": 1, - "name": "박한수", - "student_number": "2019136064", - "track": "BackEnd", - "position": "Regular", - "email": "hsp@gmail.com", - "image_url": "https://imagetest.com/asdf.jpg", - "is_deleted": false, - "created_at": "%s", - "updated_at": "%s" - }, - { - "id": 2, - "name": "최준호", - "student_number": "2019136135", - "track": "BackEnd", - "position": "Regular", - "email": "juno@gmail.com", - "image_url": "https://imagetest.com/juno.jpg", - "is_deleted": false, - "created_at": "%s", - "updated_at": "%s" - } - ]""", - response.jsonPath().getString("[0].created_at"), - response.jsonPath().getString("[0].updated_at"), - response.jsonPath().getString("[1].created_at"), - response.jsonPath().getString("[1].updated_at") + [ + { + "id": 1, + "name": "최준호", + "student_number": "2019136135", + "track": "BackEnd", + "position": "Regular", + "email": "testjuno@gmail.com", + "image_url": "https://imagetest.com/juno.jpg", + "is_deleted": false, + "created_at": "2024-01-15 12:00:00", + "updated_at": "2024-01-15 12:00:00" + }, + { + "id": 2, + "name": "박한수", + "student_number": "2019136064", + "track": "FrontEnd", + "position": "Regular", + "email": "testhsp@gmail.com", + "image_url": "https://imagetest.com/juno.jpg", + "is_deleted": false, + "created_at": "2024-01-15 12:00:00", + "updated_at": "2024-01-15 12:00:00" + } + ] + """ ); } } diff --git a/src/test/java/in/koreatech/koin/acceptance/NotificationApiTest.java b/src/test/java/in/koreatech/koin/acceptance/NotificationApiTest.java index c5cd6d45c..8f57f958c 100644 --- a/src/test/java/in/koreatech/koin/acceptance/NotificationApiTest.java +++ b/src/test/java/in/koreatech/koin/acceptance/NotificationApiTest.java @@ -1,10 +1,8 @@ package in.koreatech.koin.acceptance; -import static in.koreatech.koin.domain.user.model.UserType.STUDENT; import static in.koreatech.koin.global.domain.notification.model.NotificationSubscribeType.SHOP_EVENT; import static org.assertj.core.api.Assertions.assertThat; -import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -13,51 +11,38 @@ import in.koreatech.koin.AcceptanceTest; import in.koreatech.koin.domain.user.model.User; -import in.koreatech.koin.domain.user.model.UserGender; import in.koreatech.koin.domain.user.repository.UserRepository; -import in.koreatech.koin.global.auth.JwtProvider; +import in.koreatech.koin.fixture.UserFixture; import in.koreatech.koin.global.domain.notification.model.NotificationSubscribe; import in.koreatech.koin.global.domain.notification.model.NotificationSubscribeType; import in.koreatech.koin.global.domain.notification.repository.NotificationSubscribeRepository; +import in.koreatech.koin.support.JsonAssertions; import io.restassured.RestAssured; import io.restassured.http.ContentType; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; +@SuppressWarnings("NonAsciiCharacters") class NotificationApiTest extends AcceptanceTest { @Autowired - private JwtProvider jwtProvider; + private NotificationSubscribeRepository notificationSubscribeRepository; @Autowired - private NotificationSubscribeRepository notificationSubscribeRepository; + private UserFixture userFixture; @Autowired private UserRepository userRepository; - private static User user; - - private static String userToken; + User user; + String userToken; @BeforeEach void setUp() { - User newUser = User.builder() - .password("1234") - .nickname("셋업유저") - .name("셋업") - .phoneNumber("010-1234-5678") - .userType(STUDENT) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build(); - user = userRepository.save(newUser); - userToken = jwtProvider.createToken(user); + user = userFixture.준호_학생().getUser(); + userToken = userFixture.getToken(user); } @Test - @DisplayName("알림 구독 내역 조회한다.") + @DisplayName("알림 구독 내역을 조회한다.") void getNotificationSubscribe() { //given NotificationSubscribe notificationSubscribe = NotificationSubscribe.builder() @@ -66,8 +51,9 @@ void getNotificationSubscribe() { .build(); notificationSubscribeRepository.save(notificationSubscribe); + //when then - ExtractableResponse response = RestAssured + var response = RestAssured .given() .header("Authorization", "Bearer " + userToken) .when() @@ -76,18 +62,22 @@ void getNotificationSubscribe() { .statusCode(HttpStatus.OK.value()) .extract(); - SoftAssertions.assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getBoolean("is_permit")).isFalse(); - softly.assertThat(response.body().jsonPath().getList("subscribes").size()).isEqualTo(2); - softly.assertThat(response.body().jsonPath().getString("subscribes[0].type")) - .isEqualTo("SHOP_EVENT"); - softly.assertThat(response.body().jsonPath().getBoolean("subscribes[0].is_permit")).isTrue(); - softly.assertThat(response.body().jsonPath().getString("subscribes[1].type")).isEqualTo( - "DINING_SOLD_OUT"); - softly.assertThat(response.body().jsonPath().getBoolean("subscribes[1].is_permit")).isFalse(); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + { + "is_permit": false, + "subscribes": [ + { + "type": "SHOP_EVENT", + "is_permit": true + }, + { + "type": "DINING_SOLD_OUT", + "is_permit": false + } + ] + } + """); } @Test @@ -97,13 +87,13 @@ void createDivceToken() { String deviceToken = "testToken"; //when then - ExtractableResponse response = RestAssured + RestAssured .given() .header("Authorization", "Bearer " + userToken) .body(String.format(""" - { - "device_token": "%s" - } + { + "device_token": "%s" + } """, deviceToken)) .contentType(ContentType.JSON) .when() @@ -112,23 +102,22 @@ void createDivceToken() { .statusCode(HttpStatus.CREATED.value()) .extract(); - User changedDeviceTokenUser = userRepository.getById(user.getId()); - assertThat(changedDeviceTokenUser.getDeviceToken()).isEqualTo(deviceToken); + User result = userRepository.getById(user.getId()); + assertThat(result.getDeviceToken()).isEqualTo(deviceToken); } @Test @DisplayName("특정 알림을 구독한다.") void subscribeNotificationType() { - String deviceToken = "testToken"; - String notificationType = "SHOP_EVENT"; + String notificationType = SHOP_EVENT.name(); - RestAssured .given() + RestAssured.given() .header("Authorization", "Bearer " + userToken) .body(String.format(""" - { - "device_token": "%s" - } + { + "device_token": "%s" + } """, deviceToken)) .contentType(ContentType.JSON) .when() @@ -148,7 +137,7 @@ void subscribeNotificationType() { .statusCode(HttpStatus.CREATED.value()) .extract(); - ExtractableResponse response = RestAssured + var response = RestAssured .given() .header("Authorization", "Bearer " + userToken) .when() @@ -157,31 +146,29 @@ void subscribeNotificationType() { .statusCode(HttpStatus.OK.value()) .extract(); - SoftAssertions.assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getBoolean("is_permit")).isTrue(); - softly.assertThat(response.body().jsonPath().getList("subscribes").size()).isEqualTo(2); - softly.assertThat(response.body().jsonPath().getString("subscribes[0].type")) - .isEqualTo(notificationType); - softly.assertThat(response.body().jsonPath().getBoolean("subscribes[0].is_permit")).isTrue(); - softly.assertThat(response.body().jsonPath().getString("subscribes[1].type")).isEqualTo( - "DINING_SOLD_OUT"); - softly.assertThat(response.body().jsonPath().getBoolean("subscribes[1].is_permit")).isFalse(); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + { + "is_permit": true, + "subscribes": [ + { + "type": "SHOP_EVENT", + "is_permit": true + }, + { + "type": "DINING_SOLD_OUT", + "is_permit": false + } + ] + } + """); } @Test @DisplayName("전체 알림 구독을 취소한다. - 디바이스 토큰을 삭제한다.") void deleteDeviceToken() { - String deviceToken = "testToken"; - user.permitNotification(deviceToken); - userRepository.save(user); - User changedDeviceTokenUser = userRepository.getById(user.getId()); - - assertThat(changedDeviceTokenUser.getDeviceToken()).isEqualTo(deviceToken); RestAssured .given() @@ -192,14 +179,13 @@ void deleteDeviceToken() { .statusCode(HttpStatus.NO_CONTENT.value()) .extract(); - User noneDeviceTokenUser = userRepository.getById(user.getId()); - assertThat(noneDeviceTokenUser.getDeviceToken()).isNull(); + User result = userRepository.getById(user.getId()); + assertThat(result.getDeviceToken()).isNull(); } @Test @DisplayName("특정 알림 구독을 취소한다.") void unsubscribeNotificationType() { - var SubscribeShopEvent = NotificationSubscribe.builder() .subscribeType(SHOP_EVENT) .user(user) @@ -213,7 +199,7 @@ void unsubscribeNotificationType() { notificationSubscribeRepository.save(SubscribeShopEvent); notificationSubscribeRepository.save(SubscribeDiningSoldOut); - String notificationType = "SHOP_EVENT"; + String notificationType = SHOP_EVENT.name(); RestAssured .given() @@ -225,7 +211,7 @@ void unsubscribeNotificationType() { .statusCode(HttpStatus.NO_CONTENT.value()) .extract(); - ExtractableResponse response = RestAssured + var response = RestAssured .given() .header("Authorization", "Bearer " + userToken) .when() @@ -234,17 +220,21 @@ void unsubscribeNotificationType() { .statusCode(HttpStatus.OK.value()) .extract(); - SoftAssertions.assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getBoolean("is_permit")).isFalse(); - softly.assertThat(response.body().jsonPath().getList("subscribes").size()).isEqualTo(2); - softly.assertThat(response.body().jsonPath().getString("subscribes[0].type")) - .isEqualTo(notificationType); - softly.assertThat(response.body().jsonPath().getBoolean("subscribes[0].is_permit")).isFalse(); - softly.assertThat(response.body().jsonPath().getString("subscribes[1].type")).isEqualTo( - "DINING_SOLD_OUT"); - softly.assertThat(response.body().jsonPath().getBoolean("subscribes[1].is_permit")).isTrue(); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + { + "is_permit": false, + "subscribes": [ + { + "type": "SHOP_EVENT", + "is_permit": false + }, + { + "type": "DINING_SOLD_OUT", + "is_permit": true + } + ] + } + """); } } diff --git a/src/test/java/in/koreatech/koin/acceptance/OwnerApiTest.java b/src/test/java/in/koreatech/koin/acceptance/OwnerApiTest.java index bd47dd093..6ffcf6067 100644 --- a/src/test/java/in/koreatech/koin/acceptance/OwnerApiTest.java +++ b/src/test/java/in/koreatech/koin/acceptance/OwnerApiTest.java @@ -1,66 +1,52 @@ package in.koreatech.koin.acceptance; -import static in.koreatech.koin.domain.user.model.UserType.OWNER; -import static java.time.format.DateTimeFormatter.ofPattern; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.SoftAssertions.assertSoftly; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.mockito.Mockito.any; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.time.Clock; -import java.time.ZonedDateTime; -import java.util.List; import org.assertj.core.api.Assertions; import org.assertj.core.api.SoftAssertions; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.transaction.TransactionStatus; -import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; import in.koreatech.koin.AcceptanceTest; import in.koreatech.koin.domain.owner.model.Owner; -import in.koreatech.koin.domain.owner.model.OwnerAttachment; import in.koreatech.koin.domain.owner.model.OwnerInVerification; -import in.koreatech.koin.domain.owner.model.OwnerRegisterEvent; import in.koreatech.koin.domain.owner.repository.OwnerInVerificationRedisRepository; import in.koreatech.koin.domain.owner.repository.OwnerRepository; import in.koreatech.koin.domain.owner.repository.OwnerShopRedisRepository; import in.koreatech.koin.domain.shop.model.Shop; -import in.koreatech.koin.domain.shop.repository.ShopRepository; import in.koreatech.koin.domain.user.model.User; -import in.koreatech.koin.domain.user.model.UserGender; import in.koreatech.koin.domain.user.repository.UserRepository; -import in.koreatech.koin.global.auth.JwtProvider; +import in.koreatech.koin.fixture.ShopFixture; +import in.koreatech.koin.fixture.UserFixture; +import in.koreatech.koin.support.JsonAssertions; import io.restassured.RestAssured; import io.restassured.http.ContentType; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; +@SuppressWarnings("NonAsciiCharacters") class OwnerApiTest extends AcceptanceTest { @Autowired - private OwnerRepository ownerRepository; + private UserFixture userFixture; @Autowired - private ShopRepository shopRepository; + private ShopFixture shopFixture; @Autowired - private OwnerShopRedisRepository ownerShopRedisRepository; + private OwnerRepository ownerRepository; @Autowired - private OwnerInVerificationRedisRepository ownerInVerificationRedisRepository; + private OwnerShopRedisRepository ownerShopRedisRepository; @Autowired - private JwtProvider jwtProvider; + private OwnerInVerificationRedisRepository ownerInVerificationRedisRepository; @Autowired private TransactionTemplate transactionTemplate; @@ -71,65 +57,16 @@ class OwnerApiTest extends AcceptanceTest { @Autowired private PasswordEncoder passwordEncoder; - @BeforeEach - void setUp() { - when(clock.instant()).thenReturn( - ZonedDateTime.parse("2024-02-21 18:00:00 KST", ofPattern("yyyy-MM-dd " + "HH:mm:ss z")).toInstant()); - when(clock.getZone()).thenReturn(Clock.systemDefaultZone().getZone()); - } - @Test @DisplayName("로그인된 사장님 정보를 조회한다.") void getOwner() { // given - User user = User.builder() - .password("1234") - .nickname("셋업유저") - .name("셋업") - .phoneNumber("010-1234-5678") - .userType(OWNER) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build(); - - OwnerAttachment attachment = OwnerAttachment.builder() - .url("https://test.com/test.jpg") - .isDeleted(false) - .build(); - - Owner ownerRequest = Owner.builder() - .companyRegistrationNumber("123-45-67190") - .attachments(List.of(attachment)) - .grantShop(true) - .grantEvent(true) - .user(user) - .build(); - Owner owner = ownerRepository.save(ownerRequest); - - Shop shopRequest = Shop.builder() - .owner(owner) - .name("테스트 상점") - .internalName("테스트") - .chosung("테스트") - .phone("010-1234-5678") - .address("대전광역시 유성구 대학로 291") - .description("테스트 상점입니다.") - .delivery(true) - .deliveryPrice(3000) - .payCard(true) - .payBank(true) - .isDeleted(false) - .isEvent(false) - .remarks("비고") - .hit(0) - .build(); - Shop shop = shopRepository.save(shopRequest); - String token = jwtProvider.createToken(owner.getUser()); + Owner owner = userFixture.현수_사장님(); + Shop shop = shopFixture.마슬랜(owner); + String token = userFixture.getToken(owner.getUser()); // when then - ExtractableResponse response = RestAssured + var response = RestAssured .given() .header("Authorization", "Bearer " + token) .when() @@ -138,48 +75,33 @@ void getOwner() { .statusCode(HttpStatus.OK.value()) .extract(); - assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getString("email")).isEqualTo(user.getEmail()); - softly.assertThat(response.body().jsonPath().getString("name")).isEqualTo(user.getName()); - softly.assertThat(response.body().jsonPath().getString("company_number")) - .isEqualTo(owner.getCompanyRegistrationNumber()); - - softly.assertThat(response.body().jsonPath().getInt("attachments[0].id")) - .isEqualTo(attachment.getId().intValue()); - softly.assertThat(response.body().jsonPath().getString("attachments[0].file_url")) - .isEqualTo(attachment.getUrl()); - softly.assertThat(response.body().jsonPath().getString("attachments[0].file_name")) - .isEqualTo(attachment.getName()); - - softly.assertThat(response.body().jsonPath().getInt("shops[0].id")).isEqualTo(shop.getId().intValue()); - softly.assertThat(response.body().jsonPath().getString("shops[0].name")).isEqualTo(shop.getName()); - - softly.assertThat(response.body().jsonPath().getList("attachments").size()).isEqualTo(1); - softly.assertThat(response.body().jsonPath().getList("shops").size()).isEqualTo(1); - } - ); - } - - @Test - @DisplayName("사장님이 회원가입 인증번호 전송 요청을 한다. - 슬랙 전송 실패해도 200으로 응답") - void requestSignUpEmailVerification() { - RestAssured - .given() - .body(""" + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(String.format(""" { - "address": "test@gmail.com" + "email": "hysoo@naver.com", + "name": "테스트용_현수", + "company_number": "123-45-67190", + "attachments": [ + { + "id": 1, + "file_url": "https://test.com/현수_사장님_인증사진_1.jpg", + "file_name": "현수_사장님_인증사진_1.jpg" + }, + { + "id": 2, + "file_url": "https://test.com/현수_사장님_인증사진_2.jpg", + "file_name": "현수_사장님_인증사진_2.jpg" + } + ], + "shops": [ + { + "id": %d, + "name": "마슬랜 치킨" + } + ] } - """) - .contentType(ContentType.JSON) - .when() - .post("/owners/verification/email") - .then() - .statusCode(HttpStatus.OK.value()); - - assertDoesNotThrow(() -> - ownerInVerificationRedisRepository.getByEmail("test@gmail.com") - ); + """, shop.getId() + )); } @Test @@ -192,13 +114,16 @@ void requestAndVerifySign() { { "address": "%s" } - """, ownerEmail)) + """, ownerEmail) + ) .contentType(ContentType.JSON) .when() .post("/owners/verification/email") .then() .statusCode(HttpStatus.OK.value()); - var verify = ownerInVerificationRedisRepository.getByEmail(ownerEmail); + + var verifyCode = ownerInVerificationRedisRepository.getByEmail(ownerEmail); + RestAssured .given() .body(String.format(""" @@ -206,12 +131,13 @@ void requestAndVerifySign() { "address": "%s", "certification_code": "%s" } - """, ownerEmail, verify.getCertificationCode())) + """, ownerEmail, verifyCode.getCertificationCode())) .contentType(ContentType.JSON) .when() .post("/owners/verification/code") .then() .statusCode(HttpStatus.OK.value()); + var result = ownerInVerificationRedisRepository.findById(ownerEmail); Assertions.assertThat(result).isNotPresent(); } @@ -272,8 +198,8 @@ class ownerRegister { @Test @DisplayName("사장님이 회원가입 요청을 한다.") void register() { - // given - RestAssured + // when & then + var response = RestAssured .given() .body(""" { @@ -295,14 +221,12 @@ void register() { .when() .post("/owners/register") .then() - .statusCode(HttpStatus.OK.value()); + .statusCode(HttpStatus.OK.value()) + .extract(); // when - transactionTemplate.execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(TransactionStatus status) { + transactionTemplate.executeWithoutResult(status -> { Owner owner = ownerRepository.findByCompanyRegistrationNumber("012-34-56789").get(); - var event = new OwnerRegisterEvent(owner); assertSoftly( softly -> { softly.assertThat(owner).isNotNull(); @@ -318,7 +242,7 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { } ); } - }); + ); } @Test @@ -412,25 +336,7 @@ void registerWithoutName() { @DisplayName("사장님이 회원가입 요청을 한다 - 기존에 존재하는 상점과 함께 회원가입") void registerWithExistShop() { // given - Shop shopRequest = Shop.builder() - .name("테스트 상점") - .internalName("테스트") - .chosung("테스트") - .phone("010-1234-56778") - .address("대전광역시 유성구 대학로 291") - .description("테스트 상점입니다.") - .delivery(true) - .deliveryPrice(3000) - .payCard(true) - .payBank(true) - .isDeleted(false) - .isEvent(false) - .remarks("비고") - .hit(0) - .build(); - - var shop = shopRepository.save(shopRequest); - + Shop shop = shopFixture.마슬랜(null); RestAssured .given() .body(String.format(""" @@ -448,12 +354,13 @@ void registerWithExistShop() { "shop_id": %d, "shop_name": "기분좋은 뷔짱" } - """, shopRequest.getId())) + """, shop.getId())) .contentType(ContentType.JSON) .when() .post("/owners/register") .then() .statusCode(HttpStatus.OK.value()); + Owner owner = ownerRepository.findByCompanyRegistrationNumber("011-34-12312").get(); var ownerShop = ownerShopRedisRepository.findById(owner.getId()); assertSoftly( @@ -608,6 +515,7 @@ void ownerVerifyDuplicated() { String code = "123123"; OwnerInVerification verification = OwnerInVerification.of(email, code); ownerInVerificationRedisRepository.save(verification); + // when RestAssured .given() .body(String.format(""" @@ -623,6 +531,7 @@ void ownerVerifyDuplicated() { .then() .statusCode(HttpStatus.OK.value()); + // then RestAssured .given() .body(String.format(""" @@ -643,24 +552,14 @@ void ownerVerifyDuplicated() { @DisplayName("사장님이 비밀번호를 변경한다.") void ownerChangePassword() { // given - User user = User.builder() - .password("1234") - .nickname("주노") - .name("최준호") - .phoneNumber("010-1234-5678") - .userType(OWNER) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build(); - userRepository.save(user); - String token = jwtProvider.createToken(user); + User user = userFixture.현수_사장님().getUser(); String code = "123123"; OwnerInVerification verification = OwnerInVerification.of(user.getEmail(), code); verification.verify(); ownerInVerificationRedisRepository.save(verification); String password = "asdf1234!"; + + // when RestAssured .given() .body(String.format(""" @@ -675,6 +574,8 @@ void ownerChangePassword() { .put("/owners/password/reset") .then() .statusCode(HttpStatus.OK.value()); + + // then var result = ownerInVerificationRedisRepository.findById(user.getEmail()); User userResult = userRepository.getByEmail(user.getEmail()); SoftAssertions.assertSoftly( @@ -694,6 +595,8 @@ void ownerChangePasswordNotAuthed() { OwnerInVerification verification = OwnerInVerification.of(email, code); ownerInVerificationRedisRepository.save(verification); String password = "asdf1234!"; + + // when & then RestAssured .given() .body(String.format(""" @@ -714,35 +617,11 @@ void ownerChangePasswordNotAuthed() { @DisplayName("사장님이 회원탈퇴를 한다.") void ownerDelete() { // given - User user = User.builder() - .password("1234") - .nickname("주노") - .name("최준호") - .phoneNumber("010-1234-5678") - .userType(OWNER) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build(); - - OwnerAttachment attachment = OwnerAttachment.builder() - .url("https://test.com/test.jpg") - .isDeleted(false) - .build(); - - Owner ownerRequest = Owner.builder() - .companyRegistrationNumber("123-45-67890") - .attachments(List.of(attachment)) - .grantShop(true) - .grantEvent(true) - .user(user) - .build(); - Owner owner = ownerRepository.save(ownerRequest); - String token = jwtProvider.createToken(owner.getUser()); + Owner owner = userFixture.현수_사장님(); + String token = userFixture.getToken(owner.getUser()); - // when then - ExtractableResponse response = RestAssured + // when + RestAssured .given() .header("Authorization", "Bearer " + token) .when() @@ -751,6 +630,7 @@ void ownerDelete() { .statusCode(HttpStatus.NO_CONTENT.value()) .extract(); - assertThat(userRepository.findById(user.getId())).isNotPresent(); + // then + assertThat(userRepository.findById(owner.getId())).isNotPresent(); } } diff --git a/src/test/java/in/koreatech/koin/acceptance/OwnerShopApiTest.java b/src/test/java/in/koreatech/koin/acceptance/OwnerShopApiTest.java index 9be4cd71b..08e3e7a8e 100644 --- a/src/test/java/in/koreatech/koin/acceptance/OwnerShopApiTest.java +++ b/src/test/java/in/koreatech/koin/acceptance/OwnerShopApiTest.java @@ -1,16 +1,12 @@ package in.koreatech.koin.acceptance; -import static in.koreatech.koin.domain.user.model.UserType.OWNER; import static java.time.format.DateTimeFormatter.ofPattern; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.SoftAssertions.assertSoftly; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import java.time.Clock; import java.time.LocalDate; -import java.time.LocalTime; -import java.time.ZonedDateTime; import java.util.List; import java.util.Optional; @@ -20,18 +16,11 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; -import org.springframework.transaction.TransactionStatus; -import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; import in.koreatech.koin.AcceptanceTest; import in.koreatech.koin.domain.owner.model.Owner; -import in.koreatech.koin.domain.owner.model.OwnerAttachment; -import in.koreatech.koin.domain.owner.repository.OwnerAttachmentRepository; -import in.koreatech.koin.domain.owner.repository.OwnerRepository; -import in.koreatech.koin.domain.ownershop.dto.OwnerShopsRequest; import in.koreatech.koin.domain.shop.model.EventArticle; -import in.koreatech.koin.domain.shop.model.EventArticleImage; import in.koreatech.koin.domain.shop.model.Menu; import in.koreatech.koin.domain.shop.model.MenuCategory; import in.koreatech.koin.domain.shop.model.MenuCategoryMap; @@ -42,464 +31,264 @@ import in.koreatech.koin.domain.shop.model.ShopCategoryMap; import in.koreatech.koin.domain.shop.model.ShopImage; import in.koreatech.koin.domain.shop.model.ShopOpen; -import in.koreatech.koin.domain.shop.repository.EventArticleImageRepository; import in.koreatech.koin.domain.shop.repository.EventArticleRepository; import in.koreatech.koin.domain.shop.repository.MenuCategoryRepository; import in.koreatech.koin.domain.shop.repository.MenuRepository; -import in.koreatech.koin.domain.shop.repository.ShopCategoryMapRepository; -import in.koreatech.koin.domain.shop.repository.ShopCategoryRepository; -import in.koreatech.koin.domain.shop.repository.ShopImageRepository; -import in.koreatech.koin.domain.shop.repository.ShopOpenRepository; import in.koreatech.koin.domain.shop.repository.ShopRepository; -import in.koreatech.koin.domain.user.model.User; -import in.koreatech.koin.domain.user.model.UserGender; -import in.koreatech.koin.global.auth.JwtProvider; +import in.koreatech.koin.fixture.EventArticleFixture; +import in.koreatech.koin.fixture.MenuCategoryFixture; +import in.koreatech.koin.fixture.MenuFixture; +import in.koreatech.koin.fixture.ShopCategoryFixture; +import in.koreatech.koin.fixture.ShopFixture; +import in.koreatech.koin.fixture.UserFixture; import in.koreatech.koin.support.JsonAssertions; import io.restassured.RestAssured; import io.restassured.http.ContentType; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; +@SuppressWarnings("NonAsciiCharacters") class OwnerShopApiTest extends AcceptanceTest { @Autowired private TransactionTemplate transactionTemplate; @Autowired - private EventArticleImageRepository eventArticleImageRepository; - - @Autowired - private OwnerRepository ownerRepository; + private MenuRepository menuRepository; @Autowired private ShopRepository shopRepository; @Autowired - private ShopCategoryRepository shopCategoryRepository; + private MenuCategoryRepository menuCategoryRepository; @Autowired - private ShopOpenRepository shopOpenRepository; + private EventArticleRepository eventArticleRepository; @Autowired - private ShopImageRepository shopImageRepository; + private MenuFixture menuFixture; @Autowired - private ShopCategoryMapRepository shopCategoryMapRepository; + private UserFixture userFixture; @Autowired - private MenuCategoryRepository menuCategoryRepository; + private ShopFixture shopFixture; @Autowired - private MenuRepository menuRepository; + private ShopCategoryFixture shopCategoryFixture; @Autowired - private EventArticleRepository eventArticleRepository; + private MenuCategoryFixture menuCategoryFixture; @Autowired - private JwtProvider jwtProvider; - - @Autowired - private OwnerAttachmentRepository ownerAttachmentRepository; - - private Owner owner; - private Shop shop; - private String token; - private ShopCategory shopCategory1; - private ShopCategory shopCategory2; - private Owner otherOwner; - private String otherOwnerToken; + private EventArticleFixture eventArticleFixture; + + private Owner owner_현수; + private String token_현수; + private Owner owner_준영; + private String token_준영; + private Shop shop_마슬랜; + private ShopCategory shopCategory_치킨; + private ShopCategory shopCategory_일반; + private MenuCategory menuCategory_메인; + private MenuCategory menuCategory_사이드; @BeforeEach void setUp() { - when(clock.instant()).thenReturn( - ZonedDateTime.parse("2024-02-21 18:00:00 KST", ofPattern("yyyy-MM-dd " + "HH:mm:ss z")).toInstant()); - when(clock.getZone()).thenReturn(Clock.systemDefaultZone().getZone()); - - OwnerAttachment attachment = OwnerAttachment.builder() - .url("https://test.com/test.jpg") - .isDeleted(false) - .build(); - - Owner ownerRequest = Owner.builder() - .companyRegistrationNumber("111-45-67890") - .attachments(List.of(attachment)) - .grantShop(true) - .grantEvent(true) - .user( - User.builder() - .password("1234") - .nickname("셋업유저") - .name("셋업") - .phoneNumber("010-1234-5678") - .userType(OWNER) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build() - ) - .build(); - owner = ownerRepository.save(ownerRequest); - token = jwtProvider.createToken(owner.getUser()); - - Shop shopRequest = Shop.builder() - .owner(owner) - .name("테스트 상점") - .internalName("테스트") - .chosung("테스트") - .phone("010-1234-5678") - .address("대전광역시 유성구 대학로 291") - .description("테스트 상점입니다.") - .delivery(true) - .deliveryPrice(3000) - .payCard(true) - .payBank(true) - .isDeleted(false) - .isEvent(false) - .remarks("비고") - .hit(0) - .build(); - shop = shopRepository.save(shopRequest); - - ShopCategory shopCategoryRequest1 = ShopCategory.builder() - .isDeleted(false) - .name("테스트1") - .imageUrl("https://test.com/test1.jpg") - .build(); - - ShopCategory shopCategoryRequest2 = ShopCategory.builder() - .isDeleted(false) - .name("테스트2") - .imageUrl("https://test.com/test2.jpg") - .build(); - shopCategory1 = shopCategoryRepository.save(shopCategoryRequest1); - shopCategory2 = shopCategoryRepository.save(shopCategoryRequest2); - - var otherAttachment = OwnerAttachment.builder() - .url("https://test.com/test.jpg") - .isDeleted(false) - .build(); - - Owner otherOwnerRequest = Owner.builder() - .companyRegistrationNumber("123-45-61890") - .attachments(List.of(otherAttachment)) - .grantShop(true) - .grantEvent(true) - .user( - User.builder() - .password("1234") - .nickname("주노") - .name("최준호") - .phoneNumber("010-1234-5678") - .userType(OWNER) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build() - ) - .build(); - otherOwner = ownerRepository.save(otherOwnerRequest); - otherOwnerToken = jwtProvider.createToken(otherOwner.getUser()); + owner_현수 = userFixture.현수_사장님(); + token_현수 = userFixture.getToken(owner_현수.getUser()); + owner_준영 = userFixture.준영_사장님(); + token_준영 = userFixture.getToken(owner_준영.getUser()); + shop_마슬랜 = shopFixture.마슬랜(owner_현수); + shopCategory_치킨 = shopCategoryFixture.카테고리_치킨(); + shopCategory_일반 = shopCategoryFixture.카테고리_일반음식(); + menuCategory_메인 = menuCategoryFixture.메인메뉴(shop_마슬랜); + menuCategory_사이드 = menuCategoryFixture.사이드메뉴(shop_마슬랜); } @Test @DisplayName("사장님의 가게 목록을 조회한다.") void getOwnerShops() { // given - Shop shopRequest = Shop.builder() - .owner(owner) - .name("테스트 상점2") - .internalName("테스트") - .chosung("테스트") - .phone("010-1234-5678") - .address("대전광역시 유성구 대학로 291") - .description("테스트 상점2입니다.") - .delivery(true) - .deliveryPrice(4000) - .payCard(true) - .payBank(true) - .isDeleted(false) - .isEvent(false) - .remarks("비고2") - .hit(10) - .build(); - Shop shop2 = shopRepository.save(shopRequest); + shopFixture.신전_떡볶이(owner_현수); // when then - ExtractableResponse response = RestAssured + var response = RestAssured .given() - .header("Authorization", "Bearer " + token) + .header("Authorization", "Bearer " + token_현수) .when() .get("/owner/shops") .then() .statusCode(HttpStatus.OK.value()) .extract(); - assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getInt("count")).isEqualTo(2); - softly.assertThat(response.body().jsonPath().getList("shops").size()).isEqualTo(2); - softly.assertThat(response.body().jsonPath().getInt("shops[0].id")).isEqualTo(shop.getId()); - softly.assertThat(response.body().jsonPath().getString("shops[0].name")).isEqualTo(shop.getName()); - softly.assertThat(response.body().jsonPath().getInt("shops[1].id")).isEqualTo(shop2.getId()); - softly.assertThat(response.body().jsonPath().getString("shops[1].name")).isEqualTo(shop2.getName()); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + { + "count": 2, + "shops": [ + { + "id": 1, + "name": "마슬랜 치킨", + "is_event": false + }, + { + "id": 2, + "name": "신전 떡볶이", + "is_event": false + } + ] + } + """); } @Test @DisplayName("상점을 생성한다.") void createOwnerShop() { // given - OwnerShopsRequest.InnerOpenRequest open1 = new OwnerShopsRequest.InnerOpenRequest( - LocalTime.of(21, 0), - false, - "MONDAY", - LocalTime.of(9, 0) - ); - OwnerShopsRequest.InnerOpenRequest open2 = new OwnerShopsRequest.InnerOpenRequest( - LocalTime.of(21, 0), - false, - "WEDNESDAY", - LocalTime.of(9, 0) - ); - - List categoryIds = List.of(1); - List imageUrls = List.of( - "https://test.com/test1.jpg", - "https://test.com/test2.jpg", - "https://test.com/test3.jpg" - ); - List opens = List.of(open1, open2); - - OwnerShopsRequest ownerShopsRequest = new OwnerShopsRequest( - "대전광역시 유성구 대학로 291", - categoryIds, - true, - 4000, - "테스트 상점2입니다.", - imageUrls, - "테스트 상점2", - opens, - true, - true, - "010-1234-5678" - ); - - ShopCategory shopCategory1 = ShopCategory.builder() - .isDeleted(false) - .name("테스트1") - .imageUrl("https://test.com/test1.jpg") - .build(); - - ShopCategory shopCategory2 = ShopCategory.builder() - .isDeleted(false) - .name("테스트2") - .imageUrl("https://test.com/test2.jpg") - .build(); - shopCategoryRepository.save(shopCategory1); - shopCategoryRepository.save(shopCategory2); - - ExtractableResponse response = RestAssured + RestAssured .given() .contentType(ContentType.JSON) - .header("Authorization", "Bearer " + token) - .body(ownerShopsRequest) + .header("Authorization", "Bearer " + token_현수) + .body(String.format(""" + { + "address": "대전광역시 유성구 대학로 291", + "category_ids": [ + %d + ], + "delivery": true, + "delivery_price": 4000, + "description": "테스트 상점2입니다.", + "image_urls": [ + "https://test.com/test1.jpg", + "https://test.com/test2.jpg", + "https://test.com/test3.jpg" + ], + "name": "테스트 상점2", + "open": [ + { + "close_time": [ + 21, + 0 + ], + "closed": false, + "day_of_week": "MONDAY", + "open_time": [ + 9, + 0 + ] + }, + { + "close_time": [ + 21, + 0 + ], + "closed": false, + "day_of_week": "WEDNESDAY", + "open_time": [ + 9, + 0 + ] + } + ], + "pay_bank": true, + "pay_card": true, + "phone": "010-1234-5678" + } + """, shopCategory_치킨.getId()) + ) .when() .post("/owner/shops") .then() .statusCode(HttpStatus.CREATED.value()) .extract(); - List shops = shopRepository.findAllByOwnerId(owner.getId()); - Shop createdShop = shops.get(1); - - List shopOpens = shopOpenRepository.findAllByShopId(createdShop.getId()); - List shopImages = shopImageRepository.findAllByShopId(createdShop.getId()); - List shopCategoryMaps = shopCategoryMapRepository.findAllByShopId(createdShop.getId()); - - assertSoftly( - softly -> { - softly.assertThat(createdShop.getAddress()).isEqualTo(ownerShopsRequest.address()); - softly.assertThat(createdShop.isDelivery()).isEqualTo(ownerShopsRequest.delivery()); - softly.assertThat(createdShop.getDeliveryPrice()).isEqualTo(ownerShopsRequest.deliveryPrice()); - softly.assertThat(createdShop.getDescription()).isEqualTo(ownerShopsRequest.description()); - softly.assertThat(createdShop.getName()).isEqualTo(ownerShopsRequest.name()); - softly.assertThat(createdShop.isPayBank()).isEqualTo(ownerShopsRequest.payBank()); - softly.assertThat(createdShop.isPayCard()).isEqualTo(ownerShopsRequest.payCard()); - softly.assertThat(createdShop.getPhone()).isEqualTo(ownerShopsRequest.phone()); - softly.assertThat(shopOpens).hasSize(2); - softly.assertThat(categoryIds).containsAnyElementsOf(shopCategoryMaps.stream() - .map(shopCategory -> shopCategory.getShopCategory().getId()).toList()); - softly.assertThat(imageUrls).containsAnyElementsOf(shopImages.stream() - .map(ShopImage::getImageUrl).toList()); - } - ); + transactionTemplate.executeWithoutResult(status -> { + List shops = shopRepository.findAllByOwnerId(owner_현수.getId()); + Shop result = shops.get(1); + assertSoftly( + softly -> { + softly.assertThat(result.getAddress()).isEqualTo("대전광역시 유성구 대학로 291"); + softly.assertThat(result.getDeliveryPrice()).isEqualTo(4000); + softly.assertThat(result.getDescription()).isEqualTo("테스트 상점2입니다."); + softly.assertThat(result.getName()).isEqualTo("테스트 상점2"); + softly.assertThat(result.getShopImages()).hasSize(3); + softly.assertThat(result.getShopOpens()).hasSize(2); + softly.assertThat(result.getShopCategories()).hasSize(1); + } + ); + }); } @Test @DisplayName("상점 사장님이 특정 상점 조회") void getShop() { // given - ShopOpen open1 = ShopOpen.builder() - .openTime(LocalTime.of(0, 0)) - .closeTime(LocalTime.of(21, 0)) - .shop(shop) - .closed(false) - .dayOfWeek("MONDAY") - .build(); - - ShopOpen open2 = ShopOpen.builder() - .openTime(LocalTime.of(0, 0)) - .closeTime(LocalTime.of(0, 0)) - .shop(shop) - .closed(false) - .dayOfWeek("FRIDAY") - .build(); - - shopOpenRepository.save(open1); - shopOpenRepository.save(open2); - - ShopCategoryMap shopCategoryMap1 = ShopCategoryMap.builder() - .shop(shop) - .shopCategory(shopCategory1) - .build(); - - ShopCategoryMap shopCategoryMap2 = ShopCategoryMap.builder() - .shop(shop) - .shopCategory(shopCategory2) - .build(); - - shopCategoryMapRepository.save(shopCategoryMap1); - shopCategoryMapRepository.save(shopCategoryMap2); - - ShopImage shopImage1 = ShopImage.builder() - .imageUrl("https://test.com/test1.jpg") - .shop(shop) - .build(); - - ShopImage shopImage2 = ShopImage.builder() - .imageUrl("https://test.com/test2.jpg") - .shop(shop) - .build(); - - shopImageRepository.save(shopImage1); - shopImageRepository.save(shopImage2); - - ExtractableResponse response = RestAssured + var response = RestAssured .given() - .header("Authorization", "Bearer " + token) + .header("Authorization", "Bearer " + token_현수) .when() - .get("/owner/shops/{shopId}", shop.getId()) + .get("/owner/shops/{shopId}", shop_마슬랜.getId()) .then() .statusCode(HttpStatus.OK.value()) .extract(); - List savedShopImages = shopImageRepository.findAllByShopId(shop.getId()); - List savedMenuCategories = menuCategoryRepository.findAllByShopId(shop.getId()); - List savedShopOpens = shopOpenRepository.findAllByShopId(shop.getId()); - List savedShopCategoryMaps = shopCategoryMapRepository.findAllByShopId(shop.getId()); - JsonAssertions.assertThat(response.asPrettyString()) - .isEqualTo(String.format(""" + .isEqualTo(""" { - "address": "대전광역시 유성구 대학로 291", - "delivery": true, - "delivery_price": 3000, - "description": "테스트 상점입니다.", - "id": 1, - "image_urls": [ - "https://test.com/test1.jpg", - "https://test.com/test2.jpg" - ], - "menu_categories": [ - - ], - "name": "테스트 상점", - "open": [ - { - "day_of_week": "MONDAY", - "closed": false, - "open_time": "00:00", - "close_time": "21:00" - }, - { - "day_of_week": "FRIDAY", - "closed": false, - "open_time": "00:00", - "close_time": "00:00" - } - ], - "pay_bank": true, - "pay_card": true, - "phone": "010-1234-5678", - "shop_categories": [ - { - "id": 1, - "name": "테스트1" - }, - { - "id": 2, - "name": "테스트2" - } - ], - "updated_at": %s, - "is_event": false - } - """, response.jsonPath().getString("updated_at"))); + "address": "천안시 동남구 병천면 1600", + "delivery": true, + "delivery_price": 3000, + "description": "마슬랜 치킨입니다.", + "id": 1, + "image_urls": [ + "https://test-image.com/마슬랜.png", + "https://test-image.com/마슬랜2.png" + ], + "menu_categories": [ + { + "id": 1, + "name": "메인메뉴" + }, + { + "id": 2, + "name": "사이드메뉴" + } + ], + "name": "마슬랜 치킨", + "open": [ + { + "day_of_week": "MONDAY", + "closed": false, + "open_time": "00:00", + "close_time": "21:00" + }, + { + "day_of_week": "FRIDAY", + "closed": false, + "open_time": "00:00", + "close_time": "00:00" + } + ], + "pay_bank": true, + "pay_card": true, + "phone": "010-7574-1212", + "shop_categories": [ + + ], + "updated_at": "2024-01-15", + "is_event": false + } + """); } @Test @DisplayName("특정 상점의 모든 메뉴를 조회한다.") void findOwnerShopMenu() { // given - final long SHOP_ID = 1L; - - MenuOption menuOption1 = MenuOption.builder() - .option("일반") - .price(7000) - .build(); - - MenuOption menuOption2 = MenuOption.builder() - .option("곱빼기") - .price(7500) - .build(); - - MenuImage menuImage1 = MenuImage.builder() - .imageUrl("https://test.com/test.jpg") - .build(); - MenuImage menuImage2 = MenuImage.builder() - .imageUrl("https://test.com/hello.jpg") - .build(); - - Menu menu1 = Menu.builder() - .shopId(1) - .name("짜장면") - .description("맛있는 짜장면") - .build(); - - MenuCategory menuCategory1 = MenuCategory.builder() - .shop(shop) - .name("중식") - .build(); - - MenuCategoryMap menuCategoryMap1 = MenuCategoryMap.create(); - menuCategoryRepository.save(menuCategory1); - - menuOption1.setMenu(menu1); - menuOption2.setMenu(menu1); - menuImage1.setMenu(menu1); - menuImage2.setMenu(menu1); - - menuCategoryMap1.map(menu1, menuCategory1); - - menuRepository.save(menu1); - - ExtractableResponse response = RestAssured + menuFixture.짜장면_옵션메뉴(shop_마슬랜, menuCategory_메인); + var response = RestAssured .given() - .header("Authorization", "Bearer " + token) - .param("shopId", SHOP_ID) + .header("Authorization", "Bearer " + token_현수) + .param("shopId", shop_마슬랜.getId()) .when() .get("/owner/shops/menus") .then() @@ -507,156 +296,86 @@ void findOwnerShopMenu() { .extract(); JsonAssertions.assertThat(response.asPrettyString()) - .isEqualTo(String.format(""" + .isEqualTo(""" { - "count": 1, - "menu_categories": [ - { - "id": 1, - "name": "중식", - "menus": [ - { - "id": 1, - "name": "짜장면", - "is_hidden": false, - "is_single": false, - "single_price": null, - "option_prices": [ - { - "option": "곱빼기", - "price": 7500 - }, - { - "option": "일반", - "price": 7000 - } - ], - "description": "맛있는 짜장면", - "image_urls": [ - "https://test.com/hello.jpg", - "https://test.com/test.jpg" - ] - } - ] - } - ], - "updated_at": %s - } - """, response.jsonPath().getString("updated_at"))); + "count": 1, + "menu_categories": [ + { + "id": 1, + "name": "메인메뉴", + "menus": [ + { + "id": 1, + "name": "짜장면", + "is_hidden": false, + "is_single": false, + "single_price": null, + "option_prices": [ + { + "option": "곱빼기", + "price": 7500 + }, + { + "option": "일반", + "price": 7000 + } + ], + "description": "맛있는 짜장면", + "image_urls": [ + "https://test.com/짜장면.jpg", + "https://test.com/짜장면22.jpg" + ] + } + ] + } + ], + "updated_at": "2024-01-15" + } + """); } @Test @DisplayName("사장님이 자신의 상점 메뉴 카테고리들을 조회한다.") void findOwnerMenuCategories() { // given - final int SHOP_ID = 1; - - Menu menu = Menu.builder() - .shopId(SHOP_ID) - .name("짜장면") - .description("맛있는 짜장면") - .build(); - - MenuCategory menuCategory1 = MenuCategory.builder() - .shop(shop) - .name("이벤트 메뉴") - .build(); - - MenuCategory menuCategory2 = MenuCategory.builder() - .shop(shop) - .name("메인 메뉴") - .build(); - - menuCategoryRepository.save(menuCategory1); - menuCategoryRepository.save(menuCategory2); - - MenuCategoryMap menuCategoryMap1 = MenuCategoryMap.create(); - MenuCategoryMap menuCategoryMap2 = MenuCategoryMap.create(); - - // when then - menuCategoryMap1.map(menu, menuCategory1); - menuCategoryMap2.map(menu, menuCategory2); - - menuRepository.save(menu); + menuFixture.짜장면_단일메뉴(shop_마슬랜, menuCategory_메인); - ExtractableResponse response = RestAssured + var response = RestAssured .given() - .param("shopId", SHOP_ID) - .header("Authorization", "Bearer " + token) + .param("shopId", shop_마슬랜.getId()) + .header("Authorization", "Bearer " + token_현수) .when() .get("/owner/shops/menus/categories") .then() .statusCode(HttpStatus.OK.value()) .extract(); - - SoftAssertions.assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getInt("count")).isEqualTo(2); - - softly.assertThat(response.body().jsonPath().getList("menu_categories")) - .hasSize(2); - - softly.assertThat(response.body().jsonPath().getInt("menu_categories[0].id")) - .isEqualTo(menuCategory1.getId()); - softly.assertThat(response.body().jsonPath().getString("menu_categories[0].name")) - .isEqualTo(menuCategory1.getName()); - - softly.assertThat(response.body().jsonPath().getInt("menu_categories[1].id")) - .isEqualTo(menuCategory2.getId()); - softly.assertThat(response.body().jsonPath().getString("menu_categories[1].name")) - .isEqualTo(menuCategory2.getName()); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + { + "count": 2, + "menu_categories": [ + { + "id": 1, + "name": "메인메뉴" + }, + { + "id": 2, + "name": "사이드메뉴" + } + ] + } + """); } @Test @DisplayName("사장님이 자신의 상점의 특정 메뉴를 조회한다.") void findMenuShopOwner() { // given - MenuOption menuOption1 = MenuOption.builder() - .option("일반") - .price(7000) - .build(); - - MenuOption menuOption2 = MenuOption.builder() - .option("곱빼기") - .price(7500) - .build(); - - MenuImage menuImage1 = MenuImage.builder() - .imageUrl("https://test.com/test.jpg") - .build(); - MenuImage menuImage2 = MenuImage.builder() - .imageUrl("https://test.com/hello.jpg") - .build(); - - Menu menu = Menu.builder() - .shopId(1) - .name("짜장면") - .description("맛있는 짜장면") - .build(); - - MenuCategory menuCategory = MenuCategory.builder() - .shop(shop) - .name("중식") - .build(); - - MenuCategoryMap menuCategoryMap = MenuCategoryMap.create(); - menuCategoryRepository.save(menuCategory); - - // when then - menuOption1.setMenu(menu); - menuOption2.setMenu(menu); - menuImage1.setMenu(menu); - menuImage2.setMenu(menu); - - menuCategoryMap.map(menu, menuCategory); + Menu menu = menuFixture.짜장면_옵션메뉴(shop_마슬랜, menuCategory_메인); - menuRepository.save(menu); - - ExtractableResponse response = RestAssured + var response = RestAssured .given() - .header("Authorization", "Bearer " + token) + .header("Authorization", "Bearer " + token_현수) .when() .get("/owner/shops/menus/{menuId}", menu.getId()) .then() @@ -672,7 +391,7 @@ void findMenuShopOwner() { softly.assertThat(response.body().jsonPath().getBoolean("is_hidden")).isEqualTo(menu.isHidden()); softly.assertThat(response.body().jsonPath().getBoolean("is_single")).isFalse(); - softly.assertThat((Integer) response.body().jsonPath().get("single_price")).isNull(); + softly.assertThat((Integer)response.body().jsonPath().get("single_price")).isNull(); softly.assertThat(response.body().jsonPath().getList("option_prices")).hasSize(2); softly.assertThat(response.body().jsonPath().getString("description")).isEqualTo(menu.getDescription()); softly.assertThat(response.body().jsonPath().getList("category_ids")) @@ -689,9 +408,9 @@ void ownerCannotQueryOtherStoresWithoutPermission() { // given RestAssured .given() - .header("Authorization", "Bearer " + otherOwnerToken) + .header("Authorization", "Bearer " + token_준영) .when() - .get("/owner/shops/{shopId}", shop.getId()) + .get("/owner/shops/{shopId}", shop_마슬랜.getId()) .then() .statusCode(HttpStatus.FORBIDDEN.value()) .extract(); @@ -700,63 +419,45 @@ void ownerCannotQueryOtherStoresWithoutPermission() { @Test @DisplayName("사장님이 메뉴 카테고리를 삭제한다.") void deleteMenuCategory() { - // given - MenuCategory menuCategory = MenuCategory.builder() - .shop(shop) - .name("중식") - .build(); - MenuCategory svaedMenuCategory = menuCategoryRepository.save(menuCategory); - - ExtractableResponse response = RestAssured + // when & then + RestAssured .given() - .header("Authorization", "Bearer " + token) + .header("Authorization", "Bearer " + token_현수) .when() - .delete("/owner/shops/menus/categories/{categoryId}", svaedMenuCategory.getId()) + .delete("/owner/shops/menus/categories/{categoryId}", menuCategory_메인.getId()) .then() .statusCode(HttpStatus.NO_CONTENT.value()) .extract(); - boolean isPresent = menuCategoryRepository.findById(svaedMenuCategory.getId()).isPresent(); - SoftAssertions.assertSoftly(softly -> softly.assertThat(isPresent).isFalse()); + assertThat(menuCategoryRepository.findById(menuCategory_메인.getId())).isNotPresent(); } @Test @DisplayName("사장님이 메뉴를 삭제한다.") void deleteMenu() { // given - Menu menu = Menu.builder() - .shopId(1) - .name("짜장면") - .description("맛있는 짜장면") - .build(); - Menu savedMenu = menuRepository.save(menu); - - ExtractableResponse response = RestAssured + Menu menu = menuFixture.짜장면_단일메뉴(shop_마슬랜, menuCategory_메인); + + RestAssured .given() - .header("Authorization", "Bearer " + token) + .header("Authorization", "Bearer " + token_현수) .when() - .delete("/owner/shops/menus/{menuId}", savedMenu.getId()) + .delete("/owner/shops/menus/{menuId}", menu.getId()) .then() .statusCode(HttpStatus.NO_CONTENT.value()) .extract(); - boolean isPresent = menuRepository.findById(savedMenu.getId()).isPresent(); - SoftAssertions.assertSoftly(softly -> softly.assertThat(isPresent).isFalse()); + assertThat(menuRepository.findById(menu.getId())).isNotPresent(); } @Test @DisplayName("사장님이 옵션이 여러개인 메뉴를 추가한다.") void createManyOptionMenu() { // given - MenuCategory menuCategory = MenuCategory.builder() - .name("테스트") - .shop(shop) - .build(); - MenuCategory savedMenuCategory = menuCategoryRepository.save(menuCategory); - String categoryId = savedMenuCategory.getId().toString(); - ExtractableResponse response = RestAssured + MenuCategory menuCategory = menuCategory_메인; + var response = RestAssured .given() - .header("Authorization", "Bearer " + token) + .header("Authorization", "Bearer " + token_현수) .contentType(ContentType.JSON) .body(String.format(""" { @@ -765,7 +466,7 @@ void createManyOptionMenu() { ], "description": "테스트메뉴입니다.", "image_urls": [ - "string" + "https://test-image.com/짜장면.jpg" ], "is_single": false, "name": "짜장면", @@ -780,30 +481,27 @@ void createManyOptionMenu() { } ] } - """, categoryId)) + """, menuCategory.getId())) .when() - .post("/owner/shops/{id}/menus", shop.getId()) + .post("/owner/shops/{id}/menus", shop_마슬랜.getId()) .then() .statusCode(HttpStatus.CREATED.value()) .extract(); - transactionTemplate.execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(TransactionStatus status) { - Menu menu = menuRepository.getById(1); - assertSoftly( - softly -> { - List menuCategoryMaps = menu.getMenuCategoryMaps(); - List menuOptions = menu.getMenuOptions(); - List menuImages = menu.getMenuImages(); - softly.assertThat(menu.getDescription()).isEqualTo("테스트메뉴입니다."); - softly.assertThat(menu.getName()).isEqualTo("짜장면"); - softly.assertThat(menuImages.get(0).getImageUrl()).isEqualTo("string"); - softly.assertThat(menuCategoryMaps.get(0).getMenuCategory().getId()).isEqualTo(1); - softly.assertThat(menuOptions).hasSize(2); - } - ); - } + transactionTemplate.executeWithoutResult(status -> { + Menu menu = menuRepository.getById(1); + assertSoftly( + softly -> { + List menuCategoryMaps = menu.getMenuCategoryMaps(); + List menuOptions = menu.getMenuOptions(); + List menuImages = menu.getMenuImages(); + softly.assertThat(menu.getDescription()).isEqualTo("테스트메뉴입니다."); + softly.assertThat(menu.getName()).isEqualTo("짜장면"); + softly.assertThat(menuImages.get(0).getImageUrl()).isEqualTo("https://test-image.com/짜장면.jpg"); + softly.assertThat(menuCategoryMaps.get(0).getMenuCategory().getId()).isEqualTo(1); + softly.assertThat(menuOptions).hasSize(2); + } + ); }); } @@ -811,15 +509,10 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { @DisplayName("사장님이 옵션이 한개인 메뉴를 추가한다.") void createOneOptionMenu() { // given - MenuCategory menuCategory = MenuCategory.builder() - .name("테스트") - .shop(shop) - .build(); - MenuCategory savedMenuCategory = menuCategoryRepository.save(menuCategory); - String categoryId = savedMenuCategory.getId().toString(); - ExtractableResponse response = RestAssured + MenuCategory menuCategory = menuCategory_메인; + var response = RestAssured .given() - .header("Authorization", "Bearer " + token) + .header("Authorization", "Bearer " + token_현수) .contentType(ContentType.JSON) .body(String.format(""" { @@ -828,39 +521,36 @@ void createOneOptionMenu() { ], "description": "테스트메뉴입니다.", "image_urls": [ - "string" + "https://test-image.com/짜장면.jpg" ], "is_single": true, "name": "짜장면", "option_prices": null, "single_price": 10000 } - """, categoryId)) + """, menuCategory.getId())) .when() - .post("/owner/shops/{id}/menus", shop.getId()) + .post("/owner/shops/{id}/menus", shop_마슬랜.getId()) .then() .statusCode(HttpStatus.CREATED.value()) .extract(); - transactionTemplate.execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(TransactionStatus status) { - Menu menu = menuRepository.getById(1); - assertSoftly( - softly -> { - List menuCategoryMaps = menu.getMenuCategoryMaps(); - List menuOptions = menu.getMenuOptions(); - List menuImages = menu.getMenuImages(); - softly.assertThat(menu.getDescription()).isEqualTo("테스트메뉴입니다."); - softly.assertThat(menu.getName()).isEqualTo("짜장면"); - - softly.assertThat(menuImages.get(0).getImageUrl()).isEqualTo("string"); - softly.assertThat(menuCategoryMaps.get(0).getMenuCategory().getId()).isEqualTo(1); - - softly.assertThat(menuOptions.get(0).getPrice()).isEqualTo(10000); - } - ); - } + transactionTemplate.executeWithoutResult(status -> { + Menu menu = menuRepository.getById(1); + assertSoftly( + softly -> { + List menuCategoryMaps = menu.getMenuCategoryMaps(); + List menuOptions = menu.getMenuOptions(); + List menuImages = menu.getMenuImages(); + softly.assertThat(menu.getDescription()).isEqualTo("테스트메뉴입니다."); + softly.assertThat(menu.getName()).isEqualTo("짜장면"); + + softly.assertThat(menuImages.get(0).getImageUrl()).isEqualTo("https://test-image.com/짜장면.jpg"); + softly.assertThat(menuCategoryMaps.get(0).getMenuCategory().getId()).isEqualTo(1); + + softly.assertThat(menuOptions.get(0).getPrice()).isEqualTo(10000); + } + ); }); } @@ -868,78 +558,73 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { @DisplayName("사장님이 메뉴 카테고리를 추가한다.") void createMenuCategory() { // given - ExtractableResponse response = RestAssured + RestAssured .given() - .header("Authorization", "Bearer " + token) + .header("Authorization", "Bearer " + token_현수) .contentType(ContentType.JSON) .body(String.format(""" { - "name": "사이드 메뉴" + "name": "대박메뉴" } """)) .when() - .post("/owner/shops/{id}/menus/categories", shop.getId()) + .post("/owner/shops/{id}/menus/categories", shop_마슬랜.getId()) .then() .statusCode(HttpStatus.CREATED.value()) .extract(); - MenuCategory menuCategory = menuCategoryRepository.getById(1); + var menuCategories = menuCategoryRepository.findAllByShopId(shop_마슬랜.getId()); - assertSoftly( - softly -> softly.assertThat(menuCategory.getName()).isEqualTo("사이드 메뉴") - ); + assertThat(menuCategories).anyMatch(menuCategory -> "대박메뉴".equals(menuCategory.getName())); } @Test @DisplayName("사장님이 단일 메뉴로 수정한다.") void modifyOneMenu() { // given - Menu createdMenu = createMenu(); + Menu menu = menuFixture.짜장면_단일메뉴(shop_마슬랜, menuCategory_메인); - ExtractableResponse response = RestAssured + RestAssured .given() - .header("Authorization", "Bearer " + token) + .header("Authorization", "Bearer " + token_현수) .contentType(ContentType.JSON) .body(String.format(""" { "category_ids": [ - 2 + %d ], "description": "테스트메뉴수정", "image_urls": [ - "string2" + "https://test-image.net/테스트메뉴.jpeg" ], "is_single": true, "name": "짜장면2", "single_price": 10000 } - """)) + """, shopCategory_일반.getId())) .when() - .put("/owner/shops/menus/{menuId}", createdMenu.getId()) + .put("/owner/shops/menus/{menuId}", menu.getId()) .then() .statusCode(HttpStatus.CREATED.value()) .extract(); - transactionTemplate.execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(TransactionStatus status) { - Menu menu = menuRepository.getById(1); - assertSoftly( - softly -> { - List menuCategoryMaps = menu.getMenuCategoryMaps(); - List menuOptions = menu.getMenuOptions(); - List menuImages = menu.getMenuImages(); - softly.assertThat(menu.getDescription()).isEqualTo("테스트메뉴수정"); - softly.assertThat(menu.getName()).isEqualTo("짜장면2"); + transactionTemplate.executeWithoutResult(status -> { + Menu result = menuRepository.getById(1); + assertSoftly( + softly -> { + List menuCategoryMaps = result.getMenuCategoryMaps(); + List menuOptions = result.getMenuOptions(); + List menuImages = result.getMenuImages(); + softly.assertThat(result.getDescription()).isEqualTo("테스트메뉴수정"); + softly.assertThat(result.getName()).isEqualTo("짜장면2"); - softly.assertThat(menuImages.get(0).getImageUrl()).isEqualTo("string2"); - softly.assertThat(menuCategoryMaps.get(0).getMenuCategory().getId()).isEqualTo(2); + softly.assertThat(menuImages.get(0).getImageUrl()).isEqualTo("https://test-image.net/테스트메뉴.jpeg"); + softly.assertThat(menuCategoryMaps.get(0).getMenuCategory().getId()).isEqualTo(2); - softly.assertThat(menuOptions.get(0).getPrice()).isEqualTo(10000); + softly.assertThat(menuOptions.get(0).getPrice()).isEqualTo(10000); - } - ); - } + } + ); }); } @@ -947,20 +632,19 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { @DisplayName("사장님이 여러옵션을 가진 메뉴로 수정한다.") void modifyManyOptionMenu() { // given - Menu createdMenu = createMenu(); - - ExtractableResponse response = RestAssured + Menu menu = menuFixture.짜장면_옵션메뉴(shop_마슬랜, menuCategory_메인); + RestAssured .given() - .header("Authorization", "Bearer " + token) + .header("Authorization", "Bearer " + token_현수) .contentType(ContentType.JSON) - .body(""" + .body(String.format(""" { "category_ids": [ - 1, 2 + %d, %d ], "description": "테스트메뉴입니다.", "image_urls": [ - "string" + "https://fixed-testimage.com/수정된짜장면.png" ], "is_single": false, "name": "짜장면", @@ -975,30 +659,29 @@ void modifyManyOptionMenu() { } ] } - """) + """, menuCategory_메인.getId(), menuCategory_사이드.getId()) + ) .when() - .put("/owner/shops/menus/{menuId}", createdMenu.getId()) + .put("/owner/shops/menus/{menuId}", menu.getId()) .then() .statusCode(HttpStatus.CREATED.value()) .extract(); - transactionTemplate.execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(TransactionStatus status) { - Menu menu = menuRepository.getById(1); - assertSoftly( - softly -> { - List menuCategoryMaps = menu.getMenuCategoryMaps(); - List menuOptions = menu.getMenuOptions(); - List menuImages = menu.getMenuImages(); - softly.assertThat(menu.getDescription()).isEqualTo("테스트메뉴입니다."); - softly.assertThat(menu.getName()).isEqualTo("짜장면"); - softly.assertThat(menuImages.get(0).getImageUrl()).isEqualTo("string"); - softly.assertThat(menuCategoryMaps).hasSize(2); - softly.assertThat(menuOptions).hasSize(2); - } - ); - } + transactionTemplate.executeWithoutResult(status -> { + Menu result = menuRepository.getById(1); + assertSoftly( + softly -> { + List menuCategoryMaps = result.getMenuCategoryMaps(); + List menuOptions = result.getMenuOptions(); + List menuImages = result.getMenuImages(); + softly.assertThat(result.getDescription()).isEqualTo("테스트메뉴입니다."); + softly.assertThat(result.getName()).isEqualTo("짜장면"); + softly.assertThat(menuImages.get(0).getImageUrl()) + .isEqualTo("https://fixed-testimage.com/수정된짜장면.png"); + softly.assertThat(menuCategoryMaps).hasSize(2); + softly.assertThat(menuOptions).hasSize(2); + } + ); }); } @@ -1006,21 +689,21 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { @DisplayName("사장님이 상점을 수정한다.") void modifyShop() { // given - ExtractableResponse response = RestAssured + RestAssured .given() - .header("Authorization", "Bearer " + token) + .header("Authorization", "Bearer " + token_현수) .contentType(ContentType.JSON) - .body(""" + .body(String.format(""" { "address": "충청남도 천안시 동남구 병천면 충절로 1600", "category_ids": [ - 1, 2 + %d, %d ], "delivery": false, "delivery_price": 1000, - "description": "이번주 전 메뉴 10% 할인 이벤트합니다.", + "description": "이번주 전 메뉴 10%% 할인 이벤트합니다.", "image_urls": [ - "string2" + "https://fixed-shopimage.com/수정된_상점_이미지.png" ], "name": "써니 숯불 도시락", "open": [ @@ -1041,98 +724,50 @@ void modifyShop() { "pay_card": true, "phone": "041-123-4567" } - """) + """, shopCategory_일반.getId(), shopCategory_치킨.getId() + )) .when() - .put("/owner/shops/{id}", shop.getId()) + .put("/owner/shops/{id}", shop_마슬랜.getId()) .then() .statusCode(HttpStatus.CREATED.value()) .extract(); - transactionTemplate.execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(TransactionStatus status) { - Shop modifiedShop = shopRepository.getById(1); - List shopImages = modifiedShop.getShopImages(); - List shopOpens = modifiedShop.getShopOpens(); - List shopCategoryMaps = modifiedShop.getShopCategories(); - assertSoftly( - softly -> { - softly.assertThat(modifiedShop.getAddress()).isEqualTo("충청남도 천안시 동남구 병천면 충절로 1600"); - softly.assertThat(modifiedShop.isDeleted()).isFalse(); - softly.assertThat(modifiedShop.getDeliveryPrice()).isEqualTo(1000); - softly.assertThat(modifiedShop.getDescription()).isEqualTo("이번주 전 메뉴 10% 할인 이벤트합니다."); - softly.assertThat(modifiedShop.getName()).isEqualTo("써니 숯불 도시락"); - softly.assertThat(modifiedShop.isPayBank()).isTrue(); - softly.assertThat(modifiedShop.isPayCard()).isTrue(); - softly.assertThat(modifiedShop.getPhone()).isEqualTo("041-123-4567"); - - softly.assertThat(shopCategoryMaps.get(0).getShopCategory().getId()).isEqualTo(1); - softly.assertThat(shopCategoryMaps.get(1).getShopCategory().getId()).isEqualTo(2); - - softly.assertThat(shopImages.get(0).getImageUrl()).isEqualTo("string2"); - - softly.assertThat(shopOpens.get(0).getCloseTime()).isEqualTo("22:30"); - softly.assertThat(shopOpens.get(0).getOpenTime()).isEqualTo("10:00"); - - softly.assertThat(shopOpens.get(0).getDayOfWeek()).isEqualTo("MONDAY"); - softly.assertThat(shopOpens.get(0).getClosed()).isFalse(); - - softly.assertThat(shopOpens.get(1).getCloseTime()).isEqualTo("23:30"); - softly.assertThat(shopOpens.get(1).getOpenTime()).isEqualTo("11:00"); - - softly.assertThat(shopOpens.get(1).getDayOfWeek()).isEqualTo("SUNDAY"); - softly.assertThat(shopOpens.get(1).getClosed()).isTrue(); - } - ); - } - }); - } + transactionTemplate.executeWithoutResult(status -> { + Shop result = shopRepository.getById(1); + List shopImages = result.getShopImages(); + List shopOpens = result.getShopOpens(); + List shopCategoryMaps = result.getShopCategories(); + assertSoftly( + softly -> { + softly.assertThat(result.getAddress()).isEqualTo("충청남도 천안시 동남구 병천면 충절로 1600"); + softly.assertThat(result.isDeleted()).isFalse(); + softly.assertThat(result.getDeliveryPrice()).isEqualTo(1000); + softly.assertThat(result.getDescription()).isEqualTo("이번주 전 메뉴 10% 할인 이벤트합니다."); + softly.assertThat(result.getName()).isEqualTo("써니 숯불 도시락"); + softly.assertThat(result.isPayBank()).isTrue(); + softly.assertThat(result.isPayCard()).isTrue(); + softly.assertThat(result.getPhone()).isEqualTo("041-123-4567"); - private Menu createMenu() { - MenuCategory menuCategory1 = MenuCategory.builder() - .name("테스트") - .shop(shop) - .build(); - MenuCategory menuCategory2 = MenuCategory.builder() - .name("테스트2") - .shop(shop) - .build(); - MenuCategory savedMenuCategory = menuCategoryRepository.save(menuCategory1); - menuCategoryRepository.save(menuCategory2); - String categoryId = savedMenuCategory.getId().toString(); - ExtractableResponse response = RestAssured - .given() - .header("Authorization", "Bearer " + token) - .contentType(ContentType.JSON) - .body(String.format(""" - { - "category_ids": [ - %s - ], - "description": "테스트메뉴입니다.", - "image_urls": [ - "string" - ], - "is_single": false, - "name": "짜장면", - "option_prices": [ - { - "option": "중", - "price": 10000 - }, - { - "option": "소", - "price": 5000 - } - ] + softly.assertThat(shopCategoryMaps.get(0).getShopCategory().getId()).isEqualTo(1); + softly.assertThat(shopCategoryMaps.get(1).getShopCategory().getId()).isEqualTo(2); + + softly.assertThat(shopImages.get(0).getImageUrl()) + .isEqualTo("https://fixed-shopimage.com/수정된_상점_이미지.png"); + + softly.assertThat(shopOpens.get(0).getCloseTime()).isEqualTo("22:30"); + softly.assertThat(shopOpens.get(0).getOpenTime()).isEqualTo("10:00"); + + softly.assertThat(shopOpens.get(0).getDayOfWeek()).isEqualTo("MONDAY"); + softly.assertThat(shopOpens.get(0).getClosed()).isFalse(); + + softly.assertThat(shopOpens.get(1).getCloseTime()).isEqualTo("23:30"); + softly.assertThat(shopOpens.get(1).getOpenTime()).isEqualTo("11:00"); + + softly.assertThat(shopOpens.get(1).getDayOfWeek()).isEqualTo("SUNDAY"); + softly.assertThat(shopOpens.get(1).getClosed()).isTrue(); } - """, categoryId)) - .when() - .post("/owner/shops/{id}/menus", shop.getId()) - .then() - .statusCode(HttpStatus.CREATED.value()) - .extract(); - return menuRepository.getById(1); + ); + }); } @Test @@ -1142,7 +777,7 @@ void ownerCannotQueryOtherCategoriesWithoutPermission() { RestAssured .given() .param("shopId", 1) - .header("Authorization", "Bearer " + otherOwnerToken) + .header("Authorization", "Bearer " + token_준영) .when() .get("/owner/shops/menus/categories") .then() @@ -1156,7 +791,7 @@ void ownerCannotQueryOtherMenusWithoutPermission() { // given RestAssured .given() - .header("Authorization", "Bearer " + otherOwnerToken) + .header("Authorization", "Bearer " + token_준영) .param("shopId", 1) .when() .get("/owner/shops/menus") @@ -1169,17 +804,12 @@ void ownerCannotQueryOtherMenusWithoutPermission() { @DisplayName("권한이 없는 사장님이 메뉴 카테고리를 삭제한다.") void ownerCannotDeleteOtherCategoriesWithoutPermission() { // given - MenuCategory menuCategory = MenuCategory.builder() - .shop(shop) - .name("중식") - .build(); - MenuCategory svaedMenuCategory = menuCategoryRepository.save(menuCategory); - - ExtractableResponse response = RestAssured + MenuCategory menuCategory = menuCategoryFixture.세트메뉴(shop_마슬랜); + RestAssured .given() - .header("Authorization", "Bearer " + otherOwnerToken) + .header("Authorization", "Bearer " + token_준영) .when() - .delete("/owner/shops/menus/categories/{categoryId}", svaedMenuCategory.getId()) + .delete("/owner/shops/menus/categories/{categoryId}", menuCategory.getId()) .then() .statusCode(HttpStatus.FORBIDDEN.value()) .extract(); @@ -1189,18 +819,13 @@ void ownerCannotDeleteOtherCategoriesWithoutPermission() { @DisplayName("권한이 없는 사장님이 메뉴를 삭제한다.") void ownerCannotDeleteOtherMenusWithoutPermission() { // given - Menu menu = Menu.builder() - .shopId(1) - .name("짜장면") - .description("맛있는 짜장면") - .build(); - Menu savedMenu = menuRepository.save(menu); + Menu menu = menuFixture.짜장면_단일메뉴(shop_마슬랜, menuCategory_메인); RestAssured .given() - .header("Authorization", "Bearer " + otherOwnerToken) + .header("Authorization", "Bearer " + token_준영) .when() - .delete("/owner/shops/menus/{menuId}", savedMenu.getId()) + .delete("/owner/shops/menus/{menuId}", menu.getId()) .then() .statusCode(HttpStatus.FORBIDDEN.value()) .extract(); @@ -1211,9 +836,9 @@ void ownerCannotDeleteOtherMenusWithoutPermission() { void ownerShopCreateEvent() { LocalDate startDate = LocalDate.now(); LocalDate endDate = startDate.plusDays(10); - ExtractableResponse response = RestAssured + RestAssured .given() - .header("Authorization", "Bearer " + token) + .header("Authorization", "Bearer " + token_현수) .contentType(ContentType.JSON) .body(String.format(""" { @@ -1227,9 +852,10 @@ void ownerShopCreateEvent() { } """, startDate.format(ofPattern("yyyy-MM-dd")), - endDate.format(ofPattern("yyyy-MM-dd")))) + endDate.format(ofPattern("yyyy-MM-dd")) + )) .when() - .post("/owner/shops/{shopId}/event", shop.getId()) + .post("/owner/shops/{shopId}/event", shop_마슬랜.getId()) .then() .statusCode(HttpStatus.CREATED.value()) .extract(); @@ -1256,18 +882,10 @@ void ownerShopCreateEvent() { void ownerShopModifyEvent() { LocalDate startDate = LocalDate.now(); LocalDate endDate = startDate.plusDays(10); - EventArticle savedEvent = createEventArticle( - shop, - "테스트 제목1", - "테스트 내용1", - startDate, - endDate, - List.of("https://test.com/test1.jpg") - ); - - ExtractableResponse response = RestAssured + EventArticle eventArticle = eventArticleFixture.할인_이벤트(shop_마슬랜, startDate, endDate); + RestAssured .given() - .header("Authorization", "Bearer " + token) + .header("Authorization", "Bearer " + token_현수) .contentType(ContentType.JSON) .body(String.format(""" { @@ -1283,22 +901,22 @@ void ownerShopModifyEvent() { startDate, endDate)) .when() - .put("/owner/shops/{shopId}/events/{eventId}", shop.getId(), savedEvent.getId()) + .put("/owner/shops/{shopId}/events/{eventId}", shop_마슬랜.getId(), eventArticle.getId()) .then() .statusCode(HttpStatus.CREATED.value()) .extract(); transactionTemplate.executeWithoutResult(status -> { - EventArticle modifiedEventArticle = eventArticleRepository.getById(savedEvent.getId()); + EventArticle result = eventArticleRepository.getById(eventArticle.getId()); assertSoftly( softly -> { - softly.assertThat(modifiedEventArticle.getShop().getId()).isEqualTo(1); - softly.assertThat(modifiedEventArticle.getTitle()).isEqualTo("감성떡볶이 이벤트합니다!"); - softly.assertThat(modifiedEventArticle.getContent()).isEqualTo("테스트 이벤트입니다."); - softly.assertThat(modifiedEventArticle.getThumbnailImages().get(0).getThumbnailImage()) + softly.assertThat(result.getShop().getId()).isEqualTo(1); + softly.assertThat(result.getTitle()).isEqualTo("감성떡볶이 이벤트합니다!"); + softly.assertThat(result.getContent()).isEqualTo("테스트 이벤트입니다."); + softly.assertThat(result.getThumbnailImages().get(0).getThumbnailImage()) .isEqualTo("https://test.com/test1.jpg"); - softly.assertThat(modifiedEventArticle.getStartDate()).isEqualTo(startDate); - softly.assertThat(modifiedEventArticle.getEndDate()).isEqualTo(endDate); + softly.assertThat(result.getStartDate()).isEqualTo(startDate); + softly.assertThat(result.getEndDate()).isEqualTo(endDate); } ); }); @@ -1307,55 +925,23 @@ void ownerShopModifyEvent() { @Test @DisplayName("사장님이 이벤트를 삭제한다.") void ownerShopDeleteEvent() { - EventArticle savedEvent = createEventArticle( - shop, - "테스트 제목1", - "테스트 내용1", + EventArticle eventArticle = eventArticleFixture.할인_이벤트( + shop_마슬랜, LocalDate.of(2024, 10, 24), - LocalDate.of(2024, 10, 26), - List.of("https://test.com/test1.jpg") + LocalDate.of(2024, 10, 26) ); - ExtractableResponse response = RestAssured + RestAssured .given() - .header("Authorization", "Bearer " + token) + .header("Authorization", "Bearer " + token_현수) .contentType(ContentType.JSON) .when() - .delete("/owner/shops/{shopId}/events/{eventId}", shop.getId(), savedEvent.getId()) + .delete("/owner/shops/{shopId}/events/{eventId}", shop_마슬랜.getId(), eventArticle.getId()) .then() .statusCode(HttpStatus.NO_CONTENT.value()) .extract(); - Optional modifiedEventArticle = eventArticleRepository.findById(savedEvent.getId()); - - assertSoftly(softly -> softly.assertThat(modifiedEventArticle.isPresent()).isFalse()); - } - - private EventArticle createEventArticle( - Shop shop, - String title, - String content, - LocalDate startDate, - LocalDate endDate, - List thumbnailImages - ) { - EventArticle eventArticle = EventArticle.builder() - .shop(shop) - .title(title) - .content(content) - .ip("") - .startDate(startDate) - .endDate(endDate) - .hit(0) - .build(); - EventArticle savedEvent = eventArticleRepository.save(eventArticle); - for (String image : thumbnailImages) { - EventArticleImage eventArticleImage = EventArticleImage.builder() - .eventArticle(eventArticle) - .thumbnailImage(image) - .build(); - eventArticleImageRepository.save(eventArticleImage); - } - return eventArticleRepository.getById(savedEvent.getId()); + Optional modifiedEventArticle = eventArticleRepository.findById(eventArticle.getId()); + assertThat(modifiedEventArticle).isNotPresent(); } } diff --git a/src/test/java/in/koreatech/koin/acceptance/ShopApiTest.java b/src/test/java/in/koreatech/koin/acceptance/ShopApiTest.java index a89b1ae91..2afd15b8b 100644 --- a/src/test/java/in/koreatech/koin/acceptance/ShopApiTest.java +++ b/src/test/java/in/koreatech/koin/acceptance/ShopApiTest.java @@ -1,202 +1,65 @@ package in.koreatech.koin.acceptance; -import static in.koreatech.koin.domain.user.model.UserType.OWNER; -import static java.time.format.DateTimeFormatter.ofPattern; -import static org.assertj.core.api.SoftAssertions.assertSoftly; -import static org.mockito.Mockito.when; - -import java.time.Clock; -import java.time.Instant; import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.ZonedDateTime; -import java.util.List; import org.assertj.core.api.Assertions; -import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; -import org.springframework.transaction.TransactionStatus; -import org.springframework.transaction.support.TransactionCallbackWithoutResult; -import org.springframework.transaction.support.TransactionTemplate; import in.koreatech.koin.AcceptanceTest; import in.koreatech.koin.domain.owner.model.Owner; -import in.koreatech.koin.domain.owner.model.OwnerAttachment; -import in.koreatech.koin.domain.owner.repository.OwnerRepository; -import in.koreatech.koin.domain.shop.model.EventArticle; -import in.koreatech.koin.domain.shop.model.EventArticleImage; import in.koreatech.koin.domain.shop.model.Menu; -import in.koreatech.koin.domain.shop.model.MenuCategory; -import in.koreatech.koin.domain.shop.model.MenuCategoryMap; -import in.koreatech.koin.domain.shop.model.MenuImage; -import in.koreatech.koin.domain.shop.model.MenuOption; import in.koreatech.koin.domain.shop.model.Shop; -import in.koreatech.koin.domain.shop.model.ShopCategory; -import in.koreatech.koin.domain.shop.model.ShopCategoryMap; -import in.koreatech.koin.domain.shop.model.ShopImage; -import in.koreatech.koin.domain.shop.model.ShopOpen; -import in.koreatech.koin.domain.shop.repository.EventArticleImageRepository; -import in.koreatech.koin.domain.shop.repository.EventArticleRepository; -import in.koreatech.koin.domain.shop.repository.MenuCategoryRepository; -import in.koreatech.koin.domain.shop.repository.MenuRepository; -import in.koreatech.koin.domain.shop.repository.ShopCategoryMapRepository; -import in.koreatech.koin.domain.shop.repository.ShopCategoryRepository; -import in.koreatech.koin.domain.shop.repository.ShopImageRepository; -import in.koreatech.koin.domain.shop.repository.ShopOpenRepository; -import in.koreatech.koin.domain.shop.repository.ShopRepository; -import in.koreatech.koin.domain.user.model.User; -import in.koreatech.koin.domain.user.model.UserGender; +import in.koreatech.koin.fixture.EventArticleFixture; +import in.koreatech.koin.fixture.MenuCategoryFixture; +import in.koreatech.koin.fixture.MenuFixture; +import in.koreatech.koin.fixture.ShopCategoryFixture; +import in.koreatech.koin.fixture.ShopFixture; +import in.koreatech.koin.fixture.UserFixture; import in.koreatech.koin.support.JsonAssertions; import io.restassured.RestAssured; import io.restassured.http.ContentType; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; +@SuppressWarnings("NonAsciiCharacters") class ShopApiTest extends AcceptanceTest { @Autowired - private TransactionTemplate transactionTemplate; - - @Autowired - private MenuRepository menuRepository; - - @Autowired - private MenuCategoryRepository menuCategoryRepository; - - @Autowired - private ShopImageRepository shopImageRepository; - - @Autowired - private ShopOpenRepository shopOpenRepository; + private UserFixture userFixture; @Autowired - private ShopCategoryMapRepository shopCategoryMapRepository; + private ShopFixture shopFixture; @Autowired - private EventArticleImageRepository eventArticleImageRepository; + private MenuFixture menuFixture; @Autowired - private ShopCategoryRepository shopCategoryRepository; + private MenuCategoryFixture menuCategoryFixture; @Autowired - private OwnerRepository ownerRepository; + private EventArticleFixture eventArticleFixture; @Autowired - private ShopRepository shopRepository; + private ShopCategoryFixture shopCategoryFixture; - @Autowired - private EventArticleRepository eventArticleRepository; - - private ShopCategory shopCategory1, shopCategory2; private Shop shop; private Owner owner; @BeforeEach void setUp() { - when(clock.instant()).thenReturn( - ZonedDateTime.parse("2024-02-21 18:00:00 KST", ofPattern("yyyy-MM-dd " + "HH:mm:ss z")).toInstant()); - when(clock.getZone()).thenReturn(Clock.systemDefaultZone().getZone()); - - OwnerAttachment attachment = OwnerAttachment.builder() - .url("https://test.com/test.jpg") - .isDeleted(false) - .build(); - - Owner ownerRequest = Owner.builder() - .companyRegistrationNumber("123-45-67892") - .attachments(List.of(attachment)) - .grantShop(true) - .grantEvent(true) - .user( - User.builder() - .password("1234") - .nickname("셋업유저") - .name("셋업") - .phoneNumber("010-1234-5678") - .userType(OWNER) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build() - ) - .build(); - owner = ownerRepository.save(ownerRequest); - - Shop shopRequest = Shop.builder() - .owner(owner) - .name("테스트 상점") - .internalName("테스트") - .chosung("테스트") - .phone("010-1234-5678") - .address("대전광역시 유성구 대학로 291") - .description("테스트 상점입니다.") - .delivery(true) - .deliveryPrice(3000) - .payCard(true) - .payBank(true) - .isDeleted(false) - .isEvent(false) - .remarks("비고") - .hit(0) - .build(); - shop = shopRepository.save(shopRequest); - - ShopCategory shopCategoryRequest1 = ShopCategory.builder() - .isDeleted(false) - .name("테스트1") - .imageUrl("https://test.com/test1.jpg") - .build(); - - ShopCategory shopCategoryRequest2 = ShopCategory.builder() - .isDeleted(false) - .name("테스트2") - .imageUrl("https://test.com/test2.jpg") - .build(); - shopCategory1 = shopCategoryRepository.save(shopCategoryRequest1); - shopCategory2 = shopCategoryRepository.save(shopCategoryRequest2); + owner = userFixture.준영_사장님(); + shop = shopFixture.마슬랜(owner); } @Test @DisplayName("옵션이 하나 있는 상점의 메뉴를 조회한다.") void findMenuSingleOption() { // given - MenuOption menuOption = MenuOption.builder() - .option("일반") - .price(7000) - .build(); - - MenuImage menuImage = MenuImage.builder() - .imageUrl("https://test.com/test.jpg") - .build(); + Menu menu = menuFixture.짜장면_단일메뉴(shop, menuCategoryFixture.메인메뉴(shop)); - Menu menu = Menu.builder() - .shopId(1) - .name("짜장면") - .description("맛있는 짜장면") - .build(); - - MenuCategory menuCategory = MenuCategory.builder() - .shop(shop) - .name("중식") - .build(); - menuCategoryRepository.save(menuCategory); - - MenuCategoryMap menuCategoryMap = MenuCategoryMap.create(); - - menuOption.setMenu(menu); - menuImage.setMenu(menu); - - // when then - menuCategoryMap.map(menu, menuCategory); - menuRepository.save(menu); - - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .get("/shops/{shopId}/menus/{menuId}", menu.getShopId(), menu.getId()) @@ -204,76 +67,36 @@ void findMenuSingleOption() { .statusCode(HttpStatus.OK.value()) .extract(); - SoftAssertions.assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getInt("id")).isEqualTo(menu.getId()); - - softly.assertThat(response.body().jsonPath().getInt("shop_id")).isEqualTo(menu.getShopId()); - softly.assertThat(response.body().jsonPath().getString("name")).isEqualTo(menu.getName()); - softly.assertThat(response.body().jsonPath().getBoolean("is_hidden")).isEqualTo(menu.isHidden()); - - softly.assertThat(response.body().jsonPath().getBoolean("is_single")).isTrue(); - softly.assertThat(response.body().jsonPath().getInt("single_price")).isEqualTo(menuOption.getPrice()); - - softly.assertThat(response.body().jsonPath().getList("option_prices")).isNull(); - - softly.assertThat(response.body().jsonPath().getString("description")).isEqualTo(menu.getDescription()); - - softly.assertThat(response.body().jsonPath().getList("category_ids")) - .hasSize(menu.getMenuCategoryMaps().size()); - - softly.assertThat(response.body().jsonPath().getList("image_urls")) - .hasSize(menu.getMenuImages().size()); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + { + "id": 1, + "shop_id": 1, + "name": "짜장면", + "is_hidden": false, + "is_single": true, + "single_price": 7000, + "option_prices": null, + "description": "맛있는 짜장면", + "category_ids": [ + 1 + ], + "image_urls": [ + "https://test.com/짜장면.jpg", + "https://test.com/짜장면22.jpg" + ] + } + """ + ); } @Test @DisplayName("옵션이 여러 개 있는 상점의 메뉴를 조회한다.") void findMenuMultipleOption() { // given - MenuOption menuOption1 = MenuOption.builder() - .option("일반") - .price(7000) - .build(); - - MenuOption menuOption2 = MenuOption.builder() - .option("곱빼기") - .price(7500) - .build(); - - MenuImage menuImage1 = MenuImage.builder() - .imageUrl("https://test.com/test.jpg") - .build(); - MenuImage menuImage2 = MenuImage.builder() - .imageUrl("https://test.com/hello.jpg") - .build(); - - Menu menu = Menu.builder() - .shopId(1) - .name("짜장면") - .description("맛있는 짜장면") - .build(); - - MenuCategory menuCategory = MenuCategory.builder() - .shop(shop) - .name("중식") - .build(); - - MenuCategoryMap menuCategoryMap = MenuCategoryMap.create(); - menuCategoryRepository.save(menuCategory); - - // when then - menuOption1.setMenu(menu); - menuOption2.setMenu(menu); - menuImage1.setMenu(menu); - menuImage2.setMenu(menu); - - menuCategoryMap.map(menu, menuCategory); + Menu menu = menuFixture.짜장면_옵션메뉴(shop, menuCategoryFixture.메인메뉴(shop)); - menuRepository.save(menu); - - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .get("/shops/{shopId}/menus/{menuId}", menu.getShopId(), menu.getId()) @@ -305,10 +128,46 @@ void findMenuMultipleOption() { 1 ], "image_urls": [ - "https://test.com/hello.jpg", - "https://test.com/test.jpg" + "https://test.com/짜장면.jpg", + "https://test.com/짜장면22.jpg" ] } + HTTP/1.1 200\s + Vary: Origin + Vary: Access-Control-Request-Method + Vary: Access-Control-Request-Headers + Content-Type: application/json + Transfer-Encoding: chunked + Date: Mon, 22 Apr 2024 15:59:58 GMT + Keep-Alive: timeout=60 + Connection: keep-alive + + { + "id": 1, + "shop_id": 1, + "name": "짜장면", + "is_hidden": false, + "is_single": false, + "single_price": null, + "option_prices": [ + { + "option": "곱빼기", + "price": 7500 + }, + { + "option": "일반", + "price": 7000 + } + ], + "description": "맛있는 짜장면", + "category_ids": [ + 1 + ], + "image_urls": [ + "https://test.com/짜장면.jpg", + "https://test.com/짜장면22.jpg" + ] + } """); } @@ -316,37 +175,11 @@ void findMenuMultipleOption() { @DisplayName("상점의 메뉴 카테고리들을 조회한다.") void findShopMenuCategories() { // given - final int SHOP_ID = 1; + menuCategoryFixture.사이드메뉴(shop); + menuCategoryFixture.세트메뉴(shop); + Menu menu = menuFixture.짜장면_단일메뉴(shop, menuCategoryFixture.추천메뉴(shop)); - Menu menu = Menu.builder() - .shopId(SHOP_ID) - .name("짜장면") - .description("맛있는 짜장면") - .build(); - - MenuCategory menuCategory1 = MenuCategory.builder() - .shop(shop) - .name("이벤트 메뉴") - .build(); - - MenuCategory menuCategory2 = MenuCategory.builder() - .shop(shop) - .name("메인 메뉴") - .build(); - - menuCategoryRepository.save(menuCategory1); - menuCategoryRepository.save(menuCategory2); - - MenuCategoryMap menuCategoryMap1 = MenuCategoryMap.create(); - MenuCategoryMap menuCategoryMap2 = MenuCategoryMap.create(); - - // when then - menuCategoryMap1.map(menu, menuCategory1); - menuCategoryMap2.map(menu, menuCategory2); - - menuRepository.save(menu); - - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .get("/shops/{shopId}/menus/categories", menu.getShopId()) @@ -354,76 +187,35 @@ void findShopMenuCategories() { .statusCode(HttpStatus.OK.value()) .extract(); - SoftAssertions.assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getInt("count")).isEqualTo(2); - - softly.assertThat(response.body().jsonPath().getList("menu_categories")) - .hasSize(2); - - softly.assertThat(response.body().jsonPath().getInt("menu_categories[0].id")) - .isEqualTo(menuCategory1.getId()); - softly.assertThat(response.body().jsonPath().getString("menu_categories[0].name")) - .isEqualTo(menuCategory1.getName()); - - softly.assertThat(response.body().jsonPath().getInt("menu_categories[1].id")) - .isEqualTo(menuCategory2.getId()); - softly.assertThat(response.body().jsonPath().getString("menu_categories[1].name")) - .isEqualTo(menuCategory2.getName()); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + { + "count": 3, + "menu_categories": [ + { + "id": 1, + "name": "사이드메뉴" + }, + { + "id": 2, + "name": "세트메뉴" + }, + { + "id": 3, + "name": "추천메뉴" + } + ] + } + """); } @Test @DisplayName("특정 상점 조회") - void getShop() throws Exception { + void getShop() { // given - ShopOpen open1 = ShopOpen.builder() - .openTime(LocalTime.of(0, 0)) - .closeTime(LocalTime.of(21, 0)) - .shop(shop) - .closed(false) - .dayOfWeek("MONDAY") - .build(); - - ShopOpen open2 = ShopOpen.builder() - .openTime(LocalTime.of(0, 0)) - .closeTime(LocalTime.of(0, 0)) - .shop(shop) - .closed(false) - .dayOfWeek("FRIDAY") - .build(); - - ShopOpen newShopOpen1 = shopOpenRepository.save(open1); - ShopOpen newShopOpen2 = shopOpenRepository.save(open2); - - ShopCategoryMap shopCategoryMap1 = ShopCategoryMap.builder() - .shop(shop) - .shopCategory(shopCategory1) - .build(); - - ShopCategoryMap shopCategoryMap2 = ShopCategoryMap.builder() - .shop(shop) - .shopCategory(shopCategory2) - .build(); - - ShopCategoryMap newShopCategoryMap1 = shopCategoryMapRepository.save(shopCategoryMap1); - ShopCategoryMap newShopCategoryMap2 = shopCategoryMapRepository.save(shopCategoryMap2); - - ShopImage shopImage1 = ShopImage.builder() - .imageUrl("https://test.com/test1.jpg") - .shop(shop) - .build(); - - ShopImage shopImage2 = ShopImage.builder() - .imageUrl("https://test.com/test2.jpg") - .shop(shop) - .build(); - - ShopImage newShopImage1 = shopImageRepository.save(shopImage1); - ShopImage newShopImage2 = shopImageRepository.save(shopImage2); - - ExtractableResponse response = RestAssured + menuCategoryFixture.사이드메뉴(shop); + menuCategoryFixture.세트메뉴(shop); + var response = RestAssured .given() .when() .get("/shops/{shopId}", shop.getId()) @@ -432,21 +224,28 @@ void getShop() throws Exception { .extract(); JsonAssertions.assertThat(response.asPrettyString()) - .isEqualTo(String.format(""" + .isEqualTo(""" { - "address": "대전광역시 유성구 대학로 291", + "address": "천안시 동남구 병천면 1600", "delivery": true, "delivery_price": 3000, - "description": "테스트 상점입니다.", + "description": "마슬랜 치킨입니다.", "id": 1, "image_urls": [ - "https://test.com/test1.jpg", - "https://test.com/test2.jpg" + "https://test-image.com/마슬랜.png", + "https://test-image.com/마슬랜2.png" ], "menu_categories": [ - + { + "id": 1, + "name": "사이드메뉴" + }, + { + "id": 2, + "name": "세트메뉴" + } ], - "name": "테스트 상점", + "name": "마슬랜 치킨", "open": [ { "day_of_week": "MONDAY", @@ -463,143 +262,23 @@ void getShop() throws Exception { ], "pay_bank": true, "pay_card": true, - "phone": "010-1234-5678", + "phone": "010-7574-1212", "shop_categories": [ - { - "id": 1, - "name": "테스트1" - }, - { - "id": 2, - "name": "테스트2" - } + ], - "updated_at": "%s", + "updated_at": "2024-01-15", "is_event": false - }""", LocalDateTime.now().format(ofPattern("yyyy-MM-dd"))) + } + """ ); } @Test @DisplayName("특정 상점 모든 메뉴 조회") void getShopMenus() { - // given - MenuOption menuOption1 = MenuOption.builder() - .option("일반") - .price(7000) - .build(); - - MenuOption menuOption2 = MenuOption.builder() - .option("곱빼기") - .price(7500) - .build(); - - MenuImage menuImage1 = MenuImage.builder() - .imageUrl("https://test.com/test.jpg") - .build(); - MenuImage menuImage2 = MenuImage.builder() - .imageUrl("https://test.com/hello.jpg") - .build(); - - Menu menu1 = Menu.builder() - .shopId(1) - .name("짜장면") - .description("맛있는 짜장면") - .build(); - - MenuCategory menuCategory1 = MenuCategory.builder() - .shop(shop) - .name("중식") - .build(); - - MenuCategoryMap menuCategoryMap1 = MenuCategoryMap.create(); - menuCategoryRepository.save(menuCategory1); - - menuOption1.setMenu(menu1); - menuOption2.setMenu(menu1); - menuImage1.setMenu(menu1); - menuImage2.setMenu(menu1); - - menuCategoryMap1.map(menu1, menuCategory1); - - menuRepository.save(menu1); - - MenuOption menuOption3 = MenuOption.builder() - .option("일반") - .price(7000) - .build(); - - MenuOption menuOption4 = MenuOption.builder() - .option("곱빼기") - .price(7500) - .build(); - - MenuImage menuImage3 = MenuImage.builder() - .imageUrl("https://test.com/test.jpg") - .build(); - MenuImage menuImage4 = MenuImage.builder() - .imageUrl("https://test.com/hello.jpg") - .build(); - - Menu menu2 = Menu.builder() - .shopId(1) - .name("짜장면2") - .description("맛있는 짜장면") - .build(); - - MenuCategory menuCategory2 = MenuCategory.builder() - .shop(shop) - .name("한식") - .build(); - - MenuCategoryMap menuCategoryMap2 = MenuCategoryMap.create(); - menuCategoryRepository.save(menuCategory2); - - menuOption3.setMenu(menu2); - menuOption4.setMenu(menu2); - menuImage3.setMenu(menu2); - menuImage4.setMenu(menu2); - - menuCategoryMap2.map(menu2, menuCategory2); - - menuRepository.save(menu2); - - MenuOption menuOption5 = MenuOption.builder() - .option("일반") - .price(7000) - .build(); - - MenuImage menuImage5 = MenuImage.builder() - .imageUrl("https://test.com/test.jpg") - .build(); - MenuImage menuImage6 = MenuImage.builder() - .imageUrl("https://test.com/hello.jpg") - .build(); - - Menu menu3 = Menu.builder() - .shopId(1) - .name("짜장면3") - .description("맛있는 짜장면") - .build(); - - MenuCategoryMap menuCategoryMap3 = MenuCategoryMap.create(); - - menuOption5.setMenu(menu3); - menuImage5.setMenu(menu3); - menuImage6.setMenu(menu3); - - menuCategoryMap3.map(menu3, menuCategory2); - - menuRepository.save(menu3); - - MenuCategory menuCategory3 = MenuCategory.builder() - .shop(shop) - .name("이벤트") - .build(); - - menuCategoryRepository.save(menuCategory3); - - ExtractableResponse response = RestAssured + menuFixture.짜장면_단일메뉴(shop, menuCategoryFixture.추천메뉴(shop)); + menuFixture.짜장면_옵션메뉴(shop, menuCategoryFixture.세트메뉴(shop)); + var response = RestAssured .given() .when() .get("/shops/{shopId}/menus", shop.getId()) @@ -608,84 +287,61 @@ void getShopMenus() { .extract(); JsonAssertions.assertThat(response.asPrettyString()) - .isEqualTo(String.format(""" - { - "count": 3, - "menu_categories": [ - { - "id": 1, - "name": "중식", - "menus": [ - { - "id": 1, - "name": "짜장면", - "is_hidden": false, - "is_single": false, - "single_price": null, - "option_prices": [ - { - "option": "일반", - "price": 7000 - }, - { - "option": "곱빼기", - "price": 7500 - } - ], - "description": "맛있는 짜장면", - "image_urls": [ - "https://test.com/test.jpg", - "https://test.com/hello.jpg" - ] - } - ] - }, - { - "id": 2, - "name": "한식", - "menus": [ - { - "id": 2, - "name": "짜장면2", - "is_hidden": false, - "is_single": false, - "single_price": null, - "option_prices": [ - { - "option": "일반", - "price": 7000 - }, - { - "option": "곱빼기", - "price": 7500 - } - ], - "description": "맛있는 짜장면", - "image_urls": [ - "https://test.com/test.jpg", - "https://test.com/hello.jpg" - ] - }, - { - "id": 3, - "name": "짜장면3", - "is_hidden": false, - "is_single": true, - "single_price": 7000, - "option_prices": null, - "description": "맛있는 짜장면", - "image_urls": [ - "https://test.com/test.jpg", - "https://test.com/hello.jpg" - ] - } - ] - } - ], - "updated_at": %s - } - """, - response.jsonPath().getString("updated_at")) + .isEqualTo(""" + { + "count": 2, + "menu_categories": [ + { + "id": 1, + "name": "추천메뉴", + "menus": [ + { + "id": 1, + "name": "짜장면", + "is_hidden": false, + "is_single": true, + "single_price": 7000, + "option_prices": null, + "description": "맛있는 짜장면", + "image_urls": [ + "https://test.com/짜장면.jpg", + "https://test.com/짜장면22.jpg" + ] + } + ] + }, + { + "id": 2, + "name": "세트메뉴", + "menus": [ + { + "id": 2, + "name": "짜장면", + "is_hidden": false, + "is_single": false, + "single_price": null, + "option_prices": [ + { + "option": "곱빼기", + "price": 7500 + }, + { + "option": "일반", + "price": 7000 + } + ], + "description": "맛있는 짜장면", + "image_urls": [ + "https://test.com/짜장면.jpg", + "https://test.com/짜장면22.jpg" + ] + } + ] + } + ], + "updated_at": "2024-01-15" + } + """ ); } @@ -693,71 +349,8 @@ void getShopMenus() { @DisplayName("모든 상점 조회") void getAllShop() { // given - Shop shopRequest = Shop.builder() - .owner(owner) - .name("테스트 상점2") - .internalName("테스트2") - .chosung("테스트") - .phone("010-1234-5678") - .address("대전광역시 유성구 대학로 291") - .description("테스트 상점입니다.") - .delivery(true) - .deliveryPrice(3000) - .payCard(true) - .payBank(true) - .isDeleted(false) - .isEvent(false) - .remarks("비고") - .hit(0) - .build(); - Shop newShop = shopRepository.save(shopRequest); - - ShopOpen open1 = ShopOpen.builder() - .openTime(LocalTime.of(0, 0)) - .closeTime(LocalTime.of(21, 0)) - .shop(shop) - .closed(false) - .dayOfWeek("MONDAY") - .build(); - - ShopOpen open2 = ShopOpen.builder() - .openTime(LocalTime.of(0, 0)) - .closeTime(LocalTime.of(0, 0)) - .shop(newShop) - .closed(false) - .dayOfWeek("FRIDAY") - .build(); - - shopOpenRepository.save(open1); - shopOpenRepository.save(open2); - - ShopCategoryMap shopCategoryMap1 = ShopCategoryMap.builder() - .shop(shop) - .shopCategory(shopCategory1) - .build(); - - ShopCategoryMap shopCategoryMap2 = ShopCategoryMap.builder() - .shop(newShop) - .shopCategory(shopCategory2) - .build(); - - shopCategoryMapRepository.save(shopCategoryMap1); - shopCategoryMapRepository.save(shopCategoryMap2); - - ShopImage shopImage1 = ShopImage.builder() - .imageUrl("https://test.com/test1.jpg") - .shop(shop) - .build(); - - ShopImage shopImage2 = ShopImage.builder() - .imageUrl("https://test.com/test2.jpg") - .shop(newShop) - .build(); - - shopImageRepository.save(shopImage1); - shopImageRepository.save(shopImage2); - - ExtractableResponse response = RestAssured + Shop otherShop = shopFixture.신전_떡볶이(owner); + var response = RestAssured .given() .when() .get("/shops") @@ -765,307 +358,177 @@ void getAllShop() { .statusCode(HttpStatus.OK.value()) .extract(); - transactionTemplate.execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(TransactionStatus status) { - List shops = shopRepository.findAll(); - Shop shop1 = shops.get(0); - Shop shop2 = shops.get(1); - assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getString("count")).isEqualTo("2"); - softly.assertThat(response.body().jsonPath().getBoolean("shops[0].delivery")) - .isEqualTo(shop1.isDelivery()); - softly.assertThat(response.body().jsonPath().getInt("shops[0].id")).isEqualTo(shop1.getId()); - softly.assertThat(response.body().jsonPath().getString("shops[0].name")) - .isEqualTo(shop1.getName()); - softly.assertThat(response.body().jsonPath().getBoolean("shops[0].pay_bank")) - .isEqualTo(shop1.isPayBank()); - softly.assertThat(response.body().jsonPath().getBoolean("shops[0].pay_card")) - .isEqualTo(shop1.isPayCard()); - softly.assertThat(response.body().jsonPath().getString("shops[0].phone")) - .isEqualTo(shop1.getPhone()); - softly.assertThat(response.body().jsonPath().getList("shops[0].category_ids")).hasSize(1); - softly.assertThat(response.body().jsonPath().getList("shops[0].open")).hasSize(1); - - softly.assertThat(response.body().jsonPath().getBoolean("shops[1].delivery")) - .isEqualTo(shop2.isDelivery()); - softly.assertThat(response.body().jsonPath().getInt("shops[1].id")).isEqualTo(shop2.getId()); - softly.assertThat(response.body().jsonPath().getString("shops[1].name")) - .isEqualTo(shop2.getName()); - softly.assertThat(response.body().jsonPath().getBoolean("shops[1].pay_bank")) - .isEqualTo(shop2.isPayBank()); - softly.assertThat(response.body().jsonPath().getBoolean("shops[1].pay_card")) - .isEqualTo(shop2.isPayCard()); - softly.assertThat(response.body().jsonPath().getString("shops[1].phone")) - .isEqualTo(shop2.getPhone()); - softly.assertThat(response.body().jsonPath().getList("shops[1].category_ids")).hasSize(1); - softly.assertThat(response.body().jsonPath().getList("shops[1].open")).hasSize(1); - } - ); - } - }); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + { + "count": 2, + "shops": [ + { + "category_ids": [ + \s + ], + "delivery": true, + "id": 1, + "name": "마슬랜 치킨", + "open": [ + { + "day_of_week": "MONDAY", + "closed": false, + "open_time": "00:00", + "close_time": "21:00" + }, + { + "day_of_week": "FRIDAY", + "closed": false, + "open_time": "00:00", + "close_time": "00:00" + } + ], + "pay_bank": true, + "pay_card": true, + "phone": "010-7574-1212", + "is_event": false + }, + { + "category_ids": [ + \s + ], + "delivery": true, + "id": 2, + "name": "신전 떡볶이", + "open": [ + { + "day_of_week": "SUNDAY", + "closed": false, + "open_time": "00:00", + "close_time": "21:00" + }, + { + "day_of_week": "FRIDAY", + "closed": false, + "open_time": "00:00", + "close_time": "21:00" + } + ], + "pay_bank": true, + "pay_card": true, + "phone": "010-7788-9900", + "is_event": false + } + ] + } + """); } @Test @DisplayName("상점들의 모든 카테고리를 조회한다.") void getAllShopCategories() { // given - ExtractableResponse response = RestAssured + shopCategoryFixture.카테고리_일반음식(); + shopCategoryFixture.카테고리_치킨(); + var response = RestAssured .given() .when() .get("/shops/categories") .then() .statusCode(HttpStatus.OK.value()) .extract(); - assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getInt("total_count")).isEqualTo(2); - softly.assertThat(response.body().jsonPath().getInt("shop_categories[0].id")).isEqualTo(1); - softly.assertThat(response.body().jsonPath().getString("shop_categories[0].name")).isEqualTo("테스트1"); - softly.assertThat(response.body().jsonPath().getString("shop_categories[0].image_url")) - .isEqualTo("https://test.com/test1.jpg"); - softly.assertThat(response.body().jsonPath().getInt("shop_categories[1].id")).isEqualTo(2); - softly.assertThat(response.body().jsonPath().getString("shop_categories[1].name")).isEqualTo("테스트2"); - softly.assertThat(response.body().jsonPath().getString("shop_categories[1].image_url")) - .isEqualTo("https://test.com/test2.jpg"); - } - ); + + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + { + "total_count": 2, + "shop_categories": [ + { + "id": 1, + "image_url": "https://test-image.com/normal.jpg", + "name": "일반음식점" + }, + { + "id": 2, + "image_url": "https://test-image.com/ckicken.jpg", + "name": "치킨" + } + ] + } + """); } @Test @DisplayName("특정 상점의 이벤트들을 조회한다.") void getShopEvents() { - when(clock.instant()).thenReturn(Instant.now()); - when(clock.getZone()).thenReturn(Clock.systemDefaultZone().getZone()); - - var now = LocalDate.of(2024, 2, 21); - var user = owner.getUser(); - Shop shopRequest = Shop.builder() - .owner(owner) - .name("테스트 상점2") - .internalName("테스트2") - .chosung("테스트") - .phone("010-1234-5678") - .address("대전광역시 유성구 대학로 291") - .description("테스트 상점입니다.") - .delivery(true) - .deliveryPrice(3000) - .payCard(true) - .payBank(true) - .isDeleted(false) - .isEvent(false) - .remarks("비고") - .hit(0) - .build(); - Shop newShop = shopRepository.save(shopRequest); - - ShopOpen open1 = ShopOpen.builder() - .openTime(LocalTime.of(0, 0)) - .closeTime(LocalTime.of(21, 0)) - .shop(shop) - .closed(false) - .dayOfWeek("MONDAY") - .build(); - - ShopOpen open2 = ShopOpen.builder() - .openTime(LocalTime.of(0, 0)) - .closeTime(LocalTime.of(0, 0)) - .shop(newShop) - .closed(false) - .dayOfWeek("FRIDAY") - .build(); - - shopOpenRepository.save(open1); - shopOpenRepository.save(open2); - - ShopCategoryMap shopCategoryMap1 = ShopCategoryMap.builder() - .shop(shop) - .shopCategory(shopCategory1) - .build(); - - ShopCategoryMap shopCategoryMap2 = ShopCategoryMap.builder() - .shop(newShop) - .shopCategory(shopCategory2) - .build(); - - shopCategoryMapRepository.save(shopCategoryMap1); - shopCategoryMapRepository.save(shopCategoryMap2); - - ShopImage shopImage1 = ShopImage.builder() - .imageUrl("https://test.com/test1.jpg") - .shop(shop) - .build(); - - ShopImage shopImage2 = ShopImage.builder() - .imageUrl("https://test.com/test2.jpg") - .shop(newShop) - .build(); - - shopImageRepository.save(shopImage1); - shopImageRepository.save(shopImage2); - - EventArticle eventArticle1 = createEventArticle( - newShop, - "테스트 이벤트 1", - "

테스트 이벤트 내용1

", - LocalDate.now().minusDays(3), - LocalDate.now().plusDays(3), - List.of("https://test.com/test-thumbnail-1.jpg") + eventArticleFixture.할인_이벤트( + shop, + LocalDate.now(clock).minusDays(3), + LocalDate.now(clock).plusDays(3) ); - - EventArticle eventArticle2 = createEventArticle( - newShop, - "테스트 이벤트 2", - "

테스트 이벤트 내용2

", - LocalDate.now().minusDays(3), - LocalDate.now().plusDays(3), - List.of("https://test.com/test-thumbnail-2.jpg") + eventArticleFixture.참여_이벤트( + shop, + LocalDate.now(clock).minusDays(3), + LocalDate.now(clock).plusDays(3) ); - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() - .get("/shops/{shopId}/events", newShop.getId()) + .get("/shops/{shopId}/events", shop.getId()) .then() .statusCode(HttpStatus.OK.value()) .extract(); - JsonAssertions.assertThat(String.format(""" + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" { - "events": [ - { - "shop_id": %s, - "shop_name": "%s", - "event_id": %s, - "title": "테스트 이벤트 1", - "content": "

테스트 이벤트 내용1

", + "events": [ + { + "shop_id": 1, + "shop_name": "마슬랜 치킨", + "event_id": 1, + "title": "할인 이벤트", + "content": "사장님이 미쳤어요!", "thumbnail_images": [ - "https://test.com/test-thumbnail-1.jpg" + "https://eventimage.com/할인_이벤트.jpg", + "https://eventimage.com/할인_이벤트.jpg" ], - "start_date": "%s", - "end_date": "%s" - }, - { - "shop_id": %s, - "shop_name": "%s", - "event_id": %s, - "title": "테스트 이벤트 2", - "content": "

테스트 이벤트 내용2

", + "start_date": "2024-01-12", + "end_date": "2024-01-18" + }, + { + "shop_id": 1, + "shop_name": "마슬랜 치킨", + "event_id": 2, + "title": "참여 이벤트", + "content": "사장님과 참여해요!!!", "thumbnail_images": [ - "https://test.com/test-thumbnail-2.jpg" + "https://eventimage.com/참여_이벤트.jpg", + "https://eventimage.com/참여_이벤트.jpg" ], - "start_date": "%s", - "end_date": "%s" - } - ] - }""", - newShop.getId(), - newShop.getName(), - eventArticle1.getId(), - LocalDate.now().minusDays(3), - LocalDate.now().plusDays(3), - newShop.getId(), - newShop.getName(), - eventArticle2.getId(), - LocalDate.now().minusDays(3), - LocalDate.now().plusDays(3))).isEqualTo(response.asPrettyString()); + "start_date": "2024-01-12", + "end_date": "2024-01-18" + } + ] + } + """); } @Test @DisplayName("이벤트 진행중인 상점의 정보를 조회한다.") void getShopWithEvents() { - when(clock.instant()).thenReturn(Instant.now()); - when(clock.getZone()).thenReturn(Clock.systemDefaultZone().getZone()); - - var now = LocalDate.of(2024, 2, 21); - var user = owner.getUser(); - Shop shopRequest = Shop.builder() - .owner(owner) - .name("테스트 상점2") - .internalName("테스트2") - .chosung("테스트") - .phone("010-1234-5678") - .address("대전광역시 유성구 대학로 291") - .description("테스트 상점입니다.") - .delivery(true) - .deliveryPrice(3000) - .payCard(true) - .payBank(true) - .isDeleted(false) - .isEvent(false) - .remarks("비고") - .hit(0) - .build(); - Shop newShop = shopRepository.save(shopRequest); - - ShopOpen open1 = ShopOpen.builder() - .openTime(LocalTime.of(0, 0)) - .closeTime(LocalTime.of(21, 0)) - .shop(newShop) - .closed(false) - .dayOfWeek("MONDAY") - .build(); - - ShopOpen open2 = ShopOpen.builder() - .openTime(LocalTime.of(0, 0)) - .closeTime(LocalTime.of(0, 0)) - .shop(newShop) - .closed(false) - .dayOfWeek("FRIDAY") - .build(); - - shopOpenRepository.save(open1); - shopOpenRepository.save(open2); - - ShopCategoryMap shopCategoryMap1 = ShopCategoryMap.builder() - .shop(newShop) - .shopCategory(shopCategory1) - .build(); - - ShopCategoryMap shopCategoryMap2 = ShopCategoryMap.builder() - .shop(newShop) - .shopCategory(shopCategory2) - .build(); - - shopCategoryMapRepository.save(shopCategoryMap1); - shopCategoryMapRepository.save(shopCategoryMap2); - - ShopImage shopImage1 = ShopImage.builder() - .imageUrl("https://test.com/test1.jpg") - .shop(newShop) - .build(); - - ShopImage shopImage2 = ShopImage.builder() - .imageUrl("https://test.com/test2.jpg") - .shop(newShop) - .build(); - - shopImageRepository.save(shopImage1); - shopImageRepository.save(shopImage2); - - EventArticle eventArticle1 = createEventArticle( - newShop, - "테스트 이벤트 1", - "

테스트 이벤트 내용1

", - LocalDate.now().minusDays(3), - LocalDate.now().plusDays(3), - List.of("https://test.com/test-thumbnail-1.jpg") + eventArticleFixture.할인_이벤트( + shop, + LocalDate.now(clock).minusDays(3), + LocalDate.now(clock).plusDays(3) ); - - EventArticle eventArticle2 = createEventArticle( - newShop, - "테스트 이벤트 2", - "

테스트 이벤트 내용2

", - LocalDate.now().minusDays(3), - LocalDate.now().plusDays(3), - List.of("https://test.com/test-thumbnail-2.jpg") + eventArticleFixture.참여_이벤트( + shop, + LocalDate.now(clock).minusDays(3), + LocalDate.now(clock).plusDays(3) ); - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() - .get("/shops/{shopId}", newShop.getId()) + .get("/shops/{shopId}", shop.getId()) .then() .statusCode(HttpStatus.OK.value()) .extract(); @@ -1076,92 +539,23 @@ void getShopWithEvents() { @Test @DisplayName("이벤트 진행중이지 않은 상점의 정보를 조회한다.") void getShopWithoutEvents() { - when(clock.instant()).thenReturn( - ZonedDateTime.parse("2024-02-21 18:00:00 KST", ofPattern("yyyy-MM-dd HH:mm:ss z")).toInstant()); - when(clock.getZone()).thenReturn(Clock.systemDefaultZone().getZone()); - - var now = LocalDate.of(2024, 2, 21); - var user = owner.getUser(); - Shop shopRequest = Shop.builder() - .owner(owner) - .name("테스트 상점2") - .internalName("테스트2") - .chosung("테스트") - .phone("010-1234-5678") - .address("대전광역시 유성구 대학로 291") - .description("테스트 상점입니다.") - .delivery(true) - .deliveryPrice(3000) - .payCard(true) - .payBank(true) - .isDeleted(false) - .isEvent(false) - .remarks("비고") - .hit(0) - .build(); - Shop newShop = shopRepository.save(shopRequest); - - ShopOpen open1 = ShopOpen.builder() - .openTime(LocalTime.of(0, 0)) - .closeTime(LocalTime.of(21, 0)) - .shop(shop) - .closed(false) - .dayOfWeek("MONDAY") - .build(); - - ShopOpen open2 = ShopOpen.builder() - .openTime(LocalTime.of(0, 0)) - .closeTime(LocalTime.of(0, 0)) - .shop(newShop) - .closed(false) - .dayOfWeek("FRIDAY") - .build(); - - shopOpenRepository.save(open1); - shopOpenRepository.save(open2); - - ShopCategoryMap shopCategoryMap1 = ShopCategoryMap.builder() - .shop(shop) - .shopCategory(shopCategory1) - .build(); - - ShopCategoryMap shopCategoryMap2 = ShopCategoryMap.builder() - .shop(newShop) - .shopCategory(shopCategory2) - .build(); - - shopCategoryMapRepository.save(shopCategoryMap1); - shopCategoryMapRepository.save(shopCategoryMap2); - - ShopImage shopImage1 = ShopImage.builder() - .imageUrl("https://test.com/test1.jpg") - .shop(shop) - .build(); - - ShopImage shopImage2 = ShopImage.builder() - .imageUrl("https://test.com/test2.jpg") - .shop(newShop) - .build(); - - shopImageRepository.save(shopImage1); - shopImageRepository.save(shopImage2); - - List thumbnailImages = List.of("https://test.com/test-thumbnail-1.jpg"); - - EventArticle eventArticle1 = createEventArticle( - newShop, - "테스트 이벤트 1", - "

테스트 이벤트 내용1

", - LocalDate.now().minusDays(5), - LocalDate.now().minusDays(1), - List.of("https://test.com/test-thumbnail-1.jpg") + eventArticleFixture.할인_이벤트( + shop, + LocalDate.now(clock).plusDays(3), + LocalDate.now(clock).plusDays(5) + ); + eventArticleFixture.참여_이벤트( + shop, + LocalDate.now(clock).minusDays(5), + LocalDate.now(clock).minusDays(3) ); - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() - .get("/shops/{shopId}", newShop.getId()) + .get("/shops/{shopId}", shop.getId()) .then() + .statusCode(HttpStatus.OK.value()) .extract(); @@ -1171,33 +565,17 @@ void getShopWithoutEvents() { @Test @DisplayName("이벤트 베너 조회") void ownerShopDeleteEvent() { - when(clock.instant()).thenReturn(Instant.now()); - when(clock.getZone()).thenReturn(Clock.systemDefaultZone().getZone()); - EventArticle savedEvent1 = createEventArticle( - shop, - "테스트 제목1", - "테스트 내용1", - LocalDate.now(), - LocalDate.now().plusDays(10), - List.of("https://test.com/test1.jpg") - ); - EventArticle savedEvent2 = createEventArticle( + eventArticleFixture.참여_이벤트( shop, - "테스트 제목1", - "테스트 내용1", - LocalDate.now().minusDays(10), - LocalDate.now().minusDays(1), - List.of("https://test.com/test1.jpg") + LocalDate.now(clock), + LocalDate.now(clock).plusDays(10) ); - EventArticle savedEvent3 = createEventArticle( + eventArticleFixture.할인_이벤트( shop, - "테스트 제목3", - "테스트 내용3", - LocalDate.now().minusDays(10), - LocalDate.now().plusDays(10), - List.of("https://test.com/test1.jpg") + LocalDate.now(clock).minusDays(10), + LocalDate.now(clock).minusDays(1) ); - ExtractableResponse response = RestAssured + var response = RestAssured .given() .contentType(ContentType.JSON) .when() @@ -1207,72 +585,24 @@ void ownerShopDeleteEvent() { .extract(); JsonAssertions.assertThat(response.asPrettyString()) - .isEqualTo(String.format(""" - { - "events": [ - { - "shop_id": %s, - "shop_name": "%s", - "event_id": %s, - "title": "테스트 제목1", - "content": "테스트 내용1", - "thumbnail_images": [ - "https://test.com/test1.jpg" - ], - "start_date": %s, - "end_date": %s - }, - { - "shop_id": %s, - "shop_name": "%s", - "event_id": %s, - "title": "테스트 제목3", - "content": "테스트 내용3", - "thumbnail_images": [ - "https://test.com/test1.jpg" - ], - "start_date": %s, - "end_date": %s - } - ] - }""", - shop.getId(), - shop.getName(), - savedEvent1.getId(), - response.jsonPath().getString("events[0].start_date"), - response.jsonPath().getString("events[0].end_date"), - shop.getId(), - shop.getName(), - savedEvent3.getId(), - response.jsonPath().getString("events[1].start_date"), - response.jsonPath().getString("events[1].end_date"))); - } - - private EventArticle createEventArticle( - Shop shop, - String title, - String content, - LocalDate startDate, - LocalDate endDate, - List thumbnailImages - ) { - EventArticle eventArticle = EventArticle.builder() - .shop(shop) - .title(title) - .content(content) - .ip("") - .startDate(startDate) - .endDate(endDate) - .hit(0) - .build(); - EventArticle savedEvent = eventArticleRepository.save(eventArticle); - for (String image : thumbnailImages) { - EventArticleImage eventArticleImage = EventArticleImage.builder() - .eventArticle(eventArticle) - .thumbnailImage(image) - .build(); - eventArticleImageRepository.save(eventArticleImage); - } - return eventArticleRepository.getById(savedEvent.getId()); + .isEqualTo(""" + { + "events": [ + { + "shop_id": 1, + "shop_name": "마슬랜 치킨", + "event_id": 1, + "title": "참여 이벤트", + "content": "사장님과 참여해요!!!", + "thumbnail_images": [ + "https://eventimage.com/참여_이벤트.jpg", + "https://eventimage.com/참여_이벤트.jpg" + ], + "start_date": "2024-01-15", + "end_date": "2024-01-25" + } + ] + } + """); } } diff --git a/src/test/java/in/koreatech/koin/acceptance/TimetableApiTest.java b/src/test/java/in/koreatech/koin/acceptance/TimetableApiTest.java index dbb5fedff..29540c248 100644 --- a/src/test/java/in/koreatech/koin/acceptance/TimetableApiTest.java +++ b/src/test/java/in/koreatech/koin/acceptance/TimetableApiTest.java @@ -1,236 +1,165 @@ package in.koreatech.koin.acceptance; -import static in.koreatech.koin.domain.user.model.UserType.STUDENT; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.SoftAssertions.assertSoftly; -import java.util.List; - -import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import in.koreatech.koin.AcceptanceTest; -import in.koreatech.koin.domain.timetable.model.Lecture; import in.koreatech.koin.domain.timetable.model.Semester; import in.koreatech.koin.domain.timetable.model.TimeTable; -import in.koreatech.koin.domain.timetable.repository.LectureRepository; -import in.koreatech.koin.domain.timetable.repository.SemesterRepository; import in.koreatech.koin.domain.timetable.repository.TimeTableRepository; import in.koreatech.koin.domain.user.model.User; -import in.koreatech.koin.domain.user.model.UserGender; -import in.koreatech.koin.domain.user.repository.UserRepository; -import in.koreatech.koin.global.auth.JwtProvider; +import in.koreatech.koin.fixture.LectureFixture; +import in.koreatech.koin.fixture.SemesterFixture; +import in.koreatech.koin.fixture.TimeTableFixture; +import in.koreatech.koin.fixture.UserFixture; +import in.koreatech.koin.support.JsonAssertions; import io.restassured.RestAssured; import io.restassured.http.ContentType; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; +@SuppressWarnings("NonAsciiCharacters") class TimetableApiTest extends AcceptanceTest { @Autowired - private LectureRepository lectureRepository; + private TimeTableRepository timeTableRepository; @Autowired - private SemesterRepository semesterRepository; + private UserFixture userFixture; @Autowired - private TimeTableRepository timeTableRepository; + private LectureFixture lectureFixture; @Autowired - private UserRepository userRepository; + private SemesterFixture semesterFixture; @Autowired - private JwtProvider jwtProvider; + private TimeTableFixture timeTableFixture; @Test @DisplayName("특정 학기 강의를 조회한다") void getSemesterLecture() { - Lecture lecture1 = Lecture.builder() - .code("ARB244") - .semester("20192") - .name("건축구조의 이해 및 실습") - .grades("3") - .lectureClass("01") - .regularNumber("25") - .department("디자인ㆍ건축공학부") - .target("디자 1 건축") - .professor("이돈우") - .isEnglish("N") - .designScore("0") - .isElearning("N") - .classTime("[200, 201, 202, 203, 204, 205, 206, 207]") - .build(); - - Lecture lecture2 = Lecture.builder() - .code("ARB244") - .semester("20201") - .name("건축구조의 이해 및 실습") - .grades("3") - .lectureClass("02") - .regularNumber("30") - .department("컴퓨터공학부") - .target("컴퓨터") - .professor("허준기") - .isEnglish("N") - .designScore("0") - .isElearning("N") - .classTime("[200,201,202,203,204,205,206,207]") - .build(); - - lectureRepository.save(lecture1); - lectureRepository.save(lecture2); - - ExtractableResponse response = RestAssured + String semester = "20201"; + lectureFixture.HRD_개론(semester); + lectureFixture.건축구조의_이해_및_실습("20192"); + + var response = RestAssured .given() .when() - .param("semester_date", lecture1.getSemester()) + .param("semester_date", semester) .get("/lectures") .then() .statusCode(HttpStatus.OK.value()) .extract(); - List classTime = List.of(200L, 201L, 202L, 203L, 204L, 205L, 206L, 207L); - - assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getString("[0].code")).isEqualTo(lecture1.getCode()); - softly.assertThat(response.body().jsonPath().getString("[0].name")).isEqualTo(lecture1.getName()); - softly.assertThat(response.body().jsonPath().getString("[0].grades")).isEqualTo(lecture1.getGrades()); - softly.assertThat(response.body().jsonPath().getString("[0].lecture_class")) - .isEqualTo(lecture1.getLectureClass()); - softly.assertThat(response.body().jsonPath().getString("[0].regular_number")) - .isEqualTo(lecture1.getRegularNumber()); - softly.assertThat(response.body().jsonPath().getString("[0].department")) - .isEqualTo(lecture1.getDepartment()); - softly.assertThat(response.body().jsonPath().getString("[0].target")).isEqualTo(lecture1.getTarget()); - softly.assertThat(response.body().jsonPath().getString("[0].professor")) - .isEqualTo(lecture1.getProfessor()); - softly.assertThat(response.body().jsonPath().getString("[0].is_english")) - .isEqualTo(lecture1.getIsEnglish()); - softly.assertThat(response.body().jsonPath().getString("[0].design_score")) - .isEqualTo(lecture1.getDesignScore()); - softly.assertThat(response.body().jsonPath().getString("[0].is_elearning")) - .isEqualTo(lecture1.getIsElearning()); - softly.assertThat(response.body().jsonPath().getList("[0].class_time", Long.class)) - .containsExactlyInAnyOrderElementsOf(classTime); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + [ + { + "code": "BSM590", + "name": "컴퓨팅사고", + "grades": "3", + "lecture_class": "06", + "regular_number": "22", + "department": "기계공학부", + "target": "기공1", + "professor": "박한수,최준호", + "is_english": "", + "design_score": "0", + "is_elearning": "", + "class_time": [ + 12, 13, 14, 15, 210, 211, 212, 213 + ] + } + ] + """); } @Test @DisplayName("특정 학기 강의들을 조회한다") void getSemesterLectures() { - Lecture lecture1 = Lecture.builder() - .code("ARB244") - .semester("20192") - .name("건축구조의 이해 및 실습") - .grades("3") - .lectureClass("01") - .regularNumber("25") - .department("디자인ㆍ건축공학부") - .target("디자 1 건축") - .professor("이돈우") - .isEnglish("N") - .designScore("0") - .isElearning("N") - .classTime("[200, 201, 202, 203, 204, 205, 206, 207]") - .build(); - - Lecture lecture2 = Lecture.builder() - .code("ARB244") - .semester("20192") - .name("건축구조의 이해 및 실습") - .grades("3") - .lectureClass("02") - .regularNumber("30") - .department("컴퓨터공학부") - .target("컴퓨터") - .professor("허준기") - .isEnglish("N") - .designScore("0") - .isElearning("N") - .classTime("[200,201,202,203,204,205,206,207]") - .build(); - - Lecture lecture3 = Lecture.builder() - .code("ARB244") - .semester("20201") - .name("건축구조의 이해 및 실습") - .grades("3") - .lectureClass("02") - .regularNumber("30") - .department("컴퓨터공학부") - .target("컴퓨터") - .professor("허준기") - .isEnglish("N") - .designScore("0") - .isElearning("N") - .classTime("[200, 201, 202, 203, 204, 205, 206, 207]") - .build(); - - lectureRepository.save(lecture1); - lectureRepository.save(lecture2); - lectureRepository.save(lecture3); - - ExtractableResponse response = RestAssured + String semester = "20201"; + lectureFixture.HRD_개론(semester); + lectureFixture.건축구조의_이해_및_실습(semester); + lectureFixture.재료역학(semester); + + var response = RestAssured .given() .when() - .param("semester_date", lecture1.getSemester()) + .param("semester_date", semester) .get("/lectures") .then() .statusCode(HttpStatus.OK.value()) .extract(); - assertSoftly( - softly -> softly.assertThat(response.body().jsonPath().getList(".").size()).isEqualTo(2) - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + [ + { + "code": "BSM590", + "name": "컴퓨팅사고", + "grades": "3", + "lecture_class": "06", + "regular_number": "22", + "department": "기계공학부", + "target": "기공1", + "professor": "박한수,최준호", + "is_english": "", + "design_score": "0", + "is_elearning": "", + "class_time": [ + 12, 13, 14, 15, 210, 211, 212, 213 + ] + }, + { + "code": "ARB244", + "name": "건축구조의 이해 및 실습", + "grades": "3", + "lecture_class": "01", + "regular_number": "25", + "department": "디자인ㆍ건축공학부", + "target": "디자 1 건축", + "professor": "황현식", + "is_english": "N", + "design_score": "0", + "is_elearning": "N", + "class_time": [ + 200, 201, 202, 203, 204, 205, 206, 207 + ] + }, + { + "code": "MEB311", + "name": "재료역학", + "grades": "3", + "lecture_class": "01", + "regular_number": "35", + "department": "기계공학부", + "target": "기공전체", + "professor": "허준기", + "is_english": "", + "design_score": "0", + "is_elearning": "", + "class_time": [ + 100, 101, 102, 103, 308, 309 + ] + } + ] + """); } @Test @DisplayName("존재하지 않는 학기를 조회하면 404") void isNotSemester() { - Lecture lecture1 = Lecture.builder() - .code("ARB244") - .semester("20192") - .name("건축구조의 이해 및 실습") - .grades("3") - .lectureClass("01") - .regularNumber("25") - .department("디자인ㆍ건축공학부") - .target("디자 1 건축") - .professor("이돈우") - .isEnglish("N") - .designScore("0") - .isElearning("N") - .classTime("[200, 201, 202, 203, 204, 205, 206, 207]") - .build(); - - Lecture lecture2 = Lecture.builder() - .code("ARB244") - .semester("20201") - .name("건축구조의 이해 및 실습") - .grades("3") - .lectureClass("02") - .regularNumber("30") - .department("컴퓨터공학부") - .target("컴퓨터") - .professor("허준기") - .isEnglish("N") - .designScore("0") - .isElearning("N") - .classTime("[200,201,202,203,204,205,206,207]") - .build(); - - lectureRepository.save(lecture1); - lectureRepository.save(lecture2); - - ExtractableResponse response = RestAssured + String semester = "20201"; + lectureFixture.HRD_개론(semester); + lectureFixture.건축구조의_이해_및_실습(semester); + + RestAssured .given() .when() - .param("semester_date", 20193) + .param("semester_date", "20193") .get("/lectures") .then() .statusCode(HttpStatus.NOT_FOUND.value()) @@ -240,16 +169,12 @@ void isNotSemester() { @Test @DisplayName("모든 학기를 조회한다.") void findAllSemesters() { - Semester request1 = Semester.builder().semester("20221").build(); - Semester request2 = Semester.builder().semester("20222").build(); - Semester request3 = Semester.builder().semester("20231").build(); - Semester request4 = Semester.builder().semester("20232").build(); - semesterRepository.save(request1); - semesterRepository.save(request2); - semesterRepository.save(request3); - semesterRepository.save(request4); - - ExtractableResponse response = RestAssured + semesterFixture.semester("20221"); + semesterFixture.semester("20222"); + semesterFixture.semester("20231"); + semesterFixture.semester("20232"); + + var response = RestAssured .given() .when() .get("/semesters") @@ -257,209 +182,126 @@ void findAllSemesters() { .statusCode(HttpStatus.OK.value()) .extract(); - assertThat(response.body().jsonPath().getList(".")).hasSize(4); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + [ + { + "id": 4, + "semester": "20232" + }, + { + "id": 3, + "semester": "20231" + }, + { + "id": 2, + "semester": "20222" + }, + { + "id": 1, + "semester": "20221" + } + ] + """); } @Test @DisplayName("시간표를 조회한다.") void getTimeTables() { - User userT = User.builder() - .password("1234") - .nickname("주노") - .name("최준호") - .phoneNumber("010-1234-5678") - .userType(STUDENT) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build(); - - User user = userRepository.save(userT); - String token = jwtProvider.createToken(user); - - Semester semester20192 = Semester.builder(). - semester("20192") - .build(); - Semester semester20201 = Semester.builder(). - semester("20201") - .build(); - - Semester semester = semesterRepository.save(semester20192); - semesterRepository.save(semester20201); - - TimeTable timeTable1 = TimeTable.builder() - .user(user) - .semester(semester) - .code("CS101") - .classTitle("컴퓨터 구조") - .classTime("[14, 15, 16, 17, 204, 205, 206, 207]") - .classPlace(null) - .professor("김철수") - .grades("3") - .lectureClass("02") - .target("컴부전체") - .regularNumber("28") - .designScore("0") - .department("컴퓨터공학부") - .memo(null) - .isDeleted(false) - .build(); - - TimeTable timeTable2 = TimeTable.builder() - .user(user) - .semester(semester) - .code("CS102") - .classTitle("운영체제") - .classTime("[932]") - .classPlace(null) - .professor("홍길동") - .grades("3") - .lectureClass("01") - .target("컴부전체") - .regularNumber("40") - .designScore("0") - .department("컴퓨터공학부") - .memo(null) - .isDeleted(false) - .build(); - - TimeTable timeTable3 = TimeTable.builder() - .user(user) - .semester(semester) - .code("CS102") - .classTitle("운영체제") - .classTime("[]") - .classPlace(null) - .professor("홍길동") - .grades("3") - .lectureClass("01") - .target("컴부전체") - .regularNumber("40") - .designScore("0") - .department("컴퓨터공학부") - .memo(null) - .isDeleted(false) - .build(); - - timeTableRepository.save(timeTable1); - timeTableRepository.save(timeTable2); - timeTableRepository.save(timeTable3); - - ExtractableResponse response = RestAssured - .given() - .header("Authorization", "Bearer " + token) - .when() - .param("semester", "20192") - .get("/timetables") - .then() - .statusCode(HttpStatus.OK.value()) - .extract(); - - assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getString("semester")). - isEqualTo("20192"); - softly.assertThat(response.body().jsonPath().getList("timetable")) - .hasSize(3); - softly.assertThat(response.body().jsonPath().getInt("grades")). - isEqualTo(Integer.parseInt(timeTable1.getGrades()) - +Integer.parseInt(timeTable2.getGrades()) - +Integer.parseInt(timeTable3.getGrades())); - softly.assertThat(response.body().jsonPath().getInt("total_grades")). - isEqualTo(Integer.parseInt(timeTable1.getGrades()) - +Integer.parseInt(timeTable2.getGrades()) - +Integer.parseInt(timeTable3.getGrades())); - - softly.assertThat(response.body().jsonPath().getInt("timetable[0].id")).isEqualTo(1); - softly.assertThat(response.body().jsonPath().getString("timetable[0].regular_number")).isEqualTo("28"); - softly.assertThat(response.body().jsonPath().getString("timetable[0].code")).isEqualTo("CS101"); - softly.assertThat(response.body().jsonPath().getString("timetable[0].design_score")).isEqualTo("0"); - softly.assertThat(response.body().jsonPath().getList("timetable[0].class_time")) - .containsAll(List.of(14, 15, 16, 17, 204, 205, 206, 207)); - softly.assertThat(response.body().jsonPath().getString("timetable[0].class_place")).isEqualTo(null); - softly.assertThat(response.body().jsonPath().getString("timetable[0].memo")).isEqualTo(null); - softly.assertThat(response.body().jsonPath().getString("timetable[0].grades")).isEqualTo("3"); - softly.assertThat(response.body().jsonPath().getString("timetable[0].class_title")).isEqualTo("컴퓨터 구조"); - softly.assertThat(response.body().jsonPath().getString("timetable[0].lecture_class")).isEqualTo("02"); - softly.assertThat(response.body().jsonPath().getString("timetable[0].target")).isEqualTo("컴부전체"); - softly.assertThat(response.body().jsonPath().getString("timetable[0].professor")).isEqualTo("김철수"); - softly.assertThat(response.body().jsonPath().getString("timetable[0].department")).isEqualTo("컴퓨터공학부"); - - softly.assertThat(response.body().jsonPath().getInt("timetable[1].id")).isEqualTo(2); - softly.assertThat(response.body().jsonPath().getString("timetable[1].regular_number")).isEqualTo("40"); - softly.assertThat(response.body().jsonPath().getString("timetable[1].code")).isEqualTo("CS102"); - softly.assertThat(response.body().jsonPath().getString("timetable[1].design_score")).isEqualTo("0"); - softly.assertThat(response.body().jsonPath().getList("timetable[1].class_time")) - .containsAll(List.of(932)); - softly.assertThat(response.body().jsonPath().getString("timetable[1].class_place")).isEqualTo(null); - softly.assertThat(response.body().jsonPath().getString("timetable[1].memo")).isEqualTo(null); - softly.assertThat(response.body().jsonPath().getString("timetable[1].grades")).isEqualTo("3"); - softly.assertThat(response.body().jsonPath().getString("timetable[1].class_title")).isEqualTo("운영체제"); - softly.assertThat(response.body().jsonPath().getString("timetable[1].lecture_class")).isEqualTo("01"); - softly.assertThat(response.body().jsonPath().getString("timetable[1].target")).isEqualTo("컴부전체"); - softly.assertThat(response.body().jsonPath().getString("timetable[1].professor")).isEqualTo("홍길동"); - softly.assertThat(response.body().jsonPath().getString("timetable[1].department")).isEqualTo("컴퓨터공학부"); - - softly.assertThat(response.body().jsonPath().getInt("timetable[2].id")).isEqualTo(3); - softly.assertThat(response.body().jsonPath().getString("timetable[2].regular_number")).isEqualTo("40"); - softly.assertThat(response.body().jsonPath().getString("timetable[2].code")).isEqualTo("CS102"); - softly.assertThat(response.body().jsonPath().getString("timetable[2].design_score")).isEqualTo("0"); - softly.assertThat(response.body().jsonPath().getList("timetable[2].class_time")).isEmpty(); - softly.assertThat(response.body().jsonPath().getString("timetable[2].class_place")).isEqualTo(null); - softly.assertThat(response.body().jsonPath().getString("timetable[2].memo")).isEqualTo(null); - softly.assertThat(response.body().jsonPath().getString("timetable[2].grades")).isEqualTo("3"); - softly.assertThat(response.body().jsonPath().getString("timetable[2].class_title")).isEqualTo("운영체제"); - softly.assertThat(response.body().jsonPath().getString("timetable[2].lecture_class")).isEqualTo("01"); - softly.assertThat(response.body().jsonPath().getString("timetable[2].target")).isEqualTo("컴부전체"); - softly.assertThat(response.body().jsonPath().getString("timetable[2].professor")).isEqualTo("홍길동"); - softly.assertThat(response.body().jsonPath().getString("timetable[2].department")).isEqualTo("컴퓨터공학부"); - } - ); - - ExtractableResponse responseA = RestAssured + // given + User user = userFixture.준호_학생().getUser(); + String token = userFixture.getToken(user); + Semester semester = semesterFixture.semester("20192"); + TimeTable 이산수학 = timeTableFixture.이산수학(user, semester); + TimeTable 알고리즘및실습 = timeTableFixture.알고리즘및실습(user, semester); + TimeTable 컴퓨터구조 = timeTableFixture.컴퓨터구조(user, semester); + + // when & then + var response = RestAssured .given() .header("Authorization", "Bearer " + token) .when() - .param("semester", "20201") + .param("semester", semester.getSemester()) .get("/timetables") .then() .statusCode(HttpStatus.OK.value()) .extract(); - Assertions.assertThat(responseA.body().jsonPath().getInt("grades")).isEqualTo(0); - Assertions.assertThat(responseA.body().jsonPath().getInt("total_grades")).isEqualTo( - Integer.parseInt(timeTable1.getGrades()) - +Integer.parseInt(timeTable2.getGrades()) - +Integer.parseInt(timeTable3.getGrades()) - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(String.format(""" + { + "semester": "20192", + "timetable": [ + { + "id": %d, + "regular_number": "40", + "code": "CSE125", + "design_score": "0", + "class_time": [ + 14, 15, 16, 17, 312, 313 + ], + "class_place": null, + "memo": null, + "grades": "3", + "class_title": "이산수학", + "lecture_class": "01", + "target": "컴부전체", + "professor": "서정빈", + "department": "컴퓨터공학부" + }, + { + "id": %d, + "regular_number": "32", + "code": "CSE130", + "design_score": "0", + "class_time": [ + 14, 15, 16, 17, 310, 311, 312, 313 + ], + "class_place": null, + "memo": null, + "grades": "3", + "class_title": "알고리즘및실습", + "lecture_class": "03", + "target": "컴부전체", + "professor": "박다희", + "department": "컴퓨터공학부" + }, + { + "id": %d, + "regular_number": "28", + "code": "CS101", + "design_score": "0", + "class_time": [ + 14, 15, 16, 17, 204, 205, 206, 207 + ], + "class_place": null, + "memo": null, + "grades": "3", + "class_title": "컴퓨터 구조", + "lecture_class": "02", + "target": "컴부전체", + "professor": "김성재", + "department": "컴퓨터공학부" + } + ], + "grades": 9, + "total_grades": 9 + } + """, 이산수학.getId(), 알고리즘및실습.getId(), 컴퓨터구조.getId() + )); } @Test @DisplayName("조회된 시간표가 없으면 404에러를 반환한다.") void getTimeTablesNotFound() { - User userT = User.builder() - .password("1234") - .nickname("주노") - .name("최준호") - .phoneNumber("010-1234-5678") - .userType(STUDENT) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build(); - - User user = userRepository.save(userT); - String token = jwtProvider.createToken(user); - - Semester semester = Semester.builder(). - semester("20192") - .build(); - - semesterRepository.save(semester); - - ExtractableResponse response = RestAssured + User user = userFixture.준호_학생().getUser(); + String token = userFixture.getToken(user); + Semester semester = semesterFixture.semester("20192"); + timeTableFixture.이산수학(user, semester); + timeTableFixture.알고리즘및실습(user, semester); + timeTableFixture.컴퓨터구조(user, semester); + + RestAssured .given() .header("Authorization", "Bearer " + token) .when() @@ -468,38 +310,20 @@ void getTimeTablesNotFound() { .then() .statusCode(HttpStatus.NOT_FOUND.value()) .extract(); - } @Test @DisplayName("시간표를 생성한다.") void createTimeTables() { - User userT = User.builder() - .password("1234") - .nickname("주노") - .name("최준호") - .phoneNumber("010-1234-5678") - .userType(STUDENT) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build(); - - User user = userRepository.save(userT); - String token = jwtProvider.createToken(user); - - Semester semester = Semester.builder(). - semester("20192") - .build(); - - semesterRepository.save(semester); - - ExtractableResponse response = RestAssured + User user = userFixture.준호_학생().getUser(); + String token = userFixture.getToken(user); + Semester semester = semesterFixture.semester("20192"); + + var response = RestAssured .given() .header("Authorization", "Bearer " + token) .contentType(ContentType.JSON) - .body(""" + .body(String.format(""" { "timetable": [ { @@ -535,107 +359,74 @@ void createTimeTables() { "memo": null } ], - "semester": "20192" + "semester": "%s" } - """) + """, semester.getSemester() + )) .when() .post("/timetables") .then() .statusCode(HttpStatus.OK.value()) .extract(); - assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getString("semester")). - isEqualTo("20192"); - softly.assertThat(response.body().jsonPath().getList("timetable")) - .hasSize(2); - softly.assertThat(response.body().jsonPath().getInt("timetable[0].id")) - .isEqualTo(1); - softly.assertThat(response.body().jsonPath().getString("timetable[0].regular_number")) - .isEqualTo("25"); - softly.assertThat(response.body().jsonPath().getString("timetable[0].code")) - .isEqualTo("CPC490"); - softly.assertThat(response.body().jsonPath().getString("timetable[0].design_score")) - .isEqualTo("0"); - softly.assertThat(response.body().jsonPath().getList("timetable[0].class_time")) - .containsAll(List.of(210, 211)); - softly.assertThat(response.body().jsonPath().getString("timetable[0].class_place")) - .isEqualTo(null); - softly.assertThat(response.body().jsonPath().getString("timetable[0].memo")) - .isEqualTo(null); - softly.assertThat(response.body().jsonPath().getString("timetable[0].grades")) - .isEqualTo("3"); - softly.assertThat(response.body().jsonPath().getString("timetable[0].class_title")) - .isEqualTo("운영체제"); - softly.assertThat(response.body().jsonPath().getString("timetable[0].lecture_class")) - .isEqualTo("01"); - softly.assertThat(response.body().jsonPath().getString("timetable[0].target")) - .isEqualTo("디자 1 건축"); - softly.assertThat(response.body().jsonPath().getString("timetable[0].professor")) - .isEqualTo("이돈우"); - softly.assertThat(response.body().jsonPath().getString("timetable[0].department")) - .isEqualTo("디자인ㆍ건축공학부"); - - softly.assertThat(response.body().jsonPath().getInt("timetable[1].id")) - .isEqualTo(2); - softly.assertThat(response.body().jsonPath().getString("timetable[1].regular_number")) - .isEqualTo("38"); - softly.assertThat(response.body().jsonPath().getString("timetable[1].code")) - .isEqualTo("CSE201"); - softly.assertThat(response.body().jsonPath().getString("timetable[1].design_score")) - .isEqualTo("0"); - softly.assertThat(response.body().jsonPath().getList("timetable[1].class_time")) - .isEmpty(); - softly.assertThat(response.body().jsonPath().getString("timetable[1].class_place")) - .isEqualTo(null); - softly.assertThat(response.body().jsonPath().getString("timetable[1].memo")) - .isEqualTo(null); - softly.assertThat(response.body().jsonPath().getString("timetable[1].grades")) - .isEqualTo("1"); - softly.assertThat(response.body().jsonPath().getString("timetable[1].class_title")) - .isEqualTo("컴퓨터구조"); - softly.assertThat(response.body().jsonPath().getString("timetable[1].lecture_class")) - .isEqualTo("02"); - softly.assertThat(response.body().jsonPath().getString("timetable[1].target")) - .isEqualTo("컴퓨 3"); - softly.assertThat(response.body().jsonPath().getString("timetable[1].professor")) - .isEqualTo("이강환"); - softly.assertThat(response.body().jsonPath().getString("timetable[1].department")) - .isEqualTo("컴퓨터공학부"); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + { + "semester": "20192", + "timetable": [ + { + "id": 1, + "regular_number": "25", + "code": "CPC490", + "design_score": "0", + "class_time": [ + 210, 211 + ], + "class_place": null, + "memo": null, + "grades": "3", + "class_title": "운영체제", + "lecture_class": "01", + "target": "디자 1 건축", + "professor": "이돈우", + "department": "디자인ㆍ건축공학부" + }, + { + "id": 2, + "regular_number": "38", + "code": "CSE201", + "design_score": "0", + "class_time": [ + + ], + "class_place": null, + "memo": null, + "grades": "1", + "class_title": "컴퓨터구조", + "lecture_class": "02", + "target": "컴퓨 3", + "professor": "이강환", + "department": "컴퓨터공학부" + } + ], + "grades": 4, + "total_grades": 4 + } + """); } @Test - @DisplayName("시간표 생성시 필수 필드를 안넣을때 에러코드400을 반환한다.") + @DisplayName("시간표 생성시 필수 필드를 안넣을때 에러코드 400을 반환한다.") void createTimeTablesBadRequest() { - User userT = User.builder() - .password("1234") - .nickname("주노") - .name("최준호") - .phoneNumber("010-1234-5678") - .userType(STUDENT) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build(); - - User user = userRepository.save(userT); - String token = jwtProvider.createToken(user); - - Semester semester = Semester.builder(). - semester("20192") - .build(); - - semesterRepository.save(semester); - - ExtractableResponse response = RestAssured + User user = userFixture.준호_학생().getUser(); + String token = userFixture.getToken(user); + Semester semester = semesterFixture.semester("20192"); + + var response = RestAssured .given() .header("Authorization", "Bearer " + token) .contentType(ContentType.JSON) - .body(""" + .body(String.format(""" { "timetable": [ { @@ -656,9 +447,10 @@ void createTimeTablesBadRequest() { "memo": null } ], - "semester": "20192" + "semester": "%s" } - """) + """, semester.getSemester() + )) .when() .post("/timetables") .then() @@ -669,99 +461,44 @@ void createTimeTablesBadRequest() { @Test @DisplayName("시간표 수정한다.") void updateTimeTables() { - User userT = User.builder() - .password("1234") - .nickname("주노") - .name("최준호") - .phoneNumber("010-1234-5678") - .userType(STUDENT) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build(); - - User user = userRepository.save(userT); - String token = jwtProvider.createToken(user); - - Semester semesterT = Semester.builder(). - semester("20192") - .build(); - - Semester semester = semesterRepository.save(semesterT); - - TimeTable timeTable1 = TimeTable.builder() - .user(user) - .semester(semester) - .code("CS101") - .classTitle("컴퓨터 구조") - .classTime("[14, 15, 16, 17, 204, 205, 206, 207]") - .classPlace(null) - .professor("김철수") - .grades("3") - .lectureClass("02") - .target("컴부전체") - .regularNumber("28") - .designScore("0") - .department("컴퓨터공학부") - .memo(null) - .isDeleted(false) - .build(); - - TimeTable timeTable2 = TimeTable.builder() - .user(user) - .semester(semester) - .code("CS102") - .classTitle("운영체제") - .classTime("[932]") - .classPlace(null) - .professor("홍길동") - .grades("3") - .lectureClass("01") - .target("컴부전체") - .regularNumber("40") - .designScore("0") - .department("컴퓨터공학부") - .memo(null) - .isDeleted(false) - .build(); - - timeTableRepository.save(timeTable1); - timeTableRepository.save(timeTable2); - - ExtractableResponse response = RestAssured + User user = userFixture.준호_학생().getUser(); + String token = userFixture.getToken(user); + Semester semester = semesterFixture.semester("20192"); + TimeTable timeTable1 = timeTableFixture.이산수학(user, semester); + TimeTable timeTable2 = timeTableFixture.알고리즘및실습(user, semester); + + var response = RestAssured .given() .header("Authorization", "Bearer " + token) .contentType(ContentType.JSON) - .body(""" + .body(String.format(""" { "timetable": [ { - "id": 1, - "code": "CPC490", - "class_title": "운영체제", + "id": %d, + "code": "CPC999", + "class_title": "안녕체제", "class_time": [ - 210, - 211 + 210, 211 ], "class_place": null, - "professor": "이돈우", - "grades": "3", + "professor": "차은우", + "grades": "1", "lecture_class": "01", - "target": "디자 1 건축", + "target": "전체", "regular_number": "25", "design_score": "0", - "department": "디자인ㆍ건축공학부", + "department": "교양학부", "memo": null }, { - "id": 2, - "code": "CSE201", - "class_title": "컴퓨터구조", + "id": %d, + "code": "CSE777", + "class_title": "구조화된컴퓨터", "class_time": [ ], "class_place": null, - "professor": "이강환", + "professor": "장원영", "grades": "1", "lecture_class": "02", "target": "컴퓨 3", @@ -771,166 +508,97 @@ void updateTimeTables() { "memo": null } ], - "semester": "20192" + "semester": "%s" } - """) + """, timeTable1.getId(), timeTable2.getId(), semester.getSemester() + )) .when() .put("/timetables") .then() .statusCode(HttpStatus.OK.value()) .extract(); - assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getList("timetable")).hasSize(2); - softly.assertThat(response.body().jsonPath().getInt("timetable[0].id")).isEqualTo(1); - softly.assertThat(response.body().jsonPath().getString("timetable[0].code")).isEqualTo("CPC490"); - softly.assertThat(response.body().jsonPath().getString("timetable[0].class_title")).isEqualTo("운영체제"); - softly.assertThat(response.body().jsonPath().getList("timetable[0].class_time")) - .containsAll(List.of(210, 211)); - softly.assertThat(response.body().jsonPath().getString("timetable[0].class_place")).isEqualTo(null); - softly.assertThat(response.body().jsonPath().getString("timetable[0].professor")).isEqualTo("이돈우"); - softly.assertThat(response.body().jsonPath().getString("timetable[0].grades")).isEqualTo("3"); - softly.assertThat(response.body().jsonPath().getString("timetable[0].lecture_class")).isEqualTo("01"); - softly.assertThat(response.body().jsonPath().getString("timetable[0].target")).isEqualTo("디자 1 건축"); - softly.assertThat(response.body().jsonPath().getString("timetable[0].regular_number")).isEqualTo("25"); - softly.assertThat(response.body().jsonPath().getString("timetable[0].design_score")).isEqualTo("0"); - softly.assertThat(response.body().jsonPath().getString("timetable[0].department")) - .isEqualTo("디자인ㆍ건축공학부"); - softly.assertThat(response.body().jsonPath().getString("timetable[0].memo")).isEqualTo(null); - - softly.assertThat(response.body().jsonPath().getInt("timetable[1].id")).isEqualTo(2); - softly.assertThat(response.body().jsonPath().getString("timetable[1].code")).isEqualTo("CSE201"); - softly.assertThat(response.body().jsonPath().getString("timetable[1].class_title")).isEqualTo("컴퓨터구조"); - softly.assertThat(response.body().jsonPath().getList("timetable[1].class_time")).isEmpty(); - softly.assertThat(response.body().jsonPath().getString("timetable[1].class_place")).isEqualTo(null); - softly.assertThat(response.body().jsonPath().getString("timetable[1].professor")).isEqualTo("이강환"); - softly.assertThat(response.body().jsonPath().getString("timetable[1].grades")).isEqualTo("1"); - softly.assertThat(response.body().jsonPath().getString("timetable[1].lecture_class")).isEqualTo("02"); - softly.assertThat(response.body().jsonPath().getString("timetable[1].target")).isEqualTo("컴퓨 3"); - softly.assertThat(response.body().jsonPath().getString("timetable[1].regular_number")).isEqualTo("38"); - softly.assertThat(response.body().jsonPath().getString("timetable[1].design_score")).isEqualTo("0"); - softly.assertThat(response.body().jsonPath().getString("timetable[1].department")).isEqualTo("컴퓨터공학부"); - softly.assertThat(response.body().jsonPath().getString("timetable[1].memo")).isEqualTo(null); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + { + "semester": "20192", + "timetable": [ + { + "id": 1, + "regular_number": "25", + "code": "CPC999", + "design_score": "0", + "class_time": [ + 210, 211 + ], + "class_place": null, + "memo": null, + "grades": "1", + "class_title": "안녕체제", + "lecture_class": "01", + "target": "전체", + "professor": "차은우", + "department": "교양학부" + }, + { + "id": 2, + "regular_number": "38", + "code": "CSE777", + "design_score": "0", + "class_time": [ + + ], + "class_place": null, + "memo": null, + "grades": "1", + "class_title": "구조화된컴퓨터", + "lecture_class": "02", + "target": "컴퓨 3", + "professor": "장원영", + "department": "컴퓨터공학부" + } + ], + "grades": 2, + "total_grades": 2 + } + """); } @Test @DisplayName("시간표를 삭제한다.") void deleteTimeTable() { - User userT = User.builder() - .password("1234") - .nickname("주노") - .name("최준호") - .phoneNumber("010-1234-5678") - .userType(STUDENT) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build(); - - User user = userRepository.save(userT); - String token = jwtProvider.createToken(user); - - Semester semesterT = Semester.builder(). - semester("20192") - .build(); - - Semester semester = semesterRepository.save(semesterT); - - TimeTable timeTable = TimeTable.builder() - .user(user) - .semester(semester) - .code("CS101") - .classTitle("컴퓨터 구조") - .classTime("[14, 15, 16, 17, 204, 205, 206, 207]") - .classPlace(null) - .professor("김철수") - .grades("3") - .lectureClass("02") - .target("컴부전체") - .regularNumber("28") - .designScore("0") - .department("컴퓨터공학부") - .memo(null) - .isDeleted(false) - .build(); - - timeTableRepository.save(timeTable); + User user = userFixture.준호_학생().getUser(); + String token = userFixture.getToken(user); + Semester semester = semesterFixture.semester("20192"); + TimeTable timeTable = timeTableFixture.이산수학(user, semester); RestAssured .given() .header("Authorization", "Bearer " + token) .when() - .param("id", 1L) + .param("id", timeTable.getId()) .delete("/timetable") .then() .statusCode(HttpStatus.OK.value()); - ExtractableResponse response = RestAssured - .given() - .header("Authorization", "Bearer " + token) - .when() - .param("semester", "20192") - .get("/timetables") - .then() - .statusCode(HttpStatus.OK.value()) - .extract(); - - assertThat(response.body().jsonPath().getList("timetable")).isEmpty(); + assertThat(timeTableRepository.findById(timeTable.getId())).isNotPresent(); } @Test @DisplayName("시간표 삭제 실패시(=조회 실패시) 404 에러코드를 반환한다.") void deleteTimeTableNotFound() { - User userT = User.builder() - .password("1234") - .nickname("주노") - .name("최준호") - .phoneNumber("010-1234-5678") - .userType(STUDENT) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build(); - - User user = userRepository.save(userT); - String token = jwtProvider.createToken(user); - - Semester semesterT = Semester.builder(). - semester("20192") - .build(); - - Semester semester = semesterRepository.save(semesterT); - - TimeTable timeTable = TimeTable.builder() - .user(user) - .semester(semester) - .code("CS101") - .classTitle("컴퓨터 구조") - .classTime("[14, 15, 16, 17, 204, 205, 206, 207]") - .classPlace(null) - .professor("김철수") - .grades("3") - .lectureClass("02") - .target("컴부전체") - .regularNumber("28") - .designScore("0") - .department("컴퓨터공학부") - .memo(null) - .isDeleted(false) - .build(); - - timeTableRepository.save(timeTable); + User user = userFixture.준호_학생().getUser(); + String token = userFixture.getToken(user); + Semester semester = semesterFixture.semester("20192"); + timeTableFixture.이산수학(user, semester); + timeTableFixture.알고리즘및실습(user, semester); + timeTableFixture.컴퓨터구조(user, semester); RestAssured .given() .header("Authorization", "Bearer " + token) .when() - .param("id", 3) + .param("id", 999) .delete("/timetable") .then() .statusCode(HttpStatus.NOT_FOUND.value()); diff --git a/src/test/java/in/koreatech/koin/acceptance/TrackApiTest.java b/src/test/java/in/koreatech/koin/acceptance/TrackApiTest.java index 0e4a6a38f..4b4d6ddc1 100644 --- a/src/test/java/in/koreatech/koin/acceptance/TrackApiTest.java +++ b/src/test/java/in/koreatech/koin/acceptance/TrackApiTest.java @@ -1,42 +1,38 @@ package in.koreatech.koin.acceptance; -import java.time.format.DateTimeFormatter; - -import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import in.koreatech.koin.AcceptanceTest; -import in.koreatech.koin.domain.member.model.Member; -import in.koreatech.koin.domain.member.model.TechStack; import in.koreatech.koin.domain.member.model.Track; -import in.koreatech.koin.domain.member.repository.MemberRepository; -import in.koreatech.koin.domain.member.repository.TechStackRepository; -import in.koreatech.koin.domain.member.repository.TrackRepository; +import in.koreatech.koin.fixture.MemberFixture; +import in.koreatech.koin.fixture.TechStackFixture; +import in.koreatech.koin.fixture.TrackFixture; +import in.koreatech.koin.support.JsonAssertions; import io.restassured.RestAssured; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; +@SuppressWarnings("NonAsciiCharacters") class TrackApiTest extends AcceptanceTest { @Autowired - private TrackRepository trackRepository; + private TrackFixture trackFixture; @Autowired - private TechStackRepository techStackRepository; + private MemberFixture memberFixture; @Autowired - private MemberRepository memberRepository; + private TechStackFixture techStackFixture; @Test @DisplayName("BCSDLab 트랙 정보를 조회한다") void findTracks() { - Track request = Track.builder().name("BackEnd").build(); - Track track = trackRepository.save(request); + trackFixture.backend(); + trackFixture.frontend(); + trackFixture.ios(); - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .get("/tracks") @@ -44,49 +40,45 @@ void findTracks() { .statusCode(HttpStatus.OK.value()) .extract(); - SoftAssertions.assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getList(".").size()).isEqualTo(1); - softly.assertThat(response.body().jsonPath().getInt("[0].id")).isEqualTo(track.getId()); - softly.assertThat(response.body().jsonPath().getString("[0].name")).isEqualTo(track.getName()); - softly.assertThat(response.body().jsonPath().getInt("[0].headcount")).isEqualTo(track.getHeadcount()); - softly.assertThat(response.body().jsonPath().getBoolean("[0].is_deleted")) - .isEqualTo(track.isDeleted()); - softly.assertThat(response.body().jsonPath().getString("[0].created_at")) - .contains(track.getCreatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); - softly.assertThat(response.body().jsonPath().getString("[0].updated_at")) - .contains(track.getUpdatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + [ + { + "id": 1, + "name": "BackEnd", + "headcount": 0, + "is_deleted": false, + "created_at": "2024-01-15 12:00:00", + "updated_at": "2024-01-15 12:00:00" + }, + { + "id": 2, + "name": "FrontEnd", + "headcount": 0, + "is_deleted": false, + "created_at": "2024-01-15 12:00:00", + "updated_at": "2024-01-15 12:00:00" + }, + { + "id": 3, + "name": "iOS", + "headcount": 0, + "is_deleted": false, + "created_at": "2024-01-15 12:00:00", + "updated_at": "2024-01-15 12:00:00" + } + ] + """); } @Test @DisplayName("BCSDLab 트랙 정보 단건 조회") void findTrack() { - Track track = Track.builder().name("BackEnd").build(); - trackRepository.save(track); - - Member member = Member.builder() - .isDeleted(false) - .studentNumber("2019136064") - .imageUrl("https://imagetest.com/asdf.jpg") - .name("박한수") - .position("Regular") - .track(track) - .email("hsp@gmail.com") - .build(); - memberRepository.save(member); + Track track = trackFixture.backend(); + memberFixture.최준호(track); + techStackFixture.java(track); - TechStack techStack = TechStack.builder() - .isDeleted(false) - .imageUrl("https://testimageurl.com") - .trackId(track.getId()) - .name("Java") - .description("Language") - .build(); - techStackRepository.save(techStack); - - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .get("/tracks/{id}", track.getId()) @@ -94,56 +86,46 @@ void findTrack() { .statusCode(HttpStatus.OK.value()) .extract(); - SoftAssertions.assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getString("TrackName")).isEqualTo(track.getName()); - softly.assertThat(response.body().jsonPath().getList("Members")).hasSize(1); - softly.assertThat(response.body().jsonPath().getInt("Members[0].id")) - .isEqualTo(member.getId().longValue()); - softly.assertThat(response.body().jsonPath().getString("Members[0].name")).isEqualTo(member.getName()); - softly.assertThat(response.body().jsonPath().getString("Members[0].student_number")) - .isEqualTo(member.getStudentNumber()); - softly.assertThat(response.body().jsonPath().getString("Members[0].position")) - .isEqualTo(member.getPosition()); - softly.assertThat(response.body().jsonPath().getString("Members[0].track")) - .isEqualTo(track.getName()); - softly.assertThat(response.body().jsonPath().getString("Members[0].email")) - .isEqualTo(member.getEmail()); - softly.assertThat(response.body().jsonPath().getString("Members[0].image_url")) - .isEqualTo(member.getImageUrl()); - softly.assertThat(response.body().jsonPath().getBoolean("Members[0].is_deleted")) - .isEqualTo(member.isDeleted()); - softly.assertThat(response.body().jsonPath().getString("Members[0].updated_at")) - .contains(member.getUpdatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); - softly.assertThat(response.body().jsonPath().getString("Members[0].created_at")) - .contains(member.getCreatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); - - softly.assertThat(response.body().jsonPath().getList("TechStacks")).hasSize(1); - softly.assertThat(response.body().jsonPath().getInt("TechStacks[0].id")).isEqualTo(techStack.getId()); - softly.assertThat(response.body().jsonPath().getString("TechStacks[0].image_url")) - .isEqualTo(techStack.getImageUrl()); - softly.assertThat(response.body().jsonPath().getInt("TechStacks[0].track_id")) - .isEqualTo(techStack.getTrackId()); - softly.assertThat(response.body().jsonPath().getString("TechStacks[0].name")) - .isEqualTo(techStack.getName()); - softly.assertThat(response.body().jsonPath().getString("TechStacks[0].description")) - .isEqualTo(techStack.getDescription()); - softly.assertThat(response.body().jsonPath().getBoolean("TechStacks[0].is_deleted")).isFalse(); - softly.assertThat(response.body().jsonPath().getString("TechStacks[0].updated_at")) - .contains(techStack.getUpdatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); - softly.assertThat(response.body().jsonPath().getString("TechStacks[0].created_at")) - .contains(techStack.getCreatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + { + "TrackName": "BackEnd", + "TechStacks": [ + { + "id": 1, + "name": "Java", + "description": "Language", + "image_url": "https://testimageurl.com", + "track_id": 1, + "is_deleted": false, + "created_at": "2024-01-15 12:00:00", + "updated_at": "2024-01-15 12:00:00" + } + ], + "Members": [ + { + "id": 1, + "name": "최준호", + "student_number": "2019136135", + "position": "Regular", + "track": "BackEnd", + "email": "testjuno@gmail.com", + "image_url": "https://imagetest.com/juno.jpg", + "is_deleted": false, + "created_at": "2024-01-15 12:00:00", + "updated_at": "2024-01-15 12:00:00" + } + ] + } + """); } @Test @DisplayName("BCSDLab 트랙 정보 단건 조회 - 트랙에 속한 멤버와 기술스택이 없을 때") void findTrackWithEmptyMembersAndTechStacks() { - Track track = Track.builder().name("BackEnd").build(); - trackRepository.save(track); + Track track = trackFixture.frontend(); - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .get("/tracks/{id}", track.getId()) @@ -151,12 +133,17 @@ void findTrackWithEmptyMembersAndTechStacks() { .statusCode(HttpStatus.OK.value()) .extract(); - SoftAssertions.assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getString("TrackName")).isEqualTo(track.getName()); - softly.assertThat(response.body().jsonPath().getList("Members")).hasSize(0); - softly.assertThat(response.body().jsonPath().getList("TechStacks")).hasSize(0); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + { + "TrackName": "FrontEnd", + "TechStacks": [ + + ], + "Members": [ + + ] + } + """); } } diff --git a/src/test/java/in/koreatech/koin/acceptance/UserApiTest.java b/src/test/java/in/koreatech/koin/acceptance/UserApiTest.java index 348abe362..4cb6cb422 100644 --- a/src/test/java/in/koreatech/koin/acceptance/UserApiTest.java +++ b/src/test/java/in/koreatech/koin/acceptance/UserApiTest.java @@ -1,19 +1,13 @@ package in.koreatech.koin.acceptance; -import static in.koreatech.koin.domain.user.model.UserType.COOP; +import static in.koreatech.koin.domain.user.model.UserIdentity.UNDERGRADUATE; import static in.koreatech.koin.domain.user.model.UserType.STUDENT; -import static java.time.format.DateTimeFormatter.ofPattern; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.SoftAssertions.assertSoftly; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import java.time.Clock; -import java.time.ZonedDateTime; - -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.BeforeEach; +import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -27,15 +21,15 @@ import in.koreatech.koin.domain.user.model.Student; import in.koreatech.koin.domain.user.model.User; import in.koreatech.koin.domain.user.model.UserGender; -import in.koreatech.koin.domain.user.model.UserIdentity; import in.koreatech.koin.domain.user.repository.StudentRepository; import in.koreatech.koin.domain.user.repository.UserRepository; +import in.koreatech.koin.fixture.UserFixture; import in.koreatech.koin.global.auth.JwtProvider; +import in.koreatech.koin.support.JsonAssertions; import io.restassured.RestAssured; import io.restassured.http.ContentType; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; +@SuppressWarnings("NonAsciiCharacters") class UserApiTest extends AcceptanceTest { @Autowired @@ -50,31 +44,16 @@ class UserApiTest extends AcceptanceTest { @Autowired private TransactionTemplate transactionTemplate; - @BeforeEach - void setUp() { - when(clock.instant()).thenReturn( - ZonedDateTime.parse("2024-02-21 18:00:00 KST", ofPattern("yyyy-MM-dd " + "HH:mm:ss z")).toInstant()); - when(clock.getZone()).thenReturn(Clock.systemDefaultZone().getZone()); - } + @Autowired + private UserFixture userFixture; @Test @DisplayName("올바른 영양사 계정인지 확인한다") void coopCheckMe() { - User user = User.builder() - .password("1234") - .name("영양사") - .phoneNumber("010-1234-5678") - .userType(COOP) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build(); - - userRepository.save(user); - String token = jwtProvider.createToken(user); + User user = userFixture.준기_영양사(); + String token = userFixture.getToken(user); - ExtractableResponse response = RestAssured + var response = RestAssured .given() .header("Authorization", "Bearer " + token) .when() @@ -83,50 +62,16 @@ void coopCheckMe() { .statusCode(HttpStatus.OK.value()) .extract(); - assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getString("email")) - .isEqualTo(user.getEmail()); - softly.assertThat(response.body().jsonPath().getInt("gender")) - .isEqualTo(user.getGender().ordinal()); - softly.assertThat(response.body().jsonPath().getString("name")) - .isEqualTo(user.getName()); - softly.assertThat(response.body().jsonPath().getString("phone_number")) - .isEqualTo(user.getPhoneNumber()); - softly.assertThat(response.body().jsonPath().getString("user_type")) - .isEqualTo(user.getUserType().getValue()); - } - ); + } @Test @DisplayName("올바른 학생계정인지 확인한다") void studentCheckMe() { - Student student = Student.builder() - .studentNumber("2019136135") - .anonymousNickname("익명") - .department("컴퓨터공학부") - .userIdentity(UserIdentity.UNDERGRADUATE) - .isGraduated(false) - .user( - User.builder() - .password("1234") - .nickname("셋업유저") - .name("셋업") - .phoneNumber("010-1234-5678") - .userType(STUDENT) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build() - ) - .build(); + Student student = userFixture.준호_학생(); + String token = userFixture.getToken(student.getUser()); - studentRepository.save(student); - String token = jwtProvider.createToken(student.getUser()); - - ExtractableResponse response = RestAssured + var response = RestAssured .given() .header("Authorization", "Bearer " + token) .when() @@ -135,58 +80,28 @@ void studentCheckMe() { .statusCode(HttpStatus.OK.value()) .extract(); - User user = student.getUser(); - - assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getString("anonymous_nickname")) - .isEqualTo(student.getAnonymousNickname()); - softly.assertThat(response.body().jsonPath().getString("email")) - .isEqualTo(user.getEmail()); - softly.assertThat(response.body().jsonPath().getInt("gender")) - .isEqualTo(user.getGender().ordinal()); - softly.assertThat(response.body().jsonPath().getString("major")) - .isEqualTo(student.getDepartment()); - softly.assertThat(response.body().jsonPath().getString("name")) - .isEqualTo(user.getName()); - softly.assertThat(response.body().jsonPath().getString("nickname")) - .isEqualTo(user.getNickname()); - softly.assertThat(response.body().jsonPath().getString("phone_number")) - .isEqualTo(user.getPhoneNumber()); - softly.assertThat(response.body().jsonPath().getString("student_number")) - .isEqualTo(student.getStudentNumber()); - } - ); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + { + "anonymous_nickname": "익명", + "email": "juno@koreatech.ac.kr", + "gender": 0, + "major": "컴퓨터공학부", + "name": "테스트용_준호", + "nickname": "준호", + "phone_number": "010-1234-5678", + "student_number": "2019136135" + } + """); } @Test @DisplayName("올바른 학생계정인지 확인한다 - 토큰 정보가 올바르지 않으면 401") void studentCheckMeUnAuthorized() { - Student student = Student.builder() - .studentNumber("2019136135") - .anonymousNickname("익명") - .department("컴퓨터공학부") - .userIdentity(UserIdentity.UNDERGRADUATE) - .isGraduated(false) - .user( - User.builder() - .password("1234") - .nickname("주노") - .name("최준호") - .phoneNumber("010-1234-5678") - .userType(STUDENT) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build() - ) - .build(); - - studentRepository.save(student); + userFixture.준호_학생(); String token = "invalidToken"; - ExtractableResponse response = RestAssured + var response = RestAssured .given() .header("Authorization", "Bearer " + token) .when() @@ -199,22 +114,13 @@ void studentCheckMeUnAuthorized() { @Test @DisplayName("올바른 학생계정인지 확인한다 - 회원을 찾을 수 없으면 404") void studentCheckMeNotFound() { - User user = User.builder() - .password("1234") - .nickname("주노") - .name("최준호") - .phoneNumber("010-1234-5678") - .userType(STUDENT) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build(); - - userRepository.save(user); - String token = jwtProvider.createToken(user); + Student student = userFixture.준호_학생(); + String token = jwtProvider.createToken(student.getUser()); + transactionTemplate.executeWithoutResult(status -> + studentRepository.deleteByUserId(student.getId()) + ); - ExtractableResponse response = RestAssured + RestAssured .given() .header("Authorization", "Bearer " + token) .when() @@ -227,31 +133,10 @@ void studentCheckMeNotFound() { @Test @DisplayName("학생이 정보를 수정한다") void studentUpdateMe() { - Student student = Student.builder() - .studentNumber("2019136135") - .anonymousNickname("익명") - .department("컴퓨터공학부") - .userIdentity(UserIdentity.UNDERGRADUATE) - .isGraduated(false) - .user( - User.builder() - .password("1234") - .nickname("주노") - .name("최준호") - .phoneNumber("010-1234-5678") - .userType(STUDENT) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build() - ) - .build(); + Student student = userFixture.준호_학생(); + String token = userFixture.getToken(student.getUser()); - studentRepository.save(student); - String token = jwtProvider.createToken(student.getUser()); - - ExtractableResponse response = RestAssured + var response = RestAssured .given() .header("Authorization", "Bearer " + token) .contentType(ContentType.JSON) @@ -270,36 +155,42 @@ void studentUpdateMe() { .then() .statusCode(HttpStatus.OK.value()) .extract(); + + transactionTemplate.executeWithoutResult(status -> { + Student result = studentRepository.getById(student.getId()); + SoftAssertions.assertSoftly( + softly -> { + softly.assertThat(result.getUser().getName()).isEqualTo("서정빈"); + softly.assertThat(result.getUser().getNickname()).isEqualTo("duehee"); + softly.assertThat(result.getUser().getName()).isEqualTo("서정빈"); + softly.assertThat(result.getUser().getGender()).isEqualTo(UserGender.from(1)); + softly.assertThat(result.getStudentNumber()).isEqualTo("2019136136"); + } + ); + }); + + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(""" + { + "anonymous_nickname": "익명", + "email": "juno@koreatech.ac.kr", + "gender": 1, + "major": "기계공학부", + "name": "서정빈", + "nickname": "duehee", + "phone_number": "010-2345-6789", + "student_number": "2019136136" + } + """); } @Test @DisplayName("학생이 정보를 수정한다 - 학번의 형식이 맞지 않으면 400") void studentUpdateMeNotValidStudentNumber() { - Student student = Student.builder() - .studentNumber("2019136135") - .anonymousNickname("익명") - .department("컴퓨터공학부") - .userIdentity(UserIdentity.UNDERGRADUATE) - .isGraduated(false) - .user( - User.builder() - .password("1234") - .nickname("주노") - .name("최준호") - .phoneNumber("010-1234-5678") - .userType(STUDENT) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build() - ) - .build(); + Student student = userFixture.준호_학생(); + String token = userFixture.getToken(student.getUser()); - studentRepository.save(student); - String token = jwtProvider.createToken(student.getUser()); - - ExtractableResponse response = RestAssured + RestAssured .given() .header("Authorization", "Bearer " + token) .contentType(ContentType.JSON) @@ -323,31 +214,10 @@ void studentUpdateMeNotValidStudentNumber() { @Test @DisplayName("학생이 정보를 수정한다 - 학부의 형식이 맞지 않으면 400") void studentUpdateMeNotValidDepartment() { - Student student = Student.builder() - .studentNumber("2019136135") - .anonymousNickname("익명") - .department("컴퓨터공학부") - .userIdentity(UserIdentity.UNDERGRADUATE) - .isGraduated(false) - .user( - User.builder() - .password("1234") - .nickname("주노") - .name("최준호") - .phoneNumber("010-1234-5678") - .userType(STUDENT) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build() - ) - .build(); + Student student = userFixture.준호_학생(); + String token = userFixture.getToken(student.getUser()); - studentRepository.save(student); - String token = jwtProvider.createToken(student.getUser()); - - ExtractableResponse response = RestAssured + RestAssured .given() .header("Authorization", "Bearer " + token) .contentType(ContentType.JSON) @@ -371,31 +241,10 @@ void studentUpdateMeNotValidDepartment() { @Test @DisplayName("학생이 정보를 수정한다 - 토큰이 올바르지 않다면 401") void studentUpdateMeUnAuthorized() { - Student student = Student.builder() - .studentNumber("2019136135") - .anonymousNickname("익명") - .department("컴퓨터공학부") - .userIdentity(UserIdentity.UNDERGRADUATE) - .isGraduated(false) - .user( - User.builder() - .password("1234") - .nickname("주노") - .name("최준호") - .phoneNumber("010-1234-5678") - .userType(STUDENT) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build() - ) - .build(); - - studentRepository.save(student); + userFixture.준호_학생(); String token = "invalidToken"; - ExtractableResponse response = RestAssured + RestAssured .given() .header("Authorization", "Bearer " + token) .contentType(ContentType.JSON) @@ -419,23 +268,13 @@ void studentUpdateMeUnAuthorized() { @Test @DisplayName("학생이 정보를 수정한다 - 회원을 찾을 수 없다면 404") void studentUpdateMeNotFound() { - User user = - User.builder() - .password("1234") - .nickname("주노") - .name("최준호") - .phoneNumber("010-1234-5678") - .userType(STUDENT) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build(); - - userRepository.save(user); - String token = jwtProvider.createToken(user); + Student student = userFixture.준호_학생(); + String token = userFixture.getToken(student.getUser()); + transactionTemplate.executeWithoutResult(status -> + studentRepository.deleteByUserId(student.getId()) + ); - ExtractableResponse response = RestAssured + RestAssured .given() .header("Authorization", "Bearer " + token) .contentType(ContentType.JSON) @@ -459,66 +298,24 @@ void studentUpdateMeNotFound() { @Test @DisplayName("학생이 정보를 수정한다 - 이미 있는 닉네임이라면 409") void studentUpdateMeDuplicationNickname() { - Student student1 = Student.builder() - .studentNumber("2019136135") - .anonymousNickname("익명") - .department("컴퓨터공학부") - .userIdentity(UserIdentity.UNDERGRADUATE) - .isGraduated(false) - .user( - User.builder() - .password("1234") - .nickname("주노") - .name("최준호") - .phoneNumber("010-1234-5678") - .userType(STUDENT) - .gender(UserGender.MAN) - .email("test1@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build() - ) - .build(); - - Student student2 = Student.builder() - .studentNumber("2020136065") - .anonymousNickname("익명2") - .department("컴퓨터공학부") - .userIdentity(UserIdentity.UNDERGRADUATE) - .isGraduated(false) - .user( - User.builder() - .password("1234") - .nickname("duehee") - .name("서정빈") - .phoneNumber("010-1234-5678") - .userType(STUDENT) - .gender(UserGender.MAN) - .email("test2@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build() - ) - .build(); - - studentRepository.save(student1); - studentRepository.save(student2); - String token = jwtProvider.createToken(student1.getUser()); + Student 준호 = userFixture.준호_학생(); + Student 성빈 = userFixture.성빈_학생(); + String token = userFixture.getToken(준호.getUser()); - ExtractableResponse response = RestAssured + var response = RestAssured .given() .header("Authorization", "Bearer " + token) .contentType(ContentType.JSON) - .body(""" + .body(String.format(""" { "gender" : 0, "major" : "테스트학과", "name" : "최주노", - "nickname" : "duehee", + "nickname" : "%s", "phone_number" : "010-2345-6789", "student_number" : "2019136136" } - """) + """, 성빈.getUser().getNickname())) .when() .put("/user/student/me") .then() @@ -529,43 +326,26 @@ void studentUpdateMeDuplicationNickname() { @Test @DisplayName("회원이 탈퇴한다") void userWithdraw() { - User user = User.builder() - .password("1234") - .nickname("주노") - .name("최준호") - .phoneNumber("010-1234-5678") - .userType(STUDENT) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build(); - - userRepository.save(user); - String token = jwtProvider.createToken(user); - - transactionTemplate.execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(TransactionStatus status) { + Student student = userFixture.성빈_학생(); + String token = userFixture.getToken(student.getUser()); - RestAssured - .given() - .header("Authorization", "Bearer " + token) - .when() - .delete("/user") - .then() - .statusCode(HttpStatus.NO_CONTENT.value()) - .extract(); + RestAssured + .given() + .header("Authorization", "Bearer " + token) + .when() + .delete("/user") + .then() + .statusCode(HttpStatus.NO_CONTENT.value()) + .extract(); - assertThat(userRepository.findById(user.getId())).isNotPresent(); - } - }); + assertThat(userRepository.findById(student.getId())).isNotPresent(); } + @Test @DisplayName("이메일이 중복인지 확인한다") void emailCheckExists() { - String email = "test@koreatech.ac.kr"; + String email = "notduplicated@koreatech.ac.kr"; RestAssured .given() @@ -580,7 +360,7 @@ void emailCheckExists() { } @Test - @DisplayName("이메일이 중복인지 확인한다 - 이메일을 보내지 않으면 400") + @DisplayName("이메일이 중복인지 확인한다 - 파라미터에 이메일을 포함하지 않으면 400") void emailCheckExistsNull() { RestAssured .when() @@ -608,21 +388,9 @@ void emailCheckExistsWrongFormat() { @Test @DisplayName("이메일이 중복인지 확인한다 - 중복이면 422") void emailCheckExistsAlreadyExists() { - User user = User.builder() - .password("1234") - .nickname("주노") - .name("최준호") - .phoneNumber("010-1234-5678") - .userType(STUDENT) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build(); + User user = userFixture.성빈_학생().getUser(); - userRepository.save(user); - - ExtractableResponse response = RestAssured + var response = RestAssured .given() .param("address", user.getEmail()) .when() @@ -638,21 +406,9 @@ void emailCheckExistsAlreadyExists() { @Test @DisplayName("닉네임 중복일때 상태코드 409를 반환한다.") void checkDuplicationOfNicknameConflict() { - User user = User.builder() - .password("1234") - .nickname("주노") - .name("최준호") - .phoneNumber("010-1234-5678") - .userType(STUDENT) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build(); - - userRepository.save(user); + User user = userFixture.성빈_학생().getUser(); - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .param("nickname", user.getNickname()) @@ -661,32 +417,16 @@ void checkDuplicationOfNicknameConflict() { .statusCode(HttpStatus.CONFLICT.value()) .extract(); - assertSoftly( - softly -> { - softly.assertThat(response.body().jsonPath().getString("message")) - .contains("이미 존재하는 닉네임입니다."); - } - ); + assertThat(response.body().jsonPath().getString("message")) + .contains("이미 존재하는 닉네임입니다."); } @Test @DisplayName("닉네임 중복이 아닐시 상태코드 200을 반환한다.") void checkDuplicationOfNickname() { - User user = User.builder() - .password("1234") - .nickname("주노") - .name("최준호") - .phoneNumber("010-1234-5678") - .userType(STUDENT) - .gender(UserGender.MAN) - .email("test@koreatech.ac.kr") - .isAuthed(true) - .isDeleted(false) - .build(); - - userRepository.save(user); + User user = userFixture.성빈_학생().getUser(); - ExtractableResponse response = RestAssured + RestAssured .given() .when() .param("nickname", "철수") @@ -739,7 +479,7 @@ void getAuth() { .studentNumber("2019136135") .anonymousNickname("익명") .department("컴퓨터공학부") - .userIdentity(UserIdentity.UNDERGRADUATE) + .userIdentity(UNDERGRADUATE) .isGraduated(false) .user( User.builder() @@ -759,7 +499,7 @@ void getAuth() { studentRepository.save(student); String token = jwtProvider.createToken(student.getUser()); - ExtractableResponse response = RestAssured + var response = RestAssured .given() .header("Authorization", "Bearer " + token) .when() @@ -861,7 +601,7 @@ void authenticate() { User user1 = userRepository.getByEmail("koko123@koreatech.ac.kr"); - Assertions.assertThat(user1.isAuthed()).isTrue(); + assertThat(user1.isAuthed()).isTrue(); verify(studentEventListener).onStudentRegister(any()); } diff --git a/src/test/java/in/koreatech/koin/acceptance/VersionApiTest.java b/src/test/java/in/koreatech/koin/acceptance/VersionApiTest.java index 5ab6bbcfa..cd2adea4a 100644 --- a/src/test/java/in/koreatech/koin/acceptance/VersionApiTest.java +++ b/src/test/java/in/koreatech/koin/acceptance/VersionApiTest.java @@ -1,7 +1,5 @@ package in.koreatech.koin.acceptance; -import static org.assertj.core.api.SoftAssertions.assertSoftly; - import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -11,10 +9,10 @@ import in.koreatech.koin.domain.version.model.Version; import in.koreatech.koin.domain.version.model.VersionType; import in.koreatech.koin.domain.version.repository.VersionRepository; +import in.koreatech.koin.support.JsonAssertions; import io.restassured.RestAssured; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; +@SuppressWarnings("NonAsciiCharacters") class VersionApiTest extends AcceptanceTest { @Autowired @@ -23,30 +21,33 @@ class VersionApiTest extends AcceptanceTest { @Test @DisplayName("버전 타입을 통해 버전 정보를 조회한다.") void findVersionByType() { - VersionType versionType = VersionType.ANDROID; - String versionDetail = "1.0.0"; - - Version version = Version.builder() - .version(versionDetail) - .type(versionType.getValue()) - .build(); - - versionRepository.save(version); + Version version = versionRepository.save( + Version.builder() + .version("1.0.0") + .type(VersionType.ANDROID.getValue()) + .build() + ); // when then - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() - .get("/versions/" + versionType.getValue()) + .get("/versions/" + version.getType()) .then() .statusCode(HttpStatus.OK.value()) .extract(); - // 데이터 검증 - assertSoftly(softly -> { - softly.assertThat(response.body().jsonPath().getString("version")).isEqualTo(versionDetail); - softly.assertThat(response.body().jsonPath().getString("type")).isEqualTo(versionType.getValue()); - }); + JsonAssertions.assertThat(response.asPrettyString()) + .isEqualTo(String.format(""" + { + "id": %d, + "version": "1.0.0", + "type": "android", + "created_at": "2024-01-15 12:00:00", + "updated_at": "2024-01-15" + } + """, version.getId() + )); } @@ -54,7 +55,7 @@ void findVersionByType() { @DisplayName("버전 타입을 통해 버전 정보를 조회한다. - 저장되지 않은 버전 타입을 요청한 경우 에러가 발생한다.") void findVersionByTypeError() { VersionType failureType = VersionType.TIMETABLE; - ExtractableResponse notFoundFailureResponse = RestAssured + RestAssured .given() .when() .get("/versions/" + failureType.getValue()) @@ -63,7 +64,7 @@ void findVersionByTypeError() { .extract(); String undefinedType = "undefined"; - ExtractableResponse enumTypeFailureResponse = RestAssured + RestAssured .given() .when() .get("/versions/" + undefinedType) diff --git a/src/test/java/in/koreatech/koin/acceptance/AdminLandApiTest.java b/src/test/java/in/koreatech/koin/admin/acceptance/AdminLandApiTest.java similarity index 84% rename from src/test/java/in/koreatech/koin/acceptance/AdminLandApiTest.java rename to src/test/java/in/koreatech/koin/admin/acceptance/AdminLandApiTest.java index a4e079461..1defa4edd 100644 --- a/src/test/java/in/koreatech/koin/acceptance/AdminLandApiTest.java +++ b/src/test/java/in/koreatech/koin/admin/acceptance/AdminLandApiTest.java @@ -1,4 +1,4 @@ -package in.koreatech.koin.acceptance; +package in.koreatech.koin.admin.acceptance; import static org.assertj.core.api.SoftAssertions.assertSoftly; @@ -8,13 +8,12 @@ import org.springframework.http.HttpStatus; import in.koreatech.koin.AcceptanceTest; -import in.koreatech.koin.domain.admin.land.repository.AdminLandRepository; +import in.koreatech.koin.admin.land.repository.AdminLandRepository; import in.koreatech.koin.domain.land.model.Land; import io.restassured.RestAssured; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; -public class AdminLandApiTest extends AcceptanceTest { +@SuppressWarnings("NonAsciiCharacters") +class AdminLandApiTest extends AcceptanceTest { @Autowired private AdminLandRepository adminLandRepository; @@ -36,7 +35,7 @@ void getLands() { adminLandRepository.save(request); } - ExtractableResponse response = RestAssured + var response = RestAssured .given() .when() .param("page", 1) diff --git a/src/test/java/in/koreatech/koin/config/TestJpaConfiguration.java b/src/test/java/in/koreatech/koin/config/TestJpaConfiguration.java new file mode 100644 index 000000000..8f915ea63 --- /dev/null +++ b/src/test/java/in/koreatech/koin/config/TestJpaConfiguration.java @@ -0,0 +1,10 @@ +package in.koreatech.koin.config; + +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; + +@TestConfiguration +@EnableJpaAuditing(dateTimeProviderRef = "dateTimeProvider") +public class TestJpaConfiguration { + +} diff --git a/src/test/java/in/koreatech/koin/config/TestTimeConfig.java b/src/test/java/in/koreatech/koin/config/TestTimeConfig.java new file mode 100644 index 000000000..4b20885ff --- /dev/null +++ b/src/test/java/in/koreatech/koin/config/TestTimeConfig.java @@ -0,0 +1,28 @@ +package in.koreatech.koin.config; + +import java.time.Clock; +import java.time.LocalDateTime; +import java.util.Optional; + +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.data.auditing.DateTimeProvider; + +@TestConfiguration +public class TestTimeConfig { + + private final LocalDateTime fixedTime = LocalDateTime.of(2024, 1, 15, 12, 0); + + @Bean + public DateTimeProvider dateTimeProvider() { + return () -> Optional.of(fixedTime); + } + + @Bean + public Clock clock() { + return Clock.fixed( + fixedTime.atZone(Clock.systemDefaultZone().getZone()).toInstant(), + Clock.systemDefaultZone().getZone() + ); + } +} diff --git a/src/test/java/in/koreatech/koin/fixture/ActivityFixture.java b/src/test/java/in/koreatech/koin/fixture/ActivityFixture.java new file mode 100644 index 000000000..9f1009cad --- /dev/null +++ b/src/test/java/in/koreatech/koin/fixture/ActivityFixture.java @@ -0,0 +1,70 @@ +package in.koreatech.koin.fixture; + +import java.time.LocalDate; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import in.koreatech.koin.domain.activity.model.Activity; +import in.koreatech.koin.domain.activity.repository.ActivityRepository; + +@Component +public final class ActivityFixture { + + private final ActivityRepository activityRepository; + + @Autowired + public ActivityFixture(ActivityRepository activityRepository) { + this.activityRepository = activityRepository; + } + + public ActivityFixtureBuilder builder() { + return new ActivityFixtureBuilder(); + } + + public final class ActivityFixtureBuilder { + + private String title; + private String description; + private String imageUrls; + private LocalDate date; + private boolean isDeleted; + + public ActivityFixtureBuilder title(String title) { + this.title = title; + return this; + } + + public ActivityFixtureBuilder description(String description) { + this.description = description; + return this; + } + + public ActivityFixtureBuilder imageUrls(String imageUrls) { + this.imageUrls = imageUrls; + return this; + } + + public ActivityFixtureBuilder date(LocalDate date) { + this.date = date; + return this; + } + + public ActivityFixtureBuilder isDeleted(boolean isDeleted) { + this.isDeleted = isDeleted; + return this; + } + + public Activity build() { + return activityRepository.save( + Activity.builder() + .title(title) + .description(description) + .imageUrls(imageUrls) + .date(date) + .isDeleted(isDeleted) + .build() + ); + } + } +} diff --git a/src/test/java/in/koreatech/koin/fixture/ArticleFixture.java b/src/test/java/in/koreatech/koin/fixture/ArticleFixture.java new file mode 100644 index 000000000..257993d42 --- /dev/null +++ b/src/test/java/in/koreatech/koin/fixture/ArticleFixture.java @@ -0,0 +1,165 @@ +package in.koreatech.koin.fixture; + +import org.springframework.stereotype.Component; + +import in.koreatech.koin.domain.community.model.Article; +import in.koreatech.koin.domain.community.model.Board; +import in.koreatech.koin.domain.community.repository.ArticleRepository; +import in.koreatech.koin.domain.user.model.User; + +@Component +@SuppressWarnings("NonAsciiCharacters") +public class ArticleFixture { + + private final ArticleRepository articleRepository; + + public ArticleFixture(ArticleRepository articleRepository) { + this.articleRepository = articleRepository; + } + + public Article 자유글_1(User user, Board board) { + return articleRepository.save( + Article.builder() + .board(board) + .title("자유 글의 제목입니다") + .content("

내용

") + .user(user) + .nickname(user.getNickname()) + .hit(1) + .ip("123.21.234.321") + .isSolved(false) + .isDeleted(false) + .commentCount((byte)0) + .meta(null) + .isNotice(false) + .noticeArticleId(null) + .build() + ); + } + + public Article 자유글_2(User user, Board board) { + return articleRepository.save( + Article.builder() + .board(board) + .title("자유 글2의 제목입니다") + .content("

내용222

") + .user(user) + .nickname(user.getNickname()) + .hit(1) + .ip("127.0.0.1") + .isSolved(false) + .isDeleted(false) + .commentCount((byte)0) + .meta(null) + .isNotice(false) + .noticeArticleId(null) + .build() + ); + } + + public ArticleFixtureBuilder builder() { + return new ArticleFixtureBuilder(); + } + + public final class ArticleFixtureBuilder { + + private Board board; + private String title; + private String content; + private User user; + private String nickname; + private Integer hit; + private String ip; + private boolean isSolved; + private boolean isDeleted; + private Byte commentCount; + private String meta; + private boolean isNotice; + private Integer noticeArticleId; + + public ArticleFixtureBuilder board(Board board) { + this.board = board; + return this; + } + + public ArticleFixtureBuilder title(String title) { + this.title = title; + return this; + } + + public ArticleFixtureBuilder content(String content) { + this.content = content; + return this; + } + + public ArticleFixtureBuilder user(User user) { + this.user = user; + return this; + } + + public ArticleFixtureBuilder nickname(String nickname) { + this.nickname = nickname; + return this; + } + + public ArticleFixtureBuilder hit(Integer hit) { + this.hit = hit; + return this; + } + + public ArticleFixtureBuilder ip(String ip) { + this.ip = ip; + return this; + } + + public ArticleFixtureBuilder isSolved(boolean isSolved) { + this.isSolved = isSolved; + return this; + } + + public ArticleFixtureBuilder isDeleted(boolean isDeleted) { + this.isDeleted = isDeleted; + return this; + } + + public ArticleFixtureBuilder commentCount(Byte commentCount) { + this.commentCount = commentCount; + return this; + } + + public ArticleFixtureBuilder meta(String meta) { + this.meta = meta; + return this; + } + + public ArticleFixtureBuilder isNotice(boolean isNotice) { + this.isNotice = isNotice; + return this; + } + + public ArticleFixtureBuilder noticeArticleId(Integer noticeArticleId) { + this.noticeArticleId = noticeArticleId; + return this; + } + + public Article build() { + return articleRepository.save( + Article.builder() + .commentCount(commentCount) + .ip(ip) + .title(title) + .meta(meta) + .isSolved(isSolved) + .noticeArticleId(noticeArticleId) + .content(content) + .board(board) + .user(user) + .nickname(nickname) + .isNotice(isNotice) + .hit(hit) + .isDeleted(isDeleted) + .build() + ); + } + } +} diff --git a/src/test/java/in/koreatech/koin/fixture/BoardFixture.java b/src/test/java/in/koreatech/koin/fixture/BoardFixture.java new file mode 100644 index 000000000..f3e437f1f --- /dev/null +++ b/src/test/java/in/koreatech/koin/fixture/BoardFixture.java @@ -0,0 +1,106 @@ +package in.koreatech.koin.fixture; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import in.koreatech.koin.domain.community.model.Board; +import in.koreatech.koin.domain.community.repository.BoardRepository; + +@Component +@SuppressWarnings("NonAsciiCharacters") +public class BoardFixture { + + @Autowired + private final BoardRepository boardRepository; + + @Autowired + public BoardFixture(BoardRepository boardRepository) { + this.boardRepository = boardRepository; + } + + public Board 자유게시판() { + return boardRepository.save( + Board.builder() + .tag("FA001") + .name("자유게시판") + .isAnonymous(false) + .articleCount(0) + .isDeleted(false) + .isNotice(false) + .parentId(null) + .seq(1) + .build() + ); + } + + public BoardFixtureBuilder builder() { + return new BoardFixtureBuilder(); + } + + public final class BoardFixtureBuilder { + + private String tag; + private String name; + private boolean isAnonymous; + private Integer articleCount; + private boolean isDeleted; + private boolean isNotice; + private Integer parentId; + private Integer seq; + + public BoardFixtureBuilder tag(String tag) { + this.tag = tag; + return this; + } + + public BoardFixtureBuilder name(String name) { + this.name = name; + return this; + } + + public BoardFixtureBuilder isAnonymous(boolean isAnonymous) { + this.isAnonymous = isAnonymous; + return this; + } + + public BoardFixtureBuilder articleCount(Integer articleCount) { + this.articleCount = articleCount; + return this; + } + + public BoardFixtureBuilder isDeleted(boolean isDeleted) { + this.isDeleted = isDeleted; + return this; + } + + public BoardFixtureBuilder isNotice(boolean isNotice) { + this.isNotice = isNotice; + return this; + } + + public BoardFixtureBuilder parentId(Integer parentId) { + this.parentId = parentId; + return this; + } + + public BoardFixtureBuilder seq(Integer seq) { + this.seq = seq; + return this; + } + + public Board build() { + return boardRepository.save( + Board.builder() + .tag(tag) + .isDeleted(isDeleted) + .isAnonymous(isAnonymous) + .parentId(parentId) + .seq(seq) + .isNotice(isNotice) + .name(name) + .articleCount(articleCount) + .build() + ); + } + } +} diff --git a/src/test/java/in/koreatech/koin/fixture/BusFixture.java b/src/test/java/in/koreatech/koin/fixture/BusFixture.java new file mode 100644 index 000000000..c114335dd --- /dev/null +++ b/src/test/java/in/koreatech/koin/fixture/BusFixture.java @@ -0,0 +1,60 @@ +package in.koreatech.koin.fixture; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import in.koreatech.koin.domain.bus.model.mongo.BusCourse; +import in.koreatech.koin.domain.bus.model.mongo.Route; +import in.koreatech.koin.domain.bus.repository.BusRepository; + +@Component +@SuppressWarnings("NonAsciiCharacters") +public final class BusFixture { + + @Autowired + private final BusRepository busRepository; + + public BusFixture(BusRepository busRepository) { + this.busRepository = busRepository; + } + + public void 버스_시간표_등록() { + busRepository.save( + BusCourse.builder() + .busType("shuttle") + .region("천안") + .direction("from") + .routes( + List.of( + Route.builder() + .routeName("주중") + .runningDays(List.of("MON", "TUE", "WED", "THU", "FRI")) + .arrivalInfos( + List.of( + Route.ArrivalNode.builder() + .nodeName("한기대") + .arrivalTime("18:10") + .build(), + Route.ArrivalNode.builder() + .nodeName("신계초,운전리,연춘리") + .arrivalTime("정차") + .build(), + Route.ArrivalNode.builder() + .nodeName("천안역(학화호두과자)") + .arrivalTime("18:50") + .build(), + Route.ArrivalNode.builder() + .nodeName("터미널(신세계 앞 횡단보도)") + .arrivalTime("18:55") + .build() + ) + ) + .build() + ) + ) + .build() + ); + } +} diff --git a/src/test/java/in/koreatech/koin/fixture/DiningFixture.java b/src/test/java/in/koreatech/koin/fixture/DiningFixture.java new file mode 100644 index 000000000..cb6bdab82 --- /dev/null +++ b/src/test/java/in/koreatech/koin/fixture/DiningFixture.java @@ -0,0 +1,79 @@ +package in.koreatech.koin.fixture; + +import java.time.LocalDate; + +import org.springframework.stereotype.Component; + +import in.koreatech.koin.domain.dining.model.Dining; +import in.koreatech.koin.domain.dining.repository.DiningRepository; + +@Component +@SuppressWarnings("NonAsciiCharacters") +public class DiningFixture { + + private final DiningRepository diningRepository; + + public DiningFixture(DiningRepository diningRepository) { + this.diningRepository = diningRepository; + } + + public Dining 능수관_점심(LocalDate date) { + return diningRepository.save( + Dining.builder() + .date(date) + .type("LUNCH") + .place("능수관") + .priceCard(6000) + .priceCash(6000) + .kcal(300) + .menu(""" + ["참치김치볶음밥", "유부된장국", "땡초부추전", "누룽지탕"]""") + .build() + ); + } + + public Dining 캠퍼스2_점심(LocalDate date) { + return diningRepository.save( + Dining.builder() + .date(date) + .type("LUNCH") + .place("2캠퍼스") + .priceCard(6000) + .priceCash(6000) + .kcal(881) + .menu(""" + ["혼합잡곡밥", "가쓰오장국", "땡초부추전", "누룽지탕"]""") + .build() + ); + } + + public Dining A코스_점심(LocalDate date) { + return diningRepository.save( + Dining.builder() + .date(date) + .type("LUNCH") + .place("A코스") + .priceCard(6000) + .priceCash(6000) + .kcal(881) + .menu(""" + ["병아리콩밥", "(탕)소고기육개장", "땡초부추전", "누룽지탕"]""") + .build() + ); + } + + public Dining B코스_점심(LocalDate date) { + return diningRepository.save( + Dining.builder() + .date(date) + .type("LUNCH") + .place("B코스") + .priceCard(6000) + .priceCash(6000) + .kcal(881) + .menu(""" + ["병아리", "소고기", "땡초", "탕"]""") + .build() + ); + } +} diff --git a/src/test/java/in/koreatech/koin/fixture/EventArticleFixture.java b/src/test/java/in/koreatech/koin/fixture/EventArticleFixture.java new file mode 100644 index 000000000..308325451 --- /dev/null +++ b/src/test/java/in/koreatech/koin/fixture/EventArticleFixture.java @@ -0,0 +1,90 @@ +package in.koreatech.koin.fixture; + +import java.time.LocalDate; +import java.util.List; + +import org.springframework.stereotype.Component; + +import in.koreatech.koin.domain.shop.model.EventArticle; +import in.koreatech.koin.domain.shop.model.EventArticleImage; +import in.koreatech.koin.domain.shop.model.Shop; +import in.koreatech.koin.domain.shop.repository.EventArticleRepository; + +@Component +@SuppressWarnings("NonAsciiCharacters") +public class EventArticleFixture { + + private final EventArticleRepository eventArticleRepository; + + public EventArticleFixture( + EventArticleRepository eventArticleRepository + ) { + this.eventArticleRepository = eventArticleRepository; + } + + public EventArticle 할인_이벤트( + Shop shop, + LocalDate startDate, + LocalDate endDate + ) { + EventArticle eventArticle = eventArticleRepository.save( + EventArticle.builder() + .shop(shop) + .title("할인 이벤트") + .content("사장님이 미쳤어요!") + .ip("") + .startDate(startDate) + .endDate(endDate) + .hit(0) + .build() + ); + + eventArticle.getThumbnailImages() + .addAll( + List.of( + EventArticleImage.builder() + .thumbnailImage("https://eventimage.com/할인_이벤트.jpg") + .eventArticle(eventArticle) + .build(), + EventArticleImage.builder() + .thumbnailImage("https://eventimage.com/할인_이벤트.jpg") + .eventArticle(eventArticle) + .build() + ) + ); + return eventArticleRepository.save(eventArticle); + } + + public EventArticle 참여_이벤트( + Shop shop, + LocalDate startDate, + LocalDate endDate + ) { + EventArticle eventArticle = eventArticleRepository.save( + EventArticle.builder() + .shop(shop) + .title("참여 이벤트") + .content("사장님과 참여해요!!!") + .ip("") + .startDate(startDate) + .endDate(endDate) + .hit(0) + .build() + ); + + eventArticle.getThumbnailImages() + .addAll( + List.of( + EventArticleImage.builder() + .thumbnailImage("https://eventimage.com/참여_이벤트.jpg") + .eventArticle(eventArticle) + .build(), + EventArticleImage.builder() + .thumbnailImage("https://eventimage.com/참여_이벤트.jpg") + .eventArticle(eventArticle) + .build() + ) + ); + return eventArticleRepository.save(eventArticle); + } +} diff --git a/src/test/java/in/koreatech/koin/fixture/LandFixture.java b/src/test/java/in/koreatech/koin/fixture/LandFixture.java new file mode 100644 index 000000000..95b1e50a1 --- /dev/null +++ b/src/test/java/in/koreatech/koin/fixture/LandFixture.java @@ -0,0 +1,65 @@ +package in.koreatech.koin.fixture; + +import org.springframework.stereotype.Component; + +import in.koreatech.koin.domain.land.model.Land; +import in.koreatech.koin.domain.land.repository.LandRepository; + +@Component +@SuppressWarnings("NonAsciiCharacters") +public class LandFixture { + + private final LandRepository landRepository; + + public LandFixture(LandRepository landRepository) { + this.landRepository = landRepository; + } + + public Land 신안빌() { + return landRepository.save( + Land.builder() + .internalName("신") + .name("신안빌") + .roomType("원룸") + .latitude("37.555") + .longitude("126.555") + .floor(1) + .monthlyFee("100") + .charterFee("1000") + .deposit("1000") + .managementFee("100") + .phone("010-1234-5678") + .address("서울시 강남구") + .size("100.0") + .imageUrls(""" + ["https://example1.test.com/image.jpeg", + "https://example2.test.com/image.jpeg"] + """) + .build() + ); + } + + public Land 에듀윌() { + return landRepository.save( + Land.builder() + .internalName("에") + .name("에듀윌") + .roomType("원룸") + .latitude("37.555") + .longitude("126.555") + .floor(1) + .monthlyFee("100") + .charterFee("1000") + .deposit("1000") + .managementFee("100") + .phone("010-1133-5555") + .address("천안시 동남구 강남구") + .size("100.0") + .imageUrls(""" + ["https://example1.test.com/image.jpeg", + "https://example2.test.com/image.jpeg"] + """) + .build() + ); + } +} diff --git a/src/test/java/in/koreatech/koin/fixture/LectureFixture.java b/src/test/java/in/koreatech/koin/fixture/LectureFixture.java new file mode 100644 index 000000000..172d9ffd4 --- /dev/null +++ b/src/test/java/in/koreatech/koin/fixture/LectureFixture.java @@ -0,0 +1,97 @@ +package in.koreatech.koin.fixture; + +import org.springframework.stereotype.Component; + +import in.koreatech.koin.domain.timetable.model.Lecture; +import in.koreatech.koin.domain.timetable.repository.LectureRepository; + +@Component +@SuppressWarnings("NonAsciiCharacters") +public class LectureFixture { + + private final LectureRepository lectureRepository; + + public LectureFixture(LectureRepository lectureRepository) { + this.lectureRepository = lectureRepository; + } + + public Lecture 건축구조의_이해_및_실습(String semester) { + return lectureRepository.save( + Lecture.builder() + .code("ARB244") + .semester(semester) + .name("건축구조의 이해 및 실습") + .grades("3") + .lectureClass("01") + .regularNumber("25") + .department("디자인ㆍ건축공학부") + .target("디자 1 건축") + .professor("황현식") + .isEnglish("N") + .designScore("0") + .isElearning("N") + .classTime("[200, 201, 202, 203, 204, 205, 206, 207]") + .build() + ); + } + + public Lecture HRD_개론(String semester) { + return lectureRepository.save( + Lecture.builder() + .code("BSM590") + .semester(semester) + .name("컴퓨팅사고") + .grades("3") + .lectureClass("06") + .regularNumber("22") + .department("기계공학부") + .target("기공1") + .professor("박한수,최준호") + .isEnglish("") + .designScore("0") + .isElearning("") + .classTime("[12, 13, 14, 15, 210, 211, 212, 213]") + .build() + ); + } + + public Lecture 재료역학(String semester) { + return lectureRepository.save( + Lecture.builder() + .code("MEB311") + .semester(semester) + .name("재료역학") + .grades("3") + .lectureClass("01") + .regularNumber("35") + .department("기계공학부") + .target("기공전체") + .professor("허준기") + .isEnglish("") + .designScore("0") + .isElearning("") + .classTime("[100, 101, 102, 103, 308, 309]") + .build() + ); + } + + public Lecture 영어청해(String semester) { + return lectureRepository.save( + Lecture.builder() + .code("LAN324") + .semester(semester) + .name("영어청해") + .grades("1") + .lectureClass("09") + .regularNumber("40") + .department("교양학부") + .target("정통2") + .professor("김원경") + .isEnglish("") + .designScore("0") + .isElearning("") + .classTime("[200, 201, 202, 203]") + .build() + ); + } +} diff --git a/src/test/java/in/koreatech/koin/fixture/MemberFixture.java b/src/test/java/in/koreatech/koin/fixture/MemberFixture.java new file mode 100644 index 000000000..220f673dc --- /dev/null +++ b/src/test/java/in/koreatech/koin/fixture/MemberFixture.java @@ -0,0 +1,52 @@ +package in.koreatech.koin.fixture; + +import org.springframework.stereotype.Component; + +import in.koreatech.koin.domain.member.model.Member; +import in.koreatech.koin.domain.member.model.Track; +import in.koreatech.koin.domain.member.repository.MemberRepository; +import in.koreatech.koin.domain.member.repository.TrackRepository; + +@Component +@SuppressWarnings("NonAsciiCharacters") +public class MemberFixture { + + private final MemberRepository memberRepository; + private final TrackRepository trackRepository; + + public MemberFixture( + MemberRepository memberRepository, + TrackRepository trackRepository + ) { + this.memberRepository = memberRepository; + this.trackRepository = trackRepository; + } + + public Member 최준호(Track track) { + return memberRepository.save( + Member.builder() + .isDeleted(false) + .studentNumber("2019136135") + .imageUrl("https://imagetest.com/juno.jpg") + .name("최준호") + .position("Regular") + .track(track) + .email("testjuno@gmail.com") + .build() + ); + } + + public Member 박한수(Track track) { + return memberRepository.save( + Member.builder() + .isDeleted(false) + .studentNumber("2019136064") + .imageUrl("https://imagetest.com/juno.jpg") + .name("박한수") + .position("Regular") + .track(track) + .email("testhsp@gmail.com") + .build() + ); + } +} diff --git a/src/test/java/in/koreatech/koin/fixture/MenuCategoryFixture.java b/src/test/java/in/koreatech/koin/fixture/MenuCategoryFixture.java new file mode 100644 index 000000000..33fe89199 --- /dev/null +++ b/src/test/java/in/koreatech/koin/fixture/MenuCategoryFixture.java @@ -0,0 +1,54 @@ +package in.koreatech.koin.fixture; + +import org.springframework.stereotype.Component; + +import in.koreatech.koin.domain.shop.model.MenuCategory; +import in.koreatech.koin.domain.shop.model.Shop; +import in.koreatech.koin.domain.shop.repository.MenuCategoryRepository; + +@Component +@SuppressWarnings("NonAsciiCharacters") +public class MenuCategoryFixture { + + private final MenuCategoryRepository menuCategoryRepository; + + public MenuCategoryFixture(MenuCategoryRepository menuCategoryRepository) { + this.menuCategoryRepository = menuCategoryRepository; + } + + public MenuCategory 추천메뉴(Shop shop) { + return menuCategoryRepository.save( + MenuCategory.builder() + .shop(shop) + .name("추천메뉴") + .build() + ); + } + + public MenuCategory 사이드메뉴(Shop shop) { + return menuCategoryRepository.save( + MenuCategory.builder() + .shop(shop) + .name("사이드메뉴") + .build() + ); + } + + public MenuCategory 세트메뉴(Shop shop) { + return menuCategoryRepository.save( + MenuCategory.builder() + .shop(shop) + .name("세트메뉴") + .build() + ); + } + + public MenuCategory 메인메뉴(Shop shop) { + return menuCategoryRepository.save( + MenuCategory.builder() + .shop(shop) + .name("메인메뉴") + .build() + ); + } +} diff --git a/src/test/java/in/koreatech/koin/fixture/MenuFixture.java b/src/test/java/in/koreatech/koin/fixture/MenuFixture.java new file mode 100644 index 000000000..3b89c474d --- /dev/null +++ b/src/test/java/in/koreatech/koin/fixture/MenuFixture.java @@ -0,0 +1,114 @@ +package in.koreatech.koin.fixture; + +import java.util.List; + +import org.springframework.stereotype.Component; + +import in.koreatech.koin.domain.shop.model.Menu; +import in.koreatech.koin.domain.shop.model.MenuCategory; +import in.koreatech.koin.domain.shop.model.MenuCategoryMap; +import in.koreatech.koin.domain.shop.model.MenuImage; +import in.koreatech.koin.domain.shop.model.MenuOption; +import in.koreatech.koin.domain.shop.model.Shop; +import in.koreatech.koin.domain.shop.repository.MenuCategoryMapRepository; +import in.koreatech.koin.domain.shop.repository.MenuRepository; + +@Component +@SuppressWarnings("NonAsciiCharacters") +public class MenuFixture { + + private final MenuRepository menuRepository; + private final MenuCategoryMapRepository menuCategoryMapRepository; + + public MenuFixture( + MenuRepository menuRepository, + MenuCategoryMapRepository menuCategoryMapRepository + ) { + this.menuRepository = menuRepository; + this.menuCategoryMapRepository = menuCategoryMapRepository; + } + + public Menu 짜장면_옵션메뉴(Shop shop, MenuCategory menuCategory) { + Menu menu = menuRepository.save( + Menu.builder() + .shopId(shop.getId()) + .name("짜장면") + .description("맛있는 짜장면") + .build() + ); + + menu.getMenuImages().addAll( + List.of( + MenuImage.builder() + .menu(menu) + .imageUrl("https://test.com/짜장면.jpg") + .build(), + MenuImage.builder() + .menu(menu) + .imageUrl("https://test.com/짜장면22.jpg") + .build() + ) + ); + menu.getMenuOptions().addAll( + List.of( + MenuOption.builder() + .menu(menu) + .option("일반") + .price(7000) + .build(), + MenuOption.builder() + .menu(menu) + .option("곱빼기") + .price(7500) + .build() + ) + ); + menu.getMenuCategoryMaps().add( + MenuCategoryMap.builder() + .menu(menu) + .menuCategory(menuCategory) + .build() + ); + + return menuRepository.save(menu); + } + + public Menu 짜장면_단일메뉴(Shop shop, MenuCategory menuCategory) { + + Menu menu = menuRepository.save( + Menu.builder() + .shopId(shop.getId()) + .name("짜장면") + .description("맛있는 짜장면") + .build() + ); + + menu.getMenuImages().addAll( + List.of( + MenuImage.builder() + .menu(menu) + .imageUrl("https://test.com/짜장면.jpg") + .build(), + MenuImage.builder() + .menu(menu) + .imageUrl("https://test.com/짜장면22.jpg") + .build() + ) + ); + menu.getMenuOptions().add( + MenuOption.builder() + .menu(menu) + .option("짜장면") + .price(7000) + .build() + ); + menu.getMenuCategoryMaps().add( + MenuCategoryMap.builder() + .menu(menu) + .menuCategory(menuCategory) + .build() + ); + + return menuRepository.save(menu); + } +} diff --git a/src/test/java/in/koreatech/koin/fixture/SemesterFixture.java b/src/test/java/in/koreatech/koin/fixture/SemesterFixture.java new file mode 100644 index 000000000..5533d4bdf --- /dev/null +++ b/src/test/java/in/koreatech/koin/fixture/SemesterFixture.java @@ -0,0 +1,25 @@ +package in.koreatech.koin.fixture; + +import org.springframework.stereotype.Component; + +import in.koreatech.koin.domain.timetable.model.Semester; +import in.koreatech.koin.domain.timetable.repository.SemesterRepository; + +@Component +@SuppressWarnings("NonAsciiCharacters") +public class SemesterFixture { + + private final SemesterRepository semesterRepository; + + public SemesterFixture(SemesterRepository semesterRepository) { + this.semesterRepository = semesterRepository; + } + + public Semester semester(String semester) { + return semesterRepository.save( + Semester.builder() + .semester(semester) + .build() + ); + } +} diff --git a/src/test/java/in/koreatech/koin/fixture/ShopCategoryFixture.java b/src/test/java/in/koreatech/koin/fixture/ShopCategoryFixture.java new file mode 100644 index 000000000..27153f062 --- /dev/null +++ b/src/test/java/in/koreatech/koin/fixture/ShopCategoryFixture.java @@ -0,0 +1,37 @@ +package in.koreatech.koin.fixture; + +import org.springframework.stereotype.Component; + +import in.koreatech.koin.domain.shop.model.ShopCategory; +import in.koreatech.koin.domain.shop.repository.ShopCategoryRepository; + +@Component +@SuppressWarnings("NonAsciiCharacters") +public class ShopCategoryFixture { + + private final ShopCategoryRepository categoryRepository; + + public ShopCategoryFixture(ShopCategoryRepository categoryRepository) { + this.categoryRepository = categoryRepository; + } + + public ShopCategory 카테고리_치킨() { + return categoryRepository.save( + ShopCategory.builder() + .isDeleted(false) + .name("치킨") + .imageUrl("https://test-image.com/ckicken.jpg") + .build() + ); + } + + public ShopCategory 카테고리_일반음식() { + return categoryRepository.save( + ShopCategory.builder() + .isDeleted(false) + .name("일반음식점") + .imageUrl("https://test-image.com/normal.jpg") + .build() + ); + } +} diff --git a/src/test/java/in/koreatech/koin/fixture/ShopFixture.java b/src/test/java/in/koreatech/koin/fixture/ShopFixture.java new file mode 100644 index 000000000..2d698f98c --- /dev/null +++ b/src/test/java/in/koreatech/koin/fixture/ShopFixture.java @@ -0,0 +1,281 @@ +package in.koreatech.koin.fixture; + +import java.time.LocalTime; +import java.util.ArrayList; +import java.util.List; + +import org.springframework.stereotype.Component; + +import in.koreatech.koin.domain.owner.model.Owner; +import in.koreatech.koin.domain.shop.model.MenuCategory; +import in.koreatech.koin.domain.shop.model.Shop; +import in.koreatech.koin.domain.shop.model.ShopCategoryMap; +import in.koreatech.koin.domain.shop.model.ShopImage; +import in.koreatech.koin.domain.shop.model.ShopOpen; +import in.koreatech.koin.domain.shop.repository.ShopRepository; + +@Component +@SuppressWarnings("NonAsciiCharacters") +public final class ShopFixture { + + private final ShopRepository shopRepository; + + public ShopFixture(ShopRepository shopRepository) { + this.shopRepository = shopRepository; + } + + public Shop 마슬랜(Owner owner) { + var shop = shopRepository.save( + Shop.builder() + .owner(owner) + .name("마슬랜 치킨") + .internalName("마슬랜") + .chosung("마") + .phone("010-7574-1212") + .address("천안시 동남구 병천면 1600") + .description("마슬랜 치킨입니다.") + .delivery(true) + .deliveryPrice(3000) + .payCard(true) + .payBank(true) + .isDeleted(false) + .isEvent(false) + .remarks("비고") + .hit(0) + .build() + ); + shop.getShopImages().addAll( + List.of( + ShopImage.builder() + .shop(shop) + .imageUrl("https://test-image.com/마슬랜.png") + .build(), + ShopImage.builder() + .shop(shop) + .imageUrl("https://test-image.com/마슬랜2.png") + .build() + ) + ); + shop.getShopOpens().addAll( + List.of( + ShopOpen.builder() + .openTime(LocalTime.of(0, 0)) + .closeTime(LocalTime.of(21, 0)) + .shop(shop) + .closed(false) + .dayOfWeek("MONDAY") + .build(), + ShopOpen.builder() + .openTime(LocalTime.of(0, 0)) + .closeTime(LocalTime.of(0, 0)) + .shop(shop) + .closed(false) + .dayOfWeek("FRIDAY") + .build() + ) + ); + return shopRepository.save(shop); + } + + public Shop 신전_떡볶이(Owner owner) { + var shop = shopRepository.save( + Shop.builder() + .owner(owner) + .name("신전 떡볶이") + .internalName("신전") + .chosung("신") + .phone("010-7788-9900") + .address("천안시 동남구 병천면 1600 신전떡볶이") + .description("신전떡볶이입니다.") + .delivery(true) + .deliveryPrice(2000) + .payCard(true) + .payBank(true) + .isDeleted(false) + .isEvent(false) + .remarks("비고") + .hit(0) + .build() + ); + shop.getShopImages().addAll( + List.of( + ShopImage.builder() + .shop(shop) + .imageUrl("https://test-image.com/신전.png") + .build(), + ShopImage.builder() + .shop(shop) + .imageUrl("https://test-image.com/신전2.png") + .build() + ) + ); + shop.getShopOpens().addAll( + List.of( + ShopOpen.builder() + .openTime(LocalTime.of(0, 0)) + .closeTime(LocalTime.of(21, 0)) + .shop(shop) + .closed(false) + .dayOfWeek("SUNDAY") + .build(), + ShopOpen.builder() + .openTime(LocalTime.of(0, 0)) + .closeTime(LocalTime.of(21, 0)) + .shop(shop) + .closed(false) + .dayOfWeek("FRIDAY") + .build() + ) + ); + return shopRepository.save(shop); + } + + public ShopFixtureBuilder builder() { + return new ShopFixtureBuilder(); + } + + public final class ShopFixtureBuilder { + + private Owner owner; + private String name; + private String internalName; + private String chosung; + private String phone; + private String address; + private String description; + private boolean delivery; + private Integer deliveryPrice; + private boolean payCard; + private boolean payBank; + private boolean isDeleted; + private boolean isEvent; + private String remarks; + private Integer hit; + private List shopCategories = new ArrayList<>(); + private List shopOpens = new ArrayList<>(); + private List shopImages = new ArrayList<>(); + private List menuCategories = new ArrayList<>(); + + public ShopFixtureBuilder owner(Owner owner) { + this.owner = owner; + return this; + } + + public ShopFixtureBuilder name(String name) { + this.name = name; + return this; + } + + public ShopFixtureBuilder internalName(String internalName) { + this.internalName = internalName; + return this; + } + + public ShopFixtureBuilder chosung(String chosung) { + this.chosung = chosung; + return this; + } + + public ShopFixtureBuilder phone(String phone) { + this.phone = phone; + return this; + } + + public ShopFixtureBuilder address(String address) { + this.address = address; + return this; + } + + public ShopFixtureBuilder description(String description) { + this.description = description; + return this; + } + + public ShopFixtureBuilder delivery(boolean delivery) { + this.delivery = delivery; + return this; + } + + public ShopFixtureBuilder deliveryPrice(Integer deliveryPrice) { + this.deliveryPrice = deliveryPrice; + return this; + } + + public ShopFixtureBuilder payCard(boolean payCard) { + this.payCard = payCard; + return this; + } + + public ShopFixtureBuilder payBank(boolean payBank) { + this.payBank = payBank; + return this; + } + + public ShopFixtureBuilder isDeleted(boolean isDeleted) { + this.isDeleted = isDeleted; + return this; + } + + public ShopFixtureBuilder isEvent(boolean isEvent) { + this.isEvent = isEvent; + return this; + } + + public ShopFixtureBuilder remarks(String remarks) { + this.remarks = remarks; + return this; + } + + public ShopFixtureBuilder hit(Integer hit) { + this.hit = hit; + return this; + } + + public ShopFixtureBuilder shopCategories(List shopCategories) { + this.shopCategories = shopCategories; + return this; + } + + public ShopFixtureBuilder shopOpens(List shopOpens) { + this.shopOpens = shopOpens; + return this; + } + + public ShopFixtureBuilder shopImages(List shopImages) { + this.shopImages = shopImages; + return this; + } + + public ShopFixtureBuilder menuCategories(List menuCategories) { + this.menuCategories = menuCategories; + return this; + } + + public Shop build() { + var shop = shopRepository.save( + Shop.builder() + .description(description) + .owner(owner) + .phone(phone) + .address(address) + .payCard(payCard) + .isDeleted(isDeleted) + .isEvent(isEvent) + .delivery(delivery) + .hit(hit) + .internalName(internalName) + .name(name) + .chosung(chosung) + .deliveryPrice(deliveryPrice) + .remarks(remarks) + .payBank(payBank) + .build() + ); + shop.getShopOpens().addAll(shopOpens); + shop.getShopImages().addAll(shopImages); + shop.getMenuCategories().addAll(menuCategories); + shop.getShopCategories().addAll(shopCategories); + return shopRepository.save(shop); + } + } +} diff --git a/src/test/java/in/koreatech/koin/fixture/TechStackFixture.java b/src/test/java/in/koreatech/koin/fixture/TechStackFixture.java new file mode 100644 index 000000000..a8b833531 --- /dev/null +++ b/src/test/java/in/koreatech/koin/fixture/TechStackFixture.java @@ -0,0 +1,28 @@ +package in.koreatech.koin.fixture; + +import org.springframework.stereotype.Component; + +import in.koreatech.koin.domain.member.model.TechStack; +import in.koreatech.koin.domain.member.model.Track; +import in.koreatech.koin.domain.member.repository.TechStackRepository; + +@Component +public class TechStackFixture { + + private final TechStackRepository techStackRepository; + + public TechStackFixture(TechStackRepository techStackRepository) { + this.techStackRepository = techStackRepository; + } + + public TechStack java(Track track) { + return techStackRepository.save( + TechStack.builder() + .imageUrl("https://testimageurl.com") + .trackId(track.getId()) + .name("Java") + .description("Language") + .build() + ); + } +} diff --git a/src/test/java/in/koreatech/koin/fixture/TimeTableFixture.java b/src/test/java/in/koreatech/koin/fixture/TimeTableFixture.java new file mode 100644 index 000000000..b2c94ebf3 --- /dev/null +++ b/src/test/java/in/koreatech/koin/fixture/TimeTableFixture.java @@ -0,0 +1,107 @@ +package in.koreatech.koin.fixture; + +import org.springframework.stereotype.Component; + +import in.koreatech.koin.domain.timetable.model.Semester; +import in.koreatech.koin.domain.timetable.model.TimeTable; +import in.koreatech.koin.domain.timetable.repository.TimeTableRepository; +import in.koreatech.koin.domain.user.model.User; + +@Component +@SuppressWarnings("NonAsciiCharacters") +public class TimeTableFixture { + + private final TimeTableRepository timeTableRepository; + + public TimeTableFixture(TimeTableRepository timeTableRepository) { + this.timeTableRepository = timeTableRepository; + } + + public TimeTable 컴퓨터구조(User user, Semester semester) { + return timeTableRepository.save( + TimeTable.builder() + .user(user) + .semester(semester) + .code("CS101") + .classTitle("컴퓨터 구조") + .classTime("[14, 15, 16, 17, 204, 205, 206, 207]") + .classPlace(null) + .professor("김성재") + .grades("3") + .lectureClass("02") + .target("컴부전체") + .regularNumber("28") + .designScore("0") + .department("컴퓨터공학부") + .memo(null) + .isDeleted(false) + .build() + ); + } + + public TimeTable 운영체제(User user, Semester semester) { + return timeTableRepository.save( + TimeTable.builder() + .user(user) + .semester(semester) + .code("CS102") + .classTitle("운영체제") + .classTime("[932]") + .classPlace(null) + .professor("김원경") + .grades("3") + .lectureClass("01") + .target("컴부전체") + .regularNumber("40") + .designScore("0") + .department("컴퓨터공학부") + .memo(null) + .isDeleted(false) + .build() + ); + } + + public TimeTable 이산수학(User user, Semester semester) { + return timeTableRepository.save( + TimeTable.builder() + .user(user) + .semester(semester) + .code("CSE125") + .classTitle("이산수학") + .classTime("[14, 15, 16, 17, 312, 313]") + .classPlace(null) + .professor("서정빈") + .grades("3") + .lectureClass("01") + .target("컴부전체") + .regularNumber("40") + .designScore("0") + .department("컴퓨터공학부") + .memo(null) + .isDeleted(false) + .build() + ); + } + + public TimeTable 알고리즘및실습(User user, Semester semester) { + return timeTableRepository.save( + TimeTable.builder() + .user(user) + .semester(semester) + .code("CSE130") + .classTitle("알고리즘및실습") + .classTime("[14, 15, 16, 17, 310, 311, 312, 313]") + .classPlace(null) + .professor("박다희") + .grades("3") + .lectureClass("03") + .target("컴부전체") + .regularNumber("32") + .designScore("0") + .department("컴퓨터공학부") + .memo(null) + .isDeleted(false) + .build() + ); + } +} diff --git a/src/test/java/in/koreatech/koin/fixture/TrackFixture.java b/src/test/java/in/koreatech/koin/fixture/TrackFixture.java new file mode 100644 index 000000000..5b669dcd9 --- /dev/null +++ b/src/test/java/in/koreatech/koin/fixture/TrackFixture.java @@ -0,0 +1,40 @@ +package in.koreatech.koin.fixture; + +import org.springframework.stereotype.Component; + +import in.koreatech.koin.domain.member.model.Track; +import in.koreatech.koin.domain.member.repository.TrackRepository; + +@Component +public class TrackFixture { + + private final TrackRepository trackRepository; + + public TrackFixture(TrackRepository trackRepository) { + this.trackRepository = trackRepository; + } + + public Track backend() { + return trackRepository.save( + Track.builder() + .name("BackEnd") + .build() + ); + } + + public Track frontend() { + return trackRepository.save( + Track.builder() + .name("FrontEnd") + .build() + ); + } + + public Track ios() { + return trackRepository.save( + Track.builder() + .name("iOS") + .build() + ); + } +} diff --git a/src/test/java/in/koreatech/koin/fixture/UserFixture.java b/src/test/java/in/koreatech/koin/fixture/UserFixture.java new file mode 100644 index 000000000..2bd45ccff --- /dev/null +++ b/src/test/java/in/koreatech/koin/fixture/UserFixture.java @@ -0,0 +1,316 @@ +package in.koreatech.koin.fixture; + +import static in.koreatech.koin.domain.user.model.UserGender.MAN; +import static in.koreatech.koin.domain.user.model.UserIdentity.UNDERGRADUATE; +import static in.koreatech.koin.domain.user.model.UserType.COOP; +import static in.koreatech.koin.domain.user.model.UserType.OWNER; +import static in.koreatech.koin.domain.user.model.UserType.STUDENT; + +import java.time.LocalDateTime; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Component; + +import in.koreatech.koin.domain.owner.model.Owner; +import in.koreatech.koin.domain.owner.model.OwnerAttachment; +import in.koreatech.koin.domain.owner.repository.OwnerRepository; +import in.koreatech.koin.domain.user.model.Student; +import in.koreatech.koin.domain.user.model.User; +import in.koreatech.koin.domain.user.model.UserGender; +import in.koreatech.koin.domain.user.model.UserType; +import in.koreatech.koin.domain.user.repository.StudentRepository; +import in.koreatech.koin.domain.user.repository.UserRepository; +import in.koreatech.koin.global.auth.JwtProvider; + +@Component +@SuppressWarnings("NonAsciiCharacters") +public final class UserFixture { + + private final PasswordEncoder passwordEncoder; + private final UserRepository userRepository; + private final OwnerRepository ownerRepository; + private final StudentRepository studentRepository; + private final JwtProvider jwtProvider; + + @Autowired + public UserFixture( + PasswordEncoder passwordEncoder, + UserRepository userRepository, + OwnerRepository ownerRepository, + StudentRepository studentRepository, + JwtProvider jwtProvider + ) { + this.passwordEncoder = passwordEncoder; + this.userRepository = userRepository; + this.ownerRepository = ownerRepository; + this.studentRepository = studentRepository; + this.jwtProvider = jwtProvider; + } + + public Student 준호_학생() { + return studentRepository.save( + Student.builder() + .studentNumber("2019136135") + .anonymousNickname("익명") + .department("컴퓨터공학부") + .userIdentity(UNDERGRADUATE) + .isGraduated(false) + .user( + User.builder() + .password(passwordEncoder.encode("1234")) + .nickname("준호") + .name("테스트용_준호") + .phoneNumber("010-1234-5678") + .userType(STUDENT) + .gender(MAN) + .email("juno@koreatech.ac.kr") + .isAuthed(true) + .isDeleted(false) + .build() + ) + .build() + ); + } + + public Student 성빈_학생() { + return studentRepository.save( + Student.builder() + .studentNumber("2023100514") + .anonymousNickname("익명123") + .department("컴퓨터공학부") + .userIdentity(UNDERGRADUATE) + .isGraduated(false) + .user( + User.builder() + .password(passwordEncoder.encode("1234")) + .nickname("성빈") + .name("테스트용_성빈") + .phoneNumber("010-9941-1123") + .userType(STUDENT) + .gender(MAN) + .email("testsungbeen@koreatech.ac.kr") + .isAuthed(true) + .isDeleted(false) + .build() + ) + .build() + ); + } + + public Owner 현수_사장님() { + return ownerRepository.save( + Owner.builder() + .companyRegistrationNumber("123-45-67190") + .attachments(List.of( + OwnerAttachment.builder() + .url("https://test.com/현수_사장님_인증사진_1.jpg") + .isDeleted(false) + .build(), + OwnerAttachment.builder() + .url("https://test.com/현수_사장님_인증사진_2.jpg") + .isDeleted(false) + .build() + ) + ) + .grantShop(true) + .grantEvent(true) + .user( + User.builder() + .password(passwordEncoder.encode("1234")) + .nickname("현수") + .name("테스트용_현수") + .phoneNumber("010-9876-5432") + .userType(OWNER) + .gender(MAN) + .email("hysoo@naver.com") + .isAuthed(true) + .isDeleted(false) + .build() + ) + .build() + ); + } + + public Owner 준영_사장님() { + return ownerRepository.save( + Owner.builder() + .companyRegistrationNumber("112-80-56789") + .attachments(List.of( + OwnerAttachment.builder() + .url("https://test.com/준영_사장님_인증사진_1.jpg") + .isDeleted(false) + .build(), + OwnerAttachment.builder() + .url("https://test.com/준영_사장님_인증사진_2.jpg") + .isDeleted(false) + .build() + ) + ) + .grantShop(true) + .grantEvent(true) + .user( + User.builder() + .password(passwordEncoder.encode("1234")) + .nickname("준영") + .name("테스트용_준영") + .phoneNumber("010-9776-5112") + .userType(OWNER) + .gender(MAN) + .email("testjoonyoung@gmail.com") + .isAuthed(true) + .isDeleted(false) + .build() + ) + .build() + ); + } + + public User 준기_영양사() { + return userRepository.save( + User.builder() + .password(passwordEncoder.encode("1234")) + .nickname("준기") + .name("허준기") + .phoneNumber("010-1122-5678") + .userType(COOP) + .gender(MAN) + .email("coop@koreatech.ac.kr") + .isAuthed(true) + .isDeleted(false) + .build() + ); + } + + public String getToken(User user) { + return jwtProvider.createToken(user); + } + + public UserFixtureBuilder builder() { + return new UserFixtureBuilder(); + } + + public final class UserFixtureBuilder { + + private String password; + private String nickname; + private String name; + private String phoneNumber; + private UserType userType; + private String email; + private UserGender gender; + private boolean isAuthed; + private LocalDateTime lastLoggedAt; + private String profileImageUrl; + private Boolean isDeleted; + private String authToken; + private LocalDateTime authExpiredAt; + private String resetToken; + private LocalDateTime resetExpiredAt; + private String deviceToken; + + public UserFixtureBuilder password(String password) { + this.password = passwordEncoder.encode(password); + return this; + } + + public UserFixtureBuilder nickname(String nickname) { + this.nickname = nickname; + return this; + } + + public UserFixtureBuilder name(String name) { + this.name = name; + return this; + } + + public UserFixtureBuilder phoneNumber(String phoneNumber) { + this.phoneNumber = phoneNumber; + return this; + } + + public UserFixtureBuilder userType(UserType userType) { + this.userType = userType; + return this; + } + + public UserFixtureBuilder email(String email) { + this.email = email; + return this; + } + + public UserFixtureBuilder gender(UserGender gender) { + this.gender = gender; + return this; + } + + public UserFixtureBuilder isAuthed(boolean isAuthed) { + this.isAuthed = isAuthed; + return this; + } + + public UserFixtureBuilder lastLoggedAt(LocalDateTime lastLoggedAt) { + this.lastLoggedAt = lastLoggedAt; + return this; + } + + public UserFixtureBuilder profileImageUrl(String profileImageUrl) { + this.profileImageUrl = profileImageUrl; + return this; + } + + public UserFixtureBuilder isDeleted(Boolean isDeleted) { + this.isDeleted = isDeleted; + return this; + } + + public UserFixtureBuilder authToken(String authToken) { + this.authToken = authToken; + return this; + } + + public UserFixtureBuilder authExpiredAt(LocalDateTime authExpiredAt) { + this.authExpiredAt = authExpiredAt; + return this; + } + + public UserFixtureBuilder resetToken(String resetToken) { + this.resetToken = resetToken; + return this; + } + + public UserFixtureBuilder resetExpiredAt(LocalDateTime resetExpiredAt) { + this.resetExpiredAt = resetExpiredAt; + return this; + } + + public UserFixtureBuilder deviceToken(String deviceToken) { + this.deviceToken = deviceToken; + return this; + } + + public User build() { + return userRepository.save( + User.builder() + .phoneNumber(phoneNumber) + .authExpiredAt(authExpiredAt) + .deviceToken(deviceToken) + .lastLoggedAt(lastLoggedAt) + .isAuthed(isAuthed) + .resetExpiredAt(resetExpiredAt) + .resetToken(resetToken) + .nickname(nickname) + .authToken(authToken) + .isDeleted(isDeleted) + .email(email) + .profileImageUrl(profileImageUrl) + .gender(gender) + .password(password) + .userType(userType) + .name(name) + .build() + ); + } + } +} diff --git a/src/test/java/in/koreatech/koin/global/domain/upload/UploadServiceTest.java b/src/test/java/in/koreatech/koin/global/domain/upload/UploadServiceTest.java index cc19476e8..a7e472cd6 100644 --- a/src/test/java/in/koreatech/koin/global/domain/upload/UploadServiceTest.java +++ b/src/test/java/in/koreatech/koin/global/domain/upload/UploadServiceTest.java @@ -1,12 +1,9 @@ package in.koreatech.koin.global.domain.upload; import static in.koreatech.koin.global.domain.upload.model.ImageUploadDomain.OWNERS; -import static java.time.format.DateTimeFormatter.ofPattern; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.when; import java.time.Clock; -import java.time.ZonedDateTime; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; @@ -66,13 +63,10 @@ void setUp() { @Test void 이미지_확장자를_받아_이미지_이름을_UUID로_생성_후_Presigned_URL을_생성하여_반환한다() { // given - when(clock.instant()).thenReturn( - ZonedDateTime.parse("2024-02-21 18:00:00 KST", ofPattern("yyyy-MM-dd " + "HH:mm:ss z")).toInstant()); - when(clock.getZone()).thenReturn(Clock.systemDefaultZone().getZone()); S3Utils utils = new S3Utils( presigner, s3Client, - clock, + Clock.systemDefaultZone(), "test-bucket", "https://test-image.koreatech.in/" ); @@ -84,7 +78,7 @@ void setUp() { "hello.png" ); - UploadService uploadService = new UploadService(utils, clock); + UploadService uploadService = new UploadService(utils, Clock.systemDefaultZone()); var url = uploadService.getPresignedUrl(OWNERS, request); // then diff --git a/src/test/java/in/koreatech/koin/support/JsonAssertions.java b/src/test/java/in/koreatech/koin/support/JsonAssertions.java index 4896a3ca7..c7ef8b5d7 100644 --- a/src/test/java/in/koreatech/koin/support/JsonAssertions.java +++ b/src/test/java/in/koreatech/koin/support/JsonAssertions.java @@ -1,5 +1,7 @@ package in.koreatech.koin.support; +import java.io.IOException; +import java.util.List; import java.util.Map; import org.assertj.core.api.Assertions; @@ -9,6 +11,7 @@ public class JsonAssertions { + private static final ObjectMapper objectMapper = new ObjectMapper(); public static JsonStringAssert assertThat(String expect) { return new JsonStringAssert(expect); @@ -16,7 +19,6 @@ public static JsonStringAssert assertThat(String expect) { public static class JsonStringAssert { - private final ObjectMapper objectMapper = new ObjectMapper(); private final String expect; JsonStringAssert(String expect) { @@ -25,13 +27,22 @@ public static class JsonStringAssert { public void isEqualTo(String actual) { try { - Map responseMap = objectMapper.readValue(expect, new TypeReference<>() { + Object responseObj = parseJson(expect); + Object expectedObj = parseJson(actual); + + Assertions.assertThat(responseObj).isEqualTo(expectedObj); + } catch (Exception e) { + throw new AssertionError("json parsing error\n" + e.getMessage()); + } + } + + private Object parseJson(String json) throws IOException { + try { + return objectMapper.readValue(json, new TypeReference>() { }); - Map expectedMap = objectMapper.readValue(actual, new TypeReference<>() { + } catch (IOException e) { + return objectMapper.readValue(json, new TypeReference>() { }); - Assertions.assertThat(responseMap).isEqualTo(expectedMap); - } catch (Exception ignored) { - } } } diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml index 42d4281f5..23be46e1d 100644 --- a/src/test/resources/application.yml +++ b/src/test/resources/application.yml @@ -44,8 +44,8 @@ slack: aws: ses: - access-key: - secret-key: + access-key: testck + secret-key: testsk s3: key: test-ck @@ -57,11 +57,7 @@ koin: admin: url: https://admin-url-path.com -fcm: - koin: - url: koinAppUrl:// - -OPEN_API_KEY: +OPEN_API_KEY: test cors: allowedOrigins: