학습
Scala 테스트 주도 개발 (TDD)
Scala 테스트 주도 개발 (TDD) — 중급
테스트 주도 개발 (TDD)
1. 도입 (왜 배워야 하는가)
테스트 주도 개발(Test-Driven Development, TDD)은 소프트웨어 개발에서 품질을 보장하고, 코드의 유지 보수를 쉽게 하기 위한 중요한 방법론입니다. TDD를 통해 개발자가 작성하는 코드가 실제로 요구 사항을 충족하는지를 빠르게 확인할 수 있으며, 버그를 사전에 예방할 수 있습니다.
TDD를 모른다면 다음과 같은 문제가 발생할 수 있습니다:
- 버그 증가: 개발 후에 테스트를 진행하면 이미 구현된 코드에서 문제가 발생할 확률이 높아집니다.
- 유지 보수 어려움: 기존 코드에 대한 테스트가 없으면 나중에 기능 변경이나 버그 수정 시 불안정해질 수 있습니다.
- 의사소통 문제: 팀원 간에 코드의 의도나 기능에 대한 이해가 부족해질 수 있습니다.
- Red-Green-Refactor: TDD의 기본 사이클입니다.
2. 핵심 개념 설명
TDD의 핵심 개념은 "테스트를 먼저 작성하고, 그 테스트를 통과할 수 있는 코드를 작성하는 것" 입니다. 이 과정을 반복하면서 점진적으로 기능을 구현해 나갑니다.
- Red: 테스트를 작성하고 실패하는 상태를 확인합니다. - Green: 테스트를 통과하는 최소한의 코드를 작성합니다. - Refactor: 코드를 개선하고 최적화합니다.
관련 용어 정리
| 용어 | 설명 |
|---|---|
| 테스트 케이스 | 특정 기능에 대한 테스트를 정의하는 코드 |
| 리팩토링 | 코드 구조를 개선하는 과정 |
| 유닛 테스트 | 개별 함수 또는 메서드를 테스트하는 것 |
3. 기본 코드 예제
다음은 Scala에서 TDD를 적용해 간단한 덧셈 기능을 구현하는 예제입니다.
// 덧셈 기능을 테스트하는 클래스
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class CalculatorSpec extends AnyFlatSpec with Matchers {
"Addition" should "correctly add two numbers" in {
val calculator = new Calculator()
calculator.add(2, 3) should be(5) // 테스트 케이스
}
}
// 덧셈 기능을 구현하는 클래스
class Calculator {
def add(a: Int, b: Int): Int = a + b
}
실행 결과: 테스트가 통과하면 아무런 오류 메시지가 없습니다.
코드 한 줄씩 동작 설명
import org.scalatest.flatspec.AnyFlatSpec- ScalaTest 라이브러리에서 FlatSpec을 임포트합니다. 이는 테스트를 작성하기 위한 기본 클래스입니다.class CalculatorSpec extends AnyFlatSpec with Matchers-CalculatorSpec테스트 클래스를 정의합니다.Matchers를 사용하여 테스트 결과를 쉽게 검증합니다."Addition" should "correctly add two numbers" in { ... }- "Addition"이라는 주제로 테스트를 정의하고, 그 안에 테스트 내용을 작성합니다.val calculator = new Calculator()-Calculator클래스의 인스턴스를 생성합니다.calculator.add(2, 3) should be(5)-add메소드를 호출하여 결과가 5인지 확인합니다.- 잘못된 코드:
- 올바른 코드: 테스트 케이스를 작성한 후 구현해야 함.
- 잘못된 코드:
- 올바른 코드: 입력 타입을 확인하고 맞게 테스트해야 함.
- TDD는 품질 높은 코드를 작성하는 데 도움을 줍니다.
- Red-Green-Refactor 사이클을 통해 점진적으로 기능을 구현합니다.
- 테스트를 먼저 작성하고 그에 맞춰 코드를 작성하는 것이 중요합니다.
- Mocking과 Stubbing: 테스트에서 의존성을 관리하는 방법
- 통합 테스트와 유닛 테스트의 차이
- CI/CD 파이프라인에서 TDD 적용하기
4. 실전 활용 예제
1. 쇼핑몰에서 장바구니를 구현할 때
장바구니에 상품을 추가할 때 TDD를 활용하여 다음과 같은 테스트를 작성할 수 있습니다.
class ShoppingCartSpec extends AnyFlatSpec with Matchers {
"ShoppingCart" should "add items properly" in {
val cart = new ShoppingCart()
cart.addItem("Apple", 1) // 사과 1개 추가
cart.getItems should contain ("Apple") // 사과가 장바구니에 있어야 함
}
}
class ShoppingCart {
private var items: List[String] = List()
def addItem(item: String, quantity: Int): Unit = {
items = items :+ item // 장바구니에 아이템 추가
}
def getItems: List[String] = items // 장바구니의 아이템 반환
}
2. 사용자 로그인 기능 구현
사용자가 올바른 자격 증명으로 로그인하는지 테스트하는 예입니다.
class UserSpec extends AnyFlatSpec with Matchers {
"User" should "authenticate with valid credentials" in {
val user = new User("testUser", "password123")
user.authenticate("testUser", "password123") should be(true) // 로그인 성공
}
}
class User(val username: String, val password: String) {
def authenticate(inputUsername: String, inputPassword: String): Boolean = {
inputUsername username && inputPassword password // 인증 로직
}
}
5. 흔한 실수와 주의사항
1. 테스트를 작성하지 않고 코드 구현
class Calculator {
def add(a: Int, b: Int): Int = a + b // 테스트 없이 구현
}
2. 테스트 실패 원인을 파악하지 않음
calculator.add(2, "3") // 타입 불일치로 실패