From 358475c9cbfa42747fc213af04ab61e6cefaf9a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EA=B2=BD=EB=AF=BC?= Date: Wed, 13 Dec 2023 00:37:28 +0900 Subject: [PATCH] =?UTF-8?q?test:=20=EC=B0=A8=EB=9F=89=20=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=20=EB=8B=A8=EC=9C=84=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=84=A4?= =?UTF-8?q?=EA=B3=84=20(#46)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test: 차량 엔티티 테스트 * test: 차량 재고 엔티티 테스트 * test: 차량 예약 엔티티 테스트 * test: 차량 시험 수행 엔티티 테스트 * refactor: 엔티티 팩토리 구현 및 리팩토링 * test: 시험 수행 이력 서비스 단위 테스트 구현 * test: 차량 재고 서비스 단위 테스트 구현 * test: 시험차량 예약 테스트 및 리팩토링 * test: 차량 재고 테스트 수정 * feat: 차량 서비스 단위 테스트 구현 --- .../testcar/car/domains/car/CarService.java | 13 - .../testcar/car/domains/car/entity/Type.java | 2 + .../domains/car/model/RegisterCarRequest.java | 2 + .../carReservation/CarReservationService.java | 23 +- .../carReservation/exception/ErrorCode.java | 3 +- .../model/CarReservationRequest.java | 2 + .../model/ReturnCarReservationRequest.java | 2 + .../car/domains/carStock/CarStockService.java | 23 +- .../domains/carStock/exception/ErrorCode.java | 3 +- .../carStock/model/DeleteCarStockRequest.java | 2 + .../model/RegisterCarStockRequest.java | 2 + .../carStock/model/UpdateCarStockRequest.java | 2 + .../domains/carTest/model/CarTestRequest.java | 2 + .../testcar/car/common/CarEntityFactory.java | 68 ++++ .../java/com/testcar/car/common/Constant.java | 38 +++ .../com/testcar/car/common/DtoFactory.java | 30 ++ .../car/common/MemberEntityFactory.java | 36 +++ .../car/common/TrackEntityFactory.java | 25 ++ .../car/domains/car/CarServiceTest.java | 149 +++++++++ .../car/domains/car/TestCarServiceTest.java | 79 +++++ .../car/domains/car/entity/CarTest.java | 40 +++ .../car/request/CarRequestFactory.java | 27 ++ .../CarReservationServiceTest.java | 208 +++++++++++++ .../entity/CarReservationTest.java | 57 ++++ .../request/CarReservationRequestFactory.java | 18 ++ .../domains/carStock/CarStockServiceTest.java | 290 ++++++++++++++++++ .../domains/carStock/entity/CarStockTest.java | 58 ++++ .../request/CarStockRequestFactory.java | 33 ++ .../domains/carTest/CarTestServiceTest.java | 143 +++++++++ .../domains/carTest/entity/CarTestTest.java | 102 ++++++ .../request/CarTestRequestFactory.java | 33 ++ 31 files changed, 1490 insertions(+), 25 deletions(-) create mode 100644 src/test/java/com/testcar/car/common/CarEntityFactory.java create mode 100644 src/test/java/com/testcar/car/common/Constant.java create mode 100644 src/test/java/com/testcar/car/common/DtoFactory.java create mode 100644 src/test/java/com/testcar/car/common/MemberEntityFactory.java create mode 100644 src/test/java/com/testcar/car/common/TrackEntityFactory.java create mode 100644 src/test/java/com/testcar/car/domains/car/CarServiceTest.java create mode 100644 src/test/java/com/testcar/car/domains/car/TestCarServiceTest.java create mode 100644 src/test/java/com/testcar/car/domains/car/entity/CarTest.java create mode 100644 src/test/java/com/testcar/car/domains/car/request/CarRequestFactory.java create mode 100644 src/test/java/com/testcar/car/domains/carReservation/CarReservationServiceTest.java create mode 100644 src/test/java/com/testcar/car/domains/carReservation/entity/CarReservationTest.java create mode 100644 src/test/java/com/testcar/car/domains/carReservation/request/CarReservationRequestFactory.java create mode 100644 src/test/java/com/testcar/car/domains/carStock/CarStockServiceTest.java create mode 100644 src/test/java/com/testcar/car/domains/carStock/entity/CarStockTest.java create mode 100644 src/test/java/com/testcar/car/domains/carStock/request/CarStockRequestFactory.java create mode 100644 src/test/java/com/testcar/car/domains/carTest/CarTestServiceTest.java create mode 100644 src/test/java/com/testcar/car/domains/carTest/entity/CarTestTest.java create mode 100644 src/test/java/com/testcar/car/domains/carTest/request/CarTestRequestFactory.java diff --git a/src/main/java/com/testcar/car/domains/car/CarService.java b/src/main/java/com/testcar/car/domains/car/CarService.java index 2ba0abe..289e353 100644 --- a/src/main/java/com/testcar/car/domains/car/CarService.java +++ b/src/main/java/com/testcar/car/domains/car/CarService.java @@ -27,24 +27,11 @@ public Car findById(Long id) { .orElseThrow(() -> new NotFoundException(ErrorCode.CAR_NOT_FOUND)); } - /** 차량을 이름으로 조회합니다. */ - public Car findByName(String name) { - return carRepository - .findByNameAndDeletedFalse(name) - .orElseThrow(() -> new NotFoundException(ErrorCode.CAR_NOT_FOUND)); - } - /** 차량을 조건에 맞게 조회합니다. */ public Page findAllPageByCondition(CarFilterCondition condition, Pageable pageable) { return carRepository.findAllPageByCondition(condition, pageable); } - /** 시험 차량을 조건에 맞게 조회합니다. */ - public Page findAllWithStocksPageByCondition( - CarFilterCondition condition, Pageable pageable) { - return carRepository.findAllWithStocksPageByCondition(condition, pageable); - } - /** 새로운 차량을 등록합니다. */ public Car register(RegisterCarRequest request) { final Car car = createEntity(request); diff --git a/src/main/java/com/testcar/car/domains/car/entity/Type.java b/src/main/java/com/testcar/car/domains/car/entity/Type.java index deda305..132db95 100644 --- a/src/main/java/com/testcar/car/domains/car/entity/Type.java +++ b/src/main/java/com/testcar/car/domains/car/entity/Type.java @@ -7,7 +7,9 @@ @Getter @RequiredArgsConstructor public enum Type { + HATCHBACK("해치백"), SEDAN("세단"), + WAGON("왜건"), SUV("SUV"), TRUCK("트럭"), VAN("승합차"); diff --git a/src/main/java/com/testcar/car/domains/car/model/RegisterCarRequest.java b/src/main/java/com/testcar/car/domains/car/model/RegisterCarRequest.java index c5bc3a8..01f55dc 100644 --- a/src/main/java/com/testcar/car/domains/car/model/RegisterCarRequest.java +++ b/src/main/java/com/testcar/car/domains/car/model/RegisterCarRequest.java @@ -6,10 +6,12 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Positive; +import lombok.Builder; import lombok.Getter; import org.hibernate.validator.constraints.Length; @Getter +@Builder public class RegisterCarRequest { @NotBlank(message = "차량명을 입력해주세요.") @Length(max = 20) diff --git a/src/main/java/com/testcar/car/domains/carReservation/CarReservationService.java b/src/main/java/com/testcar/car/domains/carReservation/CarReservationService.java index 9acc727..6a9e0b9 100644 --- a/src/main/java/com/testcar/car/domains/carReservation/CarReservationService.java +++ b/src/main/java/com/testcar/car/domains/carReservation/CarReservationService.java @@ -2,6 +2,7 @@ import com.testcar.car.common.exception.BadRequestException; +import com.testcar.car.common.exception.NotFoundException; import com.testcar.car.domains.carReservation.entity.CarReservation; import com.testcar.car.domains.carReservation.entity.ReservationStatus; import com.testcar.car.domains.carReservation.exception.ErrorCode; @@ -44,7 +45,7 @@ public List findAllByMemberAndIds(Member member, List ids) final List carReservations = carReservationRepository.findAllWithCarStockByIdInAndMemberId(ids, member.getId()); if (carReservations.size() != ids.size()) { - throw new BadRequestException(ErrorCode.CAR_RESERVATION_NOT_FOUND); + throw new NotFoundException(ErrorCode.CAR_RESERVATION_NOT_FOUND); } return carReservations; } @@ -63,7 +64,6 @@ public CarReservation reserve(Member member, CarReservationRequest request) { .startedAt(now) .expiredAt(expiredAt) .build(); - carStock.updateStatus(StockStatus.RESERVED); carStockRepository.save(carStock); return carReservationRepository.save(carReservation); } @@ -73,17 +73,24 @@ public List returnCarReservation( Member member, ReturnCarReservationRequest request) { final List carReservations = this.findAllByMemberAndIds(member, request.getCarReservationIds()); - carReservations.forEach(CarReservation::updateReturn); - + carReservations.forEach( + carReservation -> { + validateCarReservationReserved(carReservation); + carReservation.updateReturn(); + }); final List carStocks = carReservations.stream().map(CarReservation::getCarStock).toList(); - carStocks.forEach(carStock -> carStock.updateStatus(StockStatus.AVAILABLE)); - - carStockRepository.saveAll(carStocks); + carStockService.returnCarStocks(carStocks); return carReservationRepository.saveAll(carReservations); } - public void validateCarStockAvailable(CarStock carStock) { + private void validateCarReservationReserved(CarReservation carReservation) { + if (carReservation.getStatus() != ReservationStatus.RESERVED) { + throw new BadRequestException(ErrorCode.CAR_RESERVATION_NOT_RESERVED); + } + } + + private void validateCarStockAvailable(CarStock carStock) { if (carStock.getStatus() != StockStatus.AVAILABLE) { throw new BadRequestException(ErrorCode.CAR_STOCK_NOT_AVAILABLE); } diff --git a/src/main/java/com/testcar/car/domains/carReservation/exception/ErrorCode.java b/src/main/java/com/testcar/car/domains/carReservation/exception/ErrorCode.java index 943aa39..b933daf 100644 --- a/src/main/java/com/testcar/car/domains/carReservation/exception/ErrorCode.java +++ b/src/main/java/com/testcar/car/domains/carReservation/exception/ErrorCode.java @@ -9,7 +9,8 @@ @RequiredArgsConstructor public enum ErrorCode implements BaseErrorCode { CAR_STOCK_NOT_AVAILABLE("CRS001", "해당 재고는 대여 불가합니다."), - CAR_RESERVATION_NOT_FOUND("CRS002", "해당 예약 정보를 찾을 수 없습니다."); + CAR_RESERVATION_NOT_FOUND("CRS002", "해당 예약 정보를 찾을 수 없습니다."), + CAR_RESERVATION_NOT_RESERVED("CRS003", "예약 중인 차량만 반납 가능합니다."); private final String code; private final String message; diff --git a/src/main/java/com/testcar/car/domains/carReservation/model/CarReservationRequest.java b/src/main/java/com/testcar/car/domains/carReservation/model/CarReservationRequest.java index 06a6713..2dcbafd 100644 --- a/src/main/java/com/testcar/car/domains/carReservation/model/CarReservationRequest.java +++ b/src/main/java/com/testcar/car/domains/carReservation/model/CarReservationRequest.java @@ -4,9 +4,11 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Positive; +import lombok.Builder; import lombok.Getter; @Getter +@Builder public class CarReservationRequest { @NotNull(message = "차량재고 ID를 입력해주세요.") @Positive(message = "차량재고 ID는 0보다 커야합니다.") diff --git a/src/main/java/com/testcar/car/domains/carReservation/model/ReturnCarReservationRequest.java b/src/main/java/com/testcar/car/domains/carReservation/model/ReturnCarReservationRequest.java index 491a494..ec0f76c 100644 --- a/src/main/java/com/testcar/car/domains/carReservation/model/ReturnCarReservationRequest.java +++ b/src/main/java/com/testcar/car/domains/carReservation/model/ReturnCarReservationRequest.java @@ -5,9 +5,11 @@ import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import java.util.List; +import lombok.Builder; import lombok.Getter; @Getter +@Builder public class ReturnCarReservationRequest { @NotNull(message = "차량 예약 ID 리스트를 입력해주세요.") @NotEmpty(message = "차량 예약 ID 리스트를 입력해주세요.") diff --git a/src/main/java/com/testcar/car/domains/carStock/CarStockService.java b/src/main/java/com/testcar/car/domains/carStock/CarStockService.java index bcc3237..aa1d6cc 100644 --- a/src/main/java/com/testcar/car/domains/carStock/CarStockService.java +++ b/src/main/java/com/testcar/car/domains/carStock/CarStockService.java @@ -6,6 +6,7 @@ import com.testcar.car.domains.car.CarService; import com.testcar.car.domains.car.entity.Car; import com.testcar.car.domains.carStock.entity.CarStock; +import com.testcar.car.domains.carStock.entity.StockStatus; import com.testcar.car.domains.carStock.exception.ErrorCode; import com.testcar.car.domains.carStock.model.DeleteCarStockRequest; import com.testcar.car.domains.carStock.model.RegisterCarStockRequest; @@ -73,11 +74,22 @@ public CarStock updateById(Long carStockId, UpdateCarStockRequest request) { return carStockRepository.save(carStock); } + /** 예약 중인 재고를 모두 반납합니다. */ + public List returnCarStocks(List carStocks) { + carStocks.forEach( + carStock -> { + validateCarStockReserved(carStock); + carStock.updateStatus(StockStatus.AVAILABLE); + }); + return carStockRepository.saveAll(carStocks); + } + /** 재고를 삭제 처리 합니다. (soft delete) */ - public List deleteAll(DeleteCarStockRequest request) { + public List deleteAll(DeleteCarStockRequest request) { final List stocks = this.findAllByIdIn(request.getIds()); stocks.forEach(CarStock::delete); - return carStockRepository.saveAll(stocks); + carStockRepository.saveAll(stocks); + return request.getIds(); } /** 영속되지 않은 재고 엔티티를 생성합니다. */ @@ -96,4 +108,11 @@ private void validateStockNumberNotDuplicated(String stockNumber) { throw new BadRequestException(ErrorCode.DUPLICATED_STOCK_NUMBER); } } + + /** 차량 재고가 예약 상태인지 검사합니다. */ + private void validateCarStockReserved(CarStock carStock) { + if (carStock.getStatus() != StockStatus.RESERVED) { + throw new BadRequestException(ErrorCode.CAR_STOCK_NOT_RESERVED); + } + } } diff --git a/src/main/java/com/testcar/car/domains/carStock/exception/ErrorCode.java b/src/main/java/com/testcar/car/domains/carStock/exception/ErrorCode.java index 9e6ca1d..c83a3ea 100644 --- a/src/main/java/com/testcar/car/domains/carStock/exception/ErrorCode.java +++ b/src/main/java/com/testcar/car/domains/carStock/exception/ErrorCode.java @@ -9,7 +9,8 @@ @RequiredArgsConstructor public enum ErrorCode implements BaseErrorCode { CAR_STOCK_NOT_FOUND("STK001", "해당 재고를 찾을 수 없습니다."), - DUPLICATED_STOCK_NUMBER("STK002", "중복된 재고번호입니다."); + DUPLICATED_STOCK_NUMBER("STK002", "중복된 재고번호입니다."), + CAR_STOCK_NOT_RESERVED("STK003", "예약중인 차량이 아닙니다."); private final String code; private final String message; diff --git a/src/main/java/com/testcar/car/domains/carStock/model/DeleteCarStockRequest.java b/src/main/java/com/testcar/car/domains/carStock/model/DeleteCarStockRequest.java index 139070a..8e3241e 100644 --- a/src/main/java/com/testcar/car/domains/carStock/model/DeleteCarStockRequest.java +++ b/src/main/java/com/testcar/car/domains/carStock/model/DeleteCarStockRequest.java @@ -6,9 +6,11 @@ import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Positive; import java.util.List; +import lombok.Builder; import lombok.Getter; @Getter +@Builder public class DeleteCarStockRequest { @NotNull(message = "차량 재고 ID를 입력해주세요.") @NotEmpty(message = "차량 재고 ID를 입력해주세요.") diff --git a/src/main/java/com/testcar/car/domains/carStock/model/RegisterCarStockRequest.java b/src/main/java/com/testcar/car/domains/carStock/model/RegisterCarStockRequest.java index d5c80fe..05ab485 100644 --- a/src/main/java/com/testcar/car/domains/carStock/model/RegisterCarStockRequest.java +++ b/src/main/java/com/testcar/car/domains/carStock/model/RegisterCarStockRequest.java @@ -7,9 +7,11 @@ import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Positive; +import lombok.Builder; import lombok.Getter; @Getter +@Builder public class RegisterCarStockRequest { @NotNull(message = "차량 ID를 입력해주세요.") @Positive(message = "차량 ID는 0보다 커야합니다.") diff --git a/src/main/java/com/testcar/car/domains/carStock/model/UpdateCarStockRequest.java b/src/main/java/com/testcar/car/domains/carStock/model/UpdateCarStockRequest.java index 13aef7c..afe238d 100644 --- a/src/main/java/com/testcar/car/domains/carStock/model/UpdateCarStockRequest.java +++ b/src/main/java/com/testcar/car/domains/carStock/model/UpdateCarStockRequest.java @@ -6,9 +6,11 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Pattern; +import lombok.Builder; import lombok.Getter; @Getter +@Builder public class UpdateCarStockRequest { @NotBlank(message = "차량 재고번호를 입력해주세요.") @Pattern(regexp = "^[0-9]{12}$", message = "차량 재고번호는 12자리 숫자만 가능합니다.") diff --git a/src/main/java/com/testcar/car/domains/carTest/model/CarTestRequest.java b/src/main/java/com/testcar/car/domains/carTest/model/CarTestRequest.java index 8437a8c..a2e4c28 100644 --- a/src/main/java/com/testcar/car/domains/carTest/model/CarTestRequest.java +++ b/src/main/java/com/testcar/car/domains/carTest/model/CarTestRequest.java @@ -6,9 +6,11 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import java.time.LocalDate; +import lombok.Builder; import lombok.Getter; @Getter +@Builder public class CarTestRequest { @NotBlank(message = "시험장 이름을 입력해주세요.") @Schema(description = "시험장 이름", example = "서산주행시험장") diff --git a/src/test/java/com/testcar/car/common/CarEntityFactory.java b/src/test/java/com/testcar/car/common/CarEntityFactory.java new file mode 100644 index 0000000..15432d8 --- /dev/null +++ b/src/test/java/com/testcar/car/common/CarEntityFactory.java @@ -0,0 +1,68 @@ +package com.testcar.car.common; + +import static com.testcar.car.common.Constant.CAR_DISPLACEMENT; +import static com.testcar.car.common.Constant.CAR_NAME; +import static com.testcar.car.common.Constant.CAR_STOCK_NUMBER; +import static com.testcar.car.common.Constant.CAR_TEST_RESULT; +import static com.testcar.car.common.Constant.CAR_TYPE; +import static com.testcar.car.common.Constant.EXPIRED_AT; +import static com.testcar.car.common.Constant.STARTED_AT; + +import com.testcar.car.domains.car.entity.Car; +import com.testcar.car.domains.car.entity.Car.CarBuilder; +import com.testcar.car.domains.carReservation.entity.CarReservation; +import com.testcar.car.domains.carReservation.entity.CarReservation.CarReservationBuilder; +import com.testcar.car.domains.carReservation.entity.ReservationStatus; +import com.testcar.car.domains.carStock.entity.CarStock; +import com.testcar.car.domains.carStock.entity.CarStock.CarStockBuilder; +import com.testcar.car.domains.carStock.entity.StockStatus; +import com.testcar.car.domains.carTest.entity.CarTest; +import com.testcar.car.domains.carTest.entity.CarTest.CarTestBuilder; + +public class CarEntityFactory { + private CarEntityFactory() {} + + public static Car createCar() { + return createCarBuilder().build(); + } + + public static CarBuilder createCarBuilder() { + return Car.builder().name(CAR_NAME).displacement(CAR_DISPLACEMENT).type(CAR_TYPE); + } + + public static CarStock createCarStock() { + return createCarStockBuilder().build(); + } + + public static CarStockBuilder createCarStockBuilder() { + return CarStock.builder() + .car(createCar()) + .stockNumber(CAR_STOCK_NUMBER) + .status(StockStatus.AVAILABLE); + } + + public static CarReservation createCarReservation() { + return createCarReservationBuilder().build(); + } + + public static CarReservationBuilder createCarReservationBuilder() { + return CarReservation.builder() + .member(MemberEntityFactory.createMember()) + .carStock(createCarStock()) + .startedAt(STARTED_AT) + .expiredAt(EXPIRED_AT) + .status(ReservationStatus.RESERVED); + } + + public static CarTest createCarTest() { + return createCarTestBuilder().build(); + } + + public static CarTestBuilder createCarTestBuilder() { + return CarTest.builder() + .member(MemberEntityFactory.createMember()) + .carStock(createCarStock()) + .performedAt(STARTED_AT) + .result(CAR_TEST_RESULT); + } +} diff --git a/src/test/java/com/testcar/car/common/Constant.java b/src/test/java/com/testcar/car/common/Constant.java new file mode 100644 index 0000000..652f82d --- /dev/null +++ b/src/test/java/com/testcar/car/common/Constant.java @@ -0,0 +1,38 @@ +package com.testcar.car.common; + + +import com.testcar.car.domains.car.entity.Type; +import com.testcar.car.domains.member.Role; +import java.time.LocalDateTime; + +public class Constant { + private Constant() {} + + /** Member */ + public static final String MEMBER_EMAIL = "test@test.com"; + + public static final String MEMBER_PASSWORD = "1234abcd@"; + public static final String MEMBER_NAME = "홍길동"; + public static final Role MEMBER_ROLE = Role.ADMIN; + public static final String DEPARTMENT_NAME = "모비스시스템팀"; + + /** Car */ + public static final String CAR_NAME = "아반떼"; + + public static final String ANOTHER_CAR_NAME = "소나타"; + public static final double CAR_DISPLACEMENT = 1.6; + public static final Type CAR_TYPE = Type.SEDAN; + public static final String CAR_STOCK_NUMBER = "123456789012"; + public static final String ANOTHER_CAR_STOCK_NUMBER = "987654321098"; + public static final LocalDateTime STARTED_AT = LocalDateTime.of(2021, 1, 1, 0, 0, 0); + public static final LocalDateTime EXPIRED_AT = LocalDateTime.of(2021, 1, 8, 0, 0, 0); + public static final String CAR_TEST_RESULT = "통과"; + + /** Track */ + public static final String TRACK_NAME = "서산주행시험장"; + + public static final String ANOTHER_TRACK_NAME = "마포주행시험장"; + public static final String TRACK_LOCATION = "충청남도 서산시 부석면"; + public static final String TRACK_DESCRIPTION = "비탈길"; + public static final double TRACK_LENGTH = 12.6; +} diff --git a/src/test/java/com/testcar/car/common/DtoFactory.java b/src/test/java/com/testcar/car/common/DtoFactory.java new file mode 100644 index 0000000..858b945 --- /dev/null +++ b/src/test/java/com/testcar/car/common/DtoFactory.java @@ -0,0 +1,30 @@ +package com.testcar.car.common; + +import static com.testcar.car.common.CarEntityFactory.createCarStock; +import static com.testcar.car.common.CarEntityFactory.createCarTest; +import static com.testcar.car.common.TrackEntityFactory.createTrack; + +import com.testcar.car.domains.car.entity.Car; +import com.testcar.car.domains.carStock.entity.CarStock; +import com.testcar.car.domains.carTest.model.vo.CarTestDto; +import com.testcar.car.domains.department.entity.Department; +import com.testcar.car.domains.member.Member; + +public class DtoFactory { + private DtoFactory() {} + + public static CarTestDto createCarTestDto() { + final Member member = MemberEntityFactory.createMember(); + final Department department = member.getDepartment(); + final CarStock carStock = createCarStock(); + final Car car = carStock.getCar(); + return new CarTestDto( + createCarTest(), + createTrack(), + member.getName(), + member.getName(), + department.getName(), + car.getName(), + carStock.getStockNumber()); + } +} diff --git a/src/test/java/com/testcar/car/common/MemberEntityFactory.java b/src/test/java/com/testcar/car/common/MemberEntityFactory.java new file mode 100644 index 0000000..6b0d2c0 --- /dev/null +++ b/src/test/java/com/testcar/car/common/MemberEntityFactory.java @@ -0,0 +1,36 @@ +package com.testcar.car.common; + +import static com.testcar.car.common.Constant.DEPARTMENT_NAME; +import static com.testcar.car.common.Constant.MEMBER_EMAIL; +import static com.testcar.car.common.Constant.MEMBER_NAME; +import static com.testcar.car.common.Constant.MEMBER_PASSWORD; +import static com.testcar.car.common.Constant.MEMBER_ROLE; + +import com.testcar.car.domains.department.entity.Department; +import com.testcar.car.domains.member.Member; +import com.testcar.car.domains.member.Member.MemberBuilder; + +public class MemberEntityFactory { + private MemberEntityFactory() {} + + public static Member createMember() { + return createMemberBuilder().build(); + } + + public static MemberBuilder createMemberBuilder() { + return Member.builder() + .email(MEMBER_EMAIL) + .password(MEMBER_PASSWORD) + .name(MEMBER_NAME) + .department(createDepartment()) + .role(MEMBER_ROLE); + } + + public static Department createDepartment() { + return createDepartmentBuilder().build(); + } + + public static Department.DepartmentBuilder createDepartmentBuilder() { + return Department.builder().name(DEPARTMENT_NAME); + } +} diff --git a/src/test/java/com/testcar/car/common/TrackEntityFactory.java b/src/test/java/com/testcar/car/common/TrackEntityFactory.java new file mode 100644 index 0000000..c3c048f --- /dev/null +++ b/src/test/java/com/testcar/car/common/TrackEntityFactory.java @@ -0,0 +1,25 @@ +package com.testcar.car.common; + +import static com.testcar.car.common.Constant.TRACK_DESCRIPTION; +import static com.testcar.car.common.Constant.TRACK_LENGTH; +import static com.testcar.car.common.Constant.TRACK_LOCATION; +import static com.testcar.car.common.Constant.TRACK_NAME; + +import com.testcar.car.domains.track.Track; +import com.testcar.car.domains.track.Track.TrackBuilder; + +public class TrackEntityFactory { + private TrackEntityFactory() {} + + public static Track createTrack() { + return createTrackBuilder().build(); + } + + public static TrackBuilder createTrackBuilder() { + return Track.builder() + .name(TRACK_NAME) + .location(TRACK_LOCATION) + .description(TRACK_DESCRIPTION) + .length(TRACK_LENGTH); + } +} diff --git a/src/test/java/com/testcar/car/domains/car/CarServiceTest.java b/src/test/java/com/testcar/car/domains/car/CarServiceTest.java new file mode 100644 index 0000000..8e8a2e3 --- /dev/null +++ b/src/test/java/com/testcar/car/domains/car/CarServiceTest.java @@ -0,0 +1,149 @@ +package com.testcar.car.domains.car; + +import static com.testcar.car.common.Constant.ANOTHER_CAR_NAME; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.then; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.testcar.car.common.CarEntityFactory; +import com.testcar.car.common.exception.BadRequestException; +import com.testcar.car.common.exception.NotFoundException; +import com.testcar.car.domains.car.entity.Car; +import com.testcar.car.domains.car.model.RegisterCarRequest; +import com.testcar.car.domains.car.model.vo.CarFilterCondition; +import com.testcar.car.domains.car.repository.CarRepository; +import com.testcar.car.domains.car.request.CarRequestFactory; +import java.util.Optional; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +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; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +@ExtendWith(MockitoExtension.class) +public class CarServiceTest { + @Mock private CarRepository carRepository; + + @InjectMocks private CarService carService; + + private static Car car; + private static final Long carId = 1L; + + @BeforeAll + public static void setUp() { + car = CarEntityFactory.createCar(); + } + + @Test + void 차량_ID로_차량_엔티티를_가져온다() { + // given + when(carRepository.findByIdAndDeletedFalse(carId)).thenReturn(Optional.of(car)); + + // when + Car result = carService.findById(carId); + + // then + assertEquals(car, result); + verify(carRepository).findByIdAndDeletedFalse(carId); + } + + @Test + void 차량_ID가_존재하지_않으면_오류가_발생한다() { + // given + when(carRepository.findByIdAndDeletedFalse(carId)).thenReturn(Optional.empty()); + + // when, then + Assertions.assertThrows( + NotFoundException.class, + () -> { + carService.findById(carId); + }); + } + + @Test + void 조건에_맞는_차량_페이지를_필터링하여_가져온다() { + // given + CarFilterCondition condition = new CarFilterCondition(); + Pageable pageable = mock(Pageable.class); + Page mockPage = mock(Page.class); + when(carRepository.findAllPageByCondition(condition, pageable)).thenReturn(mockPage); + + // when + Page result = carService.findAllPageByCondition(condition, pageable); + + // then + assertEquals(mockPage, result); + } + + @Test + void 차량을_등록한다() { + // given + RegisterCarRequest request = CarRequestFactory.createRegisterCarRequest(); + given(carRepository.save(any(Car.class))).willReturn(car); + + // when + Car newCar = carService.register(request); + + // then + then(carRepository).should().save(any(Car.class)); + assertNotNull(newCar); + } + + @Test + void 차량정보를_수정한다() { + // given + RegisterCarRequest request = CarRequestFactory.createRegisterCarRequest(); + when(carRepository.findByIdAndDeletedFalse(carId)).thenReturn(Optional.of(car)); + given(carRepository.save(any(Car.class))).willReturn(car); + + // when + Car newCar = carService.updateById(carId, request); + + // then + verify(carRepository).findByIdAndDeletedFalse(carId); + then(carRepository).should().save(any(Car.class)); + assertNotNull(newCar); + } + + @Test + void 이미_존재하는_이름의_차량으로_수정할수_없다() { + // given + RegisterCarRequest request = CarRequestFactory.createRegisterCarRequest(ANOTHER_CAR_NAME); + when(carRepository.findByIdAndDeletedFalse(carId)).thenReturn(Optional.of(car)); + when(carRepository.existsByNameAndDeletedFalse(request.getName())).thenReturn(true); + + // when + Assertions.assertThrows( + BadRequestException.class, + () -> { + carService.updateById(carId, request); + }); + then(carRepository).shouldHaveNoMoreInteractions(); + } + + @Test + void 차량을_삭제한다() { + // given + when(carRepository.findByIdAndDeletedFalse(carId)).thenReturn(Optional.of(car)); + given(carRepository.save(any(Car.class))).willReturn(car); + + // when + Car deletedCar = carService.deleteById(carId); + + // then + verify(carRepository).findByIdAndDeletedFalse(carId); + then(carRepository).should().save(any(Car.class)); + assertNotNull(deletedCar); + assertTrue(deletedCar.getDeleted()); + } +} diff --git a/src/test/java/com/testcar/car/domains/car/TestCarServiceTest.java b/src/test/java/com/testcar/car/domains/car/TestCarServiceTest.java new file mode 100644 index 0000000..3f81d48 --- /dev/null +++ b/src/test/java/com/testcar/car/domains/car/TestCarServiceTest.java @@ -0,0 +1,79 @@ +package com.testcar.car.domains.car; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.testcar.car.common.CarEntityFactory; +import com.testcar.car.common.exception.NotFoundException; +import com.testcar.car.domains.car.entity.Car; +import com.testcar.car.domains.car.model.vo.CarFilterCondition; +import com.testcar.car.domains.car.repository.CarRepository; +import java.util.Optional; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +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; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +@ExtendWith(MockitoExtension.class) +public class TestCarServiceTest { + @Mock private CarRepository carRepository; + + @InjectMocks private TestCarService testCarService; + + private static Car car; + private static final Long carId = 1L; + + @BeforeAll + public static void setUp() { + car = CarEntityFactory.createCar(); + } + + @Test + void 차량_ID로_차량_엔티티를_가져온다() { + // given + when(carRepository.findWithStocksById(carId)).thenReturn(Optional.of(car)); + + // when + Car result = testCarService.findById(carId); + + // then + assertEquals(car, result); + verify(carRepository).findWithStocksById(carId); + } + + @Test + void 차량_ID가_존재하지_않으면_오류가_발생한다() { + // given + when(carRepository.findWithStocksById(carId)).thenReturn(Optional.empty()); + + // when, then + Assertions.assertThrows( + NotFoundException.class, + () -> { + testCarService.findById(carId); + }); + } + + @Test + void 조건에_맞는_차량_페이지를_필터링하여_가져온다() { + // given + CarFilterCondition condition = new CarFilterCondition(); + Pageable pageable = mock(Pageable.class); + Page mockPage = mock(Page.class); + when(carRepository.findAllWithStocksPageByCondition(condition, pageable)) + .thenReturn(mockPage); + + // when + Page result = testCarService.findAllWithStocksPageByCondition(condition, pageable); + + // then + assertEquals(mockPage, result); + } +} diff --git a/src/test/java/com/testcar/car/domains/car/entity/CarTest.java b/src/test/java/com/testcar/car/domains/car/entity/CarTest.java new file mode 100644 index 0000000..ab23ba5 --- /dev/null +++ b/src/test/java/com/testcar/car/domains/car/entity/CarTest.java @@ -0,0 +1,40 @@ +package com.testcar.car.domains.car.entity; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.testcar.car.common.CarEntityFactory; +import org.junit.jupiter.api.Test; + +public class CarTest { + @Test + public void 차량을_생성한다() { + // given + final String name = "아반떼"; + final Double displacement = 1.6; + final Type type = Type.SEDAN; + + // when + final Car car = Car.builder().name(name).displacement(displacement).type(type).build(); + + // then + assertThat(car.getName()).isEqualTo(name); + assertThat(car.getDisplacement()).isEqualTo(displacement); + assertThat(car.getType()).isEqualTo(type); + } + + @Test + public void 차량_정보를_변경한다() { + // given + final Car car = CarEntityFactory.createCar(); + final Car updatedCar = + Car.builder().name("소나타").displacement(1600.0).type(Type.SEDAN).build(); + + // when + car.update(updatedCar); + + // then + assertThat(car.getName()).isEqualTo(updatedCar.getName()); + assertThat(car.getDisplacement()).isEqualTo(updatedCar.getDisplacement()); + assertThat(car.getType()).isEqualTo(updatedCar.getType()); + } +} diff --git a/src/test/java/com/testcar/car/domains/car/request/CarRequestFactory.java b/src/test/java/com/testcar/car/domains/car/request/CarRequestFactory.java new file mode 100644 index 0000000..770a5fc --- /dev/null +++ b/src/test/java/com/testcar/car/domains/car/request/CarRequestFactory.java @@ -0,0 +1,27 @@ +package com.testcar.car.domains.car.request; + +import static com.testcar.car.common.Constant.CAR_DISPLACEMENT; +import static com.testcar.car.common.Constant.CAR_NAME; +import static com.testcar.car.common.Constant.CAR_TYPE; + +import com.testcar.car.domains.car.model.RegisterCarRequest; + +public class CarRequestFactory { + private CarRequestFactory() {} + + public static RegisterCarRequest createRegisterCarRequest() { + return RegisterCarRequest.builder() + .name(CAR_NAME) + .type(CAR_TYPE) + .displacement(CAR_DISPLACEMENT) + .build(); + } + + public static RegisterCarRequest createRegisterCarRequest(String name) { + return RegisterCarRequest.builder() + .name(name) + .type(CAR_TYPE) + .displacement(CAR_DISPLACEMENT) + .build(); + } +} diff --git a/src/test/java/com/testcar/car/domains/carReservation/CarReservationServiceTest.java b/src/test/java/com/testcar/car/domains/carReservation/CarReservationServiceTest.java new file mode 100644 index 0000000..09da16a --- /dev/null +++ b/src/test/java/com/testcar/car/domains/carReservation/CarReservationServiceTest.java @@ -0,0 +1,208 @@ +package com.testcar.car.domains.carReservation; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyCollection; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.then; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.testcar.car.common.CarEntityFactory; +import com.testcar.car.common.MemberEntityFactory; +import com.testcar.car.common.exception.BadRequestException; +import com.testcar.car.common.exception.NotFoundException; +import com.testcar.car.domains.car.entity.Car; +import com.testcar.car.domains.carReservation.entity.CarReservation; +import com.testcar.car.domains.carReservation.entity.ReservationStatus; +import com.testcar.car.domains.carReservation.model.CarReservationRequest; +import com.testcar.car.domains.carReservation.model.ReturnCarReservationRequest; +import com.testcar.car.domains.carReservation.model.dto.CarReservationDto; +import com.testcar.car.domains.carReservation.model.vo.CarReservationFilterCondition; +import com.testcar.car.domains.carReservation.repository.CarReservationRepository; +import com.testcar.car.domains.carReservation.request.CarReservationRequestFactory; +import com.testcar.car.domains.carStock.CarStockService; +import com.testcar.car.domains.carStock.entity.CarStock; +import com.testcar.car.domains.carStock.entity.StockStatus; +import com.testcar.car.domains.carStock.repository.CarStockRepository; +import com.testcar.car.domains.member.Member; +import java.util.List; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +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; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +@ExtendWith(MockitoExtension.class) +public class CarReservationServiceTest { + @Mock private CarStockService carStockService; + @Mock private CarStockRepository carStockRepository; + @Mock private CarReservationRepository carReservationRepository; + + @InjectMocks private CarReservationService carReservationService; + + private static Member member; + private static Car car; + private static CarStock carStock; + private static List carReservations; + private static final List carReservationIds = List.of(1L, 2L); + + @BeforeAll + public static void setUp() { + member = MemberEntityFactory.createMember(); + car = CarEntityFactory.createCar(); + carStock = CarEntityFactory.createCarStock(); + carReservations = + List.of( + CarEntityFactory.createCarReservation(), + CarEntityFactory.createCarReservation()); + } + + @Test + void 조건에_맞는_시험차량_예약정보_페이지를_필터링하여_가져온다() { + // given + final CarReservationFilterCondition condition = new CarReservationFilterCondition(); + final Pageable pageable = mock(Pageable.class); + final Page mockPage = mock(Page.class); + when(carReservationRepository.findAllPageByCondition(condition, pageable)) + .thenReturn(mockPage); + + // when + Page result = + carReservationService.findAllPageByCondition(condition, pageable); + + // then + assertEquals(mockPage, result); + } + + @Test + void 자신의_시험차량_예약ID_리스트로_시험차량_예약_리스트를_가져온다() { + // given + when(carReservationRepository.findAllWithCarStockByIdInAndMemberId( + carReservationIds, member.getId())) + .thenReturn(carReservations); + + // when + List result = + carReservationService.findAllByMemberAndIds(member, carReservationIds); + + // then + assertEquals(carReservations, result); + verify(carReservationRepository) + .findAllWithCarStockByIdInAndMemberId(carReservationIds, member.getId()); + } + + @Test + void 자신의_시험차량_예약ID_리스트와_결과_개수가_일치하지_않으면_오류가_발생한다() { + // given + final List carReservationIds = List.of(1L); + when(carReservationRepository.findAllWithCarStockByIdInAndMemberId( + carReservationIds, member.getId())) + .thenReturn(carReservations); + + // when, then + Assertions.assertThrows( + NotFoundException.class, + () -> { + carReservationService.findAllByMemberAndIds(member, carReservationIds); + }); + } + + @Test + void 시험차량을_예약한다() { + // given + final CarReservation carReservation = carReservations.get(0); + final CarReservationRequest request = + CarReservationRequestFactory.createCarReservationRequest(); + given(carReservationRepository.save(any(CarReservation.class))).willReturn(carReservation); + when(carStockService.findById(request.getCarStockId())).thenReturn(carStock); + + // when + CarReservation newCarReservation = carReservationService.reserve(member, request); + + // then + then(carReservationRepository).should().save(any(CarReservation.class)); + then(carStockService).should().findById(any(Long.class)); + assertNotNull(newCarReservation); + } + + @Test + void 예약가능_상태가_아닌_시험차량은_예약할수_없다() { + // given + final CarStock unavailableCarStock = + CarEntityFactory.createCarStockBuilder().status(StockStatus.RESERVED).build(); + final CarReservationRequest request = + CarReservationRequestFactory.createCarReservationRequest(); + when(carStockService.findById(request.getCarStockId())).thenReturn(unavailableCarStock); + + // when, then + Assertions.assertThrows( + BadRequestException.class, + () -> { + carReservationService.reserve(member, request); + }); + then(carStockService).should().findById(any(Long.class)); + then(carReservationRepository).shouldHaveNoMoreInteractions(); + } + + @Test + void 예약한_시험차량을_반납한다() { + // given + final ReturnCarReservationRequest request = + CarReservationRequestFactory.createReturnCarReservationRequest(carReservationIds); + given(carReservationRepository.saveAll(anyCollection())).willReturn(carReservations); + given( + carReservationRepository.findAllWithCarStockByIdInAndMemberId( + carReservationIds, member.getId())) + .willReturn(carReservations); + + // when + List result = carReservationService.returnCarReservation(member, request); + + // then + then(carReservationRepository).should().saveAll(anyCollection()); + then(carReservationRepository) + .should() + .findAllWithCarStockByIdInAndMemberId( + request.getCarReservationIds(), member.getId()); + assertEquals(carReservations, result); + } + + @Test + void 이미_반납한_시험차량은_다시_반납할수_없다() { + // given + final CarReservation reservedCarReservation1 = + CarEntityFactory.createCarReservationBuilder() + .status(ReservationStatus.RETURNED) + .build(); + final CarReservation reservedCarReservation2 = + CarEntityFactory.createCarReservationBuilder() + .status(ReservationStatus.RETURNED) + .build(); + List ids = List.of(1L, 2L); + final ReturnCarReservationRequest request = + CarReservationRequestFactory.createReturnCarReservationRequest(ids); + final List reservedCarReservations = + List.of(reservedCarReservation1, reservedCarReservation2); + given(carReservationRepository.findAllWithCarStockByIdInAndMemberId(ids, member.getId())) + .willReturn(reservedCarReservations); + + // when, then + Assertions.assertThrows( + BadRequestException.class, + () -> { + carReservationService.returnCarReservation(member, request); + }); + then(carReservationRepository) + .should() + .findAllWithCarStockByIdInAndMemberId( + request.getCarReservationIds(), member.getId()); + then(carReservationRepository).shouldHaveNoMoreInteractions(); + } +} diff --git a/src/test/java/com/testcar/car/domains/carReservation/entity/CarReservationTest.java b/src/test/java/com/testcar/car/domains/carReservation/entity/CarReservationTest.java new file mode 100644 index 0000000..7caf0f9 --- /dev/null +++ b/src/test/java/com/testcar/car/domains/carReservation/entity/CarReservationTest.java @@ -0,0 +1,57 @@ +package com.testcar.car.domains.carReservation.entity; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.testcar.car.common.CarEntityFactory; +import com.testcar.car.common.MemberEntityFactory; +import com.testcar.car.domains.carStock.entity.CarStock; +import com.testcar.car.domains.member.Member; +import java.time.LocalDateTime; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class CarReservationTest { + private static CarStock carStock; + private static Member member; + + @BeforeAll + public static void setUp() { + member = MemberEntityFactory.createMember(); + carStock = CarEntityFactory.createCarStock(); + } + + @Test + public void 차량_예약을_생성한다() { + // given + final LocalDateTime startedAt = LocalDateTime.of(2021, 1, 1, 0, 0, 0); + final LocalDateTime expiredAt = LocalDateTime.of(2021, 1, 8, 0, 0, 0); + + // when + final CarReservation carReservation = + CarReservation.builder() + .member(member) + .carStock(carStock) + .startedAt(startedAt) + .expiredAt(expiredAt) + .status(ReservationStatus.RESERVED) + .build(); + // then + assertThat(carReservation.getMember()).isEqualTo(member); + assertThat(carReservation.getCarStock()).isEqualTo(carStock); + assertThat(carReservation.getStartedAt()).isEqualTo(startedAt); + assertThat(carReservation.getExpiredAt()).isEqualTo(expiredAt); + assertThat(carReservation.getStatus()).isEqualTo(ReservationStatus.RESERVED); + } + + @Test + public void 예약했던_차량을_반납한다() { + // given + final CarReservation carReservation = CarEntityFactory.createCarReservation(); + + // when + carReservation.updateReturn(); + + // then + assertThat(carReservation.getStatus()).isEqualTo(ReservationStatus.RETURNED); + } +} diff --git a/src/test/java/com/testcar/car/domains/carReservation/request/CarReservationRequestFactory.java b/src/test/java/com/testcar/car/domains/carReservation/request/CarReservationRequestFactory.java new file mode 100644 index 0000000..61f4e26 --- /dev/null +++ b/src/test/java/com/testcar/car/domains/carReservation/request/CarReservationRequestFactory.java @@ -0,0 +1,18 @@ +package com.testcar.car.domains.carReservation.request; + + +import com.testcar.car.domains.carReservation.model.CarReservationRequest; +import com.testcar.car.domains.carReservation.model.ReturnCarReservationRequest; +import java.util.List; + +public class CarReservationRequestFactory { + private CarReservationRequestFactory() {} + + public static CarReservationRequest createCarReservationRequest() { + return CarReservationRequest.builder().carStockId(1L).build(); + } + + public static ReturnCarReservationRequest createReturnCarReservationRequest(List ids) { + return ReturnCarReservationRequest.builder().carReservationIds(ids).build(); + } +} diff --git a/src/test/java/com/testcar/car/domains/carStock/CarStockServiceTest.java b/src/test/java/com/testcar/car/domains/carStock/CarStockServiceTest.java new file mode 100644 index 0000000..d3c46b0 --- /dev/null +++ b/src/test/java/com/testcar/car/domains/carStock/CarStockServiceTest.java @@ -0,0 +1,290 @@ +package com.testcar.car.domains.carStock; + +import static com.testcar.car.common.Constant.CAR_STOCK_NUMBER; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.then; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.testcar.car.common.CarEntityFactory; +import com.testcar.car.common.MemberEntityFactory; +import com.testcar.car.common.exception.BadRequestException; +import com.testcar.car.common.exception.NotFoundException; +import com.testcar.car.domains.car.CarService; +import com.testcar.car.domains.car.entity.Car; +import com.testcar.car.domains.carStock.entity.CarStock; +import com.testcar.car.domains.carStock.entity.StockStatus; +import com.testcar.car.domains.carStock.model.DeleteCarStockRequest; +import com.testcar.car.domains.carStock.model.RegisterCarStockRequest; +import com.testcar.car.domains.carStock.model.UpdateCarStockRequest; +import com.testcar.car.domains.carStock.model.vo.CarStockFilterCondition; +import com.testcar.car.domains.carStock.repository.CarStockRepository; +import com.testcar.car.domains.carStock.request.CarStockRequestFactory; +import com.testcar.car.domains.member.Member; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +@ExtendWith(MockitoExtension.class) +public class CarStockServiceTest { + @Mock private CarService carService; + @Mock private CarStockRepository carStockRepository; + + @InjectMocks private CarStockService carStockService; + + private static Member member; + private static Car car; + private static CarStock carStock; + private static final Long carStockId = 1L; + + @BeforeAll + public static void setUp() { + member = MemberEntityFactory.createMember(); + car = CarEntityFactory.createCar(); + carStock = CarEntityFactory.createCarStock(); + } + + @Test + void 차량_재고번호로_차량재고_엔티티를_가져온다() { + // given + final String stockNumber = CAR_STOCK_NUMBER; + when(carStockRepository.findByStockNumberAndDeletedFalse(stockNumber)) + .thenReturn(Optional.of(carStock)); + + // when + CarStock result = carStockService.findByStockNumber(stockNumber); + + // then + assertEquals(carStock, result); + verify(carStockRepository).findByStockNumberAndDeletedFalse(stockNumber); + } + + @Test + void 차량_재고번호가_존재하지_않으면_오류가_발생한다() { + // given + final String stockNumber = CAR_STOCK_NUMBER; + when(carStockRepository.findByStockNumberAndDeletedFalse(stockNumber)) + .thenReturn(Optional.empty()); + + // when, then + Assertions.assertThrows( + NotFoundException.class, + () -> { + carStockService.findByStockNumber(stockNumber); + }); + } + + @Test + void 차량_재고ID로_차량재고_엔티티를_가져온다() { + // given + when(carStockRepository.findByIdAndDeletedFalse(carStockId)) + .thenReturn(Optional.of(carStock)); + + // when + CarStock result = carStockService.findById(carStockId); + + // then + assertEquals(carStock, result); + verify(carStockRepository).findByIdAndDeletedFalse(carStockId); + } + + @Test + void 차량_재고_ID가_존재하지_않으면_오류가_발생한다() { + // given + when(carStockRepository.findByIdAndDeletedFalse(carStockId)).thenReturn(Optional.empty()); + + // when, then + Assertions.assertThrows( + NotFoundException.class, + () -> { + carStockService.findById(carStockId); + }); + } + + @Test + void 차량_재고ID_리스트로_차량재고_리스트를_가져온다() { + // given + final CarStock carStock1 = CarEntityFactory.createCarStock(); + final CarStock carStock2 = CarEntityFactory.createCarStock(); + final CarStock carStock3 = CarEntityFactory.createCarStock(); + final List carStocks = List.of(carStock1, carStock2, carStock3); + final List carStockIds = List.of(1L, 2L, 3L); + when(carStockRepository.findAllByIdInAndDeletedFalse(carStockIds)).thenReturn(carStocks); + + // when + List result = carStockService.findAllByIdIn(carStockIds); + + // then + assertEquals(carStocks, result); + verify(carStockRepository).findAllByIdInAndDeletedFalse(carStockIds); + } + + @Test + void 차량_재고ID_리스트와_결과_개수가_일치하지_않으면_오류가_발생한다() { + // given + final CarStock carStock1 = CarEntityFactory.createCarStock(); + final CarStock carStock2 = CarEntityFactory.createCarStock(); + final List fewerStocks = List.of(carStock1, carStock2); + final List carStockIds = List.of(1L, 2L, 3L); + when(carStockRepository.findAllByIdInAndDeletedFalse(carStockIds)).thenReturn(fewerStocks); + + // when, then + Assertions.assertThrows( + NotFoundException.class, + () -> { + carStockService.findAllByIdIn(carStockIds); + }); + } + + @Test + void 조건에_맞는_차량재고_페이지를_필터링하여_가져온다() { + // given + CarStockFilterCondition condition = new CarStockFilterCondition(); + Pageable pageable = mock(Pageable.class); + Page mockPage = mock(Page.class); + when(carStockRepository.findAllPageByCondition(condition, pageable)).thenReturn(mockPage); + + // when + Page result = carStockService.findAllPageByCondition(condition, pageable); + + // then + assertEquals(mockPage, result); + } + + @Test + void 차량재고를_등록한다() { + // given + RegisterCarStockRequest request = CarStockRequestFactory.createRegisterCarStockRequest(); + given(carStockRepository.save(any(CarStock.class))).willReturn(carStock); + + // when + CarStock newCarStock = carStockService.register(request); + + // then + then(carStockRepository).should().save(any(CarStock.class)); + assertNotNull(newCarStock); + } + + @Test + void 이미_등록된_재고번호로는_등록할수_없다() { + // given + RegisterCarStockRequest request = CarStockRequestFactory.createRegisterCarStockRequest(); + given(carStockRepository.existsByStockNumberAndDeletedFalse(request.getStockNumber())) + .willReturn(true); + + // when, then + Assertions.assertThrows( + BadRequestException.class, + () -> { + carStockService.register(request); + }); + then(carStockRepository).shouldHaveNoMoreInteractions(); + } + + @Test + void 차량재고를_수정한다() { + // given + UpdateCarStockRequest request = CarStockRequestFactory.createUpdateCarStockRequest(); + when(carStockRepository.findByIdAndDeletedFalse(carStockId)) + .thenReturn(Optional.of(carStock)); + given(carStockRepository.save(any(CarStock.class))).willReturn(carStock); + + // when + CarStock newCarStock = carStockService.updateById(carStockId, request); + + // then + verify(carStockRepository).findByIdAndDeletedFalse(carStockId); + then(carStockRepository).should().save(any(CarStock.class)); + assertNotNull(newCarStock); + } + + @Test + void 이미_등록된_재고번호로는_수정할수_없다() { + // given + UpdateCarStockRequest request = CarStockRequestFactory.createUpdateCarStockRequest(); + when(carStockRepository.findByIdAndDeletedFalse(carStockId)) + .thenReturn(Optional.of(carStock)); + given(carStockRepository.existsByStockNumberAndDeletedFalse(request.getStockNumber())) + .willReturn(true); + + // when, then + Assertions.assertThrows( + BadRequestException.class, + () -> { + carStockService.updateById(carStockId, request); + }); + then(carStockRepository).shouldHaveNoMoreInteractions(); + } + + @Test + void 예약중인_차량재고를_모두_반납한다() { + // given + final CarStock carStock1 = + CarEntityFactory.createCarStockBuilder().status(StockStatus.RESERVED).build(); + final CarStock carStock2 = + CarEntityFactory.createCarStockBuilder().status(StockStatus.RESERVED).build(); + final List carStocks = List.of(carStock1, carStock2); + + // when + final List returnedCarStocks = carStockService.returnCarStocks(carStocks); + + // then + returnedCarStocks.forEach( + carStock -> assertEquals(StockStatus.AVAILABLE, carStock.getStatus())); + verify(carStockRepository).saveAll(carStocks); + } + + @ParameterizedTest + @EnumSource( + value = StockStatus.class, + names = {"AVAILABLE", "UNAVAILABLE", "INSPECTION"}) + void 예약중이지_않은_차량재고는_반납할수_없다(StockStatus status) { + // given + final CarStock carStock = CarEntityFactory.createCarStockBuilder().status(status).build(); + final List carStocks = List.of(carStock); + + // when, then + Assertions.assertThrows( + BadRequestException.class, + () -> { + carStockService.returnCarStocks(carStocks); + }); + then(carStockRepository).shouldHaveNoMoreInteractions(); + } + + @Test + void 차량재고를_삭제한다() { + // given + final CarStock carStock1 = CarEntityFactory.createCarStock(); + final CarStock carStock2 = CarEntityFactory.createCarStock(); + final CarStock carStock3 = CarEntityFactory.createCarStock(); + final List carStocks = List.of(carStock1, carStock2, carStock3); + DeleteCarStockRequest request = CarStockRequestFactory.createDeleteCarStockRequest(); + when(carStockRepository.findAllByIdInAndDeletedFalse(request.getIds())) + .thenReturn(carStocks); + + // when + List deletedIds = carStockService.deleteAll(request); + + // then + verify(carStockRepository).findAllByIdInAndDeletedFalse(request.getIds()); + assertEquals(carStock1.getDeleted(), true); + assertEquals(carStock2.getDeleted(), true); + assertEquals(carStock3.getDeleted(), true); + assertEquals(deletedIds, request.getIds()); + } +} diff --git a/src/test/java/com/testcar/car/domains/carStock/entity/CarStockTest.java b/src/test/java/com/testcar/car/domains/carStock/entity/CarStockTest.java new file mode 100644 index 0000000..57c2a50 --- /dev/null +++ b/src/test/java/com/testcar/car/domains/carStock/entity/CarStockTest.java @@ -0,0 +1,58 @@ +package com.testcar.car.domains.carStock.entity; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.testcar.car.common.CarEntityFactory; +import com.testcar.car.domains.car.entity.Car; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class CarStockTest { + private static Car car; + private static CarStock carStock; + + @BeforeAll + public static void setUp() { + car = CarEntityFactory.createCar(); + carStock = CarEntityFactory.createCarStock(); + } + + @Test + public void 차량_재고를_생성한다() { + // given + final String stockNumber = "123456789012"; + final StockStatus status = StockStatus.AVAILABLE; + + // when + final CarStock newCarStock = + CarStock.builder().car(car).stockNumber(stockNumber).status(status).build(); + // then + assertThat(newCarStock.getCar()).isEqualTo(car); + assertThat(newCarStock.getStockNumber()).isEqualTo(stockNumber); + assertThat(newCarStock.getStatus()).isEqualTo(status); + } + + @Test + public void 차량_재고의_재고번호를_변경한다() { + // given + final String newStockNumber = "123456789013"; + + // when + carStock.updateStockNumber(newStockNumber); + + // then + assertThat(carStock.getStockNumber()).isEqualTo(newStockNumber); + } + + @Test + public void 차량_재고의_재고상태를_변경한다() { + // given + final StockStatus newStatus = StockStatus.INSPECTION; + + // when + carStock.updateStatus(newStatus); + + // then + assertThat(carStock.getStatus()).isEqualTo(newStatus); + } +} diff --git a/src/test/java/com/testcar/car/domains/carStock/request/CarStockRequestFactory.java b/src/test/java/com/testcar/car/domains/carStock/request/CarStockRequestFactory.java new file mode 100644 index 0000000..d412373 --- /dev/null +++ b/src/test/java/com/testcar/car/domains/carStock/request/CarStockRequestFactory.java @@ -0,0 +1,33 @@ +package com.testcar.car.domains.carStock.request; + +import static com.testcar.car.common.Constant.ANOTHER_CAR_STOCK_NUMBER; +import static com.testcar.car.common.Constant.CAR_STOCK_NUMBER; + +import com.testcar.car.domains.carStock.entity.StockStatus; +import com.testcar.car.domains.carStock.model.DeleteCarStockRequest; +import com.testcar.car.domains.carStock.model.RegisterCarStockRequest; +import com.testcar.car.domains.carStock.model.UpdateCarStockRequest; +import java.util.List; + +public class CarStockRequestFactory { + private CarStockRequestFactory() {} + + public static RegisterCarStockRequest createRegisterCarStockRequest() { + return RegisterCarStockRequest.builder() + .carId(1L) + .stockNumber(CAR_STOCK_NUMBER) + .status(StockStatus.AVAILABLE) + .build(); + } + + public static UpdateCarStockRequest createUpdateCarStockRequest() { + return UpdateCarStockRequest.builder() + .stockNumber(ANOTHER_CAR_STOCK_NUMBER) + .status(StockStatus.AVAILABLE) + .build(); + } + + public static DeleteCarStockRequest createDeleteCarStockRequest() { + return DeleteCarStockRequest.builder().ids(List.of(1L, 2L, 3L)).build(); + } +} diff --git a/src/test/java/com/testcar/car/domains/carTest/CarTestServiceTest.java b/src/test/java/com/testcar/car/domains/carTest/CarTestServiceTest.java new file mode 100644 index 0000000..a55d65b --- /dev/null +++ b/src/test/java/com/testcar/car/domains/carTest/CarTestServiceTest.java @@ -0,0 +1,143 @@ +package com.testcar.car.domains.carTest; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.then; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.testcar.car.common.CarEntityFactory; +import com.testcar.car.common.DtoFactory; +import com.testcar.car.common.MemberEntityFactory; +import com.testcar.car.common.TrackEntityFactory; +import com.testcar.car.domains.carStock.CarStockService; +import com.testcar.car.domains.carStock.entity.CarStock; +import com.testcar.car.domains.carTest.entity.CarTest; +import com.testcar.car.domains.carTest.model.CarTestRequest; +import com.testcar.car.domains.carTest.model.vo.CarTestDto; +import com.testcar.car.domains.carTest.model.vo.CarTestFilterCondition; +import com.testcar.car.domains.carTest.repository.CarTestRepository; +import com.testcar.car.domains.carTest.request.CarTestRequestFactory; +import com.testcar.car.domains.member.Member; +import com.testcar.car.domains.track.Track; +import com.testcar.car.domains.track.TrackService; +import java.util.Optional; +import org.junit.jupiter.api.BeforeAll; +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; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +@ExtendWith(MockitoExtension.class) +public class CarTestServiceTest { + @Mock private CarStockService carStockService; + + @Mock private TrackService trackService; + + @Mock private CarTestRepository carTestRepository; + + @InjectMocks private CarTestService carTestService; + + private static Member member; + private static CarStock carStock; + private static Track track; + private static CarTest carTest; + private static CarTestDto carTestDto; + private static final Long carTestId = 1L; + + @BeforeAll + public static void setUp() { + member = MemberEntityFactory.createMember(); + carStock = CarEntityFactory.createCarStock(); + track = TrackEntityFactory.createTrack(); + carTest = CarEntityFactory.createCarTest(); + carTestDto = DtoFactory.createCarTestDto(); + } + + @Test + void 시험_수행이력_ID로_수행이력_DTO를_가져온다() { + // Given + when(carTestRepository.findDetailById(carTestId)).thenReturn(Optional.of(carTestDto)); + + // When + CarTestDto result = carTestService.findById(carTestId); + + // Then + assertEquals(carTestDto, result); + verify(carTestRepository).findDetailById(carTestId); + } + + @Test + void 조건에_맞는_시험_수행이력_DTO_페이지를_필터링하여_가져온다() { + // Given + CarTestFilterCondition condition = new CarTestFilterCondition(); + Pageable pageable = mock(Pageable.class); + Page mockPage = mock(Page.class); + when(carTestRepository.findAllPageByCondition(condition, pageable)).thenReturn(mockPage); + + // When + Page result = carTestService.findAllPageByCondition(condition, pageable); + + // Then + assertEquals(mockPage, result); + } + + @Test + void 시험_수행이력을_등록한다() { + // Given + CarTestRequest request = CarTestRequestFactory.createCarTestRequest(); + when(trackService.findByName(request.getTrackName())).thenReturn(track); + when(carStockService.findByStockNumber(request.getStockNumber())).thenReturn(carStock); + given(carTestRepository.save(any(CarTest.class))).willReturn(carTestDto.getCarTest()); + + // when + CarTest newCarTestDto = carTestService.register(member, request); + + // then + then(trackService).should().findByName(anyString()); + then(carStockService).should().findByStockNumber(anyString()); + then(carTestRepository).should().save(any(CarTest.class)); + assertNotNull(newCarTestDto); + } + + @Test + void 시험_수행이력의_정보를_수정한다() { + // given + CarTestRequest request = CarTestRequestFactory.createAnotherCarTestRequest(); + when(carTestRepository.findDetailById(carTestId)).thenReturn(Optional.of(carTestDto)); + when(carStockService.findByStockNumber(anyString())).thenReturn(carStock); + when(trackService.findByName(anyString())).thenReturn(track); + + // when + CarTestDto newCarTestDto = carTestService.update(member, carTestId, request); + + // then + verify(carTestRepository).findDetailById(carTestId); + verify(carStockService).findByStockNumber(anyString()); + verify(trackService).findByName(anyString()); + verify(carTestRepository).save(any(CarTest.class)); + assertNotNull(newCarTestDto); + } + + @Test + void 시험_수행이력을_삭제한다() { + // given + when(carTestRepository.findById(carTestId)).thenReturn(Optional.of(carTest)); + + // when + Long deletedId = carTestService.delete(member, carTestId); + + // then + verify(carTestRepository).findById(carTestId); + assertEquals(carTest.getDeleted(), true); + assertEquals(carTest.getUpdateMember(), member); + assertEquals(carTestId, deletedId); + } +} diff --git a/src/test/java/com/testcar/car/domains/carTest/entity/CarTestTest.java b/src/test/java/com/testcar/car/domains/carTest/entity/CarTestTest.java new file mode 100644 index 0000000..cf297f3 --- /dev/null +++ b/src/test/java/com/testcar/car/domains/carTest/entity/CarTestTest.java @@ -0,0 +1,102 @@ +package com.testcar.car.domains.carTest.entity; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.testcar.car.common.CarEntityFactory; +import com.testcar.car.common.MemberEntityFactory; +import com.testcar.car.common.TrackEntityFactory; +import com.testcar.car.domains.carStock.entity.CarStock; +import com.testcar.car.domains.member.Member; +import com.testcar.car.domains.track.Track; +import java.time.LocalDateTime; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class CarTestTest { + private Member member; + private CarStock carStock; + private Track track; + private CarTest carTest; + + @BeforeEach + public void setUp() { + member = MemberEntityFactory.createMember(); + carStock = CarEntityFactory.createCarStock(); + track = TrackEntityFactory.createTrack(); + carTest = CarEntityFactory.createCarTest(); + } + + @Test + public void 시험_수행이력을_생성한다() { + // given + final LocalDateTime performedAt = LocalDateTime.now(); + + // when + final CarTest newCarTest = + CarTest.builder() + .member(member) + .carStock(carStock) + .track(track) + .performedAt(performedAt) + .result("통과") + .build(); + // then + assertThat(newCarTest.getMember()).isEqualTo(member); + assertThat(newCarTest.getCarStock()).isEqualTo(carStock); + assertThat(newCarTest.getTrack()).isEqualTo(track); + assertThat(newCarTest.getPerformedAt()).isEqualTo(performedAt); + assertThat(newCarTest.getResult()).isEqualTo("통과"); + } + + @Test + public void 시험_수행이력의_정보를_변경한다() { + // given + final LocalDateTime newPerformedAt = LocalDateTime.of(2021, 1, 2, 0, 0, 0); + final String newStockNumber = "123456789013"; + final String newResult = "불합격"; + + // when + carTest.update(newPerformedAt, newStockNumber, newResult); + + // then + assertThat(carTest.getPerformedAt()).isEqualTo(newPerformedAt); + assertThat(carTest.getResult()).isEqualTo(newStockNumber); + assertThat(carTest.getMemo()).isEqualTo(newResult); + } + + @Test + public void 시험_수행이력의_주행시험장을_변경한다() { + // given + final Track newTrack = Track.builder().name("마포주행시험장").build(); + + // when + carTest.updateTrack(newTrack); + + // then + assertThat(carTest.getTrack()).isEqualTo(newTrack); + } + + @Test + public void 시험_수행이력의_차량재고를_변경한다() { + // given + final CarStock newCarStock = CarEntityFactory.createCarStock(); + + // when + carTest.updateCarStock(newCarStock); + + // then + assertThat(carTest.getCarStock()).isEqualTo(newCarStock); + } + + @Test + public void 시험_수행이력의_수정인을_변경한다() { + // given + final Member newMember = Member.builder().name("홍길순").build(); + + // when + carTest.updateMemberBy(newMember); + + // then + assertThat(carTest.getUpdateMember()).isEqualTo(newMember); + } +} diff --git a/src/test/java/com/testcar/car/domains/carTest/request/CarTestRequestFactory.java b/src/test/java/com/testcar/car/domains/carTest/request/CarTestRequestFactory.java new file mode 100644 index 0000000..7a3303d --- /dev/null +++ b/src/test/java/com/testcar/car/domains/carTest/request/CarTestRequestFactory.java @@ -0,0 +1,33 @@ +package com.testcar.car.domains.carTest.request; + +import static com.testcar.car.common.Constant.ANOTHER_CAR_STOCK_NUMBER; +import static com.testcar.car.common.Constant.ANOTHER_TRACK_NAME; +import static com.testcar.car.common.Constant.CAR_STOCK_NUMBER; +import static com.testcar.car.common.Constant.TRACK_NAME; + +import com.testcar.car.domains.carTest.model.CarTestRequest; +import java.time.LocalDate; + +public class CarTestRequestFactory { + private CarTestRequestFactory() {} + + public static CarTestRequest createCarTestRequest() { + return CarTestRequest.builder() + .trackName(TRACK_NAME) + .stockNumber(CAR_STOCK_NUMBER) + .performedAt(LocalDate.now()) + .result("이상없음") + .memo("타이어 정비가 필요해보임") + .build(); + } + + public static CarTestRequest createAnotherCarTestRequest() { + return CarTestRequest.builder() + .trackName(ANOTHER_TRACK_NAME) + .stockNumber(ANOTHER_CAR_STOCK_NUMBER) + .performedAt(LocalDate.now()) + .result("이상없음") + .memo("타이어 정비가 필요해보임") + .build(); + } +}