Test Double(테스트 더블) 알아보기
xUnit Test Patterns의 저자인 제라드 메스자로스(Gerard Meszaros)가 만든 용어로,
스턴트 더블(영화 촬영에서 말하는 스턴트 대역 배우)에서 아이디어를 얻어서 만든 용어입니다.
Test Double소개
When we are writing a test in which we cannot (or chose not to) use a real depended-on component (DOC), we can replace it with a Test Double.
The Test Double doesn’t have to behave exactly like the real DOC; it merely has to provide the same API as the real one so that the SUT thinks it is the real one!
테스트 코드를 작성할 때 실제 DOC(depoended-on component; 의존 구성 요소)를 사용할 수 없다면, DOC 대신 테스트 더블로 대체할 수 있음.
테스트 더블은 실제 DOC와 똑같이 행동하지 않아도 되며, 똑같은 API만 제공하면 된다.
테스트 더블은 의존 구성요소를 사용할 수 없을 때
테스트 대상 코드와 상호작용 하는 객체입니다.
Test Double의 역할
- 테스트 대상 코드를 격리합니다.
- 테스트 속도를 개선합니다.
- 예측 불가능한 실행 요소를 제거합니다.
- 특수한 상황을 시뮬레이션합니다.
- 감춰진 정보를 얻어냅니다.
Test Double의 종류
1. Dummy
- 가장 기본적인 테스트 더블
- 단지 인스턴트화 된 객체가 필요하고, 해당 객체의 기능까지 필요하지 않은 경우에 사용
- 해당 dummy객체의 메서드가 호출되었을 때 정상 동작은 보장하지 않음
- 구현의 제외한 인터페이스 or 기본 클래스의 파생 객체
- 객체는 전달되지만 사용되지 않는 객체
2. Stub
- dummy객체가 실제로 동작하는 것처럼 보이게 만들어 놓은 객체
- 실제 코드나 아직 준비되지 못한 코드의 행동을 가장하는 행위
- 호출자를 실제 구현물로부터 격리시키는 목적으로 사용 가능
- 인터페이스 or 기본 클래스가 최소한으로 구현된 상태
- 테스트에서 호출된 요청에 대해 미리 준비해둔 결과를 제공합니다.
3. Fake
class StubCoupon {
fun isAppliable(item: String): Boolean {
return when {
item == "후라이팬" -> true
item == "시계" -> false
else -> false
}
}
}
위 코드는 그때그때 다른 결과를 리턴하도록 하드 코딩되어있는 코드입니다.
위와 같은 코드는 단순한 Test Stub으로는 만들기 힘듭니다.
위 코드는 마치 실제 로직이 구현된 것처럼 보이는데 이렇게 만들어지는 객체를 fake객체라 합니다.
- 복잡한 로직이나 객체 내부에서 필요로 하는 다른 외부 객체들의 동작을 단순화하여 구현한 객체
- 동작의 구현을 가지고 있지만 실제 프로덕션에는 적합하지 않은 객체
4. Spy
테스트에서 특정 객체가 사용되었는지,
그리고 그 객체의 예상된 메서드가 정상적으로 호출됐는지를 확인해야 하는 상황이 생기는 경우 사용합니다.
- Stub의 역할을 가지면서 호출된 내용에 대해 약간의 정보를 기록합니다.
- 테스트에서 확인하기 위한 정보
5. 1 Mock
호출에 대한 기대를 명세하고 내용에 따라 동작하도록 프로그래밍된 객체입니다.
5.2 mock을 사용해야 할 때
- 테스트 작성을 위한 환경 구축이 어려울 때
- 환경 구축을 위한 작업 시간이 많이 필요한 경우 Mock 객체를 사용
- 특정 모듈을 아직 갖고 있지 않아서 테스트 환경을 구축하지 못할 경우
- 타 부서와의 협의나 정책이 필요한 경우에도 Mock이 필요.
- 연계 모듈이라서 다른 쪽에서 승인을 해줘야 테스트가 가능한 경우, 방화벽으로 막혀 있어서 통과가 어려운 경우 등이 이에 속함.
- 테스트가 특정 경우나 순간에 의존적일 때
- 테스트 시간이 오래 걸리는 경우
5.3 상태 기반 테스트 vs 행위 기반 테스트
Mock 객체를 이해하려면 상태 기반 테스트와 행위 기반 테스트에 대한 이해가 필요합니다.
- 상태 기반 테스트(state base test)
- 특정한 메서드를 거친 후, 객체의 상태에 대해 예상값과 비교하는 방식이 상태 기반 테스트.
- eg. setName() 메소드를 호출했으면, getName() 메서드로 확인해보는 식
- 특정한 메서드를 거친 후, 객체의 상태에 대해 예상값과 비교하는 방식이 상태 기반 테스트.
- 행위 기반 테스트(behavior base test)
- 올바른 로직 수행에 대한 판단의 근거로 특정한 동작의 수행 여부를 이용한다.
- 메서드의 리턴 값이 없거나 리턴 값을 확인하는 것만으로는 예상대로 동작했음을 보증하기 어려운 경우에 사용.
- eg. methodA에 A가 입력되면 methodB는 호출되지 않아야 정상이다. 그리고 B가 입력되면 methodB가 호출돼야 정상이다. 하지만 테스트 대상이 되는 methodA만 놓고 봤을 때 입력값에 대한 차이를 methodA만으로는 알아낼 수 없다. 즉 methodB의 호출 여부를 조사하지 않으면 methodA의 정상 동작 여부를 판단할 수 없다. 만일 methodA가 정상 동작했을 경우 methodB가 반드시 호출되는 구성이라면, 반대로 methodB의 호출 여부로 methodA의 정상 여부를 판단할 수 있다고 보는 것임. 따라서 이럴 때는 methodB의 호출 여부를 확인하는 것이 테스트 시나리오의 종료 조건이 됨.
- 하지만 전통적인 테스트 케이스 작성 방식인 상태 기반 테스트에선 이런 상황에 대한 테스트 케이스를 작성하기가 매우 어렵거나 불편했음. 테스트 대상인 A가 상태를 갖고 있지 않기 때문이다.(void와 같은..)
- 이때 테스트 스파이 객체를 사용하거나 자체적으로 검증 기능을 제공하는 Mock 객체를 따로 만들어서 테스트 케이스를 작성하는 것임.
- 행위를 점검하는 걸로 테스트 케이스를 만드는 방식..
- 따라서 행위 기반 테스트를 수행할 때는 예상하는 행위들을 미리 시나리오로 만들어놓고 해당 시나리오대로 동작이 발생했는지 여부를 확인하는 것이 핵심이 된다.
5.4 Test double mock vs Mock Object
- 일반적인 테스트 더블은 상태(state를 기반으로 테스트 케이스를 작성
- Mock 객체는 행위(behavior)를 기반으로 테스트 케이스를 작성(Mockito 등등)
Mock 객체는 행위를 검증하기 위해 사용되는 객체를 지칭합니다.
행위 기반 테스트는 좀 복잡한 시나리오가 사용되는 경우가 많고,
모양이나 작성 등 여러 측면에서 어색한 경우가 많아서 만약 상태 기반으로 테스트를 할 수 있는 상황이라면
굳이 행위 기반 테스트 케이스는 만들지 않는 것이 좋습니다.
ex) Mock Object framework ,, Mockito
Mockito는 Stub 작성과 verify가중심을 이루며 다음과 같은 순서로 진행합니다.
- CreateMock: 인터페이스에 해당하는 Mock 객체를 생성
- Stub: 테스트에 필요한 Mock 객체의 동작을 지정(필요시에만)
- Exercise: 테스트 메서드 내에서 Mock 객체를 사용
- Verify: 메서드가 예상대로 호출 됬는지 검증
'Android > Test' 카테고리의 다른 글
Mockito-Kotlin Sample로 자세히 알아보기 (0) | 2019.10.28 |
---|---|
Mockito-Kotlin 알아보기 (0) | 2019.10.28 |
Test Stub이란 ? (0) | 2019.10.28 |
TDD알아보기 (4) | 2019.10.04 |
assertThat (4) | 2019.10.04 |
댓글