diff --git a/src/main/java/nextstep/DataLoader.java b/src/main/java/nextstep/DataLoader.java index dd1a3d127..5dc8a09ac 100644 --- a/src/main/java/nextstep/DataLoader.java +++ b/src/main/java/nextstep/DataLoader.java @@ -5,18 +5,23 @@ import nextstep.member.domain.RoleType; import org.springframework.stereotype.Component; -import java.util.Arrays; +import java.util.List; @Component public class DataLoader { - private MemberRepository memberRepository; + private static final String PASSWORD ="password"; + + private final MemberRepository memberRepository; public DataLoader(MemberRepository memberRepository) { this.memberRepository = memberRepository; } public void loadData() { - memberRepository.save(new Member("admin@email.com", "password", 20, Arrays.asList(RoleType.ROLE_ADMIN.name()))); - memberRepository.save(new Member("member@email.com", "password", 20, Arrays.asList(RoleType.ROLE_MEMBER.name()))); + memberRepository.save(new Member("admin@email.com", PASSWORD, 20, List.of(RoleType.ROLE_ADMIN.name()))); + + memberRepository.save(new Member("child@email.com", PASSWORD, 9, List.of(RoleType.ROLE_MEMBER.name()))); + memberRepository.save(new Member("teenager@email.com", PASSWORD, 17, List.of(RoleType.ROLE_MEMBER.name()))); + memberRepository.save(new Member("member@email.com", PASSWORD, 30, List.of(RoleType.ROLE_MEMBER.name()))); } } diff --git a/src/main/java/nextstep/subway/applicaion/FareCalculator.java b/src/main/java/nextstep/subway/applicaion/FareCalculator.java index 388d53d86..b44aa54a9 100644 --- a/src/main/java/nextstep/subway/applicaion/FareCalculator.java +++ b/src/main/java/nextstep/subway/applicaion/FareCalculator.java @@ -18,14 +18,25 @@ public class FareCalculator { private static final IntUnaryOperator BETWEEN_10_AND_50 = d -> (int) Math.ceil(d / BETWEEN_10_AND_50_DENOMINATOR) * 100; private static final IntUnaryOperator OVER_50 = d -> (int) Math.ceil(d / OVER_50_DENOMINATOR) * 100; - public int calculateOverFare(int distance) { + public int calculateOverFare(int distance, int extraFare, int age) { if (distance == 0) { return 0; } - int over50 = Math.max(distance - FIFTY, 0); - int between10and50 = Math.max(distance - over50 - MINIMUM_DISTANCE, 0); + final int over50 = Math.max(distance - FIFTY, 0); + final int between10and50 = Math.max(distance - over50 - MINIMUM_DISTANCE, 0); - return MINIMUM_FARE + BETWEEN_10_AND_50.applyAsInt(between10and50) + OVER_50.applyAsInt(over50); + final int price = MINIMUM_FARE + BETWEEN_10_AND_50.applyAsInt(between10and50) + OVER_50.applyAsInt(over50); + + return calculateByAge(age, price + extraFare); + } + + private int calculateByAge(int age, int price) { + if (age < 13 && age >= 6) { + return (price - 350) / 10 * 5; + } else if (age < 19 && age >= 13) { + return (price - 350) / 10 * 8; + } + return price; } } diff --git a/src/main/java/nextstep/subway/applicaion/LineService.java b/src/main/java/nextstep/subway/applicaion/LineService.java index 5b63335d0..645a0efa6 100644 --- a/src/main/java/nextstep/subway/applicaion/LineService.java +++ b/src/main/java/nextstep/subway/applicaion/LineService.java @@ -26,7 +26,7 @@ public LineService(LineRepository lineRepository, StationService stationService) @Transactional public LineResponse saveLine(LineRequest request) { - Line line = lineRepository.save(new Line(request.getName(), request.getColor())); + Line line = lineRepository.save(new Line(request.getName(), request.getColor(), request.getExtraFare())); if (request.getUpStationId() != null && request.getDownStationId() != null && request.getDistance() != 0) { Station upStation = stationService.findById(request.getUpStationId()); Station downStation = stationService.findById(request.getDownStationId()); diff --git a/src/main/java/nextstep/subway/applicaion/PathService.java b/src/main/java/nextstep/subway/applicaion/PathService.java index 2f1ab0e91..b74a934ac 100644 --- a/src/main/java/nextstep/subway/applicaion/PathService.java +++ b/src/main/java/nextstep/subway/applicaion/PathService.java @@ -1,5 +1,6 @@ package nextstep.subway.applicaion; +import nextstep.member.application.MemberService; import nextstep.subway.builder.PathResponseBuilder; import nextstep.subway.applicaion.dto.PathResponse; import nextstep.subway.constant.SearchType; @@ -13,23 +14,26 @@ @Service public class PathService { - private LineService lineService; - private StationService stationService; - private PathResponseBuilder pathResponseBuilder; + private final MemberService memberService; + private final LineService lineService; + private final StationService stationService; + private final PathResponseBuilder pathResponseBuilder; - public PathService(LineService lineService, StationService stationService, PathResponseBuilder pathResponseBuilder) { + public PathService(MemberService memberService, LineService lineService, StationService stationService, PathResponseBuilder pathResponseBuilder) { + this.memberService = memberService; this.lineService = lineService; this.stationService = stationService; this.pathResponseBuilder = pathResponseBuilder; } - public PathResponse findPath(Long source, Long target, SearchType searchType) { + public PathResponse findPath(String email, Long source, Long target, SearchType searchType) { + int age = memberService.findMember(email).getAge(); Station upStation = stationService.findById(source); Station downStation = stationService.findById(target); List lines = lineService.findLines(); SubwayMap subwayMap = new SubwayMap(lines); Path path = subwayMap.findPath(upStation, downStation, searchType); - return pathResponseBuilder.build(path); + return pathResponseBuilder.build(path, age); } } diff --git a/src/main/java/nextstep/subway/applicaion/dto/LineRequest.java b/src/main/java/nextstep/subway/applicaion/dto/LineRequest.java index 5381ca6d5..0377147cf 100644 --- a/src/main/java/nextstep/subway/applicaion/dto/LineRequest.java +++ b/src/main/java/nextstep/subway/applicaion/dto/LineRequest.java @@ -7,6 +7,7 @@ public class LineRequest { private Long downStationId; private int distance; private int duration; + private int extraFare; public String getName() { return name; @@ -31,4 +32,8 @@ public int getDistance() { public int getDuration() { return duration; } + + public int getExtraFare() { + return extraFare; + } } diff --git a/src/main/java/nextstep/subway/builder/PathResponseBuilder.java b/src/main/java/nextstep/subway/builder/PathResponseBuilder.java index e8e96cb8c..0b890d39f 100644 --- a/src/main/java/nextstep/subway/builder/PathResponseBuilder.java +++ b/src/main/java/nextstep/subway/builder/PathResponseBuilder.java @@ -12,19 +12,19 @@ @Component public class PathResponseBuilder { - private FareCalculator fareCalculator; + private final FareCalculator fareCalculator; public PathResponseBuilder(FareCalculator fareCalculator) { this.fareCalculator = fareCalculator; } - public PathResponse build(Path path) { + public PathResponse build(Path path, int age) { List stations = path.getStations().stream() .map(StationResponse::of) .collect(Collectors.toList()); int distance = path.extractDistance(); int duration = path.extractDuration(); - int fare = fareCalculator.calculateOverFare(distance); + int fare = fareCalculator.calculateOverFare(distance, path.getExtraFare(), age); return new PathResponse(stations, distance, duration, fare); } diff --git a/src/main/java/nextstep/subway/domain/Line.java b/src/main/java/nextstep/subway/domain/Line.java index 2a470fd5b..70b66956b 100644 --- a/src/main/java/nextstep/subway/domain/Line.java +++ b/src/main/java/nextstep/subway/domain/Line.java @@ -10,6 +10,7 @@ public class Line { private Long id; private String name; private String color; + private int extraFare; @Embedded private Sections sections = new Sections(); @@ -17,9 +18,10 @@ public class Line { public Line() { } - public Line(String name, String color) { + public Line(String name, String color, int extraFare) { this.name = name; this.color = color; + this.extraFare = extraFare; } public Long getId() { @@ -34,6 +36,10 @@ public String getColor() { return color; } + public int getExtraFare() { + return extraFare; + } + public List
getSections() { return sections.getSections(); } diff --git a/src/main/java/nextstep/subway/domain/Path.java b/src/main/java/nextstep/subway/domain/Path.java index 7ea3eb534..3f45cd440 100644 --- a/src/main/java/nextstep/subway/domain/Path.java +++ b/src/main/java/nextstep/subway/domain/Path.java @@ -21,6 +21,10 @@ public int extractDuration() { return sections.totalDuration(); } + public int getExtraFare() { + return sections.getExtraFare(); + } + public List getStations() { return sections.getStations(); } diff --git a/src/main/java/nextstep/subway/domain/Section.java b/src/main/java/nextstep/subway/domain/Section.java index 84d812570..a3638c1f8 100644 --- a/src/main/java/nextstep/subway/domain/Section.java +++ b/src/main/java/nextstep/subway/domain/Section.java @@ -62,6 +62,10 @@ public int getDuration() { return duration; } + public int getExtraFare() { + return line.getExtraFare(); + } + public boolean isSameUpStation(Station station) { return this.upStation == station; } diff --git a/src/main/java/nextstep/subway/domain/Sections.java b/src/main/java/nextstep/subway/domain/Sections.java index e05d617f6..48c6423c8 100644 --- a/src/main/java/nextstep/subway/domain/Sections.java +++ b/src/main/java/nextstep/subway/domain/Sections.java @@ -167,4 +167,8 @@ public int totalDistance() { public int totalDuration() { return sections.stream().mapToInt(Section::getDuration).sum(); } + + public int getExtraFare() { + return sections.stream().mapToInt(Section::getExtraFare).max().orElse(0); + } } diff --git a/src/main/java/nextstep/subway/ui/PathController.java b/src/main/java/nextstep/subway/ui/PathController.java index ac2683581..e01a89bba 100644 --- a/src/main/java/nextstep/subway/ui/PathController.java +++ b/src/main/java/nextstep/subway/ui/PathController.java @@ -7,6 +7,8 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import support.auth.authorization.AuthenticationPrincipal; +import support.auth.userdetails.User; @RestController public class PathController { @@ -17,7 +19,8 @@ public PathController(PathService pathService) { } @GetMapping("/paths") - public ResponseEntity findPath(@RequestParam Long source, @RequestParam Long target, @RequestParam SearchType searchType) { - return ResponseEntity.ok(pathService.findPath(source, target, searchType)); + public ResponseEntity findPath(@AuthenticationPrincipal User user, + @RequestParam Long source, @RequestParam Long target, @RequestParam SearchType searchType) { + return ResponseEntity.ok(pathService.findPath(user.getUsername(), source, target, searchType)); } } diff --git a/src/test/java/nextstep/subway/acceptance/AcceptanceTest.java b/src/test/java/nextstep/subway/acceptance/AcceptanceTest.java index fc83539fe..f0b3619e0 100644 --- a/src/test/java/nextstep/subway/acceptance/AcceptanceTest.java +++ b/src/test/java/nextstep/subway/acceptance/AcceptanceTest.java @@ -15,7 +15,7 @@ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class AcceptanceTest { private static final String EMAIL = "admin@email.com"; - private static final String PASSWORD = "password"; + public static final String PASSWORD = "password"; @LocalServerPort int port; diff --git a/src/test/java/nextstep/subway/acceptance/PathAcceptanceTest.java b/src/test/java/nextstep/subway/acceptance/PathAcceptanceTest.java index 1c449c663..8549901ea 100644 --- a/src/test/java/nextstep/subway/acceptance/PathAcceptanceTest.java +++ b/src/test/java/nextstep/subway/acceptance/PathAcceptanceTest.java @@ -1,18 +1,21 @@ package nextstep.subway.acceptance; -import io.restassured.RestAssured; import io.restassured.response.ExtractableResponse; import io.restassured.response.Response; import nextstep.subway.constant.SearchType; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.http.MediaType; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import java.util.HashMap; import java.util.Map; +import java.util.stream.Stream; import static nextstep.subway.acceptance.LineSteps.지하철_노선에_지하철_구간_생성_요청; +import static nextstep.subway.acceptance.MemberSteps.로그인_되어_있음; +import static nextstep.subway.acceptance.PathSteps.searchType에_따른_두_역의_최단_경로_조회를_요청; import static nextstep.subway.acceptance.StationSteps.지하철역_생성_요청; import static org.assertj.core.api.Assertions.assertThat; @@ -42,48 +45,60 @@ public void setUp() { 양재역 = 지하철역_생성_요청(관리자, "양재역").jsonPath().getLong("id"); 남부터미널역 = 지하철역_생성_요청(관리자, "남부터미널역").jsonPath().getLong("id"); - 이호선 = 지하철_노선_생성_요청("2호선", "green", 교대역, 강남역, 10, 4); - 신분당선 = 지하철_노선_생성_요청("신분당선", "red", 강남역, 양재역, 10, 4); - 삼호선 = 지하철_노선_생성_요청("3호선", "orange", 교대역, 남부터미널역, 2, 10); + 이호선 = 지하철_노선_생성_요청("2호선", "green", 교대역, 강남역, 10, 4, 200); + 신분당선 = 지하철_노선_생성_요청("신분당선", "red", 강남역, 양재역, 10, 4, 1000); + 삼호선 = 지하철_노선_생성_요청("3호선", "orange", 교대역, 남부터미널역, 2, 10, 300); 지하철_노선에_지하철_구간_생성_요청(관리자, 삼호선, createSectionCreateParams(남부터미널역, 양재역, 3, 1)); } @DisplayName("두 역의 최단 거리 경로를 조회한다.") - @Test - void findPathByDistance() { + @ParameterizedTest(name = "{index}: {2}") + @MethodSource("유저와_최단_거리_경로_요금") + void findPathByDistance(String email, int price, String message) { // when - ExtractableResponse response = searchType에_따른_두_역의_최단_경로_조회를_요청(교대역, 양재역, SearchType.DISTANCE); + String accessToken = 로그인_되어_있음(email, PASSWORD); + ExtractableResponse response = searchType에_따른_두_역의_최단_경로_조회를_요청(accessToken, 교대역, 양재역, SearchType.DISTANCE); // then assertThat(response.jsonPath().getList("stations.id", Long.class)).containsExactly(교대역, 남부터미널역, 양재역); assertThat(response.jsonPath().getInt("distance")).isEqualTo(5); assertThat(response.jsonPath().getInt("duration")).isEqualTo(11); - assertThat(response.jsonPath().getInt("fare")).isEqualTo(1250); + assertThat(response.jsonPath().getInt("fare")).isEqualTo(price); } @DisplayName("두 역의 최단 시간 경로를 조회한다.") - @Test - void findPathByDuration() { + @ParameterizedTest(name = "{index}: {2}") + @MethodSource("유저와_최단_시간_경로_요금") + void findPathByDuration(String email, int price, String message) { // when - ExtractableResponse response = searchType에_따른_두_역의_최단_경로_조회를_요청(교대역, 양재역, SearchType.DURATION); + String accessToken = 로그인_되어_있음(email, PASSWORD); + ExtractableResponse response = searchType에_따른_두_역의_최단_경로_조회를_요청(accessToken, 교대역, 양재역, SearchType.DURATION); // then assertThat(response.jsonPath().getList("stations.id", Long.class)).containsExactly(교대역, 강남역, 양재역); assertThat(response.jsonPath().getInt("distance")).isEqualTo(20); assertThat(response.jsonPath().getInt("duration")).isEqualTo(8); - assertThat(response.jsonPath().getInt("fare")).isEqualTo(1450); + assertThat(response.jsonPath().getInt("fare")).isEqualTo(price); } - private ExtractableResponse searchType에_따른_두_역의_최단_경로_조회를_요청(Long source, Long target, SearchType searchType) { - return RestAssured - .given().log().all() - .accept(MediaType.APPLICATION_JSON_VALUE) - .when().get("/paths?source={sourceId}&target={targetId}&searchType={searchType}", source, target, searchType.name()) - .then().log().all().extract(); + private static Stream 유저와_최단_거리_경로_요금() { + return Stream.of( + Arguments.of("child@email.com", 600, "어린이 사용자는 350원을 공제한 금액의 50%를 할인받는다."), + Arguments.of("teenager@email.com", 960, "청소년 사용자는 350원을 공제한 금액의 20%를 할인받는다."), + Arguments.of("member@email.com", 1550, "성인 사용자는 할인 안받는다.") + ); } - private Long 지하철_노선_생성_요청(String name, String color, Long upStation, Long downStation, int distance, int duration) { + private static Stream 유저와_최단_시간_경로_요금() { + return Stream.of( + Arguments.of("child@email.com", 1050, "어린이 사용자는 350원을 공제한 금액의 50%를 할인받는다."), + Arguments.of("teenager@email.com", 1680, "청소년 사용자는 350원을 공제한 금액의 20%를 할인받는다."), + Arguments.of("member@email.com", 2450, "성인 사용자는 할인 안받는다.") + ); + } + + private Long 지하철_노선_생성_요청(String name, String color, Long upStation, Long downStation, int distance, int duration, int extraFare) { Map lineCreateParams; lineCreateParams = new HashMap<>(); lineCreateParams.put("name", name); @@ -92,6 +107,7 @@ void findPathByDuration() { lineCreateParams.put("downStationId", downStation + ""); lineCreateParams.put("distance", distance + ""); lineCreateParams.put("duration", duration + ""); + lineCreateParams.put("extraFare", extraFare + ""); return LineSteps.지하철_노선_생성_요청(관리자, lineCreateParams).jsonPath().getLong("id"); } diff --git a/src/test/java/nextstep/subway/acceptance/PathSteps.java b/src/test/java/nextstep/subway/acceptance/PathSteps.java new file mode 100644 index 000000000..7db321dc7 --- /dev/null +++ b/src/test/java/nextstep/subway/acceptance/PathSteps.java @@ -0,0 +1,16 @@ +package nextstep.subway.acceptance; + +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import nextstep.subway.constant.SearchType; +import org.springframework.http.MediaType; + +public class PathSteps extends AcceptanceTestSteps { + + public static ExtractableResponse searchType에_따른_두_역의_최단_경로_조회를_요청(String accessToken, Long source, Long target, SearchType searchType) { + return given(accessToken) + .accept(MediaType.APPLICATION_JSON_VALUE) + .when().get("/paths?source={sourceId}&target={targetId}&searchType={searchType}", source, target, searchType.name()) + .then().log().all().extract(); + } +} diff --git a/src/test/java/nextstep/subway/applicaion/FareCalculatorTest.java b/src/test/java/nextstep/subway/applicaion/FareCalculatorTest.java index 4ed1ae7b2..22acee75b 100644 --- a/src/test/java/nextstep/subway/applicaion/FareCalculatorTest.java +++ b/src/test/java/nextstep/subway/applicaion/FareCalculatorTest.java @@ -1,12 +1,12 @@ package nextstep.subway.applicaion; -import nextstep.subway.applicaion.dto.PathResponse; -import org.junit.jupiter.api.Test; -import org.mockito.Mock; -import org.mockito.Spy; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.when; class FareCalculatorTest { @@ -14,15 +14,57 @@ class FareCalculatorTest { FareCalculator fareCalculator = new FareCalculator(); - @Test - void 이용_거리가_0이면_요금도_0원이다() { - 거리에_따른_가격_비교(0, 0); + @ParameterizedTest(name = "{index}: {3}: {0}km 이용 = {2}원") + @MethodSource("이용_거리_0km") + void 이용_거리가_0이면_요금도_0원이다(int distance, int age, int price, String message) { + 거리에_따른_가격_비교(distance, age, price); + } + + @ParameterizedTest(name = "{index}: {3}: {0}km 이용 = {2}원") + @MethodSource("이용_거리_10km이하") + void 이용_거리가_10km이하는_기본_요금이_나와야_한다(int distance, int age, int price, String message) { + 거리에_따른_가격_비교(distance, age, price); + } + + @ParameterizedTest(name = "{index}: {3}: {0}km 이용 = {2}원") + @MethodSource("이용_거리_10km초과_50km이하") + void 이용_거리가_10km초과_50km이하는_5km마다_100원의_추가요금이_나와야_한다(int distance, int age, int price, String message) { + 거리에_따른_가격_비교(distance, age, price); + } + + @ParameterizedTest(name = "{index}: {3}: {0}km 이용 = {2}원") + @MethodSource("이용_거리_50km초과") + void 이용_거리가_50km초과분은_8km마다_100원의_추가요금이_나와야_한다(int distance, int age, int price, String message) { + 거리에_따른_가격_비교(distance, age, price); + } + + private static int 연령별_요금(int age, int price) { + if (age < 13 && age >= 6) { + return (price - 350) / 10 * 5; + } else if (age < 19 && age >= 13) { + return (price - 350) / 10 * 8; + } + return price; } - @Test - void 이용_거리가_10km이하는_기본_요금이_나와야_한다() { - 거리에_따른_가격_비교(8, 기본_요금); - 거리에_따른_가격_비교(10, 기본_요금); + private static Stream 이용_거리_0km() { + return Stream.of( + Arguments.of(0, 6, 0, "어린이"), + Arguments.of(0, 16, 0, "청소년"), + Arguments.of(0, 26, 0, "성인") + ); + } + + private static Stream 이용_거리_10km이하() { + return Stream.of( + Arguments.of(1, 6, 연령별_요금(6, 기본_요금), "어린이"), + Arguments.of(1, 16, 연령별_요금(16, 기본_요금), "청소년"), + Arguments.of(1, 26, 연령별_요금(26, 기본_요금), "성인"), + + Arguments.of(10, 6, 연령별_요금(6, 기본_요금), "어린이"), + Arguments.of(10, 16, 연령별_요금(16, 기본_요금), "청소년"), + Arguments.of(10, 26, 연령별_요금(26, 기본_요금), "성인") + ); } /** @@ -30,25 +72,47 @@ class FareCalculatorTest { * 37km = 10km + 27km = 기본_요금 + ceil(27/5)*100 * 50km = 10km + 40km = 기본_요금 + ceil(40/5)*100 */ - @Test - void 이용_거리가_10km초과_50km이하는_5km마다_100원의_추가요금이_나와야_한다() { - 거리에_따른_가격_비교(11, 기본_요금 + 100); - 거리에_따른_가격_비교(37, 기본_요금 + 600); - 거리에_따른_가격_비교(50, 기본_요금 + 800); + private static Stream 이용_거리_10km초과_50km이하() { + final int 이용거리_11km_요금 = 기본_요금 + 100; + final int 이용거리_37km_요금 = 기본_요금 + 600; + final int 이용거리_50km_요금 = 기본_요금 + 800; + + return Stream.of( + Arguments.of(11, 6, 연령별_요금(6, 이용거리_11km_요금), "어린이"), + Arguments.of(11, 16, 연령별_요금(16, 이용거리_11km_요금), "청소년"), + Arguments.of(11, 26, 연령별_요금(26, 이용거리_11km_요금), "성인"), + + Arguments.of(37, 6, 연령별_요금(6, 이용거리_37km_요금), "어린이"), + Arguments.of(37, 16, 연령별_요금(16, 이용거리_37km_요금), "청소년"), + Arguments.of(37, 26, 연령별_요금(26, 이용거리_37km_요금), "성인"), + + Arguments.of(50, 6, 연령별_요금(6, 이용거리_50km_요금), "어린이"), + Arguments.of(50, 16, 연령별_요금(16, 이용거리_50km_요금), "청소년"), + Arguments.of(50, 26, 연령별_요금(26, 이용거리_50km_요금), "성인") + ); } /** * 51km = 10km + 40km + 1km = 기본_요금 + 8*100 + ceil(1/8)*100 * 107km = 10km + 40km + 56km = 기본_요금 + 8*100 + ceil(57/8)*100 */ - @Test - void 이용_거리가_50km초과분은_8km마다_100원의_추가요금이_나와야_한다() { - 거리에_따른_가격_비교(51, 기본_요금 + 800 + 100); - 거리에_따른_가격_비교(107, 기본_요금 + 800 + 800); + private static Stream 이용_거리_50km초과() { + final int 이용거리_51km_요금 = 기본_요금 + 800 + 100; + final int 이용거리_107km_요금 = 기본_요금 + 800 + 800; + + return Stream.of( + Arguments.of(51, 6, 연령별_요금(6, 이용거리_51km_요금), "어린이"), + Arguments.of(51, 16, 연령별_요금(16, 이용거리_51km_요금), "청소년"), + Arguments.of(51, 26, 연령별_요금(26, 이용거리_51km_요금), "성인"), + + Arguments.of(107, 6, 연령별_요금(6, 이용거리_107km_요금), "어린이"), + Arguments.of(107, 16, 연령별_요금(16, 이용거리_107km_요금), "청소년"), + Arguments.of(107, 26, 연령별_요금(26, 이용거리_107km_요금), "성인") + ); } - private void 거리에_따른_가격_비교(int distance, int price) { - int calculatedFare = fareCalculator.calculateOverFare(distance); + private void 거리에_따른_가격_비교(int distance, int age, int price) { + int calculatedFare = fareCalculator.calculateOverFare(distance, 0, age); assertThat(calculatedFare).isEqualTo(price); } diff --git a/src/test/java/nextstep/subway/documentation/Documentation.java b/src/test/java/nextstep/subway/documentation/Documentation.java index 8951ae35e..60e88761e 100644 --- a/src/test/java/nextstep/subway/documentation/Documentation.java +++ b/src/test/java/nextstep/subway/documentation/Documentation.java @@ -2,15 +2,22 @@ import io.restassured.RestAssured; import io.restassured.builder.RequestSpecBuilder; +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; import io.restassured.specification.RequestSpecification; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.restdocs.RestDocumentationContextProvider; import org.springframework.restdocs.RestDocumentationExtension; import org.springframework.test.context.ActiveProfiles; +import java.util.HashMap; +import java.util.Map; + import static org.springframework.restdocs.restassured3.RestAssuredRestDocumentation.documentationConfiguration; @ActiveProfiles("test") @@ -22,6 +29,8 @@ public class Documentation { protected RequestSpecification spec; + public String accessToken; + @BeforeEach public void setUp(RestDocumentationContextProvider restDocumentation) { RestAssured.port = port; @@ -29,5 +38,21 @@ public void setUp(RestDocumentationContextProvider restDocumentation) { this.spec = new RequestSpecBuilder() .addFilter(documentationConfiguration(restDocumentation)) .build(); + + accessToken = 로그인_요청(); + } + + public static String 로그인_요청() { + Map params = new HashMap<>(); + params.put("email", "member@email.com"); + params.put("password", "password"); + + return RestAssured.given().log().all() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .body(params) + .when().post("/login/token") + .then().log().all() + .statusCode(HttpStatus.OK.value()).extract() + .jsonPath().getString("accessToken"); } } diff --git a/src/test/java/nextstep/subway/documentation/PathDocumentation.java b/src/test/java/nextstep/subway/documentation/PathDocumentation.java index 28742a0a8..55187b2ba 100644 --- a/src/test/java/nextstep/subway/documentation/PathDocumentation.java +++ b/src/test/java/nextstep/subway/documentation/PathDocumentation.java @@ -14,8 +14,7 @@ import java.util.List; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.when; import static org.springframework.restdocs.operation.preprocess.Preprocessors.*; import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; @@ -36,7 +35,7 @@ void pathByDistance() { 1250 ); - when(pathService.findPath(anyLong(), anyLong(), any(SearchType.class))).thenReturn(pathResponse); + when(pathService.findPath(anyString(), anyLong(), anyLong(), any(SearchType.class))).thenReturn(pathResponse); searchType에_따른_두_역의_최단_경로_조회를_요청("pathWithDistance", SearchType.DISTANCE); } @@ -50,7 +49,7 @@ void pathByDuration() { 1250 ); - when(pathService.findPath(anyLong(), anyLong(), any(SearchType.class))).thenReturn(pathResponse); + when(pathService.findPath(anyString(), anyLong(), anyLong(), any(SearchType.class))).thenReturn(pathResponse); searchType에_따른_두_역의_최단_경로_조회를_요청("pathWithDuration", SearchType.DURATION); } @@ -58,6 +57,7 @@ void pathByDuration() { private ExtractableResponse searchType에_따른_두_역의_최단_경로_조회를_요청(String identifier, SearchType searchType) { return RestAssured .given(spec).log().all() + .auth().oauth2(accessToken) .filter(document(identifier, preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), diff --git a/src/test/java/nextstep/subway/unit/LineServiceMockTest.java b/src/test/java/nextstep/subway/unit/LineServiceMockTest.java index 118a5f312..1ade12117 100644 --- a/src/test/java/nextstep/subway/unit/LineServiceMockTest.java +++ b/src/test/java/nextstep/subway/unit/LineServiceMockTest.java @@ -43,7 +43,7 @@ void setUp() { ReflectionTestUtils.setField(역삼역, "id", 2L); 삼성역 = new Station("삼성역"); ReflectionTestUtils.setField(삼성역, "id", 3L); - 이호선 = new Line("2호선", "green"); + 이호선 = new Line("2호선", "green", 200); 이호선.addSection(강남역, 역삼역, 10, 4); ReflectionTestUtils.setField(이호선, "id", 1L); } diff --git a/src/test/java/nextstep/subway/unit/LineServiceTest.java b/src/test/java/nextstep/subway/unit/LineServiceTest.java index aa986a54c..a1fdcc1f5 100644 --- a/src/test/java/nextstep/subway/unit/LineServiceTest.java +++ b/src/test/java/nextstep/subway/unit/LineServiceTest.java @@ -39,7 +39,7 @@ void addSection() { } private Line createLine(Station 강남역, Station 역삼역) { - Line line = new Line("2호선", "green"); + Line line = new Line("2호선", "green", 200); line.addSection(강남역, 역삼역, 10, 4); return line; } diff --git a/src/test/java/nextstep/subway/unit/LineTest.java b/src/test/java/nextstep/subway/unit/LineTest.java index 620662cf0..a46d142ee 100644 --- a/src/test/java/nextstep/subway/unit/LineTest.java +++ b/src/test/java/nextstep/subway/unit/LineTest.java @@ -22,7 +22,7 @@ class LineTest { void setUp() { 강남역 = new Station("강남역"); 역삼역 = new Station("역삼역"); - line = new Line("2호선", "green"); + line = new Line("2호선", "green", 200); line.addSection(강남역, 역삼역, 10, 4); } diff --git a/src/test/java/nextstep/subway/unit/SubwayMapTest.java b/src/test/java/nextstep/subway/unit/SubwayMapTest.java index 5eccf2ef6..c4f88487a 100644 --- a/src/test/java/nextstep/subway/unit/SubwayMapTest.java +++ b/src/test/java/nextstep/subway/unit/SubwayMapTest.java @@ -32,9 +32,9 @@ void setUp() { 양재역 = createStation(3L, "양재역"); 남부터미널역 = createStation(4L, "남부터미널역"); - 신분당선 = new Line("신분당선", "red"); - 이호선 = new Line("2호선", "red"); - 삼호선 = new Line("3호선", "red"); + 신분당선 = new Line("신분당선", "red", 1000); + 이호선 = new Line("2호선", "red", 200); + 삼호선 = new Line("3호선", "red", 300); 신분당선.addSection(강남역, 양재역, 3, 10); 이호선.addSection(교대역, 강남역, 3, 1); @@ -56,6 +56,7 @@ void findPathByDistance() { assertThat(path.getStations()).containsExactlyElementsOf(Lists.newArrayList(교대역, 강남역, 양재역)); assertThat(path.extractDistance()).isEqualTo(6); assertThat(path.extractDuration()).isEqualTo(11); + assertThat(path.getExtraFare()).isEqualTo(1000); } @DisplayName("두 역의 최단 시간 경로를 조회한다.") @@ -72,6 +73,7 @@ void findPathByDuration() { assertThat(path.getStations()).containsExactlyElementsOf(Lists.newArrayList(교대역, 남부터미널역, 양재역)); assertThat(path.extractDistance()).isEqualTo(10); assertThat(path.extractDuration()).isEqualTo(4); + assertThat(path.getExtraFare()).isEqualTo(300); } @DisplayName("두 역의 최단 거리 경로를 반대로 조회한다.") @@ -88,6 +90,7 @@ void findPathOppositely() { assertThat(path.getStations()).containsExactlyElementsOf(Lists.newArrayList(양재역, 강남역, 교대역)); assertThat(path.extractDistance()).isEqualTo(6); assertThat(path.extractDuration()).isEqualTo(11); + assertThat(path.getExtraFare()).isEqualTo(1000); } private Station createStation(long id, String name) {