Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TestContainers로 테스트 환경 리팩토링 #438

Merged
merged 10 commits into from
Sep 7, 2023
2 changes: 2 additions & 0 deletions server/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ dependencies {

//DB
runtimeOnly 'com.mysql:mysql-connector-j'
testImplementation "org.testcontainers:junit-jupiter:1.19.0"
testImplementation 'org.testcontainers:mysql'

//JWT
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
Expand Down
18 changes: 18 additions & 0 deletions server/src/main/resources/application-test.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
spring.auth.key=testtesttesttesttesttesttesttesttesttesttesttesttesttesttest
spring.auth.accessTokenExpired=360000
spring.auth.refreshTokenExpired=36000000
spring.auth.google.tokenUri=testtesttesttesttesttest
spring.auth.google.authUri=testtesttesttesttesttest
spring.auth.google.clientId=testtesttesttesttesttest
spring.auth.google.clientSecret=testtesttesttesttesttest
spring.auth.google.redirectUri=testtesttesttesttesttest
spring.auth.google.scope=testtesttesttesttesttest
spring.auth.kakao.tokenUri=testtesttesttesttesttest
spring.auth.kakao.authUri=testtesttesttesttesttest
spring.auth.kakao.clientId=testtesttesttesttesttest
spring.auth.kakao.clientSecret=testtesttesttesttesttest
spring.auth.kakao.redirectUri=testtesttesttesttesttest
spring.auth.kakao.scope=testtesttesttesttesttest
s3.bucket=2023-team-project/2023-yozm-cafe/test
spring.servlet.multipart.max-file-size=11MB
spring.servlet.multipart.max-request-size=110MB
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.flyway.enabled=true
Expand Down
36 changes: 19 additions & 17 deletions server/src/main/resources/db/migration/V20230901153300__init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ create table if not exists `yozm-cafe`.member

create table if not exists `yozm-cafe`.liked_cafe
(
id bigint auto_increment primary key,
cafe_id bigint not null,
member_id varchar(30) not null,
id bigint auto_increment primary key,
cafe_id bigint not null,
member_id varchar(30) not null,
created_at datetime(6) not null,
constraint liked_cafe_MEMBER_ID
foreign key (member_id) references member (id),
Expand All @@ -58,28 +58,30 @@ create table if not exists `yozm-cafe`.un_viewed_cafe
foreign key (member_id) references member (id)
);

create table if not exists `yozm-cafe`.menu (
id BIGINT NOT NULL AUTO_INCREMENT,
cafe_id BIGINT NOT NULL,
priority INT NOT NULL,
name VARCHAR(255) NOT NULL,
image_url VARCHAR(512),
description VARCHAR(255),
price VARCHAR(255) NOT NULL,
is_recommended bit NOT NULL,
create table if not exists `yozm-cafe`.menu
(
id BIGINT NOT NULL AUTO_INCREMENT,
cafe_id BIGINT NOT NULL,
priority INT NOT NULL,
name VARCHAR(255) NOT NULL,
image_url VARCHAR(512),
description VARCHAR(255),
price VARCHAR(255) NOT NULL,
is_recommended bit NOT NULL,
PRIMARY KEY (id),
CONSTRAINT menu_cafe_id
foreign key (cafe_id) references cafe (id)
ON DELETE CASCADE
);

create table if not exists `yozm-cafe`.menu_board (
id BIGINT NOT NULL AUTO_INCREMENT,
cafe_id BIGINT NOT NULL,
priority INT NOT NULL,
create table if not exists `yozm-cafe`.menu_board
(
id BIGINT NOT NULL AUTO_INCREMENT,
cafe_id BIGINT NOT NULL,
priority INT NOT NULL,
image_url VARCHAR(512) NOT NULL,
PRIMARY KEY (id),
CONSTRAINT menu_board_cafe_id
foreign key (cafe_id) references cafe (id)
ON DELETE CASCADE
);
);
45 changes: 45 additions & 0 deletions server/src/test/java/com/project/yozmcafe/BaseTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.project.yozmcafe;

import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.MySQLContainer;

/**
* Application Context들이 필요할 때 상속하면 됩니다.
* Repository, Service 레이어 통합 테스트용으로 쓰면 됩니다.
*/
@SpringBootTest
@ActiveProfiles("test")
public abstract class BaseTest {

private static final String ROOT = "root";
private static final String ROOT_PASSWORD = "test";

@Autowired
private DataInitializer dataInitializer;
protected static MySQLContainer container;

static {
container = (MySQLContainer) new MySQLContainer("mysql:8.0")
.withDatabaseName("yozm-cafe")
.withEnv("MYSQL_ROOT_PASSWORD", ROOT_PASSWORD);

container.start();
}

@DynamicPropertySource
static void configureProperties(final DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", container::getJdbcUrl);
registry.add("spring.datasource.username", () -> ROOT);
registry.add("spring.datasource.password", () -> ROOT_PASSWORD);
}

@BeforeEach
void delete() {
dataInitializer.deleteAll();
}
}
72 changes: 72 additions & 0 deletions server/src/test/java/com/project/yozmcafe/DataInitializer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.project.yozmcafe;

import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.Query;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.sql.DataSource;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

@Component
@Profile("test")
public class DataInitializer {

private static final int OFF = 0;
private static final int ON = 1;
private static final int FIRST_COLUMN = 1;
private static final String FLYWAY = "flyway";

@Autowired
private DataSource dataSource;
@PersistenceContext
private EntityManager em;

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

@BeforeEach
@Transactional
public void deleteAll() {
if (deleteDMLs.isEmpty()) {
init();
}

setForeignKeyEnabled(OFF);
truncateAllTables();
setForeignKeyEnabled(ON);
}

private void setForeignKeyEnabled(final int enabled) {
em.createNativeQuery("SET foreign_key_checks = " + enabled).executeUpdate();
}

private void truncateAllTables() {
deleteDMLs.stream()
.map(em::createNativeQuery)
.forEach(Query::executeUpdate);
}

private void init() {
try (final Statement statement = dataSource.getConnection().createStatement()) {
final ResultSet resultSet = statement.executeQuery("SHOW TABLES ");

while (resultSet.next()) {
final String tableName = resultSet.getString(FIRST_COLUMN);
if (tableName.contains(FLYWAY)) {
continue;
}

deleteDMLs.add("TRUNCATE " + tableName);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
package com.project.yozmcafe.controller;

import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;

import com.project.yozmcafe.BaseTest;
import io.restassured.RestAssured;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.specification.RequestSpecification;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.restdocs.RestDocumentationContextProvider;
import org.springframework.restdocs.RestDocumentationExtension;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.Sql.ExecutionPhase;

import io.restassured.RestAssured;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.specification.RequestSpecification;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@Sql(scripts = "classpath:truncate.sql", executionPhase = ExecutionPhase.AFTER_TEST_METHOD)
@ExtendWith(RestDocumentationExtension.class)
public abstract class BaseControllerTest {
public abstract class BaseControllerTest extends BaseTest {

@LocalServerPort
private int port;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.project.yozmcafe.controller;

import com.project.yozmcafe.BaseTest;
import com.project.yozmcafe.util.AcceptanceContext;
import io.restassured.RestAssured;
import org.junit.jupiter.api.BeforeEach;
Expand All @@ -16,7 +17,7 @@
import static org.hamcrest.Matchers.is;

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class LoginArgumentResolverTest {
class LoginArgumentResolverTest extends BaseTest {

@LocalServerPort
private int port;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
package com.project.yozmcafe.domain.cafe;

import com.project.yozmcafe.BaseTest;
import com.project.yozmcafe.domain.member.MemberRepository;
import com.project.yozmcafe.fixture.Fixture;
import org.junit.jupiter.api.AfterEach;
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.jdbc.AutoConfigureTestDatabase.Replace;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.data.domain.PageRequest;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.SoftAssertions.assertSoftly;

@DataJpaTest
@AutoConfigureTestDatabase(replace = Replace.NONE)
class CafeRepositoryTest {
class CafeRepositoryTest extends BaseTest {

@Autowired
private CafeRepository cafeRepository;
Expand Down Expand Up @@ -56,7 +53,9 @@ void findSliceBy() {
final List<Cafe> cafes = cafeRepository.findSliceBy(pageRequest).getContent();

//then
assertThat(cafes).hasSize(5);
assertThat(cafes).containsExactlyInAnyOrder(cafe1, cafe2, cafe3, cafe4, cafe5);
assertSoftly(softAssertions -> {
assertThat(cafes).hasSize(5);
assertThat(cafes).containsExactlyInAnyOrder(cafe1, cafe2, cafe3, cafe4, cafe5);
});
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
package com.project.yozmcafe.domain.member;

import com.project.yozmcafe.BaseTest;
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 java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;

@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@DataJpaTest
class MemberRepositoryTest {
class MemberRepositoryTest extends BaseTest {

@Autowired
private MemberRepository memberRepository;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.project.yozmcafe.service;

import com.project.yozmcafe.BaseTest;
import com.project.yozmcafe.controller.dto.cafe.AvailableTimeRequest;
import com.project.yozmcafe.controller.dto.cafe.CafeRequest;
import com.project.yozmcafe.controller.dto.cafe.CafeResponse;
Expand All @@ -15,9 +16,6 @@
import org.junit.jupiter.api.Nested;
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.context.SpringBootTest;
import org.springframework.test.context.jdbc.Sql;

import java.time.LocalTime;
import java.util.List;
Expand All @@ -26,10 +24,7 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

@SpringBootTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Sql(scripts = "classpath:truncate.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
class CafeAdminServiceTest {
class CafeAdminServiceTest extends BaseTest {

@Autowired
private CafeAdminService cafeAdminService;
Expand Down
Loading