diff --git a/backend/build.gradle b/backend/build.gradle index 0a1b9a392..7d6c86e2a 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -43,6 +43,7 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + testImplementation 'io.rest-assured:rest-assured:5.5.0' } tasks.named('test') { diff --git a/backend/src/main/java/ddangkong/controller/balance/content/BalanceContentController.java b/backend/src/main/java/ddangkong/controller/balance/content/BalanceContentController.java new file mode 100644 index 000000000..2a040f5aa --- /dev/null +++ b/backend/src/main/java/ddangkong/controller/balance/content/BalanceContentController.java @@ -0,0 +1,25 @@ +package ddangkong.controller.balance.content; + +import ddangkong.controller.balance.content.dto.BalanceContentResponse; +import ddangkong.service.balance.content.BalanceContentService; +import jakarta.validation.constraints.Positive; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api") +@Validated +@RequiredArgsConstructor +public class BalanceContentController { + + private final BalanceContentService balanceContentService; + + @GetMapping("/balances/rooms/{roomId}/question") + public BalanceContentResponse getBalanceContent(@PathVariable @Positive Long roomId) { + return balanceContentService.findRecentBalanceContent(roomId); + } +} diff --git a/backend/src/main/java/ddangkong/controller/balance/content/dto/BalanceContentResponse.java b/backend/src/main/java/ddangkong/controller/balance/content/dto/BalanceContentResponse.java new file mode 100644 index 000000000..66543da91 --- /dev/null +++ b/backend/src/main/java/ddangkong/controller/balance/content/dto/BalanceContentResponse.java @@ -0,0 +1,27 @@ +package ddangkong.controller.balance.content.dto; + +import ddangkong.controller.balance.option.dto.BalanceOptionResponse; +import ddangkong.domain.balance.content.BalanceContent; +import ddangkong.domain.balance.content.Category; +import ddangkong.domain.balance.option.BalanceOption; +import lombok.Builder; + +public record BalanceContentResponse( + Long contentId, + Category category, + String question, + BalanceOptionResponse firstOption, + BalanceOptionResponse secondOption +) { + + @Builder + private BalanceContentResponse(BalanceContent balanceContent, + BalanceOption firstOption, + BalanceOption secondOption) { + this(balanceContent.getId(), + balanceContent.getCategory(), + balanceContent.getName(), + BalanceOptionResponse.from(firstOption), + BalanceOptionResponse.from(secondOption)); + } +} diff --git a/backend/src/main/java/ddangkong/controller/balance/option/dto/BalanceOptionResponse.java b/backend/src/main/java/ddangkong/controller/balance/option/dto/BalanceOptionResponse.java new file mode 100644 index 000000000..a2c0f7883 --- /dev/null +++ b/backend/src/main/java/ddangkong/controller/balance/option/dto/BalanceOptionResponse.java @@ -0,0 +1,12 @@ +package ddangkong.controller.balance.option.dto; + +import ddangkong.domain.balance.option.BalanceOption; + +public record BalanceOptionResponse( + Long optionId, + String name +) { + public static BalanceOptionResponse from(BalanceOption balanceOption) { + return new BalanceOptionResponse(balanceOption.getId(), balanceOption.getName()); + } +} diff --git a/backend/src/main/java/ddangkong/controller/exception/GlobalExceptionHandler.java b/backend/src/main/java/ddangkong/controller/exception/GlobalExceptionHandler.java index 0d2c4df6b..1814c07e4 100644 --- a/backend/src/main/java/ddangkong/controller/exception/GlobalExceptionHandler.java +++ b/backend/src/main/java/ddangkong/controller/exception/GlobalExceptionHandler.java @@ -1,5 +1,7 @@ package ddangkong.controller.exception; +import ddangkong.service.excpetion.BusinessLogicException; +import ddangkong.service.excpetion.ViolateDataException; import jakarta.validation.ConstraintViolationException; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; @@ -12,7 +14,10 @@ @Slf4j public class GlobalExceptionHandler { + private static final String SERVER_ERROR_MESSAGE = "서버 오류가 발생했습니다. 관리자에게 문의하세요."; + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) public ErrorResponse handleBindingException(BindException e) { log.warn(e.getMessage()); @@ -20,17 +25,34 @@ public ErrorResponse handleBindingException(BindException e) { } @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) public ErrorResponse handleConstraintViolationException(ConstraintViolationException e) { log.warn(e.getMessage()); return new ErrorResponse(e.getConstraintViolations()); } + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ErrorResponse handleBusinessLogicException(BusinessLogicException e) { + log.warn(e.getMessage()); + + return new ErrorResponse(e.getMessage()); + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public ErrorResponse handleViolateDataException(ViolateDataException e) { + log.error(e.getMessage(), e); + + return new ErrorResponse(SERVER_ERROR_MESSAGE); + } + @ExceptionHandler @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ErrorResponse handleException(Exception e) { - log.error(e.getMessage()); + log.error(e.getMessage(), e); - return new ErrorResponse("서버 오류가 발생했습니다. 관리자에게 문의하세요."); + return new ErrorResponse(SERVER_ERROR_MESSAGE); } } diff --git a/backend/src/main/java/ddangkong/domain/BaseEntity.java b/backend/src/main/java/ddangkong/domain/BaseEntity.java new file mode 100644 index 000000000..e50b10073 --- /dev/null +++ b/backend/src/main/java/ddangkong/domain/BaseEntity.java @@ -0,0 +1,19 @@ +package ddangkong.domain; + +import jakarta.persistence.Column; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.MappedSuperclass; +import java.time.LocalDateTime; +import lombok.Getter; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +@MappedSuperclass +@EntityListeners(AuditingEntityListener.class) +@Getter +public class BaseEntity { + + @CreatedDate + @Column(updatable = false, nullable = false) + private LocalDateTime createdAt; +} diff --git a/backend/src/main/java/ddangkong/domain/question/BalanceQuestion.java b/backend/src/main/java/ddangkong/domain/balance/content/BalanceContent.java similarity index 77% rename from backend/src/main/java/ddangkong/domain/question/BalanceQuestion.java rename to backend/src/main/java/ddangkong/domain/balance/content/BalanceContent.java index 20205a73c..5fb9026c3 100644 --- a/backend/src/main/java/ddangkong/domain/question/BalanceQuestion.java +++ b/backend/src/main/java/ddangkong/domain/balance/content/BalanceContent.java @@ -1,4 +1,4 @@ -package ddangkong.domain.question; +package ddangkong.domain.balance.content; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -8,17 +8,13 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import lombok.AccessLevel; -import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; -import lombok.ToString; @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) @Getter -@EqualsAndHashCode -@ToString -public class BalanceQuestion { +public class BalanceContent { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -29,5 +25,5 @@ public class BalanceQuestion { private Category category; @Column(nullable = false) - private String content; + private String name; } diff --git a/backend/src/main/java/ddangkong/domain/question/Category.java b/backend/src/main/java/ddangkong/domain/balance/content/Category.java similarity index 51% rename from backend/src/main/java/ddangkong/domain/question/Category.java rename to backend/src/main/java/ddangkong/domain/balance/content/Category.java index fe67d4c5a..07a510c27 100644 --- a/backend/src/main/java/ddangkong/domain/question/Category.java +++ b/backend/src/main/java/ddangkong/domain/balance/content/Category.java @@ -1,4 +1,4 @@ -package ddangkong.domain.question; +package ddangkong.domain.balance.content; public enum Category { EXAMPLE, diff --git a/backend/src/main/java/ddangkong/domain/room/Room.java b/backend/src/main/java/ddangkong/domain/balance/content/Room.java similarity index 77% rename from backend/src/main/java/ddangkong/domain/room/Room.java rename to backend/src/main/java/ddangkong/domain/balance/content/Room.java index 77f0cb125..7dd029e80 100644 --- a/backend/src/main/java/ddangkong/domain/room/Room.java +++ b/backend/src/main/java/ddangkong/domain/balance/content/Room.java @@ -1,20 +1,16 @@ -package ddangkong.domain.room; +package ddangkong.domain.balance.content; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import lombok.AccessLevel; -import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; -import lombok.ToString; @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) @Getter -@EqualsAndHashCode -@ToString public class Room { @Id diff --git a/backend/src/main/java/ddangkong/domain/room/RoomQuestion.java b/backend/src/main/java/ddangkong/domain/balance/content/RoomContent.java similarity index 70% rename from backend/src/main/java/ddangkong/domain/room/RoomQuestion.java rename to backend/src/main/java/ddangkong/domain/balance/content/RoomContent.java index 5972d879a..3f99b1f84 100644 --- a/backend/src/main/java/ddangkong/domain/room/RoomQuestion.java +++ b/backend/src/main/java/ddangkong/domain/balance/content/RoomContent.java @@ -1,6 +1,6 @@ -package ddangkong.domain.room; +package ddangkong.domain.balance.content; -import ddangkong.domain.question.BalanceQuestion; +import ddangkong.domain.BaseEntity; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; @@ -9,17 +9,13 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import lombok.AccessLevel; -import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; -import lombok.ToString; @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) @Getter -@EqualsAndHashCode -@ToString -public class RoomQuestion { +public class RoomContent extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -30,6 +26,6 @@ public class RoomQuestion { private Room room; @ManyToOne(optional = false, fetch = FetchType.LAZY) - @JoinColumn(name = "balance_question_id") - private BalanceQuestion balanceQuestion; + @JoinColumn(name = "balance_content_id") + private BalanceContent balanceContent; } diff --git a/backend/src/main/java/ddangkong/domain/balance/content/RoomContentRepository.java b/backend/src/main/java/ddangkong/domain/balance/content/RoomContentRepository.java new file mode 100644 index 000000000..ea9f4ce27 --- /dev/null +++ b/backend/src/main/java/ddangkong/domain/balance/content/RoomContentRepository.java @@ -0,0 +1,9 @@ +package ddangkong.domain.balance.content; + +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface RoomContentRepository extends JpaRepository { + + Optional findTopByRoomIdOrderByCreatedAtDesc(Long roomId); +} diff --git a/backend/src/main/java/ddangkong/domain/option/BalanceOption.java b/backend/src/main/java/ddangkong/domain/balance/option/BalanceOption.java similarity index 68% rename from backend/src/main/java/ddangkong/domain/option/BalanceOption.java rename to backend/src/main/java/ddangkong/domain/balance/option/BalanceOption.java index a109ce4f7..bc65918d6 100644 --- a/backend/src/main/java/ddangkong/domain/option/BalanceOption.java +++ b/backend/src/main/java/ddangkong/domain/balance/option/BalanceOption.java @@ -1,6 +1,6 @@ -package ddangkong.domain.option; +package ddangkong.domain.balance.option; -import ddangkong.domain.question.BalanceQuestion; +import ddangkong.domain.balance.content.BalanceContent; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; @@ -10,16 +10,12 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import lombok.AccessLevel; -import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; -import lombok.ToString; @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) @Getter -@EqualsAndHashCode -@ToString public class BalanceOption { @Id @@ -27,9 +23,9 @@ public class BalanceOption { private Long id; @Column(nullable = false) - private String content; + private String name; @ManyToOne(optional = false, fetch = FetchType.LAZY) - @JoinColumn(name = "balance_question_id", nullable = false) - private BalanceQuestion balanceQuestion; + @JoinColumn(name = "balance_content_id", nullable = false) + private BalanceContent balanceContent; } diff --git a/backend/src/main/java/ddangkong/domain/balance/option/BalanceOptionRepository.java b/backend/src/main/java/ddangkong/domain/balance/option/BalanceOptionRepository.java new file mode 100644 index 000000000..10d886be5 --- /dev/null +++ b/backend/src/main/java/ddangkong/domain/balance/option/BalanceOptionRepository.java @@ -0,0 +1,10 @@ +package ddangkong.domain.balance.option; + +import ddangkong.domain.balance.content.BalanceContent; +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface BalanceOptionRepository extends JpaRepository { + + List findByBalanceContent(BalanceContent balanceContent); +} diff --git a/backend/src/main/java/ddangkong/domain/vote/BalanceVote.java b/backend/src/main/java/ddangkong/domain/balance/vote/BalanceVote.java similarity index 84% rename from backend/src/main/java/ddangkong/domain/vote/BalanceVote.java rename to backend/src/main/java/ddangkong/domain/balance/vote/BalanceVote.java index 08f8c85f9..981d37155 100644 --- a/backend/src/main/java/ddangkong/domain/vote/BalanceVote.java +++ b/backend/src/main/java/ddangkong/domain/balance/vote/BalanceVote.java @@ -1,7 +1,7 @@ -package ddangkong.domain.vote; +package ddangkong.domain.balance.vote; +import ddangkong.domain.balance.option.BalanceOption; import ddangkong.domain.member.Member; -import ddangkong.domain.option.BalanceOption; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; @@ -10,16 +10,12 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import lombok.AccessLevel; -import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; -import lombok.ToString; @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) @Getter -@EqualsAndHashCode -@ToString public class BalanceVote { @Id diff --git a/backend/src/main/java/ddangkong/domain/member/Member.java b/backend/src/main/java/ddangkong/domain/member/Member.java index 6cd46d46d..efedc670b 100644 --- a/backend/src/main/java/ddangkong/domain/member/Member.java +++ b/backend/src/main/java/ddangkong/domain/member/Member.java @@ -1,6 +1,6 @@ package ddangkong.domain.member; -import ddangkong.domain.room.Room; +import ddangkong.domain.balance.content.Room; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; @@ -10,16 +10,12 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import lombok.AccessLevel; -import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; -import lombok.ToString; @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) @Getter -@EqualsAndHashCode -@ToString public class Member { @Id diff --git a/backend/src/main/java/ddangkong/service/balance/content/BalanceContentService.java b/backend/src/main/java/ddangkong/service/balance/content/BalanceContentService.java new file mode 100644 index 000000000..a3a4b6114 --- /dev/null +++ b/backend/src/main/java/ddangkong/service/balance/content/BalanceContentService.java @@ -0,0 +1,54 @@ +package ddangkong.service.balance.content; + +import ddangkong.controller.balance.content.dto.BalanceContentResponse; +import ddangkong.domain.balance.content.BalanceContent; +import ddangkong.domain.balance.content.RoomContentRepository; +import ddangkong.domain.balance.option.BalanceOption; +import ddangkong.domain.balance.option.BalanceOptionRepository; +import ddangkong.service.excpetion.BusinessLogicException; +import ddangkong.service.excpetion.ViolateDataException; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +public class BalanceContentService { + + private static final int BALANCE_OPTION_SIZE = 2; + + private final RoomContentRepository roomContentRepository; + + private final BalanceOptionRepository balanceOptionRepository; + + @Transactional(readOnly = true) + public BalanceContentResponse findRecentBalanceContent(Long roomId) { + BalanceContent balanceContent = findRecentContent(roomId); + List balanceOptions = findBalanceOptions(balanceContent); + + return BalanceContentResponse.builder() + .balanceContent(balanceContent) + .firstOption(balanceOptions.get(0)) + .secondOption(balanceOptions.get(1)) + .build(); + } + + private BalanceContent findRecentContent(Long roomId) { + return roomContentRepository.findTopByRoomIdOrderByCreatedAtDesc(roomId) + .orElseThrow(() -> new BusinessLogicException("해당 방의 질문이 존재하지 않습니다.")) + .getBalanceContent(); + } + + private List findBalanceOptions(BalanceContent balanceContent) { + List balanceOptions = balanceOptionRepository.findByBalanceContent(balanceContent); + validateBalanceOptions(balanceOptions); + return balanceOptions; + } + + private void validateBalanceOptions(List balanceOptions) { + if (balanceOptions.size() != BALANCE_OPTION_SIZE) { + throw new ViolateDataException("밸런스 게임의 선택지가 %d개입니다".formatted(balanceOptions.size())); + } + } +} diff --git a/backend/src/main/java/ddangkong/service/excpetion/BusinessLogicException.java b/backend/src/main/java/ddangkong/service/excpetion/BusinessLogicException.java new file mode 100644 index 000000000..d2b522cb4 --- /dev/null +++ b/backend/src/main/java/ddangkong/service/excpetion/BusinessLogicException.java @@ -0,0 +1,8 @@ +package ddangkong.service.excpetion; + +public class BusinessLogicException extends RuntimeException { + + public BusinessLogicException(String message) { + super(message); + } +} diff --git a/backend/src/main/java/ddangkong/service/excpetion/ViolateDataException.java b/backend/src/main/java/ddangkong/service/excpetion/ViolateDataException.java new file mode 100644 index 000000000..48192f9b1 --- /dev/null +++ b/backend/src/main/java/ddangkong/service/excpetion/ViolateDataException.java @@ -0,0 +1,8 @@ +package ddangkong.service.excpetion; + +public class ViolateDataException extends RuntimeException { + + public ViolateDataException(String message) { + super(message); + } +} diff --git a/backend/src/test/java/ddangkong/controller/BaseControllerTest.java b/backend/src/test/java/ddangkong/controller/BaseControllerTest.java new file mode 100644 index 000000000..c7516b209 --- /dev/null +++ b/backend/src/test/java/ddangkong/controller/BaseControllerTest.java @@ -0,0 +1,21 @@ +package ddangkong.controller; + + +import io.restassured.RestAssured; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.test.context.jdbc.Sql; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@Sql(scripts = "/init-test.sql") +public abstract class BaseControllerTest { + + @LocalServerPort + private int port; + + @BeforeEach + void setUp() { + RestAssured.port = port; + } +} diff --git a/backend/src/test/java/ddangkong/controller/balance/content/BalanceContentControllerTest.java b/backend/src/test/java/ddangkong/controller/balance/content/BalanceContentControllerTest.java new file mode 100644 index 000000000..67d24b7d6 --- /dev/null +++ b/backend/src/test/java/ddangkong/controller/balance/content/BalanceContentControllerTest.java @@ -0,0 +1,45 @@ +package ddangkong.controller.balance.content; + +import static org.assertj.core.api.Assertions.assertThat; + +import ddangkong.controller.BaseControllerTest; +import ddangkong.controller.balance.content.dto.BalanceContentResponse; +import ddangkong.controller.balance.option.dto.BalanceOptionResponse; +import ddangkong.domain.balance.content.Category; +import io.restassured.RestAssured; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +class BalanceContentControllerTest extends BaseControllerTest { + + @Nested + class 현재_방의_내용_조회 { + + private static final BalanceContentResponse EXPECTED_RESPONSE = new BalanceContentResponse( + 1L, Category.EXAMPLE, "민초 vs 반민초", + new BalanceOptionResponse(1L, "민초"), + new BalanceOptionResponse(2L, "반민초")); + + @Test + void 현재_방의_질문을_조회할_수_있다() { + // when + BalanceContentResponse actual = RestAssured.given().log().all() + .when().get("/api/balances/rooms/1/question") + .then().log().all() + .statusCode(200) + .extract().as(BalanceContentResponse.class); + + // then + assertThat(actual).isEqualTo(EXPECTED_RESPONSE); + } + + @Test + void 방의_식별자가_음수인_경우_예외를_던진다() { + // when & then + RestAssured.given().log().all() + .when().get("/api/balances/rooms/-1/question") + .then().log().all() + .statusCode(400); + } + } +} diff --git a/backend/src/test/java/ddangkong/domain/BaseRepositoryTest.java b/backend/src/test/java/ddangkong/domain/BaseRepositoryTest.java new file mode 100644 index 000000000..92a080765 --- /dev/null +++ b/backend/src/test/java/ddangkong/domain/BaseRepositoryTest.java @@ -0,0 +1,10 @@ +package ddangkong.domain; + +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.test.context.jdbc.Sql; + +@DataJpaTest +@Sql(scripts = "/init-test.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) +public abstract class BaseRepositoryTest { + +} diff --git a/backend/src/test/java/ddangkong/domain/balance/content/RoomContentRepositoryTest.java b/backend/src/test/java/ddangkong/domain/balance/content/RoomContentRepositoryTest.java new file mode 100644 index 000000000..67af2b4ec --- /dev/null +++ b/backend/src/test/java/ddangkong/domain/balance/content/RoomContentRepositoryTest.java @@ -0,0 +1,30 @@ +package ddangkong.domain.balance.content; + +import static org.assertj.core.api.Assertions.assertThat; + +import ddangkong.domain.BaseRepositoryTest; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +class RoomContentRepositoryTest extends BaseRepositoryTest { + + @Autowired + private RoomContentRepository roomContentRepository; + + @Nested + class 방의_최신_질문_조회 { + + @Test + void 방의_가장_최신의_질문을_조회할_수_있다() { + // given + Long recentContentId = 1L; + + // when + RoomContent actual = roomContentRepository.findTopByRoomIdOrderByCreatedAtDesc(recentContentId).get(); + + // then + assertThat(actual.getId()).isEqualTo(2L); + } + } +} diff --git a/backend/src/test/java/ddangkong/service/BaseServiceTest.java b/backend/src/test/java/ddangkong/service/BaseServiceTest.java new file mode 100644 index 000000000..614232a77 --- /dev/null +++ b/backend/src/test/java/ddangkong/service/BaseServiceTest.java @@ -0,0 +1,9 @@ +package ddangkong.service; + +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.jdbc.Sql; + +@SpringBootTest +@Sql(scripts = "/init-test.sql") +public abstract class BaseServiceTest { +} diff --git a/backend/src/test/java/ddangkong/service/balance/content/BalanceContentServiceTest.java b/backend/src/test/java/ddangkong/service/balance/content/BalanceContentServiceTest.java new file mode 100644 index 000000000..fc87fda26 --- /dev/null +++ b/backend/src/test/java/ddangkong/service/balance/content/BalanceContentServiceTest.java @@ -0,0 +1,47 @@ +package ddangkong.service.balance.content; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import ddangkong.controller.balance.content.dto.BalanceContentResponse; +import ddangkong.controller.balance.option.dto.BalanceOptionResponse; +import ddangkong.domain.balance.content.Category; +import ddangkong.service.BaseServiceTest; +import ddangkong.service.excpetion.BusinessLogicException; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +class BalanceContentServiceTest extends BaseServiceTest { + + private static final Long PROGRESS_ROOM_ID = 1L; + private static final Long NOT_EXIST_ROOM_ID = 2L; + private static final BalanceContentResponse BALANCE_CONTENT_RESPONSE = new BalanceContentResponse( + 1L, Category.EXAMPLE, "민초 vs 반민초", + new BalanceOptionResponse(1L, "민초"), + new BalanceOptionResponse(2L, "반민초")); + + @Autowired + private BalanceContentService balanceContentService; + + @Nested + class 현재_방의_밸런스_게임_내용_조회 { + + @Test + void 방의_최신_밸런스_게임_내용을_조회할_수_있다() { + // when + BalanceContentResponse actual = balanceContentService.findRecentBalanceContent(PROGRESS_ROOM_ID); + + // then + assertThat(actual).isEqualTo(BALANCE_CONTENT_RESPONSE); + } + + @Test + void 방이_없을_경우_예외를_던진다() { + // when & then + assertThatThrownBy(() -> balanceContentService.findRecentBalanceContent(NOT_EXIST_ROOM_ID)) + .isInstanceOf(BusinessLogicException.class) + .hasMessage("해당 방의 질문이 존재하지 않습니다."); + } + } +} diff --git a/backend/src/test/resources/init-test.sql b/backend/src/test/resources/init-test.sql new file mode 100644 index 000000000..90b21797b --- /dev/null +++ b/backend/src/test/resources/init-test.sql @@ -0,0 +1,34 @@ +SET REFERENTIAL_INTEGRITY FALSE; + +TRUNCATE TABLE member; +TRUNCATE TABLE balance_option; +TRUNCATE TABLE balance_content; +TRUNCATE TABLE balance_vote; +TRUNCATE TABLE room; +TRUNCATE TABLE room_content; + +ALTER TABLE member ALTER COLUMN ID RESTART WITH 1; +ALTER TABLE balance_option ALTER COLUMN ID RESTART WITH 1; +ALTER TABLE balance_content ALTER COLUMN ID RESTART WITH 1; +ALTER TABLE balance_vote ALTER COLUMN ID RESTART WITH 1; +ALTER TABLE room ALTER COLUMN ID RESTART WITH 1; +ALTER TABLE room_content ALTER COLUMN ID RESTART WITH 1; + +INSERT INTO room() VALUES (); + +INSERT INTO member(nickname, room_id) +VALUES ('mohamedeu al katan', 1), ('deundeun', 1), ('rupi', 1), ('rapper lee', 1); + +INSERT INTO room_content(room_id, balance_content_id, created_at) +VALUES (1, 2, '2024-07-18 19:50:00.000'), (1, 1, '2024-07-18 20:00:00.000'); + +INSERT INTO balance_content(category, name) +VALUES ('EXAMPLE', '민초 vs 반민초'), ('EXAMPLE', '월 200 백수 vs 월 500 직장인'); + +INSERT INTO balance_option(name, balance_content_id) +VALUES ('민초', 1), ('반민초', 1), ('월 200 백수', 2), ('월 200 직장인', 2); + +INSERT INTO balance_vote(balance_option_id, member_id) +VALUES (4, 1), (4, 2), (4, 3), (4, 4), (1, 1), (1, 2), (1, 3), (2, 4); + +SET REFERENTIAL_INTEGRITY TRUE;