테스팅(Testing)
단위 테스트(Unit Test)
위 그림은 애플리케이션의 일반적인 테스트 분류를 나타낸 것이다.
- 기능 테스트
기능 테스트는 주로 애플리케이션을 사용하는 사용자 입장에서 애플리케이션이 제공하는 기능이 올바르게 동작하는지를 테스트한다.
기능 테스트를 하는 주체는 주로 해당 애플리케이션을 개발한 개발자가 될수도 있지만 일반적으로는 테스트 전문 부서(QA 부서) 또는 외부 QA 업체가 된다.
- 통합 테스트
통합 테스트는 애플리케이션을 만든 개발자 또는 개발팀이 테스트의 주체가 되는것이 일반적이다.
통합 테스트는 클라이언트 측 툴 없이 개발자가 짜 놓은 테스트 코드를 실행시켜서 이루어지는 경우가 많다.
예를 들어, 개발자가 Controller의 API를 호출하는 테스트 코드를 작성한 후 실행하면 서비스 계층과 데이터 액세스 계층을 거쳐 DB에 실제로 접속해서 기대했던 대로 동작을 하는지 테스트 하는 것은 통합 테스트의 하나라고 볼 수 있다.
- 슬라이스 테스트
슬라이스 테스트는 애플리케이션을 특정 계층으로 쪼개어서 하는 테스트를 의미한다.
API 계층, 서비스 계층, 데이터 액세스 계층이 각각 슬라이스 테스트의 대상이 될 수 있다.
슬라이스 테스트 역시 해당 계층에서 HTTP 요청이 필요하고, 외부 서비스가 연동되기도 하며 특히나 데이터 액세스 계층의 경우 여전히 DB와 연동되어 있기 때문에 슬라이스 테스트는 단위 테스트보다는 말 그대로 계층별로 쪼개어 테스트 한다는 의미의 슬라이스 테스트라고 부른다.
슬라이스 테스트의 경우, Mock(가짜) 객체를 사용해서 계층별로 끊어서 테스트 할 수 있기 때문에 어느 정도 테스트 범위를 좁히는 것이 가능하다.
슬라이스 테스트는 단위 테스트라고 부르기에는 단위가 큰 테스트이며, 또한 애플리케이션의 일부만 테스트하기 때문에 부분 통합 테스트라고 부르기도 한다.
- 단위 테스트
일반적으로 핵심 로직 즉, 비즈니스 로직에서 사용하는 클래스들이 독립적으로 테스트하기 가장 좋은 대상이기 때문에 단위 테스트라고 부르는 경우가 가장 많다.
기능이 동작하는지 테스트하기 위해서는 메서드를 대상으로 테스트를 해야하기 때문에 단위 테스트 코드는 메서드 단위로 대부분 작성된다고 할 수 있다.
통합 테스트나 슬라이스 테스트에서 데이터베이스와 연동된다고 해서 무조건적으로 단위 테스트라고 부르기 어렵다기 보다는 데이터베이스의 상태가 테스트 이 전과 이 후가 동일하게 유지될 수 있다면 데이터베이스가 연동된다고 해도 단위 테스트에 포함될 수 는 있다.
단위 테스트의 필요성
- HTTP 요청을 보내는 등의 번거로운 일들을 단순화할 수 있다.
- 구현한 코드가 의도한 대로 동작하는지 그 결과를 빠르게 확인할 수 있다.
- 작은 단위의 테스트로 미리 버그를 찾을 수 있기 때문에 애플리케이션의 덩치가 커진 상태에서 문제의 원인을 찾아내는 것보다 상대적으로 더 적은 시간 안에 문제를 찾아낼 가능성이 높다.
- 테스트 케이스가 잘 짜여져 있으면 버그 리포트를 전받 받을 경우, 버그가 발생한 기능의 테스트 케이스를 돌려보며 문제가 발생한 원인을 단계적으로 찾아가기가 용이하다.
- 테스트 케이스(Test Case)
- 테스트를 위한 입력 데이터, 실행 조건, 기대 결과를 표현하기 위한 명세를 의미하며, 메서드 등 하나의 단위를 테스트하기 위해 작성하는 코드
단위 테스트를 위한 F.I.R.S.T 원칙
단위 테스트를 위한 테스트 케이스를 작성하기 해서 참고할 수 있는 가이드 원칙으로 F.I.R.S.T 원칙이 있다.
- Fast(빠르게)
일반적으로 작성한 테스트 케이스는 빨라야 한다는 의미이다.
- Independent(독립적으로)
각각의 테스트 케이스는 독립적이어야 한다는 의미이다.
일반적으로 테스트 케이스를 작성할 때, 클래스 단위로 해당 클래스 내의 메서드 동작을 테스트한다.
메서드는 여러 개 존재할 가능성이 높을테니 테스트 클래스 안에 테스트 케이스도 하나 이상이 될 것이다.
이 때, 어떤 테스트 케이스를 먼저 실행시켜도 실행되는 순서와 상관없이 정상적인 실행이 보장되어야 한다.
- Repeatable(반복 가능하도록)
테스트 케이스는 어떤 환경에서도 반복해서 실행이 가능해야 된다는 의미이다.
IDE 환경에서 실행을 하든, Gradle 같은 빌드 태스크에서 실행을 하든, 로컬 환경이나 서버 환경에서 실행하든 반복해서 같은 결과를 확인할 수 있어야 한다.
- Self-validating(셀프 검증이 되도록)
단위 테스트는 성공 또는 실패라는 자체 검증 결과를 보여주어야 한다는 의미이다.
- Timely(시기 적절하게)
테스트 하려는 기능 구현을 하기 직전에 작성해야 한다는 의미이다.
TDD(테스트 주도 개발) 개발 방식에서는 기능 구현 전에 실패하는 테스트 케이스를 먼저 작성하는 방식을 취하지만, 실제로 기능 구현도 되지 않은 상태에서 테스트 케이스부터 먼저 작성하는 것은 쉽지 않다.
다만, 기능 구현을 먼저 한다 하더라도 너무 많은 구현 코드가 작성된 상태에서 테스트 케이스를 작성하려면 너무 많은 시간을 들일 가능성이 있다.
구현하고자 하는 기능을 단계적으로 업그레이드하면서 그때 그대 테스트 케이스 역시 단계적으로 업그레이드하는 방식이 더 낫다고 할 수 있다.
Given-When-Then 표현 스타일
given - when - then
이라는 용어는 BDD(Behavior Driven Development)라는 테스트 방식에서 사용하는 용어이다.
단위 테스트에서 테스트 케이스의 가독성을 높이는 데 유용한 방법이다.
Given
- 테스트를 위한 준비 과정을 명시할 수 있다.
- 테스트에 필요한 전제 조건들이 포함된다고 할 수 있다.
- 테스트 대상에 전달되는 입력 값이 포함된다.
When
Then
- 테스트의 결과를 검증하는 영역이다.
- 일반적으로 예상하는 값(
expected
)과 테스트 대상 메서드의 동작 수행 결과(actual
) 값을 비교해서 기대한 대로 동작을 수행하는지 검증(Assertion)하는 코드들이 포함된다.
Assertion(어써션)
테스트 세계에서 Assertion(어써션)이라는 용어는 테스트 결과를 검증할 때 주로 사용한다.
테스트 케이스의 결과가 반드시 참(true)이어야 한다는 것을 논리적으로 표현한 것으로, '예상하는 결과 값이 참이길 바라는 것'이라고 할 수 있다.