0Pricing
C# Academy · 강의

실패하는 테스트 디버깅

실패를 재현 가능하게 만들고, 시간과 무작위성을 제거하며, 최소 사례로 축소하고, 빠른 진단을 위해 단정 메시지를 개선합니다.

실패하는 테스트 디버깅은(는) CoddyKit의 무료 C# Academy 강의입니다. 이것은 3개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 C# Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. C# Academy 강의에는 총 3개의 강의가 포함되어 있습니다.

해결 계획

실패하는 테스트를 수정하기 위한 계획:

  • 안정적으로 재현하기
  • 불안정성을 제거하기(시간/무작위성/입출력)
  • 가장 작은 실패 사례로 축소하기
  • 명확한 검증 메시지 추가하기

설계상 불안정한 테스트

UtcNow와 기본 Random을 사용하면 실행할 때마다 동작이 달라져 불안정한 테스트가 됩니다.

using System;

// Demo: occasionally fails because it depends on current second and default Random()
public static class Promo
{
  // Gives bonus on even seconds; random adds small jitter
  public static int BonusNow()
  {
    int baseBonus = (DateTime.UtcNow.Second % 2 == 0) ? 10 : 9;
    Random r = new Random(); // time-based seed → unpredictable
    return baseBonus + (r.Next(0, 2)); // 0 or 1 more
  }
}

public class Program
{
  public static void Main(string[] args)
  {
    // Simulated test: sometimes expects exactly 10, but result varies
    int got = Promo.BonusNow();
    if (got != 10) Console.WriteLine("FAIL (flaky): expected 10 but got " + got);
    else Console.WriteLine("PASS (maybe): got " + got);
  }
}

의존성 제어

시간과 Random을 주입합니다. 고정된 시드와 고정된 타임스탬프를 사용하면 실패를 재현 가능하게 만들 수 있습니다.

using System;

public interface IClock { DateTime NowUtc(); }
public sealed class FakeClock : IClock
{
  private readonly DateTime _fixedUtc;
  public FakeClock(DateTime fixedUtc) { _fixedUtc = fixedUtc; }
  public DateTime NowUtc() { return _fixedUtc; }
}

public sealed class PromoDeterministic
{
  private readonly IClock _clock;
  private readonly Random _rng;
  public PromoDeterministic(IClock clock, Random rng) { _clock = clock; _rng = rng; }

  public int BonusNow()
  {
    int baseBonus = (_clock.NowUtc().Second % 2 == 0) ? 10 : 9;
    return baseBonus + _rng.Next(0, 2);
  }
}

public static class Assert
{
  public static void AreEqual(int expected, int actual, string msg)
  {
    if (expected != actual) throw new Exception("Expected " + expected + " but got " + actual + " :: " + msg);
  }
}

public class Program
{
  public static void Main(string[] args)
  {
    try
    {
      IClock clock = new FakeClock(new DateTime(2016, 1, 1, 0, 0, 20, DateTimeKind.Utc)); // even second
      Random rng = new Random(123); // fixed seed
      PromoDeterministic p = new PromoDeterministic(clock, rng);

      int got = p.BonusNow(); // predictable now
      Assert.AreEqual(10, got, "even second, first draw should be 0");
      Console.WriteLine("PASS: deterministic promo");
    }
    catch (Exception ex)
    {
      Console.WriteLine("FAIL: " + ex.Message);
    }
  }
}

최소 재현 사례

작은 예시가 실패할 때까지 입력을 축소합니다(여기서는 빈 배열). 작은 사례일수록 추론하기 쉽습니다.

using System;

// Buggy function: average of ints, but divides by count without guarding empty input
public static class Stats
{
  public static double Average(int[] xs)
  {
    int sum = 0;
    for (int i = 0; i < xs.Length; i++) sum += xs[i];
    return sum / xs.Length; // BUG: divide by zero if empty; also int division truncates
  }
}

public static class Assert
{
  public static void Throws<T>(Action a, string msg) where T : Exception
  {
    try { a(); }
    catch (Exception ex)
    {
      if (ex is T) return;
      throw new Exception("Expected " + typeof(T).Name + " but got " + ex.GetType().Name + " :: " + msg);
    }
    throw new Exception("Expected " + typeof(T).Name + " but no exception thrown :: " + msg);
  }
}

public class Program
{
  public static void Main(string[] args)
  {
    // Minimal failing case: empty array
    Assert.Throws<DivideByZeroException>(delegate { Stats.Average(new int[0]); }, "empty input");
    Console.WriteLine("Reproduced: empty input triggers the bug.");
  }
}

수정과 메시지 품질

잘못된 입력을 방어하고, 설명적인 검증 메시지를 사용합니다(입력/기대값/허용 오차를 포함합니다).

using System;

public static class Stats
{
  public static double Average(int[] xs)
  {
    if (xs == null) throw new ArgumentNullException("xs");
    if (xs.Length == 0) throw new ArgumentException("xs must not be empty", "xs");

    double sum = 0.0; // use double to avoid integer truncation
    for (int i = 0; i < xs.Length; i++) sum += xs[i];
    return sum / xs.Length;
  }
}

public static class Assert
{
  public static void AreAlmostEqual(double expected, double actual, double eps, string msg)
  {
    if (Math.Abs(expected - actual) > eps)
      throw new Exception("Expected " + expected + " but got " + actual + " (eps " + eps + ") :: " + msg);
  }
}

public class Program
{
  public static void Main(string[] args)
  {
    try
    {
      double a = Stats.Average(new int[] { 2, 4, 6 });
      Assert.AreAlmostEqual(4.0, a, 1e-9, "average of 2,4,6");

      Console.WriteLine("PASS: fixed average with clear message");
    }
    catch (Exception ex)
    {
      Console.WriteLine("FAIL: " + ex.Message);
    }
  }
}

디버깅 체크리스트

디버깅 체크리스트:

  • 의존성 안정화(시간, 무작위성, 입출력)
  • 로컬에서 반복하여 재현
  • 최소 실패 입력으로 축소
  • 정확한 검증 메시지 추가
  • 순수 함수와 방어적 검사를 우선

불안정한 테스트의 첫 단계

간단한 확인: 간헐적으로 실패하는 테스트가 DateTime.UtcNow와 new Random()을 사용합니다. 가장 먼저 무엇을 해야 할까요?

복습

복습: 시간과 무작위성을 제어하여 안정적으로 재현하고, 입력을 축소하며, 버그를 빠르게 찾을 수 있도록 유용한 검증 메시지를 작성합니다.

자주 묻는 질문

“실패하는 테스트 디버깅” 강의는 무료인가요?

네 — “실패하는 테스트 디버깅” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 C# Academy 강의 전체를 잠금 해제할 수 있습니다. C# Academy 강의에는 총 3개의 강의가 포함되어 있습니다.

“실패하는 테스트 디버깅”에서 뭘 배우나요?

실패를 재현 가능하게 만들고, 시간과 무작위성을 제거하며, 최소 사례로 축소하고, 빠른 진단을 위해 단정 메시지를 개선합니다. 브라우저에서 직접 실행하는 실습 코드로 C# Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

C# Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 C# Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 3개 중 3번째 강의입니다.

“실패하는 테스트 디버깅” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 C# Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 C# Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. xUnit/MSTest 설정과 단정
  2. 인터페이스를 통한 가짜 객체와 테스트 데이터 작성기
  3. 실패하는 테스트 디버깅
← C# Academy(으)로 돌아가기