Jin's IT Story.
DevBasics

Mocking의 원리와 주요 패턴 분석

| 2025-08-02
목차
    복잡한 실제 기어를 투명한 파란색 설계도 형태의 가짜 기어로 대체하는 과정을 묘사한 깔끔한 테크 스타일 일러스트레이션

     Mocking은 단위 테스트에서 실제 의존 객체를 대체하기 위해 사용되는 핵심적인 테스트 기법입니다. 테스트 효율성과 정확성을 높이기 위한 필수 도구로서, 그 작동 원리와 구현 방식은 매우 체계적으로 구성되어 있습니다. 이 글에서는 Mocking의 작동 원리와 함께 실제로 많이 사용되는 주요 패턴들을 분석하여, 개발자들이 실무에서 효율적으로 활용할 수 있도록 안내합니다.

    Mocking의 핵심 원리

     Mocking은 테스트 환경에서 실제 객체를 흉내 낼 수 있는 가짜 객체(Mock Object)를 생성하여, 테스트 대상 코드의 동작을 보다 정확하게 검증할 수 있도록 돕는 방식입니다. 이를 통해 개발자는 외부 시스템이나 복잡한 의존성 없이도 원하는 상황을 인위적으로 재현할 수 있습니다.

     예를 들어, API 호출이 실패하는 상황, DB 연결이 불가능한 상황, 또는 특정 결과를 반환해야 하는 테스트 시나리오 등을 Mocking을 통해 쉽게 구성할 수 있습니다.

     Mocking의 작동 원리는 다음과 같이 요약할 수 있습니다.

     먼저 테스트 대상 코드에 필요한 의존 객체를 가짜로 생성하고, 해당 객체의 특정 메서드나 동작을 사전에 정의합니다. 이후 테스트가 실행되면 실제 객체 대신 Mock 객체가 동작하며, 테스트는 그 결과를 검증합니다.

     이 과정에서 입력값, 호출 횟수, 반환값, 예외 처리 등 다양한 시나리오를 설정할 수 있기 때문에 테스트의 유연성과 정밀도가 크게 향상됩니다.

     Mock 객체는 크게 두 가지 측면에서 활용됩니다.

     첫째는 행동 검증(Behavior Verification), 즉 어떤 메서드가 호출되었는지, 몇 번 호출되었는지를 체크하는 용도입니다.

     둘째는 상태 검증(State Verification)으로, 특정 입력값에 대해 예상된 결과를 반환하는지를 확인하는 방식입니다.

     대부분의 Mocking 프레임워크는 이 두 가지 기능을 모두 제공하며, 이를 조합하여 매우 강력한 테스트 시나리오를 구성할 수 있습니다.

    다양한 Mocking 패턴

     Mocking을 실무에 효과적으로 적용하기 위해서는 다양한 패턴을 이해하는 것이 중요합니다. 패턴은 반복되는 테스트 시나리오나 테스트 전략을 보다 구조적으로 설계할 수 있도록 도와주는 도구입니다. 여기서는 가장 널리 사용되는 3가지 Mocking 패턴을 소개합니다.

    • Setup-Call-Verify 패턴: 가장 일반적인 Mocking 방식으로, Mock 객체를 설정하고, 테스트 실행 후 동작 검증까지 수행합니다.
    • Record-Replay 패턴: Mock 객체의 동작을 사전에 녹음하고, 테스트 시 재생하여 예상된 시퀀스를 비교합니다.
    • Arrange-Act-Assert(AAA) 패턴: 테스트 구조를 정리하는 방식으로, Mock 설정도 Arrange 단계에 포함됩니다.

     그 외에도 의존성 주입(Mock Injection)이나 함수 주입(Function Injection) 등의 방식도 있으며, 이는 테스트 구조를 더 유연하게 만들어 줍니다.

    Mocking 도구별 적용 예시

     Mocking을 위해서는 전문적인 프레임워크와 도구들이 사용됩니다. 각 언어별로 다양한 라이브러리가 존재하며, 구현 방식이나 문법이 다르기 때문에 자신이 사용하는 언어와 프레임워크에 맞는 도구를 잘 선택하는 것이 중요합니다.

    • Mockito(Java): 가장 널리 사용되며, 직관적인 문법으로 행동 설정과 검증이 가능합니다.
    • Jest(JavaScript): 프런트엔드 환경에서 사용되며, 함수 단위 Mocking에 최적화되어 있습니다.
    • Moq(C#): .NET 환경에서 사용되며, Lambda 표현식을 통한 유연한 설정이 장점입니다.
    // Mockito 예제
    when(mockService.getUser()).thenReturn("홍길동");
    verify(mockService, times(1)).getUser();
    // Jest 예제
    const mockFn = jest.fn().mockReturnValue(10);
    expect(mockFn()).toBe(10);
    expect(mockFn).toHaveBeenCalled();
    // Moq 예제
    var mock = new Mock<IUserService>();
    mock.Setup(s => s.GetName()).Returns("Alice");
    mock.Verify(s => s.GetName(), Times.Once);

     각 도구는 동일한 원리를 기반으로 하며, 문법만 다를 뿐 핵심은 '동작 정의'와 '검증'이라는 점을 기억하세요.

     Mocking은 단순한 테스트 보조 기술이 아니라, 소프트웨어 품질을 높이는 핵심 전략입니다. Mocking의 원리를 이해하고 다양한 패턴을 적용하면, 테스트 효율성을 크게 높일 수 있습니다. 특히 테스트 커버리지를 극대화하고 외부 의존성에 대한 걱정 없이 안정적인 코드를 작성하려면 Mocking을 적극적으로 활용해야 합니다.

     프레임워크에 따라 문법은 달라도 원리는 같다는 점을 기억하고, 꾸준히 연습해 실무에 적용해 보세요.