From d5c469e037b2a13be2b1678535c0d5b1395fddc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EB=8F=99=ED=9B=88?= <2dh2@naver.com> Date: Tue, 17 Mar 2026 10:57:17 +0900 Subject: [PATCH] =?UTF-8?q?test:=20=EC=95=8C=EB=A6=BC=20=EA=B4=80=EB=A0=A8?= =?UTF-8?q?=20=ED=86=B5=ED=95=A9=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notification/NotificationApiTest.java | 146 ++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 src/test/java/gg/agit/konect/integration/domain/notification/NotificationApiTest.java diff --git a/src/test/java/gg/agit/konect/integration/domain/notification/NotificationApiTest.java b/src/test/java/gg/agit/konect/integration/domain/notification/NotificationApiTest.java new file mode 100644 index 00000000..414f07be --- /dev/null +++ b/src/test/java/gg/agit/konect/integration/domain/notification/NotificationApiTest.java @@ -0,0 +1,146 @@ +package gg.agit.konect.integration.domain.notification; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import gg.agit.konect.domain.notification.dto.NotificationTokenDeleteRequest; +import gg.agit.konect.domain.notification.dto.NotificationTokenRegisterRequest; +import gg.agit.konect.domain.notification.model.NotificationDeviceToken; +import gg.agit.konect.domain.notification.repository.NotificationDeviceTokenRepository; +import gg.agit.konect.domain.university.model.University; +import gg.agit.konect.domain.user.model.User; +import gg.agit.konect.support.IntegrationTestSupport; +import gg.agit.konect.support.fixture.UniversityFixture; +import gg.agit.konect.support.fixture.UserFixture; + +class NotificationApiTest extends IntegrationTestSupport { + + private static final String REGISTERED_TOKEN = "ExpoPushToken[registered-token]"; + private static final String UPDATED_TOKEN = "ExpoPushToken[updated-token]"; + private static final String INVALID_TOKEN = "invalid-token"; + + @Autowired + private NotificationDeviceTokenRepository notificationDeviceTokenRepository; + + private User user; + + @BeforeEach + void setUp() throws Exception { + University university = persist(UniversityFixture.create()); + user = persist(UserFixture.createUser(university, "알림유저", "2021136001")); + } + + @Nested + @DisplayName("GET /notifications/tokens - 내 알림 토큰 조회") + class GetMyToken { + + @Test + @DisplayName("등록된 알림 토큰을 조회한다") + void getMyTokenSuccess() throws Exception { + // given + persist(NotificationDeviceToken.of(user, REGISTERED_TOKEN)); + clearPersistenceContext(); + mockLoginUser(user.getId()); + + // when & then + performGet("/notifications/tokens") + .andExpect(status().isOk()) + .andExpect(jsonPath("$.token").value(REGISTERED_TOKEN)); + } + + @Test + @DisplayName("등록된 알림 토큰이 없으면 404를 반환한다") + void getMyTokenWhenMissingFails() throws Exception { + // given + mockLoginUser(user.getId()); + + // when & then + performGet("/notifications/tokens") + .andExpect(status().isNotFound()) + .andExpect(jsonPath("$.code").value("NOT_FOUND_NOTIFICATION_TOKEN")); + } + } + + @Nested + @DisplayName("POST /notifications/tokens - 알림 토큰 등록") + class RegisterToken { + + @Test + @DisplayName("알림 토큰을 새로 등록한다") + void registerTokenSuccess() throws Exception { + // given + mockLoginUser(user.getId()); + + // when & then + performPost("/notifications/tokens", new NotificationTokenRegisterRequest(REGISTERED_TOKEN)) + .andExpect(status().isOk()); + + clearPersistenceContext(); + assertThat(notificationDeviceTokenRepository.findByUserId(user.getId())) + .isPresent() + .get() + .extracting(NotificationDeviceToken::getToken) + .isEqualTo(REGISTERED_TOKEN); + } + + @Test + @DisplayName("이미 등록된 토큰이 있으면 새 토큰으로 갱신한다") + void registerTokenUpdatesExistingToken() throws Exception { + // given + persist(NotificationDeviceToken.of(user, REGISTERED_TOKEN)); + clearPersistenceContext(); + mockLoginUser(user.getId()); + + // when & then + performPost("/notifications/tokens", new NotificationTokenRegisterRequest(UPDATED_TOKEN)) + .andExpect(status().isOk()); + + clearPersistenceContext(); + assertThat(notificationDeviceTokenRepository.findByUserId(user.getId())) + .isPresent() + .get() + .extracting(NotificationDeviceToken::getToken) + .isEqualTo(UPDATED_TOKEN); + } + + @Test + @DisplayName("유효하지 않은 Expo 토큰이면 400을 반환한다") + void registerTokenWithInvalidTokenFails() throws Exception { + // given + mockLoginUser(user.getId()); + + // when & then + performPost("/notifications/tokens", new NotificationTokenRegisterRequest(INVALID_TOKEN)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.code").value("INVALID_NOTIFICATION_TOKEN")); + } + } + + @Nested + @DisplayName("DELETE /notifications/tokens - 알림 토큰 삭제") + class DeleteToken { + + @Test + @DisplayName("등록된 알림 토큰을 삭제한다") + void deleteTokenSuccess() throws Exception { + // given + persist(NotificationDeviceToken.of(user, REGISTERED_TOKEN)); + clearPersistenceContext(); + mockLoginUser(user.getId()); + + // when & then + performDelete("/notifications/tokens", new NotificationTokenDeleteRequest(REGISTERED_TOKEN)) + .andExpect(status().isOk()); + + clearPersistenceContext(); + assertThat(notificationDeviceTokenRepository.findByUserId(user.getId())).isEmpty(); + } + } +}