From 25374c6addf091c958c75729db020e011de6efa5 Mon Sep 17 00:00:00 2001 From: soo0711 Date: Fri, 19 Dec 2025 20:41:02 +0900 Subject: [PATCH 01/40] =?UTF-8?q?feat:=20test=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 6 ++++++ src/main/resources/application-test.yml | 9 +++++++++ 2 files changed, 15 insertions(+) create mode 100644 src/main/resources/application-test.yml diff --git a/build.gradle b/build.gradle index 24e5a665..44742ceb 100644 --- a/build.gradle +++ b/build.gradle @@ -41,6 +41,12 @@ dependencies { // Test testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + testImplementation "org.junit.jupiter:junit-jupiter:5.8.1" + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'org.springframework.boot:spring-boot-testcontainers' + testImplementation 'org.testcontainers:junit-jupiter' + testImplementation 'org.testcontainers:mysql' + testImplementation 'org.testcontainers:mongodb' // S3 implementation("software.amazon.awssdk:s3:2.31.54") diff --git a/src/main/resources/application-test.yml b/src/main/resources/application-test.yml new file mode 100644 index 00000000..8f3da0fc --- /dev/null +++ b/src/main/resources/application-test.yml @@ -0,0 +1,9 @@ +spring: + jpa: + hibernate: + ddl-auto: create-drop + show-sql: true + properties: + hibernate: + format_sql: true + dialect: org.hibernate.dialect.MySQL8Dialect \ No newline at end of file From 461acbd9f35764b039d7b72d85eb3626403d2485 Mon Sep 17 00:00:00 2001 From: soo0711 Date: Fri, 19 Dec 2025 20:48:34 +0900 Subject: [PATCH 02/40] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=20=EC=84=A4=EC=A0=95=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../leets/leenk/global/config/JpaConfig.java | 17 ----------------- .../leets/leenk/global/config/MongoConfig.java | 13 ------------- .../java/leets/leenk/LeenkApplicationTests.java | 13 ------------- 3 files changed, 43 deletions(-) delete mode 100644 src/main/java/leets/leenk/global/config/JpaConfig.java delete mode 100644 src/main/java/leets/leenk/global/config/MongoConfig.java delete mode 100644 src/test/java/leets/leenk/LeenkApplicationTests.java diff --git a/src/main/java/leets/leenk/global/config/JpaConfig.java b/src/main/java/leets/leenk/global/config/JpaConfig.java deleted file mode 100644 index b70c2db4..00000000 --- a/src/main/java/leets/leenk/global/config/JpaConfig.java +++ /dev/null @@ -1,17 +0,0 @@ -package leets.leenk.global.config; - -import org.springframework.context.annotation.Configuration; -import org.springframework.data.jpa.repository.config.EnableJpaAuditing; -import org.springframework.data.jpa.repository.config.EnableJpaRepositories; - -@Configuration -@EnableJpaAuditing -@EnableJpaRepositories(basePackages = { - "leets.leenk.domain.feed.domain.repository", - "leets.leenk.domain.user.domain.repository", - "leets.leenk.domain.media.domain.repository", - "leets.leenk.domain.leenk.domain.repository", - "leets.leenk.domain.birthday.domain.repository", -}) -public class JpaConfig { -} diff --git a/src/main/java/leets/leenk/global/config/MongoConfig.java b/src/main/java/leets/leenk/global/config/MongoConfig.java deleted file mode 100644 index 1fa68e1d..00000000 --- a/src/main/java/leets/leenk/global/config/MongoConfig.java +++ /dev/null @@ -1,13 +0,0 @@ -package leets.leenk.global.config; - -import org.springframework.context.annotation.Configuration; -import org.springframework.data.mongodb.config.EnableMongoAuditing; -import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; - -@Configuration -@EnableMongoAuditing -@EnableMongoRepositories(basePackages = { - "leets.leenk.domain.notification.domain.repository" -}) -public class MongoConfig { -} diff --git a/src/test/java/leets/leenk/LeenkApplicationTests.java b/src/test/java/leets/leenk/LeenkApplicationTests.java deleted file mode 100644 index 4983f451..00000000 --- a/src/test/java/leets/leenk/LeenkApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package leets.leenk; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class LeenkApplicationTests { - - @Test - void contextLoads() { - } - -} From 54933fb46d841dc90174c8e31254d7bff161ab61 Mon Sep 17 00:00:00 2001 From: soo0711 Date: Fri, 19 Dec 2025 20:53:42 +0900 Subject: [PATCH 03/40] =?UTF-8?q?refactor:=20=EB=AA=BD=EA=B3=A0=EB=94=94?= =?UTF-8?q?=EB=B9=84=EC=9A=A9=20base=20entity=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/entity/Notification.java | 12 ++++------- .../global/common/entity/MongoBaseEntity.java | 21 +++++++++++++++++++ 2 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 src/main/java/leets/leenk/global/common/entity/MongoBaseEntity.java diff --git a/src/main/java/leets/leenk/domain/notification/domain/entity/Notification.java b/src/main/java/leets/leenk/domain/notification/domain/entity/Notification.java index 32c97f77..dd197ced 100644 --- a/src/main/java/leets/leenk/domain/notification/domain/entity/Notification.java +++ b/src/main/java/leets/leenk/domain/notification/domain/entity/Notification.java @@ -1,29 +1,25 @@ package leets.leenk.domain.notification.domain.entity; import leets.leenk.domain.notification.domain.entity.enums.NotificationType; -import org.springframework.data.mongodb.core.mapping.Document; - -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; -import jakarta.persistence.Id; -import leets.leenk.global.common.entity.BaseEntity; +import leets.leenk.global.common.entity.MongoBaseEntity; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; @SuperBuilder @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Document(collection = "notifications") -public class Notification extends BaseEntity { +public class Notification extends MongoBaseEntity { @Id private String id; private Long userId; - @Enumerated(EnumType.STRING) private NotificationType notificationType; private Boolean isRead; diff --git a/src/main/java/leets/leenk/global/common/entity/MongoBaseEntity.java b/src/main/java/leets/leenk/global/common/entity/MongoBaseEntity.java new file mode 100644 index 00000000..d862c157 --- /dev/null +++ b/src/main/java/leets/leenk/global/common/entity/MongoBaseEntity.java @@ -0,0 +1,21 @@ +package leets.leenk.global.common.entity; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; + +import java.time.LocalDateTime; + +@Getter +@SuperBuilder +@NoArgsConstructor +public abstract class MongoBaseEntity { + + @CreatedDate + private LocalDateTime createDate; + + @LastModifiedDate + private LocalDateTime updateDate; +} From 8ba89bddfd2aa33a532ca731016edaa68f2a0404 Mon Sep 17 00:00:00 2001 From: soo0711 Date: Fri, 19 Dec 2025 21:00:39 +0900 Subject: [PATCH 04/40] =?UTF-8?q?test:=20TestContainers=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../leets/leenk/config/MysqlTestConfig.java | 19 ++++++++++++ .../leenk/config/TestContainersTest.java | 30 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 src/test/java/leets/leenk/config/MysqlTestConfig.java create mode 100644 src/test/java/leets/leenk/config/TestContainersTest.java diff --git a/src/test/java/leets/leenk/config/MysqlTestConfig.java b/src/test/java/leets/leenk/config/MysqlTestConfig.java new file mode 100644 index 00000000..02ac9ab1 --- /dev/null +++ b/src/test/java/leets/leenk/config/MysqlTestConfig.java @@ -0,0 +1,19 @@ +package leets.leenk.config; + +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.springframework.context.annotation.Bean; +import org.testcontainers.containers.MySQLContainer; + +@TestConfiguration +public class MysqlTestConfig { + + private static final String MYSQL_IMAGE = "mysql:8.0.41"; + + @Bean + @ServiceConnection + public MySQLContainer mysqlContainer() { + return new MySQLContainer<>(MYSQL_IMAGE) + .withDatabaseName("testdb"); + } +} diff --git a/src/test/java/leets/leenk/config/TestContainersTest.java b/src/test/java/leets/leenk/config/TestContainersTest.java new file mode 100644 index 00000000..400933ec --- /dev/null +++ b/src/test/java/leets/leenk/config/TestContainersTest.java @@ -0,0 +1,30 @@ +package leets.leenk.config; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; +import org.testcontainers.containers.MySQLContainer; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@Import(MysqlTestConfig.class) +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +class TestContainersTest { + + @Autowired + private MySQLContainer mysqlContainer; + + + @Test + void MySQL_컨테이너_정상_동작_테스트() { + // MySQL 컨테이너 테스트 + assertThat(mysqlContainer).isNotNull(); + assertThat(mysqlContainer.isRunning()).isTrue(); + assertThat(mysqlContainer.getDatabaseName()).isEqualTo("testdb"); + + System.out.println("MySQL Container JDBC URL: " + mysqlContainer.getJdbcUrl()); + } +} From f4edce13bc431adc17c1c21ad140895300325b10 Mon Sep 17 00:00:00 2001 From: soo0711 Date: Fri, 19 Dec 2025 21:05:55 +0900 Subject: [PATCH 05/40] =?UTF-8?q?test:=20=EC=98=88=EC=8B=9C=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/repository/UserRepositoryTest.java | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 src/test/java/leets/leenk/domain/user/domain/repository/UserRepositoryTest.java diff --git a/src/test/java/leets/leenk/domain/user/domain/repository/UserRepositoryTest.java b/src/test/java/leets/leenk/domain/user/domain/repository/UserRepositoryTest.java new file mode 100644 index 00000000..9e556e24 --- /dev/null +++ b/src/test/java/leets/leenk/domain/user/domain/repository/UserRepositoryTest.java @@ -0,0 +1,83 @@ +package leets.leenk.domain.user.domain.repository; + +import leets.leenk.config.MysqlTestConfig; +import leets.leenk.domain.user.domain.entity.User; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.time.LocalDate; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@Import(MysqlTestConfig.class) +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +class UserRepositoryTest { + + @Autowired + private UserRepository userRepository; + + @BeforeEach + void setUp() { + userRepository.deleteAll(); + } + + @Test + @DisplayName("특정 날짜에 생일인 활성 사용자만 이름순으로 조회한다") + void findAllUsersInBirthday() { + // given + LocalDate birthday = LocalDate.of(2000, 5, 15); + + User activeUser1 = createUser(1L, "김철수", birthday, 1); + User activeUser2 = createUser(2L, "이영희", birthday, 1); + User activeUser3 = createUser(3L, "박민수", birthday, 1); + + // 탈퇴한 사용자 (제외되어야 함) + User leftUser = createUser(4L, "탈퇴유저", birthday, 1); + leftUser.leave(); + + // 삭제된 사용자 (제외되어야 함) + User deletedUser = createUser(5L, "삭제유저", birthday, 1); + deletedUser.delete(); + + // 생일이 다른 사용자 (제외되어야 함) + User differentBirthdayUser = createUser(6L, "다른생일", LocalDate.of(2000, 6, 20), 1); + + // 생일이 null인 사용자 (제외되어야 함) + User noBirthdayUser = createUser(7L, "생일없음", null, 1); + + userRepository.saveAll(List.of( + activeUser1, activeUser2, activeUser3, + leftUser, deletedUser, differentBirthdayUser, noBirthdayUser + )); + + // when + List result = userRepository.findAllUsersInBirthday(5, 15); + + // then + assertThat(result).hasSize(3); + assertThat(result).extracting(User::getName) + .containsExactly("김철수", "박민수", "이영희"); // 이름순 정렬 확인 + assertThat(result).allMatch(user -> user.getBirthday().equals(birthday)); + assertThat(result).allMatch(user -> user.getLeaveDate() == null); + assertThat(result).allMatch(user -> user.getDeleteDate() == null); + } + + private User createUser(Long id, String name, LocalDate birthday, int cardinal) { + return User.builder() + .id(id) + .name(name) + .birthday(birthday) + .cardinal(cardinal) + .totalReactionCount(0) + .termsAgreement(true) + .privacyAgreement(true) + .build(); + } +} From e54aa3f274348a17f021f403529960744809f999 Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 18:35:38 +0900 Subject: [PATCH 06/40] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20test=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=A4=91?= =?UTF-8?q?=EB=B3=B5=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 1 - build.gradle~ | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 build.gradle~ diff --git a/build.gradle b/build.gradle index 44742ceb..5dd71692 100644 --- a/build.gradle +++ b/build.gradle @@ -42,7 +42,6 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' testImplementation "org.junit.jupiter:junit-jupiter:5.8.1" - testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.boot:spring-boot-testcontainers' testImplementation 'org.testcontainers:junit-jupiter' testImplementation 'org.testcontainers:mysql' diff --git a/build.gradle~ b/build.gradle~ new file mode 100644 index 00000000..44742ceb --- /dev/null +++ b/build.gradle~ @@ -0,0 +1,62 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.5.0' + id 'io.spring.dependency-management' version '1.1.7' +} + +group = 'leets' +version = '0.0.1-SNAPSHOT' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } +} + +repositories { + mavenCentral() +} + +dependencies { + //Spring + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-security' + implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server") + + // Swagger + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.8' + + // Lombok + annotationProcessor 'org.projectlombok:lombok' + compileOnly 'org.projectlombok:lombok' + + // MySQL + runtimeOnly 'com.mysql:mysql-connector-j' + + //MongoDB + implementation 'org.springframework.boot:spring-boot-starter-data-mongodb' + + // Test + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + testImplementation "org.junit.jupiter:junit-jupiter:5.8.1" + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'org.springframework.boot:spring-boot-testcontainers' + testImplementation 'org.testcontainers:junit-jupiter' + testImplementation 'org.testcontainers:mysql' + testImplementation 'org.testcontainers:mongodb' + + // S3 + implementation("software.amazon.awssdk:s3:2.31.54") + + // AWS + implementation 'io.awspring.cloud:spring-cloud-aws-starter-sqs' + implementation platform("io.awspring.cloud:spring-cloud-aws-dependencies:3.3.0") + +} + +tasks.named('test') { + useJUnitPlatform() +} From a243241d21951a8341c781fa62dc5e00ee71529f Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 18:50:02 +0900 Subject: [PATCH 07/40] =?UTF-8?q?refactor:=20Kotlin=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build.gradle b/build.gradle index 5dd71692..3b7e5c47 100644 --- a/build.gradle +++ b/build.gradle @@ -2,6 +2,10 @@ plugins { id 'java' id 'org.springframework.boot' version '3.5.0' id 'io.spring.dependency-management' version '1.1.7' + + // Kotlin + id 'org.jetbrains.kotlin.jvm' version '1.9.0' + id 'org.jetbrains.kotlin.plugin.spring' version '1.9.0' } group = 'leets' @@ -46,6 +50,9 @@ dependencies { testImplementation 'org.testcontainers:junit-jupiter' testImplementation 'org.testcontainers:mysql' testImplementation 'org.testcontainers:mongodb' + testImplementation 'org.mockito.kotlin:mockito-kotlin:5.1.0' + testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5' + testImplementation 'org.jetbrains.kotlin:kotlin-stdlib' // S3 implementation("software.amazon.awssdk:s3:2.31.54") From fc5c53c5e8e4ea151b3b3de64b54f59eddb5edc9 Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 19:58:39 +0900 Subject: [PATCH 08/40] =?UTF-8?q?test:=20User=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20Fixture=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/test/fixture/UserTestFixture.kt | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/test/java/leets/leenk/domain/user/test/fixture/UserTestFixture.kt diff --git a/src/test/java/leets/leenk/domain/user/test/fixture/UserTestFixture.kt b/src/test/java/leets/leenk/domain/user/test/fixture/UserTestFixture.kt new file mode 100644 index 00000000..7b9dd829 --- /dev/null +++ b/src/test/java/leets/leenk/domain/user/test/fixture/UserTestFixture.kt @@ -0,0 +1,38 @@ +package leets.leenk.domain.user.test.fixture + +import leets.leenk.domain.user.domain.entity.User +import java.time.LocalDate + +class UserTestFixture { + companion object { + fun createUser( + id: Long = 1L, + name: String = "테스트유저", + cardinal: Int = 1, + profileImage: String? = null, + birthday: LocalDate? = null, + thumbnail: String? = null, + mbti: String? = null, + introduction: String? = null, + fcmToken: String? = null, + kakaoTalkId: String? = null, + totalReactionCount: Long = 0L, + termsAgreement: Boolean = true, + privacyAgreement: Boolean = true + ): User = User.builder() + .id(id) + .name(name) + .cardinal(cardinal) + .profileImage(profileImage) + .birthday(birthday) + .thumbnail(thumbnail) + .mbti(mbti) + .introduction(introduction) + .fcmToken(fcmToken) + .kakaoTalkId(kakaoTalkId) + .totalReactionCount(totalReactionCount) + .termsAgreement(termsAgreement) + .privacyAgreement(privacyAgreement) + .build() + } +} \ No newline at end of file From ebd4a1ca56bb31f12383a04f1a396cfb75c7cf40 Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 20:06:21 +0900 Subject: [PATCH 09/40] =?UTF-8?q?test:=20Leenk=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20Fixture=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../leenk/test/fixture/LeenkTestFixture.kt | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt diff --git a/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt b/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt new file mode 100644 index 00000000..06ae0b2d --- /dev/null +++ b/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt @@ -0,0 +1,35 @@ +package leets.leenk.domain.leenk.test.fixture + +import leets.leenk.domain.leenk.domain.entity.Leenk +import leets.leenk.domain.leenk.domain.entity.Location +import leets.leenk.domain.leenk.domain.entity.enums.LeenkStatus +import leets.leenk.domain.user.domain.entity.User +import java.time.LocalDateTime + +class LeenkTestFixture { + companion object { + fun createLeenk( + id: Long? = null, + author: User, + location: Location, + title: String = "테스트 링크", + content: String? = "테스트 내용", + startTime: LocalDateTime = LocalDateTime.now().plusDays(1), + maxParticipants: Long = 10L, + currentParticipants: Long = 1L, + status: LeenkStatus = LeenkStatus.RECRUITING + ): Leenk { + return Leenk.builder() + .apply { id?.let { id(it) } } + .author(author) + .location(location) + .title(title) + .content(content) + .startTime(startTime) + .maxParticipants(maxParticipants) + .currentParticipants(currentParticipants) + .status(status) + .build() + } + } +} \ No newline at end of file From ec64a2ece740ee0b72cc698f9696aee56604072a Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 20:08:09 +0900 Subject: [PATCH 10/40] =?UTF-8?q?test:=20LeenkParticipants=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20Fixture=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fixture/LeenkParticipantsTestFixture.kt | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkParticipantsTestFixture.kt diff --git a/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkParticipantsTestFixture.kt b/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkParticipantsTestFixture.kt new file mode 100644 index 00000000..dd90d06d --- /dev/null +++ b/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkParticipantsTestFixture.kt @@ -0,0 +1,24 @@ +package leets.leenk.domain.leenk.test.fixture + +import leets.leenk.domain.leenk.domain.entity.Leenk +import leets.leenk.domain.leenk.domain.entity.LeenkParticipants +import leets.leenk.domain.user.domain.entity.User +import java.time.LocalDateTime + +class LeenkParticipantsTestFixture { + companion object { + fun createParticipant( + id: Long? = null, + leenk: Leenk, + participant: User, + joinedAt: LocalDateTime = LocalDateTime.now() + ): LeenkParticipants { + return LeenkParticipants.builder() + .apply { id?.let { id(it) } } + .leenk(leenk) + .participant(participant) + .joinedAt(joinedAt) + .build() + } + } +} \ No newline at end of file From e217a143526ead406ce8da9b9fc5c8b4a7d7ba0a Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 20:09:31 +0900 Subject: [PATCH 11/40] =?UTF-8?q?test:=20Location=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20Fixture=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../leenk/test/fixture/LocationTestFixture.kt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/test/java/leets/leenk/domain/leenk/test/fixture/LocationTestFixture.kt diff --git a/src/test/java/leets/leenk/domain/leenk/test/fixture/LocationTestFixture.kt b/src/test/java/leets/leenk/domain/leenk/test/fixture/LocationTestFixture.kt new file mode 100644 index 00000000..ef12ffc7 --- /dev/null +++ b/src/test/java/leets/leenk/domain/leenk/test/fixture/LocationTestFixture.kt @@ -0,0 +1,17 @@ +package leets.leenk.domain.leenk.test.fixture + +import leets.leenk.domain.leenk.domain.entity.Location + +class LocationTestFixture { + companion object { + fun createLocation( + id: Long? = null, + placeName: String = "테스트 장소" + ): Location { + return Location.builder() + .apply { id?.let { id(it) } } + .placeName(placeName) + .build() + } + } +} \ No newline at end of file From 74e0cb7d2e9505b89363449427c9a162459a37a0 Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 20:41:10 +0900 Subject: [PATCH 12/40] =?UTF-8?q?refactor:=20MockK=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 3b7e5c47..871bee1d 100644 --- a/build.gradle +++ b/build.gradle @@ -51,6 +51,7 @@ dependencies { testImplementation 'org.testcontainers:mysql' testImplementation 'org.testcontainers:mongodb' testImplementation 'org.mockito.kotlin:mockito-kotlin:5.1.0' + testImplementation "io.mockk:mockk:1.13.10" testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5' testImplementation 'org.jetbrains.kotlin:kotlin-stdlib' From 738d76bfa44a1d613426526250b30933d06859dd Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 21:12:39 +0900 Subject: [PATCH 13/40] =?UTF-8?q?fix:=20Java=2021=20=EB=B9=8C=EB=93=9C=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=ED=95=B4=EA=B2=B0=EC=9D=84=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20Kotlin=20=EB=B2=84=EC=A0=84=20=EC=97=85=EA=B7=B8?= =?UTF-8?q?=EB=A0=88=EC=9D=B4=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 871bee1d..ae784015 100644 --- a/build.gradle +++ b/build.gradle @@ -4,8 +4,8 @@ plugins { id 'io.spring.dependency-management' version '1.1.7' // Kotlin - id 'org.jetbrains.kotlin.jvm' version '1.9.0' - id 'org.jetbrains.kotlin.plugin.spring' version '1.9.0' + id 'org.jetbrains.kotlin.jvm' version '1.9.25' + id 'org.jetbrains.kotlin.plugin.spring' version '1.9.25' } group = 'leets' From fdefb58fbc084ee79b4bd350635a93d68ce144ea Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 21:14:50 +0900 Subject: [PATCH 14/40] =?UTF-8?q?test:=20LeenkUsecase=20Leenk=20=EC=B0=B8?= =?UTF-8?q?=EC=97=AC=20=EA=B8=B0=EB=8A=A5=20=EC=84=B1=EA=B3=B5=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/usecase/LeenkUsecaseTest.kt | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt diff --git a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt new file mode 100644 index 00000000..58fccb38 --- /dev/null +++ b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt @@ -0,0 +1,106 @@ +package leets.leenk.domain.leenk.application.usecase + +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import leets.leenk.domain.leenk.application.mapper.LeenkParticipantsMapper +import leets.leenk.domain.leenk.domain.entity.Leenk +import leets.leenk.domain.leenk.domain.entity.LeenkParticipants +import leets.leenk.domain.leenk.domain.entity.Location +import leets.leenk.domain.leenk.domain.entity.enums.LeenkStatus +import leets.leenk.domain.leenk.domain.service.LeenkGetService +import leets.leenk.domain.leenk.domain.service.LeenkParticipantsGetService +import leets.leenk.domain.leenk.domain.service.LeenkParticipantsSaveService +import leets.leenk.domain.leenk.test.fixture.LeenkParticipantsTestFixture +import leets.leenk.domain.leenk.test.fixture.LeenkTestFixture +import leets.leenk.domain.leenk.test.fixture.LocationTestFixture +import leets.leenk.domain.notification.application.usecase.LeenkNotificationUsecase +import leets.leenk.domain.user.domain.entity.User +import leets.leenk.domain.user.domain.service.user.UserGetService +import leets.leenk.domain.user.test.fixture.UserTestFixture +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.junit.jupiter.MockitoExtension + + +@ExtendWith(MockitoExtension::class) +class LeenkUsecaseTest { + + private val userGetService: UserGetService = mockk() + private val leenkGetService: LeenkGetService = mockk() + private val leenkParticipantsGetService: LeenkParticipantsGetService = mockk() + private val leenkParticipantsSaveService: LeenkParticipantsSaveService = mockk() + private val participantsMapper: LeenkParticipantsMapper = mockk() + private val leenkNotificationUsecase: LeenkNotificationUsecase = mockk(relaxed = true) + + private lateinit var leenkUsecase: LeenkUsecase + + private lateinit var user: User + private lateinit var recruitingLeenk: Leenk + private lateinit var participant: LeenkParticipants + private lateinit var location: Location + + @BeforeEach + fun setUp() { + leenkUsecase = LeenkUsecase( + mockk(), + mockk(), + leenkGetService, + mockk(), + mockk(), + leenkParticipantsSaveService, + leenkParticipantsGetService, + mockk(), + mockk(), + mockk(), + mockk(), + userGetService, + mockk(), + mockk(), + mockk(), + participantsMapper, + mockk(), + mockk(), + leenkNotificationUsecase + ) + + user = UserTestFixture.createUser(id = 1L, name = "김철수") + location = LocationTestFixture.createLocation(id = 1L, placeName = "테스트 장소") + recruitingLeenk = LeenkTestFixture.createLeenk( + id = 1L, + author = user, + location = location, + status = LeenkStatus.RECRUITING, + currentParticipants = 2L, + maxParticipants = 10L + ) + participant = LeenkParticipantsTestFixture.createParticipant( + leenk = recruitingLeenk, + participant = user + ) + } + + @Test + @DisplayName("모집 중인 링크에 정상적으로 참여한다") + fun participateLeenkSuccess() { + // given + every { userGetService.findById(1L) } returns user + every { leenkGetService.findById(1L) } returns recruitingLeenk + every { leenkParticipantsGetService.existsByLeenkAndParticipant(recruitingLeenk, user) } returns false + every { participantsMapper.toParticipants(recruitingLeenk, user, any()) } returns participant + every { leenkParticipantsSaveService.save(any()) } returns participant + + val initialParticipants = recruitingLeenk.currentParticipants + + // when + leenkUsecase.participateLeenk(1L, 1L) + + // then + verify(exactly = 1) { leenkParticipantsSaveService.save(participant) } + verify(exactly = 1) { leenkNotificationUsecase.saveNewLeenkParticipantNotification(recruitingLeenk, user) } + assertThat(recruitingLeenk.currentParticipants).isEqualTo(initialParticipants + 1) + } +} \ No newline at end of file From 2a3ec533a0a83cf665b3062dd3fd853721c6873e Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 21:21:28 +0900 Subject: [PATCH 15/40] =?UTF-8?q?test:=20LeenkUsecase=20Leenk=20=EB=AA=A8?= =?UTF-8?q?=EC=A7=91=20=EC=A4=91=EC=9D=B4=20=EC=95=84=EB=8B=8C=20=EB=A7=81?= =?UTF-8?q?=ED=81=AC=20=EC=B0=B8=EC=97=AC=20=EC=8B=9C=20=EC=98=88=EC=99=B8?= =?UTF-8?q?=20=EB=B0=9C=EC=83=9D=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/usecase/LeenkUsecaseTest.kt | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt index 58fccb38..792e952b 100644 --- a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt +++ b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt @@ -3,6 +3,7 @@ package leets.leenk.domain.leenk.application.usecase import io.mockk.every import io.mockk.mockk import io.mockk.verify +import leets.leenk.domain.leenk.application.exception.LeenkNotRecruitingException import leets.leenk.domain.leenk.application.mapper.LeenkParticipantsMapper import leets.leenk.domain.leenk.domain.entity.Leenk import leets.leenk.domain.leenk.domain.entity.LeenkParticipants @@ -19,6 +20,7 @@ import leets.leenk.domain.user.domain.entity.User import leets.leenk.domain.user.domain.service.user.UserGetService import leets.leenk.domain.user.test.fixture.UserTestFixture import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatThrownBy import org.junit.jupiter.api.Test import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName @@ -103,4 +105,28 @@ class LeenkUsecaseTest { verify(exactly = 1) { leenkNotificationUsecase.saveNewLeenkParticipantNotification(recruitingLeenk, user) } assertThat(recruitingLeenk.currentParticipants).isEqualTo(initialParticipants + 1) } + + @Test + @DisplayName("모집 중이 아닌 링크에 참여 시 예외가 발생한다") + fun participateLeenkNotRecruitingThrowsException() { + // given + val location = LocationTestFixture.createLocation(id = 2L) + val closedLeenk = LeenkTestFixture.createLeenk( + id = 1L, + author = user, + location = location, + status = LeenkStatus.CLOSED, + currentParticipants = 5L, + maxParticipants = 10L + ) + every { userGetService.findById(1L) } returns user + every { leenkGetService.findById(1L) } returns closedLeenk + + // when & then + assertThatThrownBy { leenkUsecase.participateLeenk(1L, 1L) } + .isInstanceOf(LeenkNotRecruitingException::class.java) + + verify(exactly = 0) { leenkParticipantsSaveService.save(any()) } + verify(exactly = 0) { leenkNotificationUsecase.saveNewLeenkParticipantNotification(any(), any()) } + } } \ No newline at end of file From b3560c0c8f3e073234e291a2e13a72583b74f17e Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 21:24:45 +0900 Subject: [PATCH 16/40] =?UTF-8?q?test:=20LeenkUsecase=20Leenk=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=20=EC=B0=B8=EC=97=AC=ED=95=9C=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=EA=B0=80=20=EB=8B=A4=EC=8B=9C=20=EC=B0=B8=EC=97=AC=20?= =?UTF-8?q?=EC=8B=9C=20=EC=98=88=EC=99=B8=20=EB=B0=9C=EC=83=9D=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/usecase/LeenkUsecaseTest.kt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt index 792e952b..14dc3915 100644 --- a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt +++ b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt @@ -3,6 +3,7 @@ package leets.leenk.domain.leenk.application.usecase import io.mockk.every import io.mockk.mockk import io.mockk.verify +import leets.leenk.domain.leenk.application.exception.AlreadyParticipatedException import leets.leenk.domain.leenk.application.exception.LeenkNotRecruitingException import leets.leenk.domain.leenk.application.mapper.LeenkParticipantsMapper import leets.leenk.domain.leenk.domain.entity.Leenk @@ -129,4 +130,21 @@ class LeenkUsecaseTest { verify(exactly = 0) { leenkParticipantsSaveService.save(any()) } verify(exactly = 0) { leenkNotificationUsecase.saveNewLeenkParticipantNotification(any(), any()) } } + + @Test + @DisplayName("이미 참여한 사용자가 다시 참여 시 예외가 발생한다") + fun participateLeenkAlreadyParticipatedThrowsException() { + // given + every { userGetService.findById(1L) } returns user + every { leenkGetService.findById(1L) } returns recruitingLeenk + every { leenkParticipantsGetService.existsByLeenkAndParticipant(recruitingLeenk, user) } returns true + + // when & then + assertThatThrownBy { leenkUsecase.participateLeenk(1L, 1L) } + .isInstanceOf(AlreadyParticipatedException::class.java) + + verify(exactly = 0) { leenkParticipantsSaveService.save(any()) } + verify(exactly = 0) { leenkNotificationUsecase.saveNewLeenkParticipantNotification(any(), any()) } + } + } \ No newline at end of file From 93d73d952febc835eaaa0cc85506efb236149c1d Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 21:27:40 +0900 Subject: [PATCH 17/40] =?UTF-8?q?test:=20LeenkUsecase=20Leenk=20=EC=B5=9C?= =?UTF-8?q?=EB=8C=80=20=EC=B0=B8=EC=97=AC=20=EC=9D=B8=EC=9B=90=20=EC=B4=88?= =?UTF-8?q?=EA=B3=BC=20=EC=8B=9C=20=EC=98=88=EC=99=B8=20=EB=B0=9C=EC=83=9D?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/usecase/LeenkUsecaseTest.kt | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt index 14dc3915..4f4ec079 100644 --- a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt +++ b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt @@ -5,6 +5,7 @@ import io.mockk.mockk import io.mockk.verify import leets.leenk.domain.leenk.application.exception.AlreadyParticipatedException import leets.leenk.domain.leenk.application.exception.LeenkNotRecruitingException +import leets.leenk.domain.leenk.application.exception.MaxParticipantsExceededException import leets.leenk.domain.leenk.application.mapper.LeenkParticipantsMapper import leets.leenk.domain.leenk.domain.entity.Leenk import leets.leenk.domain.leenk.domain.entity.LeenkParticipants @@ -147,4 +148,28 @@ class LeenkUsecaseTest { verify(exactly = 0) { leenkNotificationUsecase.saveNewLeenkParticipantNotification(any(), any()) } } + @Test + @DisplayName("최대 참여 인원을 초과하면 예외가 발생한다") + fun participateLeenkMaxParticipantsExceededThrowsException() { + // given + val location = LocationTestFixture.createLocation(id = 3L) + val fullLeenk = LeenkTestFixture.createLeenk( + id = 1L, + author = user, + location = location, + status = LeenkStatus.RECRUITING, + currentParticipants = 10L, + maxParticipants = 10L + ) + every { userGetService.findById(1L) } returns user + every { leenkGetService.findById(1L) } returns fullLeenk + every { leenkParticipantsGetService.existsByLeenkAndParticipant(fullLeenk, user) } returns false + + // when & then + assertThatThrownBy { leenkUsecase.participateLeenk(1L, 1L) } + .isInstanceOf(MaxParticipantsExceededException::class.java) + + verify(exactly = 0) { leenkParticipantsSaveService.save(any()) } + verify(exactly = 0) { leenkNotificationUsecase.saveNewLeenkParticipantNotification(any(), any()) } + } } \ No newline at end of file From fc4781913554cd739a4e2c0c71d88b88c46be3d2 Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 21:31:18 +0900 Subject: [PATCH 18/40] =?UTF-8?q?test:=20LeenkUsecase=20Leenk=20=EC=B5=9C?= =?UTF-8?q?=EB=8C=80=20=EC=B0=B8=EC=97=AC=20=EC=9D=B8=EC=9B=90=20=EC=A7=81?= =?UTF-8?q?=EC=A0=84=20=EC=B0=B8=EC=97=AC=20=EC=A0=95=EC=83=81=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EA=B2=BD=EA=B3=84=EA=B0=92=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/usecase/LeenkUsecaseTest.kt | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt index 4f4ec079..dda67006 100644 --- a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt +++ b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt @@ -172,4 +172,37 @@ class LeenkUsecaseTest { verify(exactly = 0) { leenkParticipantsSaveService.save(any()) } verify(exactly = 0) { leenkNotificationUsecase.saveNewLeenkParticipantNotification(any(), any()) } } + + @Test + @DisplayName("최대 참여 인원 직전에 참여하면 정상적으로 처리된다") + fun participateLeenkLastSlotSuccess() { + // given + val location = LocationTestFixture.createLocation(id = 4L) + val almostFullLeenk = LeenkTestFixture.createLeenk( + id = 1L, + author = user, + location = location, + status = LeenkStatus.RECRUITING, + currentParticipants = 9L, + maxParticipants = 10L + ) + val lastParticipant = LeenkParticipantsTestFixture.createParticipant( + leenk = almostFullLeenk, + participant = user + ) + + every { userGetService.findById(1L) } returns user + every { leenkGetService.findById(1L) } returns almostFullLeenk + every { leenkParticipantsGetService.existsByLeenkAndParticipant(almostFullLeenk, user) } returns false + every { participantsMapper.toParticipants(almostFullLeenk, user, any()) } returns lastParticipant + every { leenkParticipantsSaveService.save(any()) } returns lastParticipant + + // when + leenkUsecase.participateLeenk(1L, 1L) + + // then + verify(exactly = 1) { leenkParticipantsSaveService.save(lastParticipant) } + verify(exactly = 1) { leenkNotificationUsecase.saveNewLeenkParticipantNotification(almostFullLeenk, user) } + assertThat(almostFullLeenk.currentParticipants).isEqualTo(10L) + } } \ No newline at end of file From cf62bb2413591cce920e8344f7319e1b4352a557 Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 21:46:56 +0900 Subject: [PATCH 19/40] =?UTF-8?q?test:=20participateLeenk=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EB=AA=A8=EB=93=A0=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EB=A5=BC=20@Nested=20=ED=81=B4=EB=9E=98=EC=8A=A4=EB=A1=9C=20?= =?UTF-8?q?=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/usecase/LeenkUsecaseTest.kt | 239 +++++++++--------- 1 file changed, 122 insertions(+), 117 deletions(-) diff --git a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt index dda67006..315acc16 100644 --- a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt +++ b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt @@ -26,6 +26,7 @@ import org.assertj.core.api.Assertions.assertThatThrownBy import org.junit.jupiter.api.Test import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Nested import org.junit.jupiter.api.extension.ExtendWith import org.mockito.junit.jupiter.MockitoExtension @@ -87,122 +88,126 @@ class LeenkUsecaseTest { ) } - @Test - @DisplayName("모집 중인 링크에 정상적으로 참여한다") - fun participateLeenkSuccess() { - // given - every { userGetService.findById(1L) } returns user - every { leenkGetService.findById(1L) } returns recruitingLeenk - every { leenkParticipantsGetService.existsByLeenkAndParticipant(recruitingLeenk, user) } returns false - every { participantsMapper.toParticipants(recruitingLeenk, user, any()) } returns participant - every { leenkParticipantsSaveService.save(any()) } returns participant - - val initialParticipants = recruitingLeenk.currentParticipants - - // when - leenkUsecase.participateLeenk(1L, 1L) - - // then - verify(exactly = 1) { leenkParticipantsSaveService.save(participant) } - verify(exactly = 1) { leenkNotificationUsecase.saveNewLeenkParticipantNotification(recruitingLeenk, user) } - assertThat(recruitingLeenk.currentParticipants).isEqualTo(initialParticipants + 1) - } - - @Test - @DisplayName("모집 중이 아닌 링크에 참여 시 예외가 발생한다") - fun participateLeenkNotRecruitingThrowsException() { - // given - val location = LocationTestFixture.createLocation(id = 2L) - val closedLeenk = LeenkTestFixture.createLeenk( - id = 1L, - author = user, - location = location, - status = LeenkStatus.CLOSED, - currentParticipants = 5L, - maxParticipants = 10L - ) - every { userGetService.findById(1L) } returns user - every { leenkGetService.findById(1L) } returns closedLeenk - - // when & then - assertThatThrownBy { leenkUsecase.participateLeenk(1L, 1L) } - .isInstanceOf(LeenkNotRecruitingException::class.java) - - verify(exactly = 0) { leenkParticipantsSaveService.save(any()) } - verify(exactly = 0) { leenkNotificationUsecase.saveNewLeenkParticipantNotification(any(), any()) } - } - - @Test - @DisplayName("이미 참여한 사용자가 다시 참여 시 예외가 발생한다") - fun participateLeenkAlreadyParticipatedThrowsException() { - // given - every { userGetService.findById(1L) } returns user - every { leenkGetService.findById(1L) } returns recruitingLeenk - every { leenkParticipantsGetService.existsByLeenkAndParticipant(recruitingLeenk, user) } returns true - - // when & then - assertThatThrownBy { leenkUsecase.participateLeenk(1L, 1L) } - .isInstanceOf(AlreadyParticipatedException::class.java) - - verify(exactly = 0) { leenkParticipantsSaveService.save(any()) } - verify(exactly = 0) { leenkNotificationUsecase.saveNewLeenkParticipantNotification(any(), any()) } - } - - @Test - @DisplayName("최대 참여 인원을 초과하면 예외가 발생한다") - fun participateLeenkMaxParticipantsExceededThrowsException() { - // given - val location = LocationTestFixture.createLocation(id = 3L) - val fullLeenk = LeenkTestFixture.createLeenk( - id = 1L, - author = user, - location = location, - status = LeenkStatus.RECRUITING, - currentParticipants = 10L, - maxParticipants = 10L - ) - every { userGetService.findById(1L) } returns user - every { leenkGetService.findById(1L) } returns fullLeenk - every { leenkParticipantsGetService.existsByLeenkAndParticipant(fullLeenk, user) } returns false - - // when & then - assertThatThrownBy { leenkUsecase.participateLeenk(1L, 1L) } - .isInstanceOf(MaxParticipantsExceededException::class.java) - - verify(exactly = 0) { leenkParticipantsSaveService.save(any()) } - verify(exactly = 0) { leenkNotificationUsecase.saveNewLeenkParticipantNotification(any(), any()) } - } - - @Test - @DisplayName("최대 참여 인원 직전에 참여하면 정상적으로 처리된다") - fun participateLeenkLastSlotSuccess() { - // given - val location = LocationTestFixture.createLocation(id = 4L) - val almostFullLeenk = LeenkTestFixture.createLeenk( - id = 1L, - author = user, - location = location, - status = LeenkStatus.RECRUITING, - currentParticipants = 9L, - maxParticipants = 10L - ) - val lastParticipant = LeenkParticipantsTestFixture.createParticipant( - leenk = almostFullLeenk, - participant = user - ) - - every { userGetService.findById(1L) } returns user - every { leenkGetService.findById(1L) } returns almostFullLeenk - every { leenkParticipantsGetService.existsByLeenkAndParticipant(almostFullLeenk, user) } returns false - every { participantsMapper.toParticipants(almostFullLeenk, user, any()) } returns lastParticipant - every { leenkParticipantsSaveService.save(any()) } returns lastParticipant - - // when - leenkUsecase.participateLeenk(1L, 1L) - - // then - verify(exactly = 1) { leenkParticipantsSaveService.save(lastParticipant) } - verify(exactly = 1) { leenkNotificationUsecase.saveNewLeenkParticipantNotification(almostFullLeenk, user) } - assertThat(almostFullLeenk.currentParticipants).isEqualTo(10L) + @Nested + @DisplayName("participateLeenk 관련 테스트") + inner class ParticipateLeenkTests { + @Test + @DisplayName("모집 중인 링크에 정상적으로 참여한다") + fun participateLeenkSuccess() { + // given + every { userGetService.findById(1L) } returns user + every { leenkGetService.findById(1L) } returns recruitingLeenk + every { leenkParticipantsGetService.existsByLeenkAndParticipant(recruitingLeenk, user) } returns false + every { participantsMapper.toParticipants(recruitingLeenk, user, any()) } returns participant + every { leenkParticipantsSaveService.save(any()) } returns participant + + val initialParticipants = recruitingLeenk.currentParticipants + + // when + leenkUsecase.participateLeenk(1L, 1L) + + // then + verify(exactly = 1) { leenkParticipantsSaveService.save(participant) } + verify(exactly = 1) { leenkNotificationUsecase.saveNewLeenkParticipantNotification(recruitingLeenk, user) } + assertThat(recruitingLeenk.currentParticipants).isEqualTo(initialParticipants + 1) + } + + @Test + @DisplayName("모집 중이 아닌 링크에 참여 시 예외가 발생한다") + fun participateLeenkNotRecruitingThrowsException() { + // given + val location = LocationTestFixture.createLocation(id = 2L) + val closedLeenk = LeenkTestFixture.createLeenk( + id = 1L, + author = user, + location = location, + status = LeenkStatus.CLOSED, + currentParticipants = 5L, + maxParticipants = 10L + ) + every { userGetService.findById(1L) } returns user + every { leenkGetService.findById(1L) } returns closedLeenk + + // when & then + assertThatThrownBy { leenkUsecase.participateLeenk(1L, 1L) } + .isInstanceOf(LeenkNotRecruitingException::class.java) + + verify(exactly = 0) { leenkParticipantsSaveService.save(any()) } + verify(exactly = 0) { leenkNotificationUsecase.saveNewLeenkParticipantNotification(any(), any()) } + } + + @Test + @DisplayName("이미 참여한 사용자가 다시 참여 시 예외가 발생한다") + fun participateLeenkAlreadyParticipatedThrowsException() { + // given + every { userGetService.findById(1L) } returns user + every { leenkGetService.findById(1L) } returns recruitingLeenk + every { leenkParticipantsGetService.existsByLeenkAndParticipant(recruitingLeenk, user) } returns true + + // when & then + assertThatThrownBy { leenkUsecase.participateLeenk(1L, 1L) } + .isInstanceOf(AlreadyParticipatedException::class.java) + + verify(exactly = 0) { leenkParticipantsSaveService.save(any()) } + verify(exactly = 0) { leenkNotificationUsecase.saveNewLeenkParticipantNotification(any(), any()) } + } + + @Test + @DisplayName("최대 참여 인원을 초과하면 예외가 발생한다") + fun participateLeenkMaxParticipantsExceededThrowsException() { + // given + val location = LocationTestFixture.createLocation(id = 3L) + val fullLeenk = LeenkTestFixture.createLeenk( + id = 1L, + author = user, + location = location, + status = LeenkStatus.RECRUITING, + currentParticipants = 10L, + maxParticipants = 10L + ) + every { userGetService.findById(1L) } returns user + every { leenkGetService.findById(1L) } returns fullLeenk + every { leenkParticipantsGetService.existsByLeenkAndParticipant(fullLeenk, user) } returns false + + // when & then + assertThatThrownBy { leenkUsecase.participateLeenk(1L, 1L) } + .isInstanceOf(MaxParticipantsExceededException::class.java) + + verify(exactly = 0) { leenkParticipantsSaveService.save(any()) } + verify(exactly = 0) { leenkNotificationUsecase.saveNewLeenkParticipantNotification(any(), any()) } + } + + @Test + @DisplayName("최대 참여 인원 직전에 참여하면 정상적으로 처리된다") + fun participateLeenkLastSlotSuccess() { + // given + val location = LocationTestFixture.createLocation(id = 4L) + val almostFullLeenk = LeenkTestFixture.createLeenk( + id = 1L, + author = user, + location = location, + status = LeenkStatus.RECRUITING, + currentParticipants = 9L, + maxParticipants = 10L + ) + val lastParticipant = LeenkParticipantsTestFixture.createParticipant( + leenk = almostFullLeenk, + participant = user + ) + + every { userGetService.findById(1L) } returns user + every { leenkGetService.findById(1L) } returns almostFullLeenk + every { leenkParticipantsGetService.existsByLeenkAndParticipant(almostFullLeenk, user) } returns false + every { participantsMapper.toParticipants(almostFullLeenk, user, any()) } returns lastParticipant + every { leenkParticipantsSaveService.save(any()) } returns lastParticipant + + // when + leenkUsecase.participateLeenk(1L, 1L) + + // then + verify(exactly = 1) { leenkParticipantsSaveService.save(lastParticipant) } + verify(exactly = 1) { leenkNotificationUsecase.saveNewLeenkParticipantNotification(almostFullLeenk, user) } + assertThat(almostFullLeenk.currentParticipants).isEqualTo(10L) + } } } \ No newline at end of file From 990f4e46947a7797113c4cadfced654809defd54 Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 22:20:16 +0900 Subject: [PATCH 20/40] =?UTF-8?q?test:=20LeenkUsecase=20closeLeenk=20?= =?UTF-8?q?=EC=A0=95=EC=83=81=20=EB=8F=99=EC=9E=91=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/usecase/LeenkUsecaseTest.kt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt index 315acc16..6da1a75b 100644 --- a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt +++ b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt @@ -210,4 +210,23 @@ class LeenkUsecaseTest { assertThat(almostFullLeenk.currentParticipants).isEqualTo(10L) } } + + @Nested + @DisplayName("closeLeenk 관련 테스트") + inner class CloseLeenkTests { + @Test + @DisplayName("링크 작성자가 모집 중인 링크를 정상적으로 마감한다") + fun closeLeenkSuccess() { + // given + every { userGetService.findById(1L) } returns user + every { leenkGetService.findById(1L) } returns recruitingLeenk + + // when + leenkUsecase.closeLeenk(1L, 1L) + + // then + assertThat(recruitingLeenk.status).isEqualTo(LeenkStatus.CLOSED) + verify(exactly = 1) { leenkNotificationUsecase.saveLeenkClosedNotification(recruitingLeenk) } + } + } } \ No newline at end of file From 4e606a442097d1c644e733080f78f0aca7f912f3 Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 22:24:46 +0900 Subject: [PATCH 21/40] =?UTF-8?q?test:=20LeenkUsecase=20Leenk=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=EC=9E=90=EA=B0=80=20=EC=95=84=EB=8B=8C=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=EC=9E=90=EA=B0=80=20=EB=A7=81=ED=81=AC=20=EB=A7=88?= =?UTF-8?q?=EA=B0=90=20=EC=8B=9C=EB=8F=84=20=EC=8B=9C=20=EC=98=88=EC=99=B8?= =?UTF-8?q?=20=EB=B0=9C=EC=83=9D=20=EA=B2=80=EC=A6=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/usecase/LeenkUsecaseTest.kt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt index 6da1a75b..9517a908 100644 --- a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt +++ b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt @@ -6,6 +6,7 @@ import io.mockk.verify import leets.leenk.domain.leenk.application.exception.AlreadyParticipatedException import leets.leenk.domain.leenk.application.exception.LeenkNotRecruitingException import leets.leenk.domain.leenk.application.exception.MaxParticipantsExceededException +import leets.leenk.domain.leenk.application.exception.NotLeenkOwnerException import leets.leenk.domain.leenk.application.mapper.LeenkParticipantsMapper import leets.leenk.domain.leenk.domain.entity.Leenk import leets.leenk.domain.leenk.domain.entity.LeenkParticipants @@ -228,5 +229,21 @@ class LeenkUsecaseTest { assertThat(recruitingLeenk.status).isEqualTo(LeenkStatus.CLOSED) verify(exactly = 1) { leenkNotificationUsecase.saveLeenkClosedNotification(recruitingLeenk) } } + + @Test + @DisplayName("링크 작성자가 아닌 사용자가 마감 시도 시 예외가 발생한다") + fun closeLeenkNotOwnerThrowsException() { + // given + val otherUser = UserTestFixture.createUser(id = 2L, name = "김영희") + every { userGetService.findById(2L) } returns otherUser + every { leenkGetService.findById(1L) } returns recruitingLeenk + + // when & then + assertThatThrownBy { leenkUsecase.closeLeenk(2L, 1L) } + .isInstanceOf(NotLeenkOwnerException::class.java) + + assertThat(recruitingLeenk.status).isEqualTo(LeenkStatus.RECRUITING) + verify(exactly = 0) { leenkNotificationUsecase.saveLeenkClosedNotification(any()) } + } } } \ No newline at end of file From ae7d5b60eaed5b20b8d0e42fd13c07f9dcd85b49 Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 22:28:25 +0900 Subject: [PATCH 22/40] =?UTF-8?q?test:=20LeenkUsecase=20Leenk=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=20=EB=A7=88=EA=B0=90=EB=90=9C=20=EB=A7=81=ED=81=AC?= =?UTF-8?q?=EB=A5=BC=20=EB=8B=A4=EC=8B=9C=20=EB=A7=88=EA=B0=90=ED=95=A0=20?= =?UTF-8?q?=EB=95=8C=20=EC=98=88=EC=99=B8=20=EB=B0=9C=EC=83=9D=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/usecase/LeenkUsecaseTest.kt | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt index 9517a908..eb348c9e 100644 --- a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt +++ b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt @@ -3,10 +3,7 @@ package leets.leenk.domain.leenk.application.usecase import io.mockk.every import io.mockk.mockk import io.mockk.verify -import leets.leenk.domain.leenk.application.exception.AlreadyParticipatedException -import leets.leenk.domain.leenk.application.exception.LeenkNotRecruitingException -import leets.leenk.domain.leenk.application.exception.MaxParticipantsExceededException -import leets.leenk.domain.leenk.application.exception.NotLeenkOwnerException +import leets.leenk.domain.leenk.application.exception.* import leets.leenk.domain.leenk.application.mapper.LeenkParticipantsMapper import leets.leenk.domain.leenk.domain.entity.Leenk import leets.leenk.domain.leenk.domain.entity.LeenkParticipants @@ -245,5 +242,27 @@ class LeenkUsecaseTest { assertThat(recruitingLeenk.status).isEqualTo(LeenkStatus.RECRUITING) verify(exactly = 0) { leenkNotificationUsecase.saveLeenkClosedNotification(any()) } } + + @Test + @DisplayName("이미 마감된 링크를 다시 마감 시 예외가 발생한다") + fun closeLeenkAlreadyClosedThrowsException() { + // given + val closedLeenk = LeenkTestFixture.createLeenk( + id = 1L, + author = user, + location = location, + status = LeenkStatus.CLOSED, + currentParticipants = 5L, + maxParticipants = 10L + ) + every { userGetService.findById(1L) } returns user + every { leenkGetService.findById(1L) } returns closedLeenk + + // when & then + assertThatThrownBy { leenkUsecase.closeLeenk(1L, 1L) } + .isInstanceOf(LeenkAlreadyClosedException::class.java) + + verify(exactly = 0) { leenkNotificationUsecase.saveLeenkClosedNotification(any()) } + } } } \ No newline at end of file From adcb4c0ebcf66730ffca1d76577be0798d0efdd8 Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 22:42:40 +0900 Subject: [PATCH 23/40] =?UTF-8?q?test:=20LeenkTestFixture=EC=97=90=20?= =?UTF-8?q?=EB=A7=88=EA=B0=90=EB=90=9C=20=EB=A7=81=ED=81=AC=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20createClosedLeenk=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../leenk/test/fixture/LeenkTestFixture.kt | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt b/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt index 06ae0b2d..cea1d854 100644 --- a/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt +++ b/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt @@ -31,5 +31,22 @@ class LeenkTestFixture { .status(status) .build() } + + fun createClosedLeenk( + id: Long? = null, + author: User, + location: Location, + currentParticipants: Long = 5L, + maxParticipants: Long = 10L + ): Leenk { + return createLeenk( + id = id, + author = author, + location = location, + status = LeenkStatus.CLOSED, + currentParticipants = currentParticipants, + maxParticipants = maxParticipants + ) + } } -} \ No newline at end of file +} From 6686587d8f5df7e77240cf7f05f7959fbccc69ea Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 22:45:56 +0900 Subject: [PATCH 24/40] =?UTF-8?q?test:=20=EC=A4=91=EB=B3=B5=EB=90=9C=20clo?= =?UTF-8?q?sedLeenk=20=EC=83=9D=EC=84=B1=20=EC=BD=94=EB=93=9C=EB=A5=BC=20F?= =?UTF-8?q?ixture=EB=A1=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../leenk/application/usecase/LeenkUsecaseTest.kt | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt index eb348c9e..9c66bf03 100644 --- a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt +++ b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt @@ -115,13 +115,10 @@ class LeenkUsecaseTest { fun participateLeenkNotRecruitingThrowsException() { // given val location = LocationTestFixture.createLocation(id = 2L) - val closedLeenk = LeenkTestFixture.createLeenk( + val closedLeenk = LeenkTestFixture.createClosedLeenk( id = 1L, author = user, - location = location, - status = LeenkStatus.CLOSED, - currentParticipants = 5L, - maxParticipants = 10L + location = location ) every { userGetService.findById(1L) } returns user every { leenkGetService.findById(1L) } returns closedLeenk @@ -247,13 +244,10 @@ class LeenkUsecaseTest { @DisplayName("이미 마감된 링크를 다시 마감 시 예외가 발생한다") fun closeLeenkAlreadyClosedThrowsException() { // given - val closedLeenk = LeenkTestFixture.createLeenk( + val closedLeenk = LeenkTestFixture.createClosedLeenk( id = 1L, author = user, - location = location, - status = LeenkStatus.CLOSED, - currentParticipants = 5L, - maxParticipants = 10L + location = location ) every { userGetService.findById(1L) } returns user every { leenkGetService.findById(1L) } returns closedLeenk From 5589dbe4e6db1bfe1517a326dc80e1df93d51b7b Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 22:49:11 +0900 Subject: [PATCH 25/40] =?UTF-8?q?test:=20LeenkTestFixture=EC=97=90=20?= =?UTF-8?q?=EC=B5=9C=EB=8C=80=20=EC=B0=B8=EC=97=AC=20=EC=9D=B8=EC=9B=90?= =?UTF-8?q?=EC=9D=B8=20Leenk=20=EC=83=9D=EC=84=B1=20createFullLeenk=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../leenk/test/fixture/LeenkTestFixture.kt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt b/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt index cea1d854..272b2279 100644 --- a/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt +++ b/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt @@ -48,5 +48,21 @@ class LeenkTestFixture { maxParticipants = maxParticipants ) } + + fun createFullLeenk( + id: Long? = null, + author: User, + location: Location, + maxParticipants: Long = 10L + ): Leenk { + return createLeenk( + id = id, + author = author, + location = location, + status = LeenkStatus.RECRUITING, + currentParticipants = maxParticipants, + maxParticipants = maxParticipants + ) + } } } From a750d786b3bbec02bf01ad68426b53c37fdca9f5 Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 22:51:20 +0900 Subject: [PATCH 26/40] =?UTF-8?q?test:=20fullLeenk=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=EB=A5=BC=20Fixture=EB=A1=9C=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/leenk/application/usecase/LeenkUsecaseTest.kt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt index 9c66bf03..dc290aff 100644 --- a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt +++ b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt @@ -152,13 +152,10 @@ class LeenkUsecaseTest { fun participateLeenkMaxParticipantsExceededThrowsException() { // given val location = LocationTestFixture.createLocation(id = 3L) - val fullLeenk = LeenkTestFixture.createLeenk( + val fullLeenk = LeenkTestFixture.createFullLeenk( id = 1L, author = user, - location = location, - status = LeenkStatus.RECRUITING, - currentParticipants = 10L, - maxParticipants = 10L + location = location ) every { userGetService.findById(1L) } returns user every { leenkGetService.findById(1L) } returns fullLeenk From 18ac943caabea03c624ac6886d50e92b79102fcd Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 22:52:28 +0900 Subject: [PATCH 27/40] =?UTF-8?q?test:=20LeenkTestFixture=EC=97=90=20?= =?UTF-8?q?=EA=B1=B0=EC=9D=98=20=EA=BD=89=20=EC=B0=AC=20=EB=A7=81=ED=81=AC?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1=20createAlmostFullLeenk=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../leenk/test/fixture/LeenkTestFixture.kt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt b/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt index 272b2279..9d4ccb42 100644 --- a/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt +++ b/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt @@ -64,5 +64,21 @@ class LeenkTestFixture { maxParticipants = maxParticipants ) } + + fun createAlmostFullLeenk( + id: Long? = null, + author: User, + location: Location, + maxParticipants: Long = 10L + ): Leenk { + return createLeenk( + id = id, + author = author, + location = location, + status = LeenkStatus.RECRUITING, + currentParticipants = maxParticipants - 1, + maxParticipants = maxParticipants + ) + } } } From 7e5511fe15f435a5971c98d49794ee2a331b2e8d Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 22:53:29 +0900 Subject: [PATCH 28/40] =?UTF-8?q?test:=20almostFullLeenk=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EC=BD=94=EB=93=9C=EB=A5=BC=20Fixture=EB=A1=9C=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/leenk/application/usecase/LeenkUsecaseTest.kt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt index dc290aff..d83d342a 100644 --- a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt +++ b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt @@ -174,14 +174,12 @@ class LeenkUsecaseTest { fun participateLeenkLastSlotSuccess() { // given val location = LocationTestFixture.createLocation(id = 4L) - val almostFullLeenk = LeenkTestFixture.createLeenk( + val almostFullLeenk = LeenkTestFixture.createAlmostFullLeenk( id = 1L, author = user, - location = location, - status = LeenkStatus.RECRUITING, - currentParticipants = 9L, - maxParticipants = 10L + location = location ) + val lastParticipant = LeenkParticipantsTestFixture.createParticipant( leenk = almostFullLeenk, participant = user From 9a18f93d2fa34d9e0aa9bfa8be49a8e9f0397591 Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 23:11:45 +0900 Subject: [PATCH 29/40] =?UTF-8?q?test:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20Location=20=EC=83=9D=EC=84=B1=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/leenk/application/usecase/LeenkUsecaseTest.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt index d83d342a..b4264c5c 100644 --- a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt +++ b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt @@ -114,7 +114,6 @@ class LeenkUsecaseTest { @DisplayName("모집 중이 아닌 링크에 참여 시 예외가 발생한다") fun participateLeenkNotRecruitingThrowsException() { // given - val location = LocationTestFixture.createLocation(id = 2L) val closedLeenk = LeenkTestFixture.createClosedLeenk( id = 1L, author = user, @@ -151,7 +150,6 @@ class LeenkUsecaseTest { @DisplayName("최대 참여 인원을 초과하면 예외가 발생한다") fun participateLeenkMaxParticipantsExceededThrowsException() { // given - val location = LocationTestFixture.createLocation(id = 3L) val fullLeenk = LeenkTestFixture.createFullLeenk( id = 1L, author = user, @@ -173,7 +171,6 @@ class LeenkUsecaseTest { @DisplayName("최대 참여 인원 직전에 참여하면 정상적으로 처리된다") fun participateLeenkLastSlotSuccess() { // given - val location = LocationTestFixture.createLocation(id = 4L) val almostFullLeenk = LeenkTestFixture.createAlmostFullLeenk( id = 1L, author = user, @@ -254,4 +251,4 @@ class LeenkUsecaseTest { verify(exactly = 0) { leenkNotificationUsecase.saveLeenkClosedNotification(any()) } } } -} \ No newline at end of file +} From 2271960061754c350a2a9a8cdba376f19e563962 Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 23:14:20 +0900 Subject: [PATCH 30/40] =?UTF-8?q?test:=20finishedLeenk=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EC=BD=94=EB=93=9C=EB=A5=BC=20Fixture=EB=A1=9C=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../leenk/test/fixture/LeenkTestFixture.kt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt b/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt index 9d4ccb42..e72b6245 100644 --- a/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt +++ b/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt @@ -80,5 +80,22 @@ class LeenkTestFixture { maxParticipants = maxParticipants ) } + + fun createFinishedLeenk( + id: Long? = null, + author: User, + location: Location, + currentParticipants: Long = 10L, + maxParticipants: Long = 10L + ): Leenk { + return createLeenk( + id = id, + author = author, + location = location, + status = LeenkStatus.FINISHED, + currentParticipants = currentParticipants, + maxParticipants = maxParticipants + ) + } } } From ef9b3a87b17c5346606c151a90aaef10b43332f4 Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 23:16:58 +0900 Subject: [PATCH 31/40] =?UTF-8?q?test:=20LeenkUsecase=20Leenk=20=EC=99=84?= =?UTF-8?q?=EB=A3=8C=EB=90=9C=20=EC=83=81=ED=83=9C=EC=9D=98=20=EB=A7=81?= =?UTF-8?q?=ED=81=AC=20=EB=A7=88=EA=B0=90=20=EC=8B=9C=20=EC=98=88=EC=99=B8?= =?UTF-8?q?=20=EB=B0=9C=EC=83=9D=20=EA=B2=80=EC=A6=9D=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/usecase/LeenkUsecaseTest.kt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt index b4264c5c..8e3b87f4 100644 --- a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt +++ b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt @@ -250,5 +250,24 @@ class LeenkUsecaseTest { verify(exactly = 0) { leenkNotificationUsecase.saveLeenkClosedNotification(any()) } } + + @Test + @DisplayName("완료된 상태의 링크를 마감 시 예외가 발생한다") + fun closeLeenkCompletedStatusThrowsException() { + // given + val completedLeenk = LeenkTestFixture.createFinishedLeenk( + id = 1L, + author = user, + location = location + ) + every { userGetService.findById(1L) } returns user + every { leenkGetService.findById(1L) } returns completedLeenk + + // when & then + assertThatThrownBy { leenkUsecase.closeLeenk(1L, 1L) } + .isInstanceOf(LeenkAlreadyClosedException::class.java) + + verify(exactly = 0) { leenkNotificationUsecase.saveLeenkClosedNotification(any()) } + } } } From 10d53499342e64b37c17c0a84cf6de03b6af112e Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 23:26:49 +0900 Subject: [PATCH 32/40] =?UTF-8?q?chore:=20build.gradle~=20=EB=B0=B1?= =?UTF-8?q?=EC=97=85=20=ED=8C=8C=EC=9D=BC=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle~ | 62 --------------------------------------------------- 1 file changed, 62 deletions(-) delete mode 100644 build.gradle~ diff --git a/build.gradle~ b/build.gradle~ deleted file mode 100644 index 44742ceb..00000000 --- a/build.gradle~ +++ /dev/null @@ -1,62 +0,0 @@ -plugins { - id 'java' - id 'org.springframework.boot' version '3.5.0' - id 'io.spring.dependency-management' version '1.1.7' -} - -group = 'leets' -version = '0.0.1-SNAPSHOT' - -java { - toolchain { - languageVersion = JavaLanguageVersion.of(21) - } -} - -repositories { - mavenCentral() -} - -dependencies { - //Spring - implementation 'org.springframework.boot:spring-boot-starter-web' - implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - implementation 'org.springframework.boot:spring-boot-starter-security' - implementation 'org.springframework.boot:spring-boot-starter-validation' - implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server") - - // Swagger - implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.8' - - // Lombok - annotationProcessor 'org.projectlombok:lombok' - compileOnly 'org.projectlombok:lombok' - - // MySQL - runtimeOnly 'com.mysql:mysql-connector-j' - - //MongoDB - implementation 'org.springframework.boot:spring-boot-starter-data-mongodb' - - // Test - testImplementation 'org.springframework.boot:spring-boot-starter-test' - testRuntimeOnly 'org.junit.platform:junit-platform-launcher' - testImplementation "org.junit.jupiter:junit-jupiter:5.8.1" - testImplementation 'org.springframework.boot:spring-boot-starter-test' - testImplementation 'org.springframework.boot:spring-boot-testcontainers' - testImplementation 'org.testcontainers:junit-jupiter' - testImplementation 'org.testcontainers:mysql' - testImplementation 'org.testcontainers:mongodb' - - // S3 - implementation("software.amazon.awssdk:s3:2.31.54") - - // AWS - implementation 'io.awspring.cloud:spring-cloud-aws-starter-sqs' - implementation platform("io.awspring.cloud:spring-cloud-aws-dependencies:3.3.0") - -} - -tasks.named('test') { - useJUnitPlatform() -} From b9ce301767daa0e76666647248152b71c10d55a7 Mon Sep 17 00:00:00 2001 From: soo0711 Date: Sun, 21 Dec 2025 23:29:56 +0900 Subject: [PATCH 33/40] =?UTF-8?q?style:=20=EA=B0=9C=ED=96=89=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-test.yml | 2 +- .../domain/leenk/test/fixture/LeenkParticipantsTestFixture.kt | 2 +- .../leenk/domain/leenk/test/fixture/LocationTestFixture.kt | 2 +- .../leets/leenk/domain/user/test/fixture/UserTestFixture.kt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/resources/application-test.yml b/src/main/resources/application-test.yml index 8f3da0fc..751a56a8 100644 --- a/src/main/resources/application-test.yml +++ b/src/main/resources/application-test.yml @@ -6,4 +6,4 @@ spring: properties: hibernate: format_sql: true - dialect: org.hibernate.dialect.MySQL8Dialect \ No newline at end of file + dialect: org.hibernate.dialect.MySQL8Dialect diff --git a/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkParticipantsTestFixture.kt b/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkParticipantsTestFixture.kt index dd90d06d..0d63587a 100644 --- a/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkParticipantsTestFixture.kt +++ b/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkParticipantsTestFixture.kt @@ -21,4 +21,4 @@ class LeenkParticipantsTestFixture { .build() } } -} \ No newline at end of file +} diff --git a/src/test/java/leets/leenk/domain/leenk/test/fixture/LocationTestFixture.kt b/src/test/java/leets/leenk/domain/leenk/test/fixture/LocationTestFixture.kt index ef12ffc7..0acc00bb 100644 --- a/src/test/java/leets/leenk/domain/leenk/test/fixture/LocationTestFixture.kt +++ b/src/test/java/leets/leenk/domain/leenk/test/fixture/LocationTestFixture.kt @@ -14,4 +14,4 @@ class LocationTestFixture { .build() } } -} \ No newline at end of file +} diff --git a/src/test/java/leets/leenk/domain/user/test/fixture/UserTestFixture.kt b/src/test/java/leets/leenk/domain/user/test/fixture/UserTestFixture.kt index 7b9dd829..a948a430 100644 --- a/src/test/java/leets/leenk/domain/user/test/fixture/UserTestFixture.kt +++ b/src/test/java/leets/leenk/domain/user/test/fixture/UserTestFixture.kt @@ -35,4 +35,4 @@ class UserTestFixture { .privacyAgreement(privacyAgreement) .build() } -} \ No newline at end of file +} From f5db8cf97e424b7eebce6abe4a10749b8f2b408b Mon Sep 17 00:00:00 2001 From: soo0711 Date: Mon, 22 Dec 2025 14:49:34 +0900 Subject: [PATCH 34/40] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=9D=98=EC=A1=B4=EC=84=B1,=20=EC=96=B4=EB=85=B8?= =?UTF-8?q?=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 1 - .../domain/leenk/application/usecase/LeenkUsecaseTest.kt | 5 +---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index ae784015..4be46dff 100644 --- a/build.gradle +++ b/build.gradle @@ -50,7 +50,6 @@ dependencies { testImplementation 'org.testcontainers:junit-jupiter' testImplementation 'org.testcontainers:mysql' testImplementation 'org.testcontainers:mongodb' - testImplementation 'org.mockito.kotlin:mockito-kotlin:5.1.0' testImplementation "io.mockk:mockk:1.13.10" testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5' testImplementation 'org.jetbrains.kotlin:kotlin-stdlib' diff --git a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt index 8e3b87f4..483eeb58 100644 --- a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt +++ b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt @@ -21,15 +21,12 @@ import leets.leenk.domain.user.domain.service.user.UserGetService import leets.leenk.domain.user.test.fixture.UserTestFixture import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatThrownBy -import org.junit.jupiter.api.Test import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Nested -import org.junit.jupiter.api.extension.ExtendWith -import org.mockito.junit.jupiter.MockitoExtension +import org.junit.jupiter.api.Test -@ExtendWith(MockitoExtension::class) class LeenkUsecaseTest { private val userGetService: UserGetService = mockk() From 77b54dee74437897acf2fc961c4699330333bb27 Mon Sep 17 00:00:00 2001 From: soo0711 Date: Thu, 8 Jan 2026 22:46:29 +0900 Subject: [PATCH 35/40] =?UTF-8?q?refactor:=20LeenkUsecaseTest=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=EC=9E=90=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EA=B0=80?= =?UTF-8?q?=EB=8F=85=EC=84=B1=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/usecase/LeenkUsecaseTest.kt | 111 ++++++++++++++---- 1 file changed, 89 insertions(+), 22 deletions(-) diff --git a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt index 483eeb58..b0330648 100644 --- a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt +++ b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt @@ -4,19 +4,25 @@ import io.mockk.every import io.mockk.mockk import io.mockk.verify import leets.leenk.domain.leenk.application.exception.* +import leets.leenk.domain.leenk.application.mapper.LeenkMapper import leets.leenk.domain.leenk.application.mapper.LeenkParticipantsMapper +import leets.leenk.domain.leenk.application.mapper.LocationMapper import leets.leenk.domain.leenk.domain.entity.Leenk import leets.leenk.domain.leenk.domain.entity.LeenkParticipants import leets.leenk.domain.leenk.domain.entity.Location import leets.leenk.domain.leenk.domain.entity.enums.LeenkStatus -import leets.leenk.domain.leenk.domain.service.LeenkGetService -import leets.leenk.domain.leenk.domain.service.LeenkParticipantsGetService -import leets.leenk.domain.leenk.domain.service.LeenkParticipantsSaveService +import leets.leenk.domain.leenk.domain.service.* import leets.leenk.domain.leenk.test.fixture.LeenkParticipantsTestFixture import leets.leenk.domain.leenk.test.fixture.LeenkTestFixture import leets.leenk.domain.leenk.test.fixture.LocationTestFixture +import leets.leenk.domain.media.application.mapper.MediaMapper +import leets.leenk.domain.media.domain.service.MediaDeleteService +import leets.leenk.domain.media.domain.service.MediaGetService +import leets.leenk.domain.media.domain.service.MediaSaveService import leets.leenk.domain.notification.application.usecase.LeenkNotificationUsecase import leets.leenk.domain.user.domain.entity.User +import leets.leenk.domain.user.domain.service.NotionDatabaseService +import leets.leenk.domain.user.domain.service.SlackWebhookService import leets.leenk.domain.user.domain.service.user.UserGetService import leets.leenk.domain.user.test.fixture.UserTestFixture import org.assertj.core.api.Assertions.assertThat @@ -29,43 +35,104 @@ import org.junit.jupiter.api.Test class LeenkUsecaseTest { - private val userGetService: UserGetService = mockk() + private val locationSaveService: LocationSaveService = mockk() + private val leenkSaveService: LeenkSaveService = mockk() private val leenkGetService: LeenkGetService = mockk() - private val leenkParticipantsGetService: LeenkParticipantsGetService = mockk() + private val leenkUpdateService: LeenkUpdateService = mockk() + private val leenkDeleteService: LeenkDeleteService = mockk() + private val leenkParticipantsSaveService: LeenkParticipantsSaveService = mockk() + private val leenkParticipantsGetService: LeenkParticipantsGetService = mockk() + private val leenkParticipantsDeleteService: LeenkParticipantsDeleteService = mockk() + + private val mediaSaveService: MediaSaveService = mockk() + private val mediaGetService: MediaGetService = mockk() + private val mediaDeleteService: MediaDeleteService = mockk() + + private val userGetService: UserGetService = mockk() + private val slackWebhookService: SlackWebhookService = mockk() + private val notionDatabaseService: NotionDatabaseService = mockk() + + private val leenkMapper: LeenkMapper = mockk() private val participantsMapper: LeenkParticipantsMapper = mockk() + private val locationMapper: LocationMapper = mockk() + private val mediaMapper: MediaMapper = mockk() + private val leenkNotificationUsecase: LeenkNotificationUsecase = mockk(relaxed = true) private lateinit var leenkUsecase: LeenkUsecase - private lateinit var user: User private lateinit var recruitingLeenk: Leenk private lateinit var participant: LeenkParticipants private lateinit var location: Location - @BeforeEach - fun setUp() { - leenkUsecase = LeenkUsecase( - mockk(), - mockk(), + private fun createLeenkUsecase( + locationSaveService: LocationSaveService, + leenkSaveService: LeenkSaveService, + leenkGetService: LeenkGetService, + leenkUpdateService: LeenkUpdateService, + leenkDeleteService: LeenkDeleteService, + leenkParticipantsSaveService: LeenkParticipantsSaveService, + leenkParticipantsGetService: LeenkParticipantsGetService, + leenkParticipantsDeleteService: LeenkParticipantsDeleteService, + mediaSaveService: MediaSaveService, + mediaGetService: MediaGetService, + mediaDeleteService: MediaDeleteService, + userGetService: UserGetService, + slackWebhookService: SlackWebhookService, + notionDatabaseService: NotionDatabaseService, + leenkMapper: LeenkMapper, + participantsMapper: LeenkParticipantsMapper, + locationMapper: LocationMapper, + mediaMapper: MediaMapper, + leenkNotificationUsecase: LeenkNotificationUsecase + ): LeenkUsecase { + return LeenkUsecase( + locationSaveService, + leenkSaveService, leenkGetService, - mockk(), - mockk(), + leenkUpdateService, + leenkDeleteService, leenkParticipantsSaveService, leenkParticipantsGetService, - mockk(), - mockk(), - mockk(), - mockk(), + leenkParticipantsDeleteService, + mediaSaveService, + mediaGetService, + mediaDeleteService, userGetService, - mockk(), - mockk(), - mockk(), + slackWebhookService, + notionDatabaseService, + leenkMapper, participantsMapper, - mockk(), - mockk(), + locationMapper, + mediaMapper, leenkNotificationUsecase ) + } + + @BeforeEach + fun setUp() { + leenkUsecase = createLeenkUsecase( + locationSaveService = locationSaveService, + leenkSaveService = leenkSaveService, + leenkGetService = leenkGetService, + leenkUpdateService = leenkUpdateService, + leenkDeleteService = leenkDeleteService, + leenkParticipantsSaveService = leenkParticipantsSaveService, + leenkParticipantsGetService = leenkParticipantsGetService, + leenkParticipantsDeleteService = leenkParticipantsDeleteService, + mediaSaveService = mediaSaveService, + mediaGetService = mediaGetService, + mediaDeleteService = mediaDeleteService, + userGetService = userGetService, + slackWebhookService = slackWebhookService, + notionDatabaseService = notionDatabaseService, + leenkMapper = leenkMapper, + participantsMapper = participantsMapper, + locationMapper = locationMapper, + mediaMapper = mediaMapper, + leenkNotificationUsecase = leenkNotificationUsecase + ) user = UserTestFixture.createUser(id = 1L, name = "김철수") location = LocationTestFixture.createLocation(id = 1L, placeName = "테스트 장소") From 15a9cff6396dda9fc841158efaa10188b58dbf53 Mon Sep 17 00:00:00 2001 From: soo0711 Date: Thu, 8 Jan 2026 22:52:19 +0900 Subject: [PATCH 36/40] =?UTF-8?q?refactor:=20LeenkUsecaseTest=20=EC=B5=9C?= =?UTF-8?q?=EB=8C=80=20=EC=B0=B8=EC=97=AC=20=EC=9D=B8=EC=9B=90=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=ED=95=98=EB=93=9C=EC=BD=94=EB=94=A9=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt index b0330648..d0590750 100644 --- a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt +++ b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt @@ -258,7 +258,7 @@ class LeenkUsecaseTest { // then verify(exactly = 1) { leenkParticipantsSaveService.save(lastParticipant) } verify(exactly = 1) { leenkNotificationUsecase.saveNewLeenkParticipantNotification(almostFullLeenk, user) } - assertThat(almostFullLeenk.currentParticipants).isEqualTo(10L) + assertThat(almostFullLeenk.currentParticipants).isEqualTo(almostFullLeenk.maxParticipants) } } From ae4792c7eed4a83c9e9cb469c31afb240f966340 Mon Sep 17 00:00:00 2001 From: soo0711 Date: Thu, 8 Jan 2026 22:57:22 +0900 Subject: [PATCH 37/40] =?UTF-8?q?refactor:=20LeenkUsecaseTest=20=EB=B6=88?= =?UTF-8?q?=ED=95=84=EC=9A=94=ED=95=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/leenk/application/usecase/LeenkUsecaseTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt index d0590750..77cf996f 100644 --- a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt +++ b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt @@ -134,8 +134,8 @@ class LeenkUsecaseTest { leenkNotificationUsecase = leenkNotificationUsecase ) - user = UserTestFixture.createUser(id = 1L, name = "김철수") - location = LocationTestFixture.createLocation(id = 1L, placeName = "테스트 장소") + user = UserTestFixture.createUser(id = 1L) + location = LocationTestFixture.createLocation(id = 1L) recruitingLeenk = LeenkTestFixture.createLeenk( id = 1L, author = user, From aa4c05d5e4f606f51c807b97120fb3a53eb3a251 Mon Sep 17 00:00:00 2001 From: soo0711 Date: Fri, 9 Jan 2026 00:44:52 +0900 Subject: [PATCH 38/40] =?UTF-8?q?test:=20Kotlin=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index 2f0e6ab4..23a7f6f0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -58,6 +58,8 @@ dependencies { testImplementation("org.testcontainers:junit-jupiter") testImplementation("org.testcontainers:mysql") testImplementation("org.testcontainers:mongodb") + testImplementation("io.mockk:mockk:1.14.7") + testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") // Kotest testImplementation("io.kotest:kotest-runner-junit5:5.9.1") From c9c818f6f535c9fe3b4021513131ea3b7d219b20 Mon Sep 17 00:00:00 2001 From: soo0711 Date: Fri, 9 Jan 2026 00:46:13 +0900 Subject: [PATCH 39/40] =?UTF-8?q?test:=20Kotlin=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=9D=BC=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/usecase/LeenkUsecaseTest.kt | 36 ++++++++++--------- .../fixture/LeenkParticipantsTestFixture.kt | 10 ++++-- .../leenk/test/fixture/LeenkTestFixture.kt | 10 ++++-- 3 files changed, 33 insertions(+), 23 deletions(-) diff --git a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt index 77cf996f..99186071 100644 --- a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt +++ b/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt @@ -26,11 +26,7 @@ import leets.leenk.domain.user.domain.service.SlackWebhookService import leets.leenk.domain.user.domain.service.user.UserGetService import leets.leenk.domain.user.test.fixture.UserTestFixture import org.assertj.core.api.Assertions.assertThat -import org.assertj.core.api.Assertions.assertThatThrownBy -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.junit.jupiter.api.* class LeenkUsecaseTest { @@ -187,8 +183,9 @@ class LeenkUsecaseTest { every { leenkGetService.findById(1L) } returns closedLeenk // when & then - assertThatThrownBy { leenkUsecase.participateLeenk(1L, 1L) } - .isInstanceOf(LeenkNotRecruitingException::class.java) + assertThrows { + leenkUsecase.participateLeenk(1L, 1L) + } verify(exactly = 0) { leenkParticipantsSaveService.save(any()) } verify(exactly = 0) { leenkNotificationUsecase.saveNewLeenkParticipantNotification(any(), any()) } @@ -203,8 +200,9 @@ class LeenkUsecaseTest { every { leenkParticipantsGetService.existsByLeenkAndParticipant(recruitingLeenk, user) } returns true // when & then - assertThatThrownBy { leenkUsecase.participateLeenk(1L, 1L) } - .isInstanceOf(AlreadyParticipatedException::class.java) + assertThrows { + leenkUsecase.participateLeenk(1L, 1L) + } verify(exactly = 0) { leenkParticipantsSaveService.save(any()) } verify(exactly = 0) { leenkNotificationUsecase.saveNewLeenkParticipantNotification(any(), any()) } @@ -224,8 +222,9 @@ class LeenkUsecaseTest { every { leenkParticipantsGetService.existsByLeenkAndParticipant(fullLeenk, user) } returns false // when & then - assertThatThrownBy { leenkUsecase.participateLeenk(1L, 1L) } - .isInstanceOf(MaxParticipantsExceededException::class.java) + assertThrows { + leenkUsecase.participateLeenk(1L, 1L) + } verify(exactly = 0) { leenkParticipantsSaveService.save(any()) } verify(exactly = 0) { leenkNotificationUsecase.saveNewLeenkParticipantNotification(any(), any()) } @@ -289,8 +288,9 @@ class LeenkUsecaseTest { every { leenkGetService.findById(1L) } returns recruitingLeenk // when & then - assertThatThrownBy { leenkUsecase.closeLeenk(2L, 1L) } - .isInstanceOf(NotLeenkOwnerException::class.java) + assertThrows { + leenkUsecase.closeLeenk(2L, 1L) + } assertThat(recruitingLeenk.status).isEqualTo(LeenkStatus.RECRUITING) verify(exactly = 0) { leenkNotificationUsecase.saveLeenkClosedNotification(any()) } @@ -309,8 +309,9 @@ class LeenkUsecaseTest { every { leenkGetService.findById(1L) } returns closedLeenk // when & then - assertThatThrownBy { leenkUsecase.closeLeenk(1L, 1L) } - .isInstanceOf(LeenkAlreadyClosedException::class.java) + assertThrows { + leenkUsecase.closeLeenk(1L, 1L) + } verify(exactly = 0) { leenkNotificationUsecase.saveLeenkClosedNotification(any()) } } @@ -328,8 +329,9 @@ class LeenkUsecaseTest { every { leenkGetService.findById(1L) } returns completedLeenk // when & then - assertThatThrownBy { leenkUsecase.closeLeenk(1L, 1L) } - .isInstanceOf(LeenkAlreadyClosedException::class.java) + assertThrows { + leenkUsecase.closeLeenk(1L, 1L) + } verify(exactly = 0) { leenkNotificationUsecase.saveLeenkClosedNotification(any()) } } diff --git a/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkParticipantsTestFixture.kt b/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkParticipantsTestFixture.kt index 0d63587a..e36fc79a 100644 --- a/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkParticipantsTestFixture.kt +++ b/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkParticipantsTestFixture.kt @@ -13,12 +13,16 @@ class LeenkParticipantsTestFixture { participant: User, joinedAt: LocalDateTime = LocalDateTime.now() ): LeenkParticipants { - return LeenkParticipants.builder() - .apply { id?.let { id(it) } } + val builder = LeenkParticipants.builder() .leenk(leenk) .participant(participant) .joinedAt(joinedAt) - .build() + + if (id != null) { + builder.id(id) + } + + return builder.build() } } } diff --git a/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt b/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt index e72b6245..406b3f1f 100644 --- a/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt +++ b/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt @@ -19,8 +19,7 @@ class LeenkTestFixture { currentParticipants: Long = 1L, status: LeenkStatus = LeenkStatus.RECRUITING ): Leenk { - return Leenk.builder() - .apply { id?.let { id(it) } } + val builder = Leenk.builder() .author(author) .location(location) .title(title) @@ -29,7 +28,12 @@ class LeenkTestFixture { .maxParticipants(maxParticipants) .currentParticipants(currentParticipants) .status(status) - .build() + + if (id != null) { + builder.id(id) + } + + return builder.build() } fun createClosedLeenk( From 140c5b3ed9f6bd47ff3fa97ddf546f05f35b27aa Mon Sep 17 00:00:00 2001 From: soo0711 Date: Fri, 9 Jan 2026 00:51:36 +0900 Subject: [PATCH 40/40] =?UTF-8?q?chore:=20Kotlin=20=EC=86=8C=EC=8A=A4=20?= =?UTF-8?q?=EB=94=94=EB=A0=89=ED=84=B0=EB=A6=AC=20=EA=B5=AC=EC=A1=B0=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt | 0 .../domain/leenk/test/fixture/LeenkParticipantsTestFixture.kt | 0 .../leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt | 0 .../leets/leenk/domain/leenk/test/fixture/LocationTestFixture.kt | 0 .../leets/leenk/domain/user/test/fixture/UserTestFixture.kt | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename src/test/{java => kotlin}/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt (100%) rename src/test/{java => kotlin}/leets/leenk/domain/leenk/test/fixture/LeenkParticipantsTestFixture.kt (100%) rename src/test/{java => kotlin}/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt (100%) rename src/test/{java => kotlin}/leets/leenk/domain/leenk/test/fixture/LocationTestFixture.kt (100%) rename src/test/{java => kotlin}/leets/leenk/domain/user/test/fixture/UserTestFixture.kt (100%) diff --git a/src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt b/src/test/kotlin/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt similarity index 100% rename from src/test/java/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt rename to src/test/kotlin/leets/leenk/domain/leenk/application/usecase/LeenkUsecaseTest.kt diff --git a/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkParticipantsTestFixture.kt b/src/test/kotlin/leets/leenk/domain/leenk/test/fixture/LeenkParticipantsTestFixture.kt similarity index 100% rename from src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkParticipantsTestFixture.kt rename to src/test/kotlin/leets/leenk/domain/leenk/test/fixture/LeenkParticipantsTestFixture.kt diff --git a/src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt b/src/test/kotlin/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt similarity index 100% rename from src/test/java/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt rename to src/test/kotlin/leets/leenk/domain/leenk/test/fixture/LeenkTestFixture.kt diff --git a/src/test/java/leets/leenk/domain/leenk/test/fixture/LocationTestFixture.kt b/src/test/kotlin/leets/leenk/domain/leenk/test/fixture/LocationTestFixture.kt similarity index 100% rename from src/test/java/leets/leenk/domain/leenk/test/fixture/LocationTestFixture.kt rename to src/test/kotlin/leets/leenk/domain/leenk/test/fixture/LocationTestFixture.kt diff --git a/src/test/java/leets/leenk/domain/user/test/fixture/UserTestFixture.kt b/src/test/kotlin/leets/leenk/domain/user/test/fixture/UserTestFixture.kt similarity index 100% rename from src/test/java/leets/leenk/domain/user/test/fixture/UserTestFixture.kt rename to src/test/kotlin/leets/leenk/domain/user/test/fixture/UserTestFixture.kt