테스트 격리란 무엇인가?

김명수·2026년 1월 15일

매일메일

목록 보기
87/127
post-thumbnail

테스트 격리란 무엇인가?

●테스트 격리란 무엇인가?

  • 테스트 격리(Test Isolation) 는 각 테스트가 서로 독립적으로 실행되도록 보장하는 것을 말하며, 어떤 테스트가 실행되더라도 다른 테스트의 결과나 상태에 영향을 주거나 받지 않아야 한다는 의미

  • 테스트 격리가 중요한 이유는 격리가 제대로 이루어지지 않으면 비결정적 테스트가 발생할 수 있기 때문이며 비결정적(Non-deterministic) 테스트는 같은 테스트를 여러 번 실행했을 때 항상 같은 결과를 내지 않는 테스트를 말하며 예를 들어, 테스트가 데이터베이스와 같은 공유 자원에 의존할 경우 실행 순서나 다른 테스트의 실행 여부에 따라 성공 또는 실패 결과가 달라질 수 있으며 비결정적 테스트는 실패했을 때 실제 코드의 문제인지, 비결정적 요인 때문인지 판단하기 어려워지며 따라서 테스트가 항상 동일한 조건에서 예측 가능한 결과를 낼 수 있도록 격리하는 것이 중요

●Spring에서 같은 데이터베이스를 사용하는 테스트는 어떻게 격리할 수 있을까?

@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
@SpringBootTest
class MyIntegrationTest {
    // ...
}
  • Spring의 테스트 컨텍스트는 애플리케이션 컨텍스트를 캐싱해서 각각의 테스트에서 재사용하며 @DirtiesContext 어노테이션을 사용하면 테스트마다 새로운 애플리케이션 컨텍스트를 로드하여 완전한 격리를 보장할 수 있지만 애플리케이션 컨텍스트를 매번 새로 로드하는 것은 비용이 크고 시간이 오래 걸리는 작업이기 때문에 성능이 저하된다는 단점이 있음
@Sql("/truncate.sql")
@SpringBootTest
class MyIntegrationTest {
    // ...
}
  • @Sql 어노테이션을 사용하면 테스트 실행 전 또는 후에 특정 SQL 스크립트를 실행할 수 있으며 이때 TRUNCATE DDL을 사용하여 테이블 자체를 비움으로써 테스트 간 독립된 테이블을 사용할 수 있습니다. 하지만 테이블이 추가될 때마다 SQL 스크립트를 수정해야 하기 때문에 유지보수 비용이 발생한다는 단점이 있음
@Transactional
@SpringBootTest
class MyIntegrationTest {
    // ...
}
  • @Transactional 어노테이션을 사용하면 테스트가 실행된 후 트랜잭션을 롤백하여 데이터베이스 상태를 원래대로 유지할 수 있으며 이 방법을 사용할 때는 몇 가지 주의할 점이 있음

1.의도치 않은 트랜잭션 적용으로 프로덕션 환경과 다른 조건에서 테스트될 수 있으며 예를 들면, OSIV를 꺼두고 @Transactional도 없는 상태에서 지연로딩된 엔티티를 조회하면 LazyInitializationException이 발생하지만, 테스트에서는 트랜잭션이 열려 있어서 예외가 발생하지 않지만 실제로는 실패할 코드가 테스트에서는 성공하는 거짓 음성이 나타날 수 있음

거짓 양성(False Positive): 프로덕션 코드는 정상 동작하지만 테스트는 실패

거짓 음성(False Negative): 프로덕션 코드는 실패하지만 테스트는 통과

2.@SpringBootTest의 WebEnvironment가 DEFINE_PORT 또는 RANDOM_PORT일 경우, 별도의 스레드에서 서블릿 컨테이너가 실행되기 때문에 테스트의 트랜잭션 롤백이 적용되지 않음
3.프로덕션 코드의 트랜잭션 전파 레벨을 REQUIRES_NEW로 설정했을 경우 새로운 트랜잭션을 생성하기 때문에 테스트 트랜잭션과 무관하여 롤백되지 않음
4.비동기 메서드는 새로운 스레드에서 실행되기 때문에 롤백되지 않음

profile
신입개발자

0개의 댓글