Skip to content

Commit

Permalink
Merge pull request #152 from kakao-tech-campus-2nd-step3/develop
Browse files Browse the repository at this point in the history
10주차 Master PR
  • Loading branch information
stopmin authored Nov 12, 2024
2 parents 8e3fce5 + d220cf7 commit 8bb6a43
Show file tree
Hide file tree
Showing 8 changed files with 324 additions and 25 deletions.
20 changes: 19 additions & 1 deletion .github/workflows/ci-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ permissions:

jobs:
test:
env:
IMP_API_KEY: ${{ secrets.IMP_API_KEY }}
IMP_SECRET_KEY: ${{ secrets.IMP_SECRET_KEY }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
runs-on: ubuntu-latest
steps:
- name: Checkout code
Expand All @@ -21,6 +26,9 @@ jobs:
with:
java-version: '21'
distribution: 'adopt'
env:
IMP_API_KEY: ${{ secrets.IMP_API_KEY }}
IMP_SECRET_KEY: ${{ secrets.IMP_SECRET_KEY }}

- name: Cache Gradle packages
uses: actions/cache@v3
Expand All @@ -29,12 +37,22 @@ jobs:
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
env:
IMP_API_KEY: ${{ secrets.IMP_API_KEY }}
IMP_SECRET_KEY: ${{ secrets.IMP_SECRET_KEY }}

- name: Upload test report
if: always()
uses: actions/upload-artifact@v3
with:
name: test-report
path: build/reports/tests/test

- name: Grant execute permission for gradlew
run: chmod +x ./gradlew

- name: Run tests
run: ./gradlew test
run: SPRING_PROFILES_ACTIVE=[test] ./gradlew test
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Expand Down
7 changes: 6 additions & 1 deletion src/main/java/poomasi/domain/farm/entity/Farm.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public class Farm {
private OrderedFarm orderedFarm;

@Builder
public Farm(Long id, String name, Long ownerId, String address, String addressDetail, Double latitude, Double longitude, String description, int experiencePrice, Integer maxCapacity, Integer maxReservation) {
public Farm(Long id, String name, Long ownerId, String address, String addressDetail, Double latitude, Double longitude, String description, int experiencePrice, Integer maxCapacity, Integer maxReservation, LocalDateTime deletedAt) {
this.id = id;
this.name = name;
this.ownerId = ownerId;
Expand All @@ -97,6 +97,7 @@ public Farm(Long id, String name, Long ownerId, String address, String addressDe
this.experiencePrice = experiencePrice;
this.maxCapacity = maxCapacity;
this.maxReservation = maxReservation;
this.deletedAt = deletedAt;
}

public Farm updateFarm(FarmUpdateRequest farmUpdateRequest) {
Expand All @@ -120,4 +121,8 @@ public void updateMaxCapacity(Integer maxCapacity) {
public void updateMaxReservation(Integer maxReservation) {
this.maxReservation = maxReservation;
}

public void delete() {
this.deletedAt = LocalDateTime.now();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
package poomasi.domain.farm._schedule.service;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import poomasi.domain.farm._schedule.dto.FarmScheduleRequest;
import poomasi.domain.farm._schedule.dto.FarmScheduleResponse;
import poomasi.domain.farm._schedule.dto.FarmScheduleUpdateRequest;
import poomasi.domain.farm._schedule.entity.FarmSchedule;
import poomasi.domain.farm._schedule.repository.FarmScheduleRepository;
import poomasi.global.error.BusinessException;

import java.time.LocalDate;
import java.time.LocalTime;
import java.util.List;
import java.util.Optional;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static poomasi.global.error.BusinessError.*;

@ExtendWith(MockitoExtension.class)
class FarmScheduleServiceTest {
@InjectMocks
private FarmScheduleService farmScheduleService;

@Mock
private FarmScheduleRepository farmScheduleRepository;

@Nested
@DisplayName("농장 스케줄 추가")
class AddFarmSchedule {
@Test
@DisplayName("정상적으로 스케줄을 추가한다")
void should_addFarmSchedule() {
// given
FarmScheduleUpdateRequest request = new FarmScheduleUpdateRequest(1L, LocalDate.now(), LocalTime.of(10, 0), LocalTime.of(12, 0));

given(farmScheduleRepository.findByFarmIdAndDate(1L, LocalDate.now())).willReturn(List.of());

// when
farmScheduleService.addFarmSchedule(request);

// then
FarmSchedule farmSchedule = FarmSchedule.builder()
.farmId(1L)
.date(LocalDate.now())
.startTime(LocalTime.of(10, 0))
.endTime(LocalTime.of(12, 0))
.build();
assertAll(
() -> assertEquals(1L, farmSchedule.getFarmId()),
() -> assertEquals(LocalDate.now(), farmSchedule.getDate()),
() -> assertEquals(LocalTime.of(10, 0), farmSchedule.getStartTime()),
() -> assertEquals(LocalTime.of(12, 0), farmSchedule.getEndTime())
);
}

@Test
@DisplayName("시작 시간이 종료 시간보다 늦은 경우 예외를 발생시킨다")
void should_throwException_when_startTimeIsAfterEndTime() {
// given
FarmScheduleUpdateRequest request = new FarmScheduleUpdateRequest(1L, LocalDate.now(), LocalTime.of(10, 0), LocalTime.of(9, 0));

// when & then
BusinessException exception = assertThrows(BusinessException.class, () -> farmScheduleService.addFarmSchedule(request));
assertEquals(START_TIME_SHOULD_BE_BEFORE_END_TIME, exception.getBusinessError());
}

@Test
@DisplayName("이미 등록된 스케줄이 있는 경우 예외를 발생시킨다")
void should_throwException_when_scheduleAlreadyExists() {
// given
FarmSchedule farmSchedule = FarmSchedule.builder()
.startTime(LocalTime.of(10, 0))
.endTime(LocalTime.of(12, 0))
.build();
List<FarmSchedule> farmSchedules = List.of(farmSchedule);

given(farmScheduleRepository.findByFarmIdAndDate(1L, LocalDate.now())).willReturn(farmSchedules);

FarmScheduleUpdateRequest request = new FarmScheduleUpdateRequest(1L, LocalDate.now(), LocalTime.of(11, 0), LocalTime.of(13, 0));

// when & then
BusinessException exception = assertThrows(BusinessException.class, () -> farmScheduleService.addFarmSchedule(request));
assertEquals(FARM_SCHEDULE_ALREADY_EXISTS, exception.getBusinessError());
}

@Test
@DisplayName("중복된 스케줄이 있는 경우 save 메서드가 호출되지 않는다")
void should_notCallSave_when_scheduleAlreadyExists() {
// given
FarmSchedule farmSchedule = FarmSchedule.builder()
.startTime(LocalTime.of(10, 0))
.endTime(LocalTime.of(12, 0))
.build();
List<FarmSchedule> farmSchedules = List.of(farmSchedule);

given(farmScheduleRepository.findByFarmIdAndDate(1L, LocalDate.now())).willReturn(farmSchedules);

FarmScheduleUpdateRequest request = new FarmScheduleUpdateRequest(1L, LocalDate.now(), LocalTime.of(11, 0), LocalTime.of(13, 0));

// when & then
assertThrows(BusinessException.class, () -> farmScheduleService.addFarmSchedule(request));
verify(farmScheduleRepository, never()).save(any(FarmSchedule.class));
}
}

@Nested
@DisplayName("농장 스케줄 조회")
class GetFarmSchedules {
@Test
@DisplayName("텅 빈 스케줄을 조회한다")
void should_getEmptyFarmSchedules() {
// given
LocalDate date = LocalDate.now();
given(farmScheduleRepository.findByFarmIdAndDate(1L, date)).willReturn(List.of());

// when
List<FarmSchedule> farmSchedules = farmScheduleService.getFarmScheduleByFarmIdAndDate(1L, date);

// then
assertTrue(farmSchedules.isEmpty());
}

@Test
@DisplayName("특정 날짜의 스케줄을 조회한다")
void should_getFarmSchedulesBySpecificDate() {
// given
LocalDate date = LocalDate.now();
FarmSchedule farmSchedule = FarmSchedule.builder()
.farmId(1L)
.date(date)
.startTime(LocalTime.of(10, 0))
.endTime(LocalTime.of(12, 0))
.build();
given(farmScheduleRepository.findByFarmIdAndDate(1L, date)).willReturn(List.of(farmSchedule));

// when
List<FarmSchedule> farmSchedules = farmScheduleService.getFarmScheduleByFarmIdAndDate(1L, date);

// then
assertAll(
() -> assertEquals(1, farmSchedules.size()),
() -> assertEquals(1L, farmSchedules.get(0).getFarmId()),
() -> assertEquals(date, farmSchedules.get(0).getDate()),
() -> assertEquals(LocalTime.of(10, 0), farmSchedules.get(0).getStartTime()),
() -> assertEquals(LocalTime.of(12, 0), farmSchedules.get(0).getEndTime())
);
}

@Test
@DisplayName("스케줄이 없는 날짜에 대해 빈 리스트를 반환한다")
void should_returnEmptyList_when_noSchedulesOnDate() {
// given
LocalDate date = LocalDate.of(2024, 11, 12);
given(farmScheduleRepository.findByFarmIdAndDate(1L, date)).willReturn(List.of());

// when
List<FarmSchedule> result = farmScheduleService.getFarmScheduleByFarmIdAndDate(1L, date);

// then
assertTrue(result.isEmpty());
}

@Test
@DisplayName("특정 월에 해당하는 스케줄을 올바르게 조회한다")
void should_returnSchedulesWithinSpecifiedMonth() {
// given
LocalDate startDate = LocalDate.of(2024, 11, 1);
LocalDate endDate = LocalDate.of(2024, 11, 30);
FarmSchedule farmSchedule = FarmSchedule.builder()
.farmId(1L)
.date(LocalDate.of(2024, 11, 10))
.startTime(LocalTime.of(10, 0))
.endTime(LocalTime.of(12, 0))
.build();

given(farmScheduleRepository.findByFarmIdAndDateRange(1L, startDate, endDate)).willReturn(List.of(farmSchedule));

// when
FarmScheduleRequest request = new FarmScheduleRequest(1L, 2024, 11);
List<FarmScheduleResponse> result = farmScheduleService.getFarmSchedulesByYearAndMonth(request);

// then
assertEquals(1, result.size());
assertEquals(farmSchedule.getDate(), result.get(0).date());
assertEquals(farmSchedule.getStartTime(), result.get(0).startTime());
assertEquals(farmSchedule.getEndTime(), result.get(0).endTime());
}

@Test
@DisplayName("존재하지 않는 스케줄 ID로 조회 시 예외가 발생한다")
void should_throwException_when_scheduleIdNotFound() {
// given
Long invalidId = 999L;
given(farmScheduleRepository.findById(invalidId)).willReturn(Optional.empty());

// when & then
BusinessException exception = assertThrows(BusinessException.class, () -> farmScheduleService.getFarmScheduleByScheduleId(invalidId));
assertEquals(FARM_SCHEDULE_NOT_FOUND, exception.getBusinessError());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,5 +137,41 @@ void should_deleteFarm_when_ownerMatches() {
// then
verify(farmRepository).delete(farm);
}

@Test
@DisplayName("농장이 존재하지 않는 경우 예외를 발생시킨다")
void should_throwException_when_farmNotExistOnDelete() {
// given
Long farmId = 1L;
Long farmerId = 1L;
given(farmRepository.findByIdAndDeletedAtIsNull(farmId)).willReturn(Optional.empty());

// when & then
assertThatThrownBy(() -> farmFarmerService.deleteFarm(farmerId, farmId))
.isInstanceOf(BusinessException.class)
.hasFieldOrPropertyWithValue("businessError", BusinessError.FARM_NOT_FOUND);
}

@Test
@DisplayName("농장이 이미 삭제된 경우 예외를 발생시킨다")
void should_throwException_when_farmAlreadyDeleted() {
// given
Long farmId = 1L;
Long farmerId = 1L;
Farm farm = Farm.builder()
.id(farmId)
.name("Farm")
.ownerId(farmerId)
.deletedAt(null)
.build();

given(farmRepository.findByIdAndDeletedAtIsNull(farmId)).willReturn(Optional.of(farm));

// when
farmFarmerService.deleteFarm(farmerId, farmId);

// then
verify(farmRepository).delete(farm);
}
}
}
13 changes: 13 additions & 0 deletions src/test/java/poomasi/domain/farm/service/FarmServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,19 @@ void should_throwException_when_farmNotExist() {
.isInstanceOf(BusinessException.class)
.hasFieldOrPropertyWithValue("businessError", BusinessError.FARM_NOT_FOUND);
}

@Test
@DisplayName("농장이 삭제된 경우 예외를 발생시킨다")
void should_throwException_when_farmIsDeleted() {
// given
Farm farm = FarmTestHelper.makeRandomFarm();
farm.delete();

// when & then
assertThatThrownBy(() -> farmService.getFarmByFarmId(farm.getId()))
.isInstanceOf(BusinessException.class)
.hasFieldOrPropertyWithValue("businessError", BusinessError.FARM_NOT_FOUND);
}
}

}
Loading

0 comments on commit 8bb6a43

Please sign in to comment.