diff --git a/src/test/java/com/backend/server/config/ControllerTest.java b/src/test/java/com/backend/server/config/ControllerTest.java
index fd003fee..aae0484f 100644
--- a/src/test/java/com/backend/server/config/ControllerTest.java
+++ b/src/test/java/com/backend/server/config/ControllerTest.java
@@ -1,26 +1,27 @@
package com.backend.server.config;
-import jakarta.transaction.Transactional;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
-import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestExecutionListeners;
/**
- * 로그인을 자동으로 해주어, 컨트롤러 레이어의 테스트를 쉽게 할수 있게 해주는 어노테이션입니다.
- * dev 서버용 인증필터를 사용해서, 요청에 JWT 토큰이 없어도 관리자 계정으로 자동으로 인증됩니다.
+ * 실제 요청을 통한 테스트를 쉽게 작성하게 해주는 어노테이션입니다.
+ * 1. 새로운 DB를 생성 / 삭제하여 테스트를 격리합니다.(테스크 클래스 마다)
+ * 2. @Transactional 을 이용하여 테스트 메소드마다 DB 변경사항을 롤백합니다.
+ * 3. 요청에 JWT 토큰이 없어도 관리자 계정으로 자동으로 인증됩니다.
+ * 4. api rate limit 제한을 해제합니다. (분당 5회 호출 제한 등등을 해제)
+ * (인증을 위해 관리자 계정을 DB에 추가합니다.)
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
-@Transactional
-@SpringBootTest
+@DatabaseTest
@AutoConfigureMockMvc
@ActiveProfiles("dev")
@Import({MockMvcConfig.class, FakeRateLimitConfig.class, TestDatabaseConfig.class})
diff --git a/src/test/java/com/backend/server/config/DatabaseTest.java b/src/test/java/com/backend/server/config/DatabaseTest.java
index 89c5e437..6e7f908e 100644
--- a/src/test/java/com/backend/server/config/DatabaseTest.java
+++ b/src/test/java/com/backend/server/config/DatabaseTest.java
@@ -11,8 +11,11 @@
/**
* DB 를 사용하는 테스트는 이 어노테이션을 쓰면 됩니다.
- * 1. 새로운 DB를 생성 / 삭제하여 테스트를 격리합니다.
- * 2. @Transactional 을 통해 DB 변경사항들을 롤백합니다.
+ * 1. 새로운 DB를 생성하여 테스트를 격리합니다.(테스크 클래스 마다)
+ * 2. @Transactional 로 테스트 메소드마다 DB 변경사항을 롤백합니다.
+ * @see
+ * Junit5 로 병렬 테스트를 할 경우 @DirtiesContext 를 사용해선 안됩니다. (공식문서)
+ *
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
diff --git a/src/test/java/com/backend/server/config/TestDatabaseConfig.java b/src/test/java/com/backend/server/config/TestDatabaseConfig.java
index 9c18c633..107cf1f6 100644
--- a/src/test/java/com/backend/server/config/TestDatabaseConfig.java
+++ b/src/test/java/com/backend/server/config/TestDatabaseConfig.java
@@ -1,24 +1,31 @@
package com.backend.server.config;
-import static com.backend.server.support.TestDatabaseUtil.TestDatabaseSettings.URL_TEMPLATE;
+import static com.backend.server.support.TestDatabaseUtil.PASSWORD;
+import static com.backend.server.support.TestDatabaseUtil.URL_TEMPLATE;
+import static com.backend.server.support.TestDatabaseUtil.USER;
import com.backend.server.support.TestDatabaseUtil;
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
+import javax.sql.DataSource;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
-import org.springframework.test.context.DynamicPropertyRegistrar;
+import org.springframework.context.annotation.Primary;
-/**
- * 테스트 격리를 위한 db 를 생성 / 삭제합니다.
- */
@TestConfiguration
public class TestDatabaseConfig {
@Bean
- DynamicPropertyRegistrar apiPropertiesRegistrar() {
- return registry -> {
- registry.add(URL_TEMPLATE.getYmlPath(),
- () -> URL_TEMPLATE.getValue() + TestDatabaseUtil.createTestDatabase());
- registry.add("spring.jpa.hibernate.ddl-auto", () -> "create");
- };
+ @Primary
+ public DataSource dataSource() {
+ HikariConfig config = new HikariConfig();
+ config.setJdbcUrl(URL_TEMPLATE + TestDatabaseUtil.createTestDatabase());
+ config.setUsername(USER);
+ config.setPassword(PASSWORD);
+ config.setDriverClassName("org.postgresql.Driver");
+ config.setMaximumPoolSize(5);
+ config.setPoolName("TestHikariPool");
+
+ return new HikariDataSource(config);
}
}
diff --git a/src/test/java/com/backend/server/support/TestDatabaseUtil.java b/src/test/java/com/backend/server/support/TestDatabaseUtil.java
index 79699e40..23be91b4 100644
--- a/src/test/java/com/backend/server/support/TestDatabaseUtil.java
+++ b/src/test/java/com/backend/server/support/TestDatabaseUtil.java
@@ -1,9 +1,5 @@
package com.backend.server.support;
-import static com.backend.server.support.TestDatabaseUtil.TestDatabaseSettings.PASSWORD;
-import static com.backend.server.support.TestDatabaseUtil.TestDatabaseSettings.URL;
-import static com.backend.server.support.TestDatabaseUtil.TestDatabaseSettings.USER;
-
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
@@ -12,24 +8,15 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
public class TestDatabaseUtil {
- @AllArgsConstructor
- @Getter
- public enum TestDatabaseSettings {
- URL("spring.datasource.url", "jdbc:postgresql://localhost:5432/cec"),
- URL_TEMPLATE("spring.datasource.url", "jdbc:postgresql://localhost:5432/"),
- DRIVER("spring.datasource.driver-class-name", "org.postgresql.Driver"),
- USER("spring.datasource.username", "cec"),
- PASSWORD("spring.datasource.password", "1234"),
- DB_NAME("test.db.name", "dbName");
- final String ymlPath, value;
- }
+ public static final String URL_TEMPLATE = "jdbc:postgresql://localhost:5432/";
+ public static final String USER = "cec";
+ public static final String PASSWORD = "1234";
- public static final String PREFIX = "test_db_";
+ private static final String URL = "jdbc:postgresql://localhost:5432/cec";
+ private static final String PREFIX = "test_db_";
private static final ConcurrentMap dbNames = new ConcurrentHashMap<>();
private static final Random random = new Random();
@@ -42,7 +29,7 @@ public static String createTestDatabase() {
final String dbId = String.valueOf(random.nextLong(0L, Long.MAX_VALUE));
final String dbName = PREFIX + dbId;
- try (Connection conn = DriverManager.getConnection(URL.getValue(), USER.getValue(), PASSWORD.getValue());
+ try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
Statement stmt = conn.createStatement()) {
stmt.executeUpdate("CREATE DATABASE \"" + dbName + "\"");
System.out.println(dbName + " 생성 성공.");
@@ -50,7 +37,7 @@ public static String createTestDatabase() {
throw new RuntimeException("DB 생성 실패: " + dbName, e);
}
- dbNames.put(dbName, "true");
+ dbNames.put(dbId, dbName);
if (!isTriggered.get()) {
isTriggered.set(true);
Runtime.getRuntime().addShutdownHook(new Thread(TestDatabaseUtil::dropAllTestDatabases));
@@ -62,9 +49,9 @@ public static String createTestDatabase() {
* 아직 삭제되지 않은 db 들을 전부 삭제합니다.
*/
public static void dropAllTestDatabases() {
- try (Connection conn = DriverManager.getConnection(URL.getValue(), USER.getValue(), PASSWORD.getValue());
+ try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
Statement stmt = conn.createStatement()) {
- for (String dbName : dbNames.keySet()) {
+ for (String dbName : dbNames.values()) {
try {
stmt.executeUpdate("DROP DATABASE IF EXISTS \"" + dbName + "\" WITH ( FORCE )");
System.out.println(dbName + " 삭제 성공.");
diff --git a/src/test/resources/junit-platform.properties b/src/test/resources/junit-platform.properties
index a69c0f0f..2a882a6c 100644
--- a/src/test/resources/junit-platform.properties
+++ b/src/test/resources/junit-platform.properties
@@ -1,2 +1,8 @@
junit.jupiter.displayname.generator.default = \
- org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores
\ No newline at end of file
+ org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores
+
+# https://docs.junit.org/current/user-guide/#writing-tests-parallel-execution
+# https://docs.spring.io/spring-framework/reference/testing/testcontext-framework/parallel-test-execution.html
+junit.jupiter.execution.parallel.enabled=true
+junit.jupiter.execution.parallel.mode.classes.default = concurrent
+junit.jupiter.execution.parallel.mode.default = same_thread
\ No newline at end of file