단위 테스트에서 단위는 무엇인가?
단위 테스트는 일반적으로 고립된 코드 단위를 테스트하는 것이다. 코립된 코드 단위는 순수함수, 순수함수 안에서 사용할 수 있는 클래스와 비순수함수이다.
마틴 파울러의 리팩토링 책에 보면 첫 예제에서 use case 하나에 대해서만 테스트를 만들고 리팩토링을 하는 것을 볼 수 있다. use case는 외부에서 도메인을 사용하는 유일한 길이기 때문에 테스트 단위가 되어야 한다. TDD(test driven development)에서 낮은 수준의 함수나 메소드을 테스트 하는 대신 use case 만을 테스트 하는 것이 BDD(behavior driven development)이다. use case에서 공유 의존을 사용하는 경우 공유 의존을 대체하여 단위 테스트를 하기 위해 인터페이스를 추가하고 외부 test double로 대체해서 테스트를 한다. 여기에서의 인터페이스는 일반적인 인터페이스를 뜻하는 것으로 특정 언어에서의 인터페이스 뿐만 아니라 함수 시그니처도 포함한다. 외부 의존은 공유 의존의 일부로 내가 통제할 수 있는 코드 밖에 있는 것으로 운영체제, 파일, 데이터베이스, 네트워크, UI, 키보드, 마우스 입력, 프레임워크, 라이브러리 등이다. use case 일부를 순수함수로 뽑아내어 테스트 할 수도 있다.
정리하자면 테스트 하는 코드 단위는
- 공유 의존이 없거나 공유 의존을 인터페이스와 test double로 대체한 use case
- 순수함수
- 순수함수 안에서 사용할 수 있는 클래스
- 순수함수 안에서 사용할 수 있는 비순수함수 이다.
private 메소드는 테스트에 사용하면 안 된다. public 메소드를 통해 간접적으로 테스트를 해야 한다. 또는 design by contracts를 이용하는 방법도 있다.
일반적으로 use case는 데이터베이스를 사용하는 경우가 많기 때문에 외부 의존이 있다. 예를 들어 자료구조 라이브러리 같은 것을 만드는 경우 use case는 각 자료구조의 모듈 또는 클래스이기 때문에 프로그래밍 언어만으로 구현이 가능해서 외부 의존이 없다.
use case에 있는 외부 의존을 반드시 test double로 대체할 필요는 없다. 테스트를 할 수 있고 테스트가 충분히 빠르다면 외부 의존을 그대로 사용해도 된다. 인터넷이 안 되는 배나 비행기 또는 오지에서 코드를 만들 때에는 test double이 필요할 수도 있다. 단위 테스트가 아닌 통합 테스트가 되지만 그런 구분은 테스트가 빠르다면 아무 의미가 없다. 테스트의 결과를 즉시 볼 수 있기 때문에 빠른 개발 사이클을 돌릴 수 있기 때문이다. 데이터베이스의 경우 mock이나 stub를 만드는 것 보다 DBMS에서 제공하는 테스트용 메인 메모리 데이터베이스를 이용한 fake를 사용하는게 원래의 데이터베이스에 가까운 테스트가 가능하기 때문에 테스트가 충분히 빠르다면 fake를 사용한다.