본문 바로가기
카테고리 없음

📝 C# MSTest에서 발생하는 테스트 문제 및 해결 전략 | TDD 문제 해결 가이드

by bbongz 2025. 3. 24.

 

이전 글에서는 Moq의존성 주입(DI) 을 활용해 테스트의 유연성을 강화하는 방법을 배웠습니다.
하지만 실전에서 TDD를 적용하다 보면 다양한 문제가 발생합니다.
이번 글에서는 테스트 실패 원인 분석해결 전략을 구체적인 예제와 함께 설명하겠습니다. 😎

이번 글에서는 다음 내용을 중점적으로 다룹니다:
✔️ 테스트 실패 원인 및 해결책
✔️ 비결정적(Flaky) 테스트 문제 해결
✔️ 성능 저하 문제 해결
✔️ 코드 리팩토링 전략


1. 테스트 실패 원인 및 해결책

테스트가 실패하는 원인은 대부분 다음과 같은 경우에 해당합니다:

🔴 1) 코드 오류

  • 논리 오류 → 로직이 잘못 구현된 경우
  • 잘못된 입력 값 처리 → 예외 처리 누락

해결책:

👉 디버거를 사용해 코드 동작 확인
👉 예외 처리 로직 강화


🔴 2) 테스트 코드 오류

  • 테스트 메서드에서 잘못된 값 설정
  • Assert 구문 오류

해결책:

👉 테스트 코드의 Arrange → Act → Assert 순서 점검
👉 Assert에서 기대 값과 실제 값이 정확한지 확인


🔴 3) 외부 의존성 문제

  • DB, API 등 외부 시스템이 다운된 경우
  • 파일 접근 문제 발생

해결책:

👉 Moq 등을 사용해 외부 의존성 제거
👉 네트워크 의존성 최소화


🔴 4) 시간 및 상태 의존성 문제

  • 특정 시간대에서만 테스트가 실패하는 경우
  • 상태 변화에 따라 테스트 결과가 달라지는 경우

해결책:

👉 고정된 값(Mock) 사용
👉 상태 의존성을 없애기 위해 독립적인 상태 유지


🚀 2. 비결정적(Flaky) 테스트 문제 해결

비결정적 테스트는 같은 코드에서도 매번 다른 결과가 나오는 경우입니다.
원인은 비동기 코드, 시간 의존성, 상태 의존성 등에서 발생할 수 있습니다.


문제 상황: 비동기 코드에서 테스트 실패

[TestMethod]
public async Task GetDataAsync_ShouldReturnCorrectData()
{
    // Arrange
    var service = new DataService();

    // Act
    var result = await service.GetDataAsync();

    // Assert
    Assert.AreEqual("ExpectedData", result);
}

👉 테스트가 간헐적으로 실패하는 경우 발생


해결책: 비동기 코드에서 Task.Delay 제거

  • 비동기 테스트에서 Task.Delay 사용 시 실패 가능성 증가
  • Task.Delay 대신 Mock 객체로 비동기 처리 시뮬레이션

수정된 코드 (Moq 적용)

[TestMethod]
public async Task GetDataAsync_ShouldReturnCorrectData()
{
    // Arrange
    var mockService = new Mock<IDataService>();
    mockService.Setup(x => x.GetDataAsync())
               .ReturnsAsync("ExpectedData");

    // Act
    var result = await mockService.Object.GetDataAsync();

    // Assert
    Assert.AreEqual("ExpectedData", result);
}

👉 비동기 테스트 문제 해결


🚀 3. 성능 저하 문제 해결

테스트 코드가 많아지면 테스트 실행 시간이 급격히 증가할 수 있습니다.

🔴 성능 저하 원인

  • 과도한 반복 테스트
  • DB 및 API 호출이 많음
  • 파일 접근 시 발생하는 I/O 병목

해결책 1: 불필요한 반복 제거

테스트마다 동일한 상태 설정을 반복하면 성능이 저하됩니다.
👉 TestInitialize로 상태 설정 코드 통합

[TestClass]
public class CalculatorTests
{
    private Calculator _calculator;

    [TestInitialize]
    public void Setup()
    {
        _calculator = new Calculator();
    }

    [TestMethod]
    public void Add_ShouldReturnSumOfTwoNumbers()
    {
        int result = _calculator.Add(2, 3);
        Assert.AreEqual(5, result);
    }
}

해결책 2: DB 호출 제거 및 Mock 사용

테스트에서 DB나 API 호출이 필요하면 Mock 객체로 대체합니다.

[TestMethod]
public void GetData_ShouldReturnCorrectValue()
{
    var mockService = new Mock<IDataService>();
    mockService.Setup(x => x.GetData())
               .Returns("TestData");

    var result = mockService.Object.GetData();

    Assert.AreEqual("TestData", result);
}

👉 테스트 실행 시간 단축


🚀 4. 코드 리팩토링 전략

테스트 코드의 품질을 높이려면 주기적으로 리팩토링이 필요합니다.

전략 1: 중복 코드 제거

테스트 코드에서 공통된 부분을 TestInitialize로 통합합니다.

전략 2: 테스트 케이스 명확화

테스트 이름에서 명확한 동작을 정의합니다.
👉 MethodName_ExpectedBehavior_InputCondition 형식 사용

예시:
✅ Add_ShouldReturnSum_WhenTwoPositiveNumbers
✅ Divide_ShouldThrowException_WhenDividingByZero


전략 3: 매직 넘버 제거

테스트 코드에서 의미 없는 숫자는 상수로 치환합니다.

const int ExpectedResult = 5;

[TestMethod]
public void Add_ShouldReturnSum_WhenTwoPositiveNumbers()
{
    int result = _calculator.Add(2, 3);
    Assert.AreEqual(ExpectedResult, result);
}

👉 테스트 코드 가독성 및 유지보수성 강화


🚀 5. 실제 발생 가능한 문제 및 해결 전략 요약

문제 유형 원인 해결책
코드 오류 로직 오류, 예외 처리 누락 디버그, 예외 처리 강화
테스트 코드 오류 잘못된 입력 값, Assert 오류 Arrange-Act-Assert 점검
외부 의존성 문제 API, DB 연결 문제 Moq, DI로 의존성 제거
시간/상태 문제 특정 시간대, 상태 의존성 문제 Mock 객체로 상태 시뮬레이션
성능 저하 반복 코드, 외부 호출 TestInitialize, Mock 사용

🎯 마무리 및 다음 단계

지금까지 다음 내용을 완성했습니다:
✔️ TDD에서 발생할 수 있는 문제와 원인 분석
✔️ 성능 저하 및 Flaky 테스트 해결 전략
✔️ 리팩토링을 통한 테스트 코드 최적화

다음 글에서는 TDD 적용 사례최종 리뷰를 진행하겠습니다.

 

👉 다음 글: C# MSTest에서 TDD 적용 사례 및 결론 (6편)