From 6b8ddcf63f89469bf6ccae527ccc1cd3d28b18cc Mon Sep 17 00:00:00 2001 From: pushedrumex Date: Tue, 10 Dec 2024 16:40:12 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EB=A7=A4=EC=9E=A5=20=EC=A7=80=EC=97=AD?= =?UTF-8?q?=20=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20API=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/verby/indp/domain/region/Region.java | 37 ++++++++++++++ .../region/controller/RegionController.java | 22 +++++++++ .../region/repository/RegionRepository.java | 14 ++++++ .../domain/region/service/RegionService.java | 22 +++++++++ .../indp/domain/region/vo/RegionName.java | 20 ++++++++ .../com/verby/indp/domain/store/Store.java | 13 +++-- .../indp/domain/store/constant/Region.java | 9 ---- .../store/controller/StoreController.java | 3 +- .../dto/response/FindRegionsResponse.java | 15 ++++++ .../store/repository/StoreRepository.java | 2 +- .../domain/store/service/StoreService.java | 25 ++++++++-- .../RecommendationAcceptanceTest.java | 11 ++++- .../indp/acceptance/StoreAcceptanceTest.java | 26 +++++++--- .../acceptance/support/StoreApiSupporter.java | 3 +- .../verby/indp/domain/BaseControllerTest.java | 4 ++ .../recommendation/RecommendationTest.java | 5 +- .../RecommendationControllerTest.java | 7 ++- .../service/RecommendationServiceTest.java | 5 +- .../controller/RegionControllerTest.java | 45 +++++++++++++++++ .../domain/region/fixture/RegionFixture.java | 11 +++++ .../region/service/RegionServiceTest.java | 48 +++++++++++++++++++ .../store/controller/StoreControllerTest.java | 35 +++++++------- .../domain/store/fixture/StoreFixture.java | 16 ++++--- .../store/repository/StoreRepositoryTest.java | 18 +++++-- .../store/service/StoreServiceTest.java | 39 ++++++++++----- 25 files changed, 378 insertions(+), 77 deletions(-) create mode 100644 src/main/java/com/verby/indp/domain/region/Region.java create mode 100644 src/main/java/com/verby/indp/domain/region/controller/RegionController.java create mode 100644 src/main/java/com/verby/indp/domain/region/repository/RegionRepository.java create mode 100644 src/main/java/com/verby/indp/domain/region/service/RegionService.java create mode 100644 src/main/java/com/verby/indp/domain/region/vo/RegionName.java delete mode 100644 src/main/java/com/verby/indp/domain/store/constant/Region.java create mode 100644 src/main/java/com/verby/indp/domain/store/dto/response/FindRegionsResponse.java create mode 100644 src/test/java/com/verby/indp/domain/region/controller/RegionControllerTest.java create mode 100644 src/test/java/com/verby/indp/domain/region/fixture/RegionFixture.java create mode 100644 src/test/java/com/verby/indp/domain/region/service/RegionServiceTest.java diff --git a/src/main/java/com/verby/indp/domain/region/Region.java b/src/main/java/com/verby/indp/domain/region/Region.java new file mode 100644 index 0000000..ecb4778 --- /dev/null +++ b/src/main/java/com/verby/indp/domain/region/Region.java @@ -0,0 +1,37 @@ +package com.verby.indp.domain.region; + +import com.verby.indp.domain.region.vo.RegionName; +import jakarta.persistence.Column; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Entity +@Table(name = "region") +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class Region { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "region_id") + private Long regionId; + + @Embedded + private RegionName name; + + @Column(name = "sequence") + private Integer sequence = Integer.MAX_VALUE; + + public Region(String name) { + this.name = new RegionName(name); + } + + public String getRegion() { + return name.getName(); + } +} diff --git a/src/main/java/com/verby/indp/domain/region/controller/RegionController.java b/src/main/java/com/verby/indp/domain/region/controller/RegionController.java new file mode 100644 index 0000000..e566b2c --- /dev/null +++ b/src/main/java/com/verby/indp/domain/region/controller/RegionController.java @@ -0,0 +1,22 @@ +package com.verby.indp.domain.region.controller; + +import com.verby.indp.domain.region.service.RegionService; +import com.verby.indp.domain.store.dto.response.FindRegionsResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api") +@RequiredArgsConstructor +public class RegionController { + + private final RegionService regionService; + + @GetMapping("/regions") + public ResponseEntity findRegions() { + return ResponseEntity.ok(regionService.findRegions()); + } +} diff --git a/src/main/java/com/verby/indp/domain/region/repository/RegionRepository.java b/src/main/java/com/verby/indp/domain/region/repository/RegionRepository.java new file mode 100644 index 0000000..9eca93d --- /dev/null +++ b/src/main/java/com/verby/indp/domain/region/repository/RegionRepository.java @@ -0,0 +1,14 @@ +package com.verby.indp.domain.region.repository; + +import com.verby.indp.domain.region.Region; +import com.verby.indp.domain.region.vo.RegionName; +import java.util.List; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface RegionRepository extends JpaRepository { + + Optional findByName(RegionName name); + + List findAllByOrderBySequenceAsc(); +} diff --git a/src/main/java/com/verby/indp/domain/region/service/RegionService.java b/src/main/java/com/verby/indp/domain/region/service/RegionService.java new file mode 100644 index 0000000..4d8027e --- /dev/null +++ b/src/main/java/com/verby/indp/domain/region/service/RegionService.java @@ -0,0 +1,22 @@ +package com.verby.indp.domain.region.service; + +import com.verby.indp.domain.region.Region; +import com.verby.indp.domain.region.repository.RegionRepository; +import com.verby.indp.domain.store.dto.response.FindRegionsResponse; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class RegionService { + + private final RegionRepository regionRepository; + + public FindRegionsResponse findRegions() { + List regions = regionRepository.findAllByOrderBySequenceAsc(); + return FindRegionsResponse.from(regions); + } +} diff --git a/src/main/java/com/verby/indp/domain/region/vo/RegionName.java b/src/main/java/com/verby/indp/domain/region/vo/RegionName.java new file mode 100644 index 0000000..08da3f7 --- /dev/null +++ b/src/main/java/com/verby/indp/domain/region/vo/RegionName.java @@ -0,0 +1,20 @@ +package com.verby.indp.domain.region.vo; + +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Embeddable +@NoArgsConstructor(access = lombok.AccessLevel.PROTECTED) +public class RegionName { + + @Column(name = "name") + private String name; + + public RegionName(String name) { + this.name = name; + } + +} diff --git a/src/main/java/com/verby/indp/domain/store/Store.java b/src/main/java/com/verby/indp/domain/store/Store.java index fad1b30..032cad4 100644 --- a/src/main/java/com/verby/indp/domain/store/Store.java +++ b/src/main/java/com/verby/indp/domain/store/Store.java @@ -1,21 +1,20 @@ package com.verby.indp.domain.store; -import static jakarta.persistence.EnumType.STRING; - import com.verby.indp.domain.common.entity.BaseTimeEntity; import com.verby.indp.domain.common.vo.Address; +import com.verby.indp.domain.region.Region; import com.verby.indp.domain.song.SongForm; -import com.verby.indp.domain.store.constant.Region; import com.verby.indp.domain.store.vo.StoreName; import com.verby.indp.domain.theme.Theme; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Embedded; import jakarta.persistence.Entity; -import jakarta.persistence.Enumerated; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; import jakarta.persistence.Table; import java.util.ArrayList; @@ -41,8 +40,8 @@ public class Store extends BaseTimeEntity { @Embedded private Address address; - @Enumerated(STRING) - @Column(name = "region") + @ManyToOne + @JoinColumn(name = "region_id") private Region region; @OneToMany(mappedBy = "store", orphanRemoval = true, cascade = CascadeType.ALL) @@ -136,7 +135,7 @@ public String getName() { } public String getRegion() { - return region.name(); + return region.getRegion(); } public String getAddress() { diff --git a/src/main/java/com/verby/indp/domain/store/constant/Region.java b/src/main/java/com/verby/indp/domain/store/constant/Region.java deleted file mode 100644 index be20944..0000000 --- a/src/main/java/com/verby/indp/domain/store/constant/Region.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.verby.indp.domain.store.constant; - -public enum Region { - 서울, - 경기, - 대전, - 부산, - ; -} diff --git a/src/main/java/com/verby/indp/domain/store/controller/StoreController.java b/src/main/java/com/verby/indp/domain/store/controller/StoreController.java index bc7d332..f385300 100644 --- a/src/main/java/com/verby/indp/domain/store/controller/StoreController.java +++ b/src/main/java/com/verby/indp/domain/store/controller/StoreController.java @@ -1,6 +1,5 @@ package com.verby.indp.domain.store.controller; -import com.verby.indp.domain.store.constant.Region; import com.verby.indp.domain.store.dto.request.AddStoreByAdminRequest; import com.verby.indp.domain.store.dto.request.UpdateStoreByAdminRequest; import com.verby.indp.domain.store.dto.response.FindSimpleStoresResponse; @@ -37,7 +36,7 @@ public ResponseEntity findSimpleStores(Pageable pageab @GetMapping("/stores") public ResponseEntity findStores( Pageable pageable, - @RequestParam(name = "region", required = false) Region region + @RequestParam(name = "region", required = false) String region ) { return ResponseEntity.ok(storeService.findStores(pageable, region)); } diff --git a/src/main/java/com/verby/indp/domain/store/dto/response/FindRegionsResponse.java b/src/main/java/com/verby/indp/domain/store/dto/response/FindRegionsResponse.java new file mode 100644 index 0000000..4f0c8aa --- /dev/null +++ b/src/main/java/com/verby/indp/domain/store/dto/response/FindRegionsResponse.java @@ -0,0 +1,15 @@ +package com.verby.indp.domain.store.dto.response; + +import com.verby.indp.domain.region.Region; +import java.util.List; + +public record FindRegionsResponse(List regions) { + + public static FindRegionsResponse from(List regions) { + List stringRegions = regions.stream() + .map(Region::getRegion) + .toList(); + + return new FindRegionsResponse(stringRegions); + } +} diff --git a/src/main/java/com/verby/indp/domain/store/repository/StoreRepository.java b/src/main/java/com/verby/indp/domain/store/repository/StoreRepository.java index 1c3f412..26eca4c 100644 --- a/src/main/java/com/verby/indp/domain/store/repository/StoreRepository.java +++ b/src/main/java/com/verby/indp/domain/store/repository/StoreRepository.java @@ -1,7 +1,7 @@ package com.verby.indp.domain.store.repository; +import com.verby.indp.domain.region.Region; import com.verby.indp.domain.store.Store; -import com.verby.indp.domain.store.constant.Region; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/src/main/java/com/verby/indp/domain/store/service/StoreService.java b/src/main/java/com/verby/indp/domain/store/service/StoreService.java index 3779ce3..3127e7f 100644 --- a/src/main/java/com/verby/indp/domain/store/service/StoreService.java +++ b/src/main/java/com/verby/indp/domain/store/service/StoreService.java @@ -1,11 +1,14 @@ package com.verby.indp.domain.store.service; + import com.verby.indp.domain.common.exception.NotFoundException; +import com.verby.indp.domain.region.Region; +import com.verby.indp.domain.region.repository.RegionRepository; +import com.verby.indp.domain.region.vo.RegionName; import com.verby.indp.domain.song.SongForm; import com.verby.indp.domain.song.repository.SongFormRepository; import com.verby.indp.domain.song.vo.SongFormName; import com.verby.indp.domain.store.Store; -import com.verby.indp.domain.store.constant.Region; import com.verby.indp.domain.store.dto.request.AddStoreByAdminRequest; import com.verby.indp.domain.store.dto.request.UpdateStoreByAdminRequest; import com.verby.indp.domain.store.dto.response.FindSimpleStoresResponse; @@ -32,6 +35,7 @@ public class StoreService { private final StoreRepository storeRepository; private final ThemeRepository themeRepository; private final SongFormRepository songFormRepository; + private final RegionRepository regionRepository; public FindSimpleStoresResponse findSimpleStores(Pageable pageable) { Page page = storeRepository.findAllByOrderByStoreIdAsc(pageable); @@ -39,14 +43,15 @@ public FindSimpleStoresResponse findSimpleStores(Pageable pageable) { return FindSimpleStoresResponse.from(page); } - public FindStoresResponse findStores(Pageable pageable, Region region) { - if (region == null) { + public FindStoresResponse findStores(Pageable pageable, String regionName) { + if (regionName == null) { Page page = storeRepository.findAllByOrderByStoreIdAsc( pageable); return FindStoresResponse.from(page); } + Region region = getRegionByName(regionName); Page page = storeRepository.findAllByRegionOrderByStoreIdAsc(pageable, region); return FindStoresResponse.from(page); @@ -74,7 +79,7 @@ public long addStore(AddStoreByAdminRequest request) { Store store = new Store( request.name(), request.address(), - Region.valueOf(request.region()), + getRegion(request.name()), List.of(request.imageUrl()), getThemes(request.themes()), getSongForms(request.songForms()) @@ -89,7 +94,7 @@ public void updateStore(Long storeId, UpdateStoreByAdminRequest request) { store.update( request.name(), request.address(), - Region.valueOf(request.region()), + getRegion(request.name()), List.of(request.imageUrl()), getThemes(request.themes()), getSongForms(request.songForms()) @@ -121,8 +126,18 @@ private ArrayList getThemes(List names) { return themes; } + private Region getRegion(String name) { + return regionRepository.findByName(new RegionName(name)) + .orElseGet(() -> regionRepository.save(new Region(name))); + } + private Store getStoreById(long storeId) { return storeRepository.findById(storeId) .orElseThrow(() -> new NotFoundException("존재하지 않는 매장입니다.")); } + + private Region getRegionByName(String name) { + return regionRepository.findByName(new RegionName(name)) + .orElseThrow(() -> new NotFoundException("등록되지 않은 지역입니다.")); + } } diff --git a/src/test/java/com/verby/indp/acceptance/RecommendationAcceptanceTest.java b/src/test/java/com/verby/indp/acceptance/RecommendationAcceptanceTest.java index 3f7f3e5..6348cbc 100644 --- a/src/test/java/com/verby/indp/acceptance/RecommendationAcceptanceTest.java +++ b/src/test/java/com/verby/indp/acceptance/RecommendationAcceptanceTest.java @@ -1,10 +1,13 @@ package com.verby.indp.acceptance; +import static com.verby.indp.domain.region.fixture.RegionFixture.region; import static com.verby.indp.domain.store.fixture.StoreFixture.store; import static org.assertj.core.api.Assertions.assertThat; import com.verby.indp.acceptance.support.RecommendationSupporter; import com.verby.indp.domain.recommendation.dto.request.RegisterRecommendationRequest; +import com.verby.indp.domain.region.Region; +import com.verby.indp.domain.region.repository.RegionRepository; import com.verby.indp.domain.store.Store; import com.verby.indp.domain.store.repository.StoreRepository; import io.restassured.response.ExtractableResponse; @@ -19,11 +22,17 @@ class RecommendationAcceptanceTest extends BaseAcceptanceTest { @Autowired private StoreRepository storeRepository; + @Autowired + private RegionRepository regionRepository; + @Test @DisplayName("추천 음악 정보를 등록한다.") void registerRecommendation() { // given - Store store = store(); + Region 서울 = region("서울"); + regionRepository.save(서울); + + Store store = store(서울); storeRepository.save(store); String information = "아이유-밤편지"; diff --git a/src/test/java/com/verby/indp/acceptance/StoreAcceptanceTest.java b/src/test/java/com/verby/indp/acceptance/StoreAcceptanceTest.java index 6e3af68..4dcd9e6 100644 --- a/src/test/java/com/verby/indp/acceptance/StoreAcceptanceTest.java +++ b/src/test/java/com/verby/indp/acceptance/StoreAcceptanceTest.java @@ -1,18 +1,18 @@ package com.verby.indp.acceptance; +import static com.verby.indp.domain.region.fixture.RegionFixture.region; import static com.verby.indp.domain.song.fixture.SongFormFixture.songForm; -import static com.verby.indp.domain.store.constant.Region.경기; -import static com.verby.indp.domain.store.constant.Region.서울; import static com.verby.indp.domain.store.fixture.StoreFixture.stores; import static com.verby.indp.domain.theme.fixture.ThemeFixture.theme; import static org.assertj.core.api.Assertions.assertThat; import com.verby.indp.acceptance.support.StoreApiSupporter; +import com.verby.indp.domain.region.Region; +import com.verby.indp.domain.region.repository.RegionRepository; import com.verby.indp.domain.song.SongForm; import com.verby.indp.domain.song.repository.SongFormRepository; import com.verby.indp.domain.store.Store; -import com.verby.indp.domain.store.constant.Region; import com.verby.indp.domain.store.dto.response.FindSimpleStoresResponse; import com.verby.indp.domain.store.dto.response.FindStoresResponse; import com.verby.indp.domain.store.repository.StoreRepository; @@ -36,6 +36,9 @@ class StoreAcceptanceTest extends BaseAcceptanceTest { @Autowired private StoreRepository storeRepository; + @Autowired + private RegionRepository regionRepository; + @Autowired private ThemeRepository themeRepository; @@ -50,7 +53,9 @@ void findSimpleStores() { int page = 0; int size = 10; - List stores = stores(List.of(), List.of(), count); + Region 서울 = region("서울"); + regionRepository.save(서울); + List stores = stores(서울, List.of(), List.of(), count); storeRepository.saveAll(stores); Pageable pageable = PageRequest.of(page, size); @@ -72,7 +77,11 @@ void findSimpleStores() { @DisplayName("특정 지역의 매장 목록을 조회한다.") void findStoresOfRegion() { // given - Region region = 경기; + Region 서울 = region("서울"); + Region 경기 = region("경기"); + regionRepository.save(서울); + regionRepository.save(경기); + int seoulCount = 5; int gyeonggiCount = 15; @@ -102,7 +111,7 @@ void findStoresOfRegion() { FindStoresResponse expected = FindStoresResponse.from(pageStores); // when - ExtractableResponse result = StoreApiSupporter.findStores(page, size, region); + ExtractableResponse result = StoreApiSupporter.findStores(page, size, 경기.getRegion()); // then assertThat(result.statusCode()).isEqualTo(200); @@ -114,6 +123,11 @@ void findStoresOfRegion() { @DisplayName("전체 지역의 매장 목록을 조회한다.") void findStores() { // given + Region 서울 = region("서울"); + Region 경기 = region("경기"); + regionRepository.save(서울); + regionRepository.save(경기); + int seoulCount = 5; int gyeonggiCount = 15; diff --git a/src/test/java/com/verby/indp/acceptance/support/StoreApiSupporter.java b/src/test/java/com/verby/indp/acceptance/support/StoreApiSupporter.java index c035d7c..0d8625f 100644 --- a/src/test/java/com/verby/indp/acceptance/support/StoreApiSupporter.java +++ b/src/test/java/com/verby/indp/acceptance/support/StoreApiSupporter.java @@ -3,7 +3,6 @@ import static io.restassured.RestAssured.given; import static io.restassured.http.ContentType.JSON; -import com.verby.indp.domain.store.constant.Region; import io.restassured.response.ExtractableResponse; import io.restassured.response.Response; @@ -20,7 +19,7 @@ public static ExtractableResponse findSimpleStores(int page, int size) .extract(); } - public static ExtractableResponse findStores(int page, int size, Region region) { + public static ExtractableResponse findStores(int page, int size, String region) { return given().log().all() .accept(JSON) .when().log().all() diff --git a/src/test/java/com/verby/indp/domain/BaseControllerTest.java b/src/test/java/com/verby/indp/domain/BaseControllerTest.java index 0a208ec..b2f6c36 100644 --- a/src/test/java/com/verby/indp/domain/BaseControllerTest.java +++ b/src/test/java/com/verby/indp/domain/BaseControllerTest.java @@ -10,6 +10,7 @@ import com.verby.indp.domain.auth.service.AuthService; import com.verby.indp.domain.contact.service.ContactService; import com.verby.indp.domain.recommendation.service.RecommendationService; +import com.verby.indp.domain.region.service.RegionService; import com.verby.indp.domain.store.service.StoreService; import com.verby.indp.global.image.ImageService; import com.verby.indp.global.jwt.TokenManager; @@ -61,6 +62,9 @@ public abstract class BaseControllerTest { @MockBean protected ImageService imageService; + @MockBean + protected RegionService regionService; + protected String accessToken = accessToken(); @BeforeEach diff --git a/src/test/java/com/verby/indp/domain/recommendation/RecommendationTest.java b/src/test/java/com/verby/indp/domain/recommendation/RecommendationTest.java index 51cb645..d5b1fe4 100644 --- a/src/test/java/com/verby/indp/domain/recommendation/RecommendationTest.java +++ b/src/test/java/com/verby/indp/domain/recommendation/RecommendationTest.java @@ -1,10 +1,12 @@ package com.verby.indp.domain.recommendation; +import static com.verby.indp.domain.region.fixture.RegionFixture.region; import static com.verby.indp.domain.store.fixture.StoreFixture.store; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchException; import com.verby.indp.domain.common.exception.BadRequestException; +import com.verby.indp.domain.region.Region; import com.verby.indp.domain.store.Store; import java.util.List; import org.junit.jupiter.api.DisplayName; @@ -21,7 +23,8 @@ class NewRecommendation { @DisplayName("성공: Recommendation 을 생성한다.") void newRecommendation() { // given - Store store = store(List.of(), List.of()); + Region 서울 = region("서울"); + Store store = store(서울, List.of(), List.of()); String information = "공차"; String phoneNumber = "01012345678"; diff --git a/src/test/java/com/verby/indp/domain/recommendation/controller/RecommendationControllerTest.java b/src/test/java/com/verby/indp/domain/recommendation/controller/RecommendationControllerTest.java index cf56037..1be0103 100644 --- a/src/test/java/com/verby/indp/domain/recommendation/controller/RecommendationControllerTest.java +++ b/src/test/java/com/verby/indp/domain/recommendation/controller/RecommendationControllerTest.java @@ -1,6 +1,7 @@ package com.verby.indp.domain.recommendation.controller; import static com.verby.indp.domain.recommendation.fixture.RecommendationFixture.recommendation; +import static com.verby.indp.domain.region.fixture.RegionFixture.region; import static com.verby.indp.domain.store.fixture.StoreFixture.store; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.when; @@ -16,6 +17,7 @@ import com.verby.indp.domain.BaseControllerTest; import com.verby.indp.domain.recommendation.Recommendation; import com.verby.indp.domain.recommendation.dto.request.RegisterRecommendationRequest; +import com.verby.indp.domain.region.Region; import com.verby.indp.domain.store.Store; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -29,9 +31,10 @@ class RecommendationControllerTest extends BaseControllerTest { @DisplayName("성공: 추천 음악 정보를 등록한다.") void registerRecommendation() throws Exception { // given - Store store = store(); + Region 서울 = region("서울"); + Store store = store(서울); ReflectionTestUtils.setField(store, "storeId", 1L); - Recommendation recommendation = recommendation(store()); + Recommendation recommendation = recommendation(store(서울)); RegisterRecommendationRequest request = new RegisterRecommendationRequest(store.getStoreId(), recommendation.getInformation(), recommendation.getPhoneNumber()); diff --git a/src/test/java/com/verby/indp/domain/recommendation/service/RecommendationServiceTest.java b/src/test/java/com/verby/indp/domain/recommendation/service/RecommendationServiceTest.java index cc65055..06ebbd4 100644 --- a/src/test/java/com/verby/indp/domain/recommendation/service/RecommendationServiceTest.java +++ b/src/test/java/com/verby/indp/domain/recommendation/service/RecommendationServiceTest.java @@ -1,6 +1,7 @@ package com.verby.indp.domain.recommendation.service; import static com.verby.indp.domain.recommendation.fixture.RecommendationFixture.recommendation; +import static com.verby.indp.domain.region.fixture.RegionFixture.region; import static com.verby.indp.domain.store.fixture.StoreFixture.store; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchException; @@ -15,6 +16,7 @@ import com.verby.indp.domain.recommendation.dto.request.RegisterRecommendationRequest; import com.verby.indp.domain.recommendation.event.RecommendationMailEvent; import com.verby.indp.domain.recommendation.repository.RecommendationRepository; +import com.verby.indp.domain.region.Region; import com.verby.indp.domain.store.Store; import com.verby.indp.domain.store.repository.StoreRepository; import java.util.Optional; @@ -51,7 +53,8 @@ class RegisterRecommendation { @DisplayName("성공: 추천 음악 정보를 저장한다.") void registerRecommendation() { // given - Store store = store(); + Region 서울 = region("서울"); + Store store = store(서울); ReflectionTestUtils.setField(store, "storeId", 1L); Recommendation recommendation = recommendation(store); ReflectionTestUtils.setField(recommendation, "recommendationId", 1L); diff --git a/src/test/java/com/verby/indp/domain/region/controller/RegionControllerTest.java b/src/test/java/com/verby/indp/domain/region/controller/RegionControllerTest.java new file mode 100644 index 0000000..159118b --- /dev/null +++ b/src/test/java/com/verby/indp/domain/region/controller/RegionControllerTest.java @@ -0,0 +1,45 @@ +package com.verby.indp.domain.region.controller; + +import static com.verby.indp.domain.region.fixture.RegionFixture.region; +import static org.mockito.Mockito.when; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.payload.JsonFieldType.ARRAY; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.verby.indp.domain.BaseControllerTest; +import com.verby.indp.domain.region.Region; +import com.verby.indp.domain.store.dto.response.FindRegionsResponse; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.test.web.servlet.ResultActions; + +class RegionControllerTest extends BaseControllerTest { + + @Test + @DisplayName("성공 : 지역 목록을 조회한다.") + void findRegions() throws Exception { + // given + List regions = List.of(region("서울"), region("경기")); + FindRegionsResponse response = FindRegionsResponse.from(regions); + + when(regionService.findRegions()).thenReturn(response); + + // when + ResultActions resultActions = mockMvc.perform( + get("/api/regions") + ); + + // then + resultActions.andExpect(status().isOk()) + .andDo( + restDocs.document( + responseFields( + fieldWithPath("regions").type(ARRAY).description("매장 지역 목록") + ) + ) + ); + } +} diff --git a/src/test/java/com/verby/indp/domain/region/fixture/RegionFixture.java b/src/test/java/com/verby/indp/domain/region/fixture/RegionFixture.java new file mode 100644 index 0000000..e2e00c0 --- /dev/null +++ b/src/test/java/com/verby/indp/domain/region/fixture/RegionFixture.java @@ -0,0 +1,11 @@ +package com.verby.indp.domain.region.fixture; + +import com.verby.indp.domain.region.Region; + +public class RegionFixture { + + public static Region region(String name) { + return new Region(name); + } + +} diff --git a/src/test/java/com/verby/indp/domain/region/service/RegionServiceTest.java b/src/test/java/com/verby/indp/domain/region/service/RegionServiceTest.java new file mode 100644 index 0000000..4c486c5 --- /dev/null +++ b/src/test/java/com/verby/indp/domain/region/service/RegionServiceTest.java @@ -0,0 +1,48 @@ +package com.verby.indp.domain.region.service; + +import static com.verby.indp.domain.region.fixture.RegionFixture.region; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import com.verby.indp.domain.region.Region; +import com.verby.indp.domain.region.repository.RegionRepository; +import com.verby.indp.domain.store.dto.response.FindRegionsResponse; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class RegionServiceTest { + + @InjectMocks + private RegionService regionService; + + @Mock + private RegionRepository regionRepository; + + @Nested + @DisplayName("findRegions 메서드 실행 시") + class FindRegions { + + @Test + @DisplayName("성공 : 매장 지역 목록을 조회한다.") + void findRegions() { + // given + List regions = List.of(region("서울"), region("경기")); + FindRegionsResponse expected = FindRegionsResponse.from(regions); + when(regionRepository.findAllByOrderBySequenceAsc()).thenReturn(regions); + + // when + FindRegionsResponse result = regionService.findRegions(); + + // then + assertThat(result).isEqualTo(expected); + } + } + +} diff --git a/src/test/java/com/verby/indp/domain/store/controller/StoreControllerTest.java b/src/test/java/com/verby/indp/domain/store/controller/StoreControllerTest.java index e2278a2..b899b49 100644 --- a/src/test/java/com/verby/indp/domain/store/controller/StoreControllerTest.java +++ b/src/test/java/com/verby/indp/domain/store/controller/StoreControllerTest.java @@ -1,7 +1,7 @@ package com.verby.indp.domain.store.controller; import static com.verby.indp.domain.auth.fixture.AdminFixture.admin; -import static com.verby.indp.domain.store.constant.Region.서울; +import static com.verby.indp.domain.region.fixture.RegionFixture.region; import static com.verby.indp.domain.store.fixture.StoreFixture.store; import static com.verby.indp.domain.store.fixture.StoreFixture.storesWithId; import static org.mockito.ArgumentMatchers.any; @@ -26,19 +26,17 @@ import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; import static org.springframework.restdocs.request.RequestDocumentation.queryParameters; -import static org.springframework.restdocs.snippet.Attributes.key; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.verby.indp.domain.BaseControllerTest; +import com.verby.indp.domain.region.Region; import com.verby.indp.domain.store.Store; -import com.verby.indp.domain.store.constant.Region; import com.verby.indp.domain.store.dto.request.AddStoreByAdminRequest; import com.verby.indp.domain.store.dto.request.UpdateStoreByAdminRequest; import com.verby.indp.domain.store.dto.response.FindSimpleStoresResponse; import com.verby.indp.domain.store.dto.response.FindStoreByAdminResponse; import com.verby.indp.domain.store.dto.response.FindStoresByAdminResponse; import com.verby.indp.domain.store.dto.response.FindStoresResponse; -import java.util.Arrays; import java.util.List; import java.util.Optional; import org.junit.jupiter.api.DisplayName; @@ -60,7 +58,8 @@ void findSimpleStores() throws Exception { int page = 0; int size = 2; - List stores = storesWithId(List.of(), List.of(), count); + Region 서울 = region("서울"); + List stores = storesWithId(서울, List.of(), List.of(), count); Pageable pageable = PageRequest.of(page, size); Page pageStores = new PageImpl<>(stores.subList(page * size, size), pageable, count); @@ -101,7 +100,7 @@ void findSimpleStores() throws Exception { @DisplayName("성공: 지역별 매장 목록을 조회한다.") void findStores() throws Exception { // given - Region region = 서울; + Region 서울 = region("서울"); int count = 10; int page = 0; @@ -113,14 +112,14 @@ void findStores() throws Exception { FindStoresResponse response = FindStoresResponse.from(pageStores); - when(storeService.findStores(pageable, region)).thenReturn(response); + when(storeService.findStores(pageable, 서울.getRegion())).thenReturn(response); // when ResultActions resultActions = mockMvc.perform( get("/api/stores") .param("page", String.valueOf(page)) .param("size", String.valueOf(size)) - .param("region", region.name() + .param("region", 서울.getRegion() ) ); @@ -132,12 +131,6 @@ void findStores() throws Exception { parameterWithName("page").description("페이지 번호").optional(), parameterWithName("size").description("페이지 사이즈").optional(), parameterWithName("region").description("지역").optional() - .attributes( - key("constraints").value( - String.join(", ", Arrays.stream(Region.values()).map( - Region::name).toArray(String[]::new)) - ) - ) ), responseFields( fieldWithPath("pageInfo").type(OBJECT).description("페이지 정보"), @@ -159,6 +152,8 @@ void findStores() throws Exception { @DisplayName("성공 : (관리자) 매장 목록을 조회한다.") void findStoresByAdmin() throws Exception { // given + com.verby.indp.domain.region.Region 서울 = region("서울"); + int count = 10; int page = 0; int size = 2; @@ -212,7 +207,8 @@ void findStoresByAdmin() throws Exception { @DisplayName("성공 : (관리자) 매장을 조회한다.") void findStoreByAdmin() throws Exception { // given - Store store = store(); + Region 서울 = region("서울"); + Store store = store(서울); ReflectionTestUtils.setField(store, "storeId", 1L); FindStoreByAdminResponse response = FindStoreByAdminResponse.from(store); @@ -251,7 +247,8 @@ void findStoreByAdmin() throws Exception { @DisplayName("성공 : (관리자) 매장을 삭제한다.") void removeStoreByAdmin() throws Exception { // given - Store store = store(); + Region 서울 = region("서울"); + Store store = store(서울); ReflectionTestUtils.setField(store, "storeId", 1L); when(adminRepository.findById(any())).thenReturn(Optional.of(admin())); @@ -281,7 +278,8 @@ void removeStoreByAdmin() throws Exception { @DisplayName("성공 : (관리자) 매장을 추가한다.") void addStoreByAdmin() throws Exception { // given - Store store = store(); + Region 서울 = region("서울"); + Store store = store(서울); AddStoreByAdminRequest request = new AddStoreByAdminRequest(store.getName(), store.getAddress(), store.getRegion(), store.getImage().get(0), store.getThemes(), store.getSongForms()); @@ -324,7 +322,8 @@ void addStoreByAdmin() throws Exception { @DisplayName("성공 : (관리자) 매장 정보를 수정한다.") void updateStoreByAdmin() throws Exception { // given - Store store = store(); + Region 서울 = region("서울"); + Store store = store(서울); ReflectionTestUtils.setField(store, "storeId", 1L); UpdateStoreByAdminRequest request = new UpdateStoreByAdminRequest( store.getName(), store.getAddress(), store.getRegion(), diff --git a/src/test/java/com/verby/indp/domain/store/fixture/StoreFixture.java b/src/test/java/com/verby/indp/domain/store/fixture/StoreFixture.java index ae4bb79..648d9fc 100644 --- a/src/test/java/com/verby/indp/domain/store/fixture/StoreFixture.java +++ b/src/test/java/com/verby/indp/domain/store/fixture/StoreFixture.java @@ -1,8 +1,8 @@ package com.verby.indp.domain.store.fixture; +import com.verby.indp.domain.region.Region; import com.verby.indp.domain.song.SongForm; import com.verby.indp.domain.store.Store; -import com.verby.indp.domain.store.constant.Region; import com.verby.indp.domain.theme.Theme; import java.util.ArrayList; import java.util.List; @@ -15,13 +15,12 @@ public class StoreFixture { private static final String STORE_NAME = "StoreName"; private static final String STORE_ADDRESS = "StoreAddress"; private static final List IMAGE_URL_LIST = List.of("imageUrl1"); - public static final Region STORE_REGION = Region.서울; - public static Store store() { + public static Store store(Region region) { return new Store( STORE_NAME, STORE_ADDRESS, - STORE_REGION, + region, IMAGE_URL_LIST, List.of(), List.of() @@ -29,13 +28,14 @@ public static Store store() { } public static Store store( + Region region, List themes, List songForms ) { return new Store( STORE_NAME, STORE_ADDRESS, - STORE_REGION, + region, IMAGE_URL_LIST, themes, songForms @@ -58,23 +58,25 @@ public static Store store( } public static List stores( + Region region, List themes, List songForms, int count ) { return IntStream.range(0, count) - .mapToObj(i -> store(themes, songForms)) + .mapToObj(i -> store(region, themes, songForms)) .collect(Collectors.toCollection(ArrayList::new)); } public static List storesWithId( + Region region, List themes, List songForms, int count ) { return IntStream.range(0, count) .mapToObj(i -> { - Store store = store(themes, songForms); + Store store = store(region, themes, songForms); ReflectionTestUtils.setField(store, "storeId", (long) i); return store; }) diff --git a/src/test/java/com/verby/indp/domain/store/repository/StoreRepositoryTest.java b/src/test/java/com/verby/indp/domain/store/repository/StoreRepositoryTest.java index 39e2b68..e73d9d5 100644 --- a/src/test/java/com/verby/indp/domain/store/repository/StoreRepositoryTest.java +++ b/src/test/java/com/verby/indp/domain/store/repository/StoreRepositoryTest.java @@ -1,12 +1,13 @@ package com.verby.indp.domain.store.repository; +import static com.verby.indp.domain.region.fixture.RegionFixture.region; import static com.verby.indp.domain.song.fixture.SongFormFixture.songForm; -import static com.verby.indp.domain.store.constant.Region.경기; -import static com.verby.indp.domain.store.constant.Region.서울; import static com.verby.indp.domain.store.fixture.StoreFixture.stores; import static com.verby.indp.domain.theme.fixture.ThemeFixture.theme; import static org.assertj.core.api.Assertions.assertThat; +import com.verby.indp.domain.region.Region; +import com.verby.indp.domain.region.repository.RegionRepository; import com.verby.indp.domain.song.SongForm; import com.verby.indp.domain.song.repository.SongFormRepository; import com.verby.indp.domain.store.Store; @@ -34,6 +35,9 @@ class StoreRepositoryTest { @Autowired private SongFormRepository songFormRepository; + @Autowired + private RegionRepository regionRepository; + @Nested @DisplayName("findAllByOrderByStoreIdAsc 메소드 실행 시") class FindAllByOrderByStoreIdAsc { @@ -52,8 +56,11 @@ void findAllByOrderByCreatedAtAsc() { SongForm songForm = songForm(); songFormRepository.save(songForm); + Region 서울 = region("서울"); + regionRepository.save(서울); + Pageable pageable = PageRequest.of(page, size); - List stores = stores(List.of(theme), List.of(songForm), count); + List stores = stores(서울, List.of(theme), List.of(songForm), count); storeRepository.saveAll(stores); @@ -86,6 +93,11 @@ void findAllByRegionOrderByStoreIdAsc() { int page = 0; int size = 10; + Region 서울 = region("서울"); + Region 경기 = region("경기"); + regionRepository.save(서울); + regionRepository.save(경기); + Theme theme = theme(); themeRepository.save(theme); diff --git a/src/test/java/com/verby/indp/domain/store/service/StoreServiceTest.java b/src/test/java/com/verby/indp/domain/store/service/StoreServiceTest.java index abeaa30..a88bb39 100644 --- a/src/test/java/com/verby/indp/domain/store/service/StoreServiceTest.java +++ b/src/test/java/com/verby/indp/domain/store/service/StoreServiceTest.java @@ -1,9 +1,8 @@ package com.verby.indp.domain.store.service; +import static com.verby.indp.domain.region.fixture.RegionFixture.region; import static com.verby.indp.domain.song.fixture.SongFormFixture.songForm; -import static com.verby.indp.domain.store.constant.Region.경기; -import static com.verby.indp.domain.store.constant.Region.서울; import static com.verby.indp.domain.store.fixture.StoreFixture.store; import static com.verby.indp.domain.store.fixture.StoreFixture.storesWithId; import static com.verby.indp.domain.theme.fixture.ThemeFixture.theme; @@ -15,11 +14,12 @@ import static org.mockito.Mockito.when; import com.verby.indp.domain.common.exception.NotFoundException; +import com.verby.indp.domain.region.Region; +import com.verby.indp.domain.region.repository.RegionRepository; import com.verby.indp.domain.song.SongForm; import com.verby.indp.domain.song.repository.SongFormRepository; import com.verby.indp.domain.song.vo.SongFormName; import com.verby.indp.domain.store.Store; -import com.verby.indp.domain.store.constant.Region; import com.verby.indp.domain.store.dto.request.AddStoreByAdminRequest; import com.verby.indp.domain.store.dto.response.FindSimpleStoresResponse; import com.verby.indp.domain.store.dto.response.FindStoreByAdminResponse; @@ -60,6 +60,9 @@ class StoreServiceTest { @Mock private SongFormRepository songFormRepository; + @Mock + private RegionRepository regionRepository; + @Nested @DisplayName("findSimpleStores 메소드 실행 시") class FindSimpleStores { @@ -68,11 +71,13 @@ class FindSimpleStores { @DisplayName("성공: size 만큼 간단한 매장 정보를 조회 한다.") void findSimpleStores() { // given + Region 서울 = region("서울"); + int count = 20; int page = 0; int size = 10; - List stores = storesWithId(List.of(), List.of(), count); + List stores = storesWithId(서울, List.of(), List.of(), count); Pageable pageable = PageRequest.of(page, size); Page pageStores = new PageImpl<>(stores.subList(page, size), pageable, count); @@ -100,7 +105,7 @@ class FindStores { @DisplayName("성공: size 만큼 특정 지역의 매장 정보를 조회 한다.") void findStoresOfRegion() { // given - Region region = 서울; + Region 서울 = region("서울"); int seoulCount = 5; int page = 0; @@ -113,11 +118,12 @@ void findStoresOfRegion() { FindStoresResponse expected = FindStoresResponse.from(pageStores); - when(storeRepository.findAllByRegionOrderByStoreIdAsc(pageable, region)).thenReturn( + when(regionRepository.findByName(any())).thenReturn(Optional.of(서울)); + when(storeRepository.findAllByRegionOrderByStoreIdAsc(pageable, 서울)).thenReturn( pageStores); // when - FindStoresResponse result = storeService.findStores(pageable, region); + FindStoresResponse result = storeService.findStores(pageable, 서울.getRegion()); // then assertThat(result).isEqualTo(expected); @@ -131,7 +137,10 @@ void findStoresOfRegion() { @DisplayName("성공: size 만큼 전체 지역의 매장 정보를 조회 한다.") void findStores() { // given - Region nullRegion = null; + Region 서울 = region("서울"); + Region 경기 = region("경기"); + + String nullRegion = null; int seoulCount = 5; int gyeonggiCount = 15; @@ -173,6 +182,8 @@ class FindStoresByAdmin { @DisplayName("성공: size 만큼 매장 정보를 조회 한다.") void findStoresOfRegion() { // given + Region 서울 = region("서울"); + int page = 0; int size = 10; int count = 1; @@ -206,8 +217,9 @@ class FindStoreByAdmin { @DisplayName("성공 : storeId 에 해당하는 매장 정보를 조회한다.") void findStoreById() { // given + Region 서울 = region("서울"); long storeId = 1; - Store store = store(); + Store store = store(서울); FindStoreByAdminResponse expected = FindStoreByAdminResponse.from(store); @@ -262,7 +274,8 @@ class AddStores { @DisplayName("성공 : 새로운 매장 정보가 저징된다.") void saveStore() { // given - Store store = store(); + Region 서울 = region("서울"); + Store store = store(서울); ReflectionTestUtils.setField(store, "storeId", 1L); AddStoreByAdminRequest request = new AddStoreByAdminRequest( store.getName(), store.getAddress(), store.getRegion(), @@ -281,9 +294,10 @@ void saveStore() { @DisplayName("성공 : 새로운 테마와 매장 정보가 저징된다.") void saveStoreWithNewTheme() { // given + Region 서울 = region("서울"); ThemeName newThemeName = new ThemeName("newThemeName"); Theme newTheme = new Theme(newThemeName.getName()); - Store store = store(List.of(newTheme), List.of()); + Store store = store(서울, List.of(newTheme), List.of()); ReflectionTestUtils.setField(store, "storeId", 1L); AddStoreByAdminRequest request = new AddStoreByAdminRequest( @@ -305,9 +319,10 @@ void saveStoreWithNewTheme() { @DisplayName("성공 : 새로운 곡 구성과 매장 정보가 저징된다.") void saveStoreWithSongForm() { // given + Region 서울 = region("서울"); SongFormName newSongFormName = new SongFormName("newSongFormName"); SongForm newSongForm = new SongForm(newSongFormName.getName()); - Store store = store(List.of(), List.of(newSongForm)); + Store store = store(서울, List.of(), List.of(newSongForm)); ReflectionTestUtils.setField(store, "storeId", 1L); AddStoreByAdminRequest request = new AddStoreByAdminRequest(