Skip to content

Commit

Permalink
[DEV-32] 로컬 db mysql 변환 및 TestContainer 설정 (#75)
Browse files Browse the repository at this point in the history
  • Loading branch information
KoSeonJe authored Aug 15, 2024
1 parent c9f3752 commit 9c225ef
Show file tree
Hide file tree
Showing 19 changed files with 259 additions and 85 deletions.
38 changes: 24 additions & 14 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,32 +26,42 @@ repositories {
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
//develop
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-validation'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
implementation 'org.springdoc:springdoc-openapi-ui:1.6.11'
implementation 'org.springframework.boot:spring-boot-configuration-processor'

implementation 'io.hypersistence:hypersistence-utils-hibernate-55:3.7.2'

implementation 'com.auth0:java-jwt:4.2.1'

implementation 'io.awspring.cloud:spring-cloud-starter-aws:2.4.4'
//db
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'com.mysql:mysql-connector-j'
runtimeOnly 'com.h2database:h2'

//etc(기타)
implementation 'io.awspring.cloud:spring-cloud-starter-aws:2.4.4'
implementation 'org.apache.poi:poi:5.2.0'
implementation 'org.apache.poi:poi-ooxml:5.2.0'
implementation 'org.springframework.boot:spring-boot-configuration-processor'

implementation 'io.hypersistence:hypersistence-utils-hibernate-55:3.7.2'
implementation 'io.sentry:sentry-logback:7.6.0'
implementation 'org.springdoc:springdoc-openapi-ui:1.6.11'

implementation 'com.fasterxml.jackson.core:jackson-core:2.17.0'

compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
annotationProcessor 'org.projectlombok:lombok'

//security
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'com.auth0:java-jwt:4.2.1'

//test
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
// TestContainer
testImplementation 'org.testcontainers:testcontainers:1.20.0'
testImplementation 'org.testcontainers:junit-jupiter:1.20.0'
// mysql 컨테이너
testImplementation 'org.testcontainers:mysql:1.20.0'
}

tasks.named('test') {
Expand Down
17 changes: 17 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
services:
ddingdong-local-db:
image: mysql:8.0
container_name: ddingdong_local_mysql
platform: linux/x86_64
environment: # 환경 변수 설정
MYSQL_ROOT_PASSWORD: 1234
MYSQL_DATABASE: ddingdong_local_db
MYSQL_CHARSET: utf8mb4
MYSQL_COLLATION: utf8mb4_unicode_ci
TZ: Asia/Seoul
ports:
- "3307:3306"
volumes:
- backup-store:/var/lib/mysql
volumes:
backup-store :
15 changes: 6 additions & 9 deletions src/main/resources/application-local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,21 @@ spring:
on-profile: local

datasource:
url: jdbc:h2:tcp://localhost/~/projects/ddingdong/ddingdong
driver-class-name: org.h2.Driver
username: sa
password:
url: jdbc:mysql://localhost:3307/ddingdong_local_db
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 1234

jpa:
hibernate:
ddl-auto: create
show-sql: true
properties:
hibernate:
format_sql: true
dialect: org.hibernate.dialect.MySQL8InnoDBDialect
show-sql: true
defer-datasource-initialization: true

sql:
init:
mode: always

h2:
console:
enabled: true
9 changes: 2 additions & 7 deletions src/main/resources/application-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,15 @@ spring:
activate:
on-profile: test

datasource:
url: jdbc:h2:mem:ddingdongdb;
driver-class-name: org.h2.Driver
username: sa
password:

jpa:
hibernate:
ddl-auto: create
show-sql: true
properties:
hibernate:
show-sql: true
format_sql: true
auto_quote_keyword: true
dialect: org.hibernate.dialect.MySQL8InnoDBDialect

sql:
init:
Expand Down
10 changes: 10 additions & 0 deletions src/test/java/ddingdong/ddingdongBE/common/config/TestConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package ddingdong.ddingdongBE.common.config;

import ddingdong.ddingdongBE.common.support.DataInitializer;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Import;

@TestConfiguration
@Import(DataInitializer.class)
public class TestConfig {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package ddingdong.ddingdongBE.common.support;

import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Profile("test")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Component
public class DataInitializer {

private static final String OFF_FOREIGN_CONSTRAINTS = "SET foreign_key_checks = false";
private static final String ON_FOREIGN_CONSTRAINTS = "SET foreign_key_checks = true";
private static final String TRUNCATE_SQL_FORMAT = "TRUNCATE %s";

private static final List<String> truncationDMLs = new ArrayList<>();

@PersistenceContext
private EntityManager em;

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void deleteAll() {
if (truncationDMLs.isEmpty()) {
init();
}

em.createNativeQuery(OFF_FOREIGN_CONSTRAINTS).executeUpdate();
truncationDMLs.stream()
.map(em::createNativeQuery)
.forEach(Query::executeUpdate);
em.createNativeQuery(ON_FOREIGN_CONSTRAINTS).executeUpdate();
}

private void init() {
final List<String> tableNames = em.createNativeQuery("SHOW TABLES ").getResultList();

tableNames.stream()
.map(tableName -> String.format(TRUNCATE_SQL_FORMAT, tableName))
.forEach(truncationDMLs::add);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package ddingdong.ddingdongBE.common.support;

import ddingdong.ddingdongBE.common.config.TestConfig;
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.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;

@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public abstract class DataJpaTestSupport extends TestContainerSupport {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package ddingdong.ddingdongBE.common.support;


import static lombok.AccessLevel.PROTECTED;

import ddingdong.ddingdongBE.common.config.TestConfig;
import lombok.NoArgsConstructor;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.JdbcDatabaseContainer;
import org.testcontainers.containers.MySQLContainer;

@NoArgsConstructor(access = PROTECTED)
@ActiveProfiles("test")
@Import(TestConfig.class)
public abstract class TestContainerSupport {

private static final String MYSQL_IMAGE = "mysql:8";
private static final int MYSQL_PORT = 3306;
private static final JdbcDatabaseContainer<?> MYSQL;

@Autowired
private DataInitializer dataInitializer;

// 싱글톤
static {
MYSQL = new MySQLContainer<>(MYSQL_IMAGE)
.withExposedPorts(MYSQL_PORT)
.withReuse(true);

MYSQL.start();
}

// 동적으로 DB 속성 할당
@DynamicPropertySource
public static void setUp(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.driver-class-name", MYSQL::getDriverClassName);
registry.add("spring.datasource.url", MYSQL::getJdbcUrl);
registry.add("spring.datasource.username", MYSQL::getUsername);
registry.add("spring.datasource.password", MYSQL::getPassword);
}

@BeforeEach
void delete() {
dataInitializer.deleteAll();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package ddingdong.ddingdongBE.common.support;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;

@SpringBootTest
@AutoConfigureMockMvc
public abstract class WebApiIntegrationTestSupport extends TestContainerSupport {

@Autowired
protected MockMvc mockMvc;

@Autowired
protected ObjectMapper objectMapper;

protected String toJson(Object object) throws JsonProcessingException {
return objectMapper.writeValueAsString(object);
}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package ddingdong.ddingdongBE.support;
package ddingdong.ddingdongBE.common.support;

import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import ddingdong.ddingdongBE.domain.club.service.ClubService;
import ddingdong.ddingdongBE.domain.documents.controller.AdminDocumentController;
import ddingdong.ddingdongBE.domain.documents.controller.DocumentController;
Expand All @@ -25,37 +27,44 @@

@ActiveProfiles("test")
@WebMvcTest(controllers = {
AdminDocumentController.class,
DocumentController.class,
AdminQuestionController.class,
QuestionController.class,
AdminScoreHistoryController.class,
ClubScoreHistoryController.class
AdminDocumentController.class,
DocumentController.class,
AdminQuestionController.class,
QuestionController.class,
AdminScoreHistoryController.class,
ClubScoreHistoryController.class
})
public abstract class WebApiTestSupport {

@Autowired
private WebApplicationContext context;
@Autowired
protected MockMvc mockMvc;
@MockBean
protected DocumentService documentService;
@MockBean
protected FileService fileService;
@MockBean
protected FileInformationService fileInformationService;
@MockBean
protected QuestionService questionService;
@MockBean
protected ClubService clubService;
@MockBean
protected ScoreHistoryService scoreHistoryService;

@BeforeEach
void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
public abstract class WebApiUnitTestSupport {

@Autowired
private WebApplicationContext context;
@Autowired
protected MockMvc mockMvc;
@MockBean
protected DocumentService documentService;
@MockBean
protected FileService fileService;
@MockBean
protected FileInformationService fileInformationService;
@MockBean
protected QuestionService questionService;
@MockBean
protected ClubService clubService;
@MockBean
protected ScoreHistoryService scoreHistoryService;

@Autowired
protected ObjectMapper objectMapper;

protected String toJson(Object object) throws JsonProcessingException {
return objectMapper.writeValueAsString(object);
}

@BeforeEach
void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(context)
.apply(springSecurity())
.build();
}

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package ddingdong.ddingdongBE.support;
package ddingdong.ddingdongBE.common.support;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package ddingdong.ddingdongBE.support;
package ddingdong.ddingdongBE.common.support;

import ddingdong.ddingdongBE.auth.PrincipalDetails;
import ddingdong.ddingdongBE.domain.user.entity.Role;
Expand Down
Loading

0 comments on commit 9c225ef

Please sign in to comment.