TDD vs BDD

Seung jun Cha·2022년 8월 12일
0

1. TDD

  • 선 기능개발 후 테스트의 문제점
  1. 테스트 자체의 누락 가능성 : 시간문제 등
  2. 특정 테스트 케이스만 검증할 가능성 : 정상동작하는 코드를 먼저 구현하면 해당 코드가 정상적으로 작동하는지만 테스트하는데에 집중하고 예외케이스를 잊을 수 있음
  3. 잘못된 구현을 늦게 발견할 가능성
  • Test Driven Development (테스트 주도 개발)
    테스트 코드를 먼저 만들고 테스트를 통과하기 위한 코드를 작성하면서 개발을 주도한다.
    • 코드 변경에 의한 사이드 이펙트를 최대한 줄일 수 있는 예방책
    • 새로운 기능 추가 시에 수시로 빠르게 테스트 가능
    • 서비스 요구사항 변경이나 리팩토링으로 인해 코드 수정이 필요한 상황에서 더 유연하고 안정적인 대응
    • 테스트 코드를 작성하는 과정에서 자연스럽게 코드의 모듈화를 고민하게 되는 등의 부수적인 이점
    • red-green-refactoring : 테스트코드 작성-> 테스트를 통과하기위한 최소한의 코드 작성(막 만들어도 됨) -> 리팩토링
  1. 비어있는 클래스와 클래스 테스트를 생성한다.
public class Calculator {

}

public class CalculatorTest {
    Calculaotr calc = new Calculator();
}
  1. 만드려고 하는 기능과 리턴값을 테스트에 작성한다.
public class Calculator {

}

public class CalculatorTest {
    Calculaotr calc = new Calculator();

    @Test
    void plus() {
        int a = 10;
        int b = 20;
        int result = calc.plus(a, b);
    }

}

현재 Calculator 클래스에는 plus라는 메서드가 존재하지 않기 때문에 실패하게 된다

  1. 클래스에 해당 메서드를 통과할 수 있는 간단한 클래스를 구현한다.
public class Calculator {
    public int plus(int a, int b) {
        return 0;  // 리턴값은 상관없이 컴파일만 되는 것을 목표로
    };
}

public class CalculatorTest {
    Calculaotr calc = new Calculator();

    @Test
    void plus() {
        int a = 10;
        int b = 20;
        int result = calc.plus(a, b);
    }
}
  1. Calculator 클래스에서 어떤 결과를 내어야 할지 CalculatorTest 클래스에서 테스트 결과로 정의한다.
public class Calculator {
    public int plus(int a, int b) {
        return 0;  // 리턴값은 상관없이 컴파일만 되는 것을 목표로
    };
}

public class CalculatorTest {
    Calculaotr calc = new Calculator();

    @Test
    void plus() {
        int a = 10;
        int b = 20;
        int result = calc.plus(a, b);

        assertEquals(result, a + b);
        
    }
}
  1. Calculator 클래스에서 해당 테스트를 통과할 수 있는 로직을 구현한다.
public class Calculator {
    public int plus(int a, int b) {
        return a + b;
    };
}

public class CalculatorTest {
    Calculaotr calc = new Calculator();

    @Test
    void plus() {
        int a = 10;
        int b = 20;
        int result = calc.plus(a, b);

        assertEquals(result, a + b);
    }
}

2. BDD

  • Behavior Driven Development (행동 기반 개발)
    • TDD 에서는 사실상 테스트 코드를 이용한 구현에 초점이 맞춰저 있다.
    • BDD는 TDD에서 파생된 기법으로 함수단위의 테스트가 아닌 시나리오에 기반한 테스트케이스 작성에 집중한다.
    • BDDMockito를 사용하는데 Mockito 라이브러리 내에 존재하는 BDDMockito 클래스를 말 하며 BDD 지향적인 개발을 mockito 에서 api 형태로 제공한다.

2-1 given, when, then

  • Given
    • 테스트를 위해 주어진 상태
    • 테스트 대상에게 주어진 조건
    • 테스트가 동작하기 위해 주어진 환경
  • When
    • 테스트 대상에게 가해진 어떠한 상태
    • 테스트 대상에게 주어진 어떠한 조건
    • 테스트 대상의 상태를 변경시키기 위한 환경
  • Then
    • 앞선 과정의 결과

순수 Mockito에서 BDD의 Given / When / Then 을 위해서 when(obj) 메서드와 thenReturn() 이용하고 verity() 구문을 이용해 검증한다.
하지만 가독성이 떨어지고 이해가 어렵다는 이유로 BDDMockito가 등장한다. 기능은 같지만 이름만 다른 클래스라고 생각해도 될 것 같다.

2-2 BDDMockito

  • BDDMockito의 코드를 살펴보면 Mockito을 상속한 클래스임을 알 수 있다. 그리고 동작이나 사용하는 방법 또한 Mockito와 거의 차이가 없다.

2-2-1 Mocking 할 메서드

  • Mocking 할 메서드에는 테스트 대상이 특정 결과를 수행하기 위해 연관된 객체의 연산을 주입해주면 된다.
    MemberService 에는 현재 isExistByEmail 메서드가 존재하고 해당 메서드 내부에 MemberRepository 인스턴스가 existsByEmail 연산을 수행하고 있으므로 우리는 MemberRepository의 existsByEmail 을 가짜로 주입해주면 된다.
    (MemberService를 테스트해야 하는데 MemberRepository가 작동하는 메서드가 연관되어 있으니 mock 메서드로 넣어준다는 뜻인 듯)

2-2-2 해당 메서드의 파라미터

  • 모든 값을 받았을 때의 행동 정의하기 : any()
    • 모든 객체가 들어왔을 때의 행동은 any(Object object) 를 이용할 수 있다. 여기서는 String 인 모든 객체가 가능하다는 말
  • 특정 값을 받았을 때의 행동 정의하기 : eq()
    • 특정한 값 또는 객체가 들어와야할 때, 사용하는게 바로 eq() 메서드이다.

출처 및 참고
https://wonit.tistory.com/493
Mockito와 BDDMockito는 뭐가 다를까?

0개의 댓글