Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test : 사용자가 숨은그림찾기 게임 정보를 조회하는 로직 테스트코드 작성, Clock 객체 모킹하여 LocalDateTime.now()에 주입 (CC-147) #28

Merged
merged 13 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
package ai.softeer.caecae.findinggame.service;

import ai.softeer.caecae.findinggame.domain.dto.FindingGameDailyInfo;
import ai.softeer.caecae.findinggame.domain.dto.response.FindingGameInfoResponseDto;
import ai.softeer.caecae.findinggame.domain.entity.FindingGame;
import ai.softeer.caecae.findinggame.domain.enums.AnswerType;
import ai.softeer.caecae.findinggame.repository.FindGameDbRepository;
import ai.softeer.caecae.racinggame.domain.dto.request.RegisterFindingGamePeriodRequestDto;
import ai.softeer.caecae.findinggame.domain.dto.response.FindingGameInfoResponseDto;
import ai.softeer.caecae.racinggame.domain.dto.response.RegisterFindingGamePeriodResponseDto;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.Clock;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
Expand All @@ -20,54 +17,8 @@
@RequiredArgsConstructor
public class FindingGameService {
private final FindGameDbRepository findGameDbRepository;

/**
* 어드민이 숨은캐스퍼찾기 게임 기간을 등록하는 로직
*
* @param req 게임 시작 날짜
* @return 게임 시작 날짜, 종료 날짜(+6일)
*/
@Transactional
public RegisterFindingGamePeriodResponseDto registerFindingGamePeriod(RegisterFindingGamePeriodRequestDto req) {
List<FindingGame> findingGames = findGameDbRepository.findAll();
// 등록된 게임 정보가 없으면 생성하기
if (findingGames.isEmpty()) {
findingGames = initFindingGames();
}

// 게임 정보 기간 업데이트
LocalDate date = req.startDate();
for (FindingGame findingGame : findingGames) {
findingGame.updateFindingGamePeriod(
date.atTime(15, 15),
date.plusDays(1).atTime(14, 15)
);
date = date.plusDays(1);
}


findGameDbRepository.saveAll(findingGames);

return RegisterFindingGamePeriodResponseDto.builder()
.startDate(req.startDate())
.endDate(req.startDate().plusDays(6))
.build();
}

// 7개의 숨은캐스퍼찾기 게임 정보 객체 초기화
private List<FindingGame> initFindingGames() {
List<FindingGame> findingGames = new ArrayList<>();
for (int day = 0; day < 7; day++) {
findingGames.add(
FindingGame.builder()
.questionImageUrl("no-image")
.numberOfWinners(315)
.answerType(AnswerType.UNSELECTED)
.build());
}
return findingGames;
}

private final Clock clock; // 테스트코드 의존성 주입을 위한 빈

/**
* 전체 게임 정보와, 최근/다음 게임의 인덱스를 반환하는 로직
*
Expand All @@ -76,12 +27,11 @@ private List<FindingGame> initFindingGames() {
@Transactional(readOnly = true)
public FindingGameInfoResponseDto getFindingGameInfo() {
List<FindingGame> findingGames = findGameDbRepository.findAllByOrderByStartTime();

int recentGameIndex = -1;
int nextGameIndex = -1;
for (int i = 0; i < findingGames.size(); i++) {
FindingGame findingGame = findingGames.get(i);
if (findingGame.getStartTime().isBefore(LocalDateTime.now())) {
if (findingGame.getStartTime().isBefore(LocalDateTime.now(clock))) {
recentGameIndex = i;
}
}
Expand All @@ -108,4 +58,12 @@ public FindingGameInfoResponseDto getFindingGameInfo() {
.nextGameIndex(nextGameIndex)
.build();
}

// 테스트용
public LocalDateTime testUtcClockInstant() {
findGameDbRepository.findAllByOrderByStartTime();
return LocalDateTime.now(clock);
}

}

22 changes: 22 additions & 0 deletions src/main/java/ai/softeer/caecae/global/config/TimeConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package ai.softeer.caecae.global.config;

import jakarta.annotation.PostConstruct;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.Clock;
import java.util.TimeZone;

@Configuration
public class TimeConfig {

@Bean
public Clock clock() {
return Clock.systemDefaultZone();
}

@PostConstruct
void started() {
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Seoul"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package ai.softeer.caecae.findinggame.service;

import ai.softeer.caecae.findinggame.domain.dto.response.FindingGameInfoResponseDto;
import ai.softeer.caecae.findinggame.domain.entity.FindingGame;
import ai.softeer.caecae.findinggame.domain.enums.AnswerType;
import ai.softeer.caecae.findinggame.repository.FindGameDbRepository;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

import java.time.Clock;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;
import java.util.TimeZone;

import static org.mockito.BDDMockito.given;

@ExtendWith(MockitoExtension.class)
class FindingGameServiceTest {

@InjectMocks
private FindingGameService findingGameService;

@Mock
private FindGameDbRepository findGameDbRepository;

@Mock
private Clock clock;

// 7일치의 숨은그림찾기 게임 정보
private final List<FindingGame> findingGames = new ArrayList<>();
private static LocalDateTime integrityDateTime;


@BeforeAll
static void timeSetUp() {
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Seoul"));
integrityDateTime = LocalDateTime.of(2024, 5, 5, 10, 10);
}

@BeforeEach
void setUp() {
// 8/1 ~ 8/7 게임
LocalDateTime baseTime = LocalDateTime.of(2024, 8, 1, 15, 15);
for (int day = 0; day < 7; day++) {
findingGames.add(
FindingGame.builder()
.id(day + 1)
.questionImageUrl("url")
.startTime(baseTime.plusDays(day))
.endTime(baseTime.plusDays(day + 1).minusHours(1))
.numberOfWinners(315)
.answerType(AnswerType.PIXEL)
.build()
);
}

Mockito.when(findGameDbRepository.findAllByOrderByStartTime()).thenReturn(findingGames);

given(clock.getZone()).willReturn(ZoneId.systemDefault());
}

@Test
@DisplayName("LocalDateTime과 비교하여, Clock.instant의 시간에 TimeZone의 시차가 적용되는지 테스트 하기 - 같은 시간")
void testUtcClockInstant1() {
// Given
given(clock.instant()).willReturn(Instant.parse("2024-05-05T10:10:00Z"));

// When
// Clock을 사용하여 LocalDateTime 생성
LocalDateTime time = findingGameService.testUtcClockInstant();

// Then
Assertions.assertThat(time).isNotEqualTo(integrityDateTime);
}

@Test
@DisplayName("LocalDateTime과 Clock.instant의 시간에 UTC+9의 시차가 적용되는지 테스트 하기 - UTC+9")
void testUtcClockInstant2() {
// Given
given(clock.instant()).willReturn(Instant.parse("2024-05-05T10:10:00Z").minusSeconds(9 * 3600));

// When
// Clock을 사용하여 LocalDateTime 생성
LocalDateTime time = findingGameService.testUtcClockInstant();

// Then
Assertions.assertThat(time).isEqualTo(integrityDateTime);
}


@Test
@DisplayName("Given_일주일치 게임 정보 입력 When_게임 시작 전 Then_최근게임 인덱스가 -1")
void getFindingGameInfo_1() {
// Given
// LocalDateTime.now()에서 사용할 clock 객체 모킹
given(clock.instant()).willReturn(Instant.parse("2024-08-01T09:00:00Z").minusSeconds(9 * 3600));

// When
FindingGameInfoResponseDto findingGameInfo = findingGameService.getFindingGameInfo();

// Then
Assertions.assertThat(findingGameInfo).isNotNull();
Assertions.assertThat(findingGameInfo.recentGameIndex()).isEqualTo(-1);
Assertions.assertThat(findingGameInfo.nextGameIndex()).isEqualTo(0);
}

@Test
@DisplayName("Given_일주일치 게임 정보 입력 When_게임 진행 중(첫날) Then_최근게임 인덱스가 0")
void getFindingGameInfo_2() {
// Given
// LocalDateTime.now()에서 사용할 clock 객체 모킹
given(clock.instant()).willReturn(Instant.parse("2024-08-01T17:00:00Z").minusSeconds(9 * 3600));

// When
FindingGameInfoResponseDto findingGameInfo = findingGameService.getFindingGameInfo();

// Then
Assertions.assertThat(findingGameInfo).isNotNull();
Assertions.assertThat(findingGameInfo.recentGameIndex()).isEqualTo(0);
Assertions.assertThat(findingGameInfo.nextGameIndex()).isEqualTo(1);
}

@Test
@DisplayName("Given_일주일치 게임 정보 입력 When_게임 진행 중(마지막날) Then_최근게임 인덱스가 6")
void getFindingGameInfo_3() {
// Given
// LocalDateTime.now()에서 사용할 clock 객체 모킹
given(clock.instant()).willReturn(Instant.parse("2024-08-08T10:00:00Z").minusSeconds(9 * 3600));

// When
FindingGameInfoResponseDto findingGameInfo = findingGameService.getFindingGameInfo();

// Then
Assertions.assertThat(findingGameInfo).isNotNull();
Assertions.assertThat(findingGameInfo.recentGameIndex()).isEqualTo(6);
Assertions.assertThat(findingGameInfo.nextGameIndex()).isEqualTo(-1);
}

@Test
@DisplayName("Given_일주일치 게임 정보 입력 When_게임 진행 종료 Then_다음게임 인덱스가 -1")
void getFindingGameInfo_4() {
// Given
// LocalDateTime.now()에서 사용할 clock 객체 모킹
given(clock.instant()).willReturn(Instant.parse("2032-08-08T16:00:00Z").minusSeconds(9 * 3600));

// When
FindingGameInfoResponseDto findingGameInfo = findingGameService.getFindingGameInfo();

// Then
Assertions.assertThat(findingGameInfo).isNotNull();
Assertions.assertThat(findingGameInfo.recentGameIndex()).isEqualTo(6);
Assertions.assertThat(findingGameInfo.nextGameIndex()).isEqualTo(-1);
}
}
Loading