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

Scala 고급 테스트 기법

Scala 고급 테스트 기법 — 고급

고급 테스트 기법

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

소프트웨어 개발에서 테스트는 필수적인 과정입니다. 특히, 고급 테스트 기법은 복잡한 시스템을 다루는 데 필요합니다. 실무에서는 코드의 품질을 보장하고 버그를 조기에 발견하기 위해 자동화된 테스트를 작성합니다. 고급 테스트 기법을 배우지 않으면 다음과 같은 문제가 발생할 수 있습니다:

  • 버그 발견 지연: 초기 단계에서 버그를 발견하지 못하면, 나중에 수정 비용이 증가합니다.
  • 기능 추가 시 리그레션 발생: 기존 기능을 수정하거나 새로운 기능을 추가할 때 기존 기능에 문제가 발생할 수 있습니다.
  • 코드 품질 저하: 테스트가 없으면 코드의 품질이 저하되고, 유지 보수가 어려워집니다.
  • 2. 핵심 개념 설명

    고급 테스트 기법에는 여러 가지가 있지만, 여기서는 특히 중요한 세 가지 개념을 설명하겠습니다.

    개념정의
    Mocking테스트 중에 의존성을 대체하여 특정 동작이나 상태를 시뮬레이션하는 기법
    Stubbing특정 메서드 호출에 대한 고정된 응답을 제공하는 기법
    Property-Based Testing다양한 입력을 자동으로 생성하여 테스트하는 기법

    실생활 비유

  • Mocking: 친구와의 약속을 대신 잡아주는 대리인처럼, 실제 객체 대신 가짜 객체를 사용하여 특정 동작을 시뮬레이션합니다.
  • Stubbing: 요리 레시피에서 재료를 고정해 두듯이, 특정 메서드 호출에 대해 항상 같은 결과를 반환하도록 설정합니다.
  • Property-Based Testing: 다양한 재료로 요리해 보는 것처럼, 다양한 입력을 사용하여 코드의 동작을 검증합니다.
  • 3. 기본 코드 예제

    여기서는 ScalaTest와 Mockito를 사용한 Mocking과 Stubbing의 기본 예제를 보여드리겠습니다.

    import org.scalatest.flatspec.AnyFlatSpec
    import org.mockito.Mockito._
    
    class Calculator {
      def add(a: Int, b: Int): Int = a + b
    }
    
    class CalculatorTest extends AnyFlatSpec {
      "Calculator" should "add two numbers" in {
        val calculator = new Calculator
        assert(calculator.add(2, 3)  5)
      }
    
      it should "mock add method" in {
        val mockCalculator = mock(classOf[Calculator])
        when(mockCalculator.add(2, 3)).thenReturn(10)
    
        // mockCalculator의 add 메서드를 호출하면 항상 10을 반환
        assert(mockCalculator.add(2, 3)  10)
      }
    }

    실행 결과

    - Calculator should add two numbers
    - Calculator should mock add method

    코드 한 줄씩 동작 설명

    1. import org.scalatest.flatspec.AnyFlatSpec: ScalaTest의 FlatSpec 스타일을 가져옵니다.
    2. class Calculator: Calculator 클래스를 정의합니다.
    3. def add(a: Int, b: Int): Int = a + b: 두 숫자를 더하는 메서드를 정의합니다.
    4. class CalculatorTest extends AnyFlatSpec: 테스트 클래스를 정의합니다.
    5. it should "add two numbers" in {...}: 첫 번째 테스트 케이스를 정의합니다.
    6. assert(calculator.add(2, 3) == 5): 2와 3을 더한 결과가 5인지 확인합니다.
    7. it should "mock add method" in {...}: 두 번째 테스트 케이스를 정의합니다.
    8. val mockCalculator = mock(classOf[Calculator]): Calculator 클래스의 mock 객체를 생성합니다.
    9. when(mockCalculator.add(2, 3)).thenReturn(10): mock 객체의 add 메서드가 항상 10을 반환하도록 설정합니다.
    10. assert(mockCalculator.add(2, 3) == 10): mock 객체의 add 메서드를 호출하고 결과를 검증합니다.
    11. 4. 실전 활용 예제

      예제 1: 쇼핑몰 장바구니의 총합 계산

      쇼핑몰에서 장바구니의 총합을 계산할 때, 각 아이템의 가격을 가져오는 메서드를 Mocking하여 테스트할 수 있습니다.

      class ShoppingCart {
        def totalPrice(items: List[Int]): Int = items.map(price).sum
      
        def price(itemId: Int): Int = {
          // 실제 DB에서 가격을 가져오는 로직
          ???
        }
      }
      
      // 테스트 코드
      class ShoppingCartTest extends AnyFlatSpec {
        it should "calculate total price using mocked price method" in {
          val mockCart = mock(classOf[ShoppingCart])
          when(mockCart.price(1)).thenReturn(100)
          when(mockCart.price(2)).thenReturn(200)
      
          val total = mockCart.totalPrice(List(1, 2))
          assert(total == 300) // 100 + 200
        }
      }

      예제 2: 사용자 인증 서비스

      사용자 인증 서비스에서 외부 API를 호출하는 부분을 Stubbing하여 테스트할 수 있습니다.

      class AuthService {
        def isAuthenticated(userId: String): Boolean = {
          // 외부 API 호출
          ???
        }
      }
      
      // 테스트 코드
      class AuthServiceTest extends AnyFlatSpec {
        it should "return true for authenticated user" in {
          val mockAuthService = mock(classOf[AuthService])
          when(mockAuthService.isAuthenticated("user123")).thenReturn(true)
      
          assert(mockAuthService.isAuthenticated("user123"))
        }
      }

      5. 흔한 실수와 주의사항

      실수 1: Mock 객체를 잘못 사용

    12. 잘못된 코드:
    13.   val mockCalculator = new Calculator // 실제 객체를 생성
    14. 올바른 코드:
    15.   val mockCalculator = mock(classOf[Calculator]) // Mock 객체 생성

      실수 2: Stubbing을 잊음

    16. 잘못된 코드:
    17.   assert(mockCalculator.add(2, 3) == 10) // Stubbing이 없어서 실패
    18. 올바른 코드:
    19.   when(mockCalculator.add(2, 3)).thenReturn(10) // Stubbing 추가

      6. 정리

    20. Mocking과 Stubbing은 테스트에서 의존성을 관리하는 중요한 기법입니다.
    21. Property-Based Testing은 다양한 입력을 사용하여 코드의 정확성을 검증합니다.
    22. 테스트를 통해 버그를 조기에 발견하고, 코드 품질을 향상시킬 수 있습니다.
    23. 다음 학습 추천 주제

    24. Test-Driven Development (TDD)
    25. Behavior-Driven Development (BDD)
    26. Continuous Integration (CI)와 테스트 자동화