개발 일지가 꽤나 밀려버렸습니다.
일단 오늘 일지부터 작성하고 천천히 밀린 걸 써보겠습니다.
오늘은 드디어 Github Actions의 CI 과정에 테스트를 도입했습니다.
사실 지금까지는 gradle의 -x test 옵션으로 테스트 없이 빌드만 진행했었습니다.
검색과 추천 성능평가 및 데이터 셋업 테스트 때문에 바로 옵션을 빼서 테스트를 진행하기가 애매했기에
조금 시간이 걸렸네요.
1. Github Actions CI 워크플로우 개선
- name: Build with Gradle
run: ./gradlew build -x test --no-daemon
기존의 다음과 같은 코드에서
- name: Build with all tests
run: ./gradlew build --no-daemon
위와 같은 코드로 변경하였습니다.
초기에는 PR 생성 시에는 통합 테스트를 진행하지 않을까 했지만
통합 테스트를 포함하여도 현재 3분만에 CI 과정이 끝나므로 포함하였습니다.
@Tag("evaluation")
@Slf4j
public class LambdaOptimizationTest extends RecommendationTestBase {
@Tag("evaluation-setup")
@Disabled("데이터 셋업용 - CI 제외")
@Slf4j
public class RecommendationTestDataSetup extends RecommendationTestBase {
문제가 되었던 평가 테스트와 데이터 셋업은 JUnit의 태그 기능을 활용하여 테스트를 분리했습니다.
tasks.named('test') {
useJUnitPlatform() useJUnitPlatform {
if (project.hasProperty('excludeIntegration')) {
excludeTags 'integration'
}
excludeTags 'evaluation-setup', 'evaluation'
}
testLogging {
events "passed", "skipped", "failed"
exceptionFormat "full"
showStandardStreams = false
}
} }
tasks.register('integrationTest', Test) {
useJUnitPlatform {
includeTags 'integration'
excludeTags 'evaluation-setup', 'evaluation'
}
testLogging {
events "passed", "skipped", "failed"
exceptionFormat "full"
showStandardStreams = false
}
shouldRunAfter tasks.named('test')
}
tasks.register('evaluationTest', Test) {
useJUnitPlatform {
includeTags 'evaluation'
excludeTags 'evaluation-setup', 'integration'
}
testLogging {
events "passed", "skipped", "failed"
exceptionFormat "full"
}
}
위와 같이 build.gradle을 구성하여
전체 테스트(통합테스트 제외 옵션 O, 단위 + 통합),
통합 테스트(단위 + 통합)
평가 테스트
를 각각 진행할 수 있도록 task를 구성했습니다.
@Tag("integration")
@SpringBootTest
@AutoConfigureMockMvc
@Import(IntegrationTestConfig.class)
@ActiveProfiles("integrationtest")
public abstract class IntegrationTestBase {
}
통합 테스트 클래스들은 다음 추상 클래스를 상속하도록 하여 코드 중복을 제거하였고,
환경 설정또한 통일하였습니다.
2. 테스트 컨테이너에 싱글턴 패턴 적용
기존에는 통합 테스트마다 테스트 컨테이너가 생성되었다가 삭제되며,
이로 인한 자원 소모 및 시간 소모가 심했습니다.
각각의 통합테스트를 실행하는 경우보다 전체 통합 테스트를 한 번에 실행하는 경우가 많으므로
통합 테스트 환경을 통일하고,
이 컨테이너들을 싱글턴 패턴을 적용해 같은 JVM 내에서 재사용할 수 있도록 적용하였습니다.
package com.techfork.global.configuration;
import com.redis.testcontainers.RedisContainer;
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;
import org.testcontainers.elasticsearch.ElasticsearchContainer;
import org.testcontainers.utility.DockerImageName;
@TestConfiguration(proxyBeanMethods = false)
public class IntegrationTestConfig {
private static final ElasticsearchContainer elasticsearch =
new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:8.18.0")
.withEnv("xpack.security.enabled", "false")
.withEnv("discovery.type", "single-node")
.withEnv("ES_JAVA_OPTS", "-Xms256m -Xmx256m");
private static final MySQLContainer<?> mysql =
new MySQLContainer<>("mysql:8.0.36");
private static final RedisContainer redis =
new RedisContainer(DockerImageName.parse("redis:7.2-alpine"));
static {
elasticsearch.start();
mysql.start();
redis.start();
}
@Bean
@ServiceConnection
ElasticsearchContainer elasticsearchContainer() {
return elasticsearch;
}
@Bean
@ServiceConnection
MySQLContainer<?> mySQLContainer() {
return mysql;
}
@Bean
@ServiceConnection
RedisContainer redisContainer() {
return redis;
}
}
이를 통해 실행 시간(175초 -> 60초)과 메모리 사용(3GB -> 1GB) 부분에서
약 60%정도의 감소를 이뤄냈습니다.
앞으로 테스트 커버리지를 늘려서 더더욱 안정성있는 어플리케이션을 보장하도록 노력하겠습니다.
'프로젝트 > Techfork' 카테고리의 다른 글
| [26/01/22] 오늘의 개발 일지 - 개발자 토큰 API 구현 및 Spring Security Testing 삽질 (2) | 2026.01.23 |
|---|---|
| [26/01/23] 오늘의 개발 일지 - baseUrl 문제 해결 및 쿠키 도메인 에러 해결 (0) | 2026.01.23 |
| [26/01/14] 오늘의 개발 일지 - 카카오 소셜 로그인 구현 (2) | 2026.01.15 |
| [26/01/10] 오늘의 개발일지 - 온보딩 API 수정, 테스트 코드 작성, 엔티티 생성 성능 최적화 (0) | 2026.01.11 |
| [26/01/07] 오늘의 개발 일지 - Resilience4j 설정 개선 및 JdbcTemplate를 활용한 배치 처리 (0) | 2026.01.08 |