IMCAT.DEV
로그인 가입
C# 고급 테스트

C# 테스트 주도 개발(TDD)

C# 테스트 주도 개발(TDD) — 고급

테스트 주도 개발(TDD)

1. 도입 (왜 배워야 하는가)

테스트 주도 개발(TDD)은 소프트웨어 개발에서 코드의 품질을 보장하고 유지보수를 용이하게 만드는 매우 중요한 개발 방법론입니다. TDD를 통해 개발자는 요구사항을 명확히 이해하고, 이를 바탕으로 테스트 케이스를 작성한 후, 실제 코드를 구현합니다. 이렇게 하면 코드가 의도한 대로 작동하는지 즉시 확인할 수 있으며, 버그를 조기에 발견할 수 있습니다.

만약 TDD를 모른다면, 다음과 같은 문제에 직면할 수 있습니다:

  • 버그 발견 지연: 코드 작성 후 테스트를 나중에 수행하게 되어 버그를 늦게 발견하게 됩니다.
  • 불확실한 코드 품질: 코드가 제대로 작동하는지 확신할 수 없으므로, 배포 후 문제가 발생할 위험이 커집니다.
  • 유지보수의 어려움: 기존 코드에 대한 테스트가 없으면, 기능 변경 시 다른 부분에 영향을 미칠 수 있습니다.
  • 2. 핵심 개념 설명

    TDD는 기본적으로 "테스트를 먼저 작성하고, 그 테스트를 통과하는 코드를 작성하라"는 원칙에 기반합니다. 이 방법론은 다음의 세 가지 단계로 구성됩니다.

    1. Red: 실패하는 테스트를 작성합니다. (예: 원하는 기능이 구현되지 않아 테스트가 실패하는 상태)
    2. Green: 테스트를 통과하는 최소한의 코드를 작성합니다. (예: 기능이 구현되어 테스트가 성공하는 상태)
    3. Refactor: 코드를 개선합니다. (예: 코드의 가독성을 높이고, 중복을 제거하여 유지보수를 쉽게 합니다)
    4. 관련 용어 정리

      용어설명
      단위 테스트개별 구성 요소의 기능을 검증하는 테스트
      리팩토링코드의 구조를 변경하여 가독성을 높이는 과정
      테스트 커버리지테스트가 코드의 얼마나 많은 부분을 검증하는지를 나타내는 지표

      3. 기본 코드 예제

      다음은 TDD의 기본 원칙을 보여주는 간단한 예제입니다. 두 수의 합을 계산하는 기능을 구현합니다.

      using NUnit.Framework;
      
      [TestFixture]
      public class MathTests
      {
          [Test]
          public void Add_TwoPositiveNumbers_ReturnsSum()
          {
              // Arrange
              var math = new Math();
              int a = 5;
              int b = 7;
      
              // Act
              var result = math.Add(a, b);
      
              // Assert
              Assert.AreEqual(12, result);
          }
      }
      
      public class Math
      {
          public int Add(int a, int b)
          {
              return a + b; // 5 + 7 = 12
          }
      }

      실행 결과: 테스트가 성공적으로 통과합니다.

    5. 코드 한 줄씩 동작 설명:
    6. 1. MathTests 클래스는 NUnit 테스트 프레임워크의 테스트 케이스를 정의합니다. 2. Add_TwoPositiveNumbers_ReturnsSum 메서드는 두 개의 양수를 더하는 테스트를 정의합니다. 3. Arrange 단계에서 Math 객체와 두 개의 정수 a, b를 초기화합니다. 4. Act 단계에서 Add 메서드를 호출하여 결과를 얻습니다. 5. Assert 단계에서 예상한 결과(12)와 실제 결과를 비교하여 테스트를 검증합니다.

      4. 실전 활용 예제

      예제 1: 쇼핑몰 장바구니 기능

      쇼핑몰에서 장바구니에 상품을 추가하는 기능을 TDD로 구현할 수 있습니다.

      using NUnit.Framework;
      using System.Collections.Generic;
      
      [TestFixture]
      public class ShoppingCartTests
      {
          [Test]
          public void Add_Item_IncreasesItemCount()
          {
              // Arrange
              var cart = new ShoppingCart();
              var item = new Item("Apple", 1.0);
      
              // Act
              cart.Add(item);
      
              // Assert
              Assert.AreEqual(1, cart.ItemCount);
          }
      }
      
      public class ShoppingCart
      {
          private List<Item> items = new List<Item>();
          public int ItemCount => items.Count;
      
          public void Add(Item item)
          {
              items.Add(item); // 장바구니에 아이템 추가
          }
      }
      
      public class Item
      {
          public string Name { get; }
          public double Price { get; }
      
          public Item(string name, double price)
          {
              Name = name;
              Price = price;
          }
      }

      예제 2: 사용자 등록 기능

      사용자가 등록할 때 이메일 형식이 유효한지 확인하는 기능을 TDD로 구현할 수 있습니다.

      using NUnit.Framework;
      using System.Text.RegularExpressions;
      
      [TestFixture]
      public class UserRegistrationTests
      {
          [Test]
          public void Register_InvalidEmail_ThrowsException()
          {
              // Arrange
              var user = new User();
      
              // Act & Assert
              Assert.Throws<FormatException>(() => user.Register("invalid-email"));
          }
      }
      
      public class User
      {
          public void Register(string email)
          {
              if (!IsValidEmail(email))
              {
                  throw new FormatException("Invalid email format"); // 이메일 형식 확인
              }
          }
      
          private bool IsValidEmail(string email)
          {
              return Regex.IsMatch(email, @"^[^@\s]+@[^@\s]+\.[^@\s]+$"); // 정규 표현식으로 이메일 검증
          }
      }

      5. 흔한 실수와 주의사항

    7. 실수: 테스트를 작성하지 않고 코드를 먼저 작성하기
    8. - 잘못된 코드: 코드를 작성하고 나서 테스트를 하는 경우. - 올바른 코드: 먼저 테스트를 작성하고 그 테스트를 통과하는 코드를 작성해야 함.

    9. 실수: 테스트의 독립성을 유지하지 않음
    10. - 잘못된 코드: 한 테스트가 다른 테스트의 결과에 의존하는 경우. - 올바른 코드: 각 테스트는 독립적으로 실행될 수 있도록 설계해야 함.

    11. 실수: 리팩토링을 두려워함
    12. - 잘못된 코드: 리팩토링 없이 코드가 복잡해지는 경우. - 올바른 코드: 리팩토링 후 테스트가 통과하는지 항상 확인해야 함.

      6. 정리

    13. TDD는 코드 품질을 높이고 유지보수를 용이하게 하는 방법론입니다.
    14. Red-Green-Refactor 사이클을 따라 테스트를 먼저 작성하는 것이 중요합니다.
    15. 테스트의 독립성을 유지하고 리팩토링을 두려워하지 않아야 합니다.
    16. 다음에 학습하면 좋은 주제

    17. 지속적 통합(CI)과 지속적 배포(CD)
    18. Mocking과 Stubbing 기법
    19. 테스트 자동화 도구 및 프레임워크 (예: Moq, xUnit)