최근 애플리케이션을 개발할 때 테스트 코드로 로직을 확인하는 과정이 점점 더 중요하게 여겨지고 있다. 많은 개발자들이 테스트 코드를 더 잘 작성하고 활용할 수 있는 방법에 대해 고민했고, 그 결과 *애자일 방법론 중 하나인 테스트 주도 개발(TDD; Test-Driven Development)도 등장했다.
애자일 방법론: 애자일(Agile)은 ‘기민한, 민첩한’이라는 뜻으로 일정한 주기를 가지고 빠르게 제품을 출시하여 고객의 요구사항, 변화된 환경에 맞게 요구를 더 하고 수정해나가는 탄력적인 방법론을 말한다.
개발 단계에서 테스트 코드를 작성하는 이유 중 대표적으로는 다음과 같은 이유가 있다.
테스트 코드를 작성할 때에는 애플리케이션을 사용하면서 발생할 수 있는 여러 상황에 맞춰 작성해야 한다. 일부러 오류가 발생할 수 있는 테스트 코드를 작성해서 예외 처리가 잘 작동하는지를 확인하거나, 정확히 의도한 코드를 작성해서 결괏값이 잘 나오는지 검토하는 등 여러 테스트 코드를 통해 애플리케이션 코드를 검증해야 한다.
또한 일반적으로 애플리케이션이 개발되면 거기에서 멈추지 않고 서비스 업데이트를 하며 코드를 추가하고 수정하는데, 이것은 다른 코드에 영향을 주는 작업이기에 혹시 모를 부작용 방지를 위해 테스트 코드를 작성하고 실행해야 한다.
마지막 이유로는 타 개발자들과의 소통때문이다. 개발자들은 대부분 협업을 통해 프로젝트를 진행한다. 다른 사람이 작성한 코드를 바로 이해한다는 건 쉽지 않다. 이때, 동작 검증을 위해 작성된 테스트 코드를 애플리케이션 코드와 비교하면서 보면 작성자의 의도가 파악되어 동료의 코드를 이해하기가 쉬워진다.
테스트 방법은 여러 기준으로 분류할 수 있지만, 그 중 테스트 대상 범위를 기준으로 구분하면 단위 테스트(Unit Test)와 통합 테스트(Integration Test)로 구분된다.
☝️ V 모델(V-model)에서의 확인(Validation) 단계
단위 테스트는 가장 작은 단위의 테스트 방식이다. 일반적으로 메서드 단위로 테스트를 수행하게 되며, 메서드 호출을 통해 의도한 결괏값이 나오는지 확인하는 수준으로 진행한다. 단위 테스트는 *테스트 비용이 적게 들기 때문에 테스트 피드백을 빠르게 받을 수 있다.
통합 테스트는 모듈을 통합하는 과정에서의 호환성 등을 포함해 애플리케이션이 정상적으로 동작하는지 확인하기 위해 수행하는 테스트 방식이다. 테스트를 수행할 때마다 모든 컴포넌트가 동작해야 하기 때문에 테스트 비용이 커지는 단점이 있다.
테스트 유형 | 설명 | 테스트 범위 |
---|---|---|
단위 테스트 | 모듈을 독립적으로 테스트 | 특정 모듈에 대한 테스트만 진행 (DB, 네트워크 같은 외부 요인 제외) |
통합 테스트 | 여러 모듈을 함께 테스트 | 외부 요인들을 포함해 애플리케이션이 온전히 동작하는지를 확인 |
Tip 테스트 비용이란?
테스트 비용이란 용어는 소프트웨어 공학에서 많이 사용된다. 여기서의 비용은 금전적인 비용을 포함해 시간, 인력과 같은 개발에 필요한 것들을 포괄한다.
테스트 코드를 작성하는 방법은 다양하다. 여기서는 그중 많은 사람들이 사용하는 'Given-When-Then' 패턴과 'F.I.R.S.T' 전략을 소개한다.
Given-When-Then 패턴은 테스트 코드를 표현하는 방식 중 하나이다. 단어에서 유추할 수 있듯이 다음과 같은 단계를 설정해서 각 단계의 목적에 맞게 코드를 작성한다.
Given-When-Then 패턴은 테스트 주도 개발에서 파생된 BDD(Behavior-Driven-Development; 행위 주도 개발)을 통해 탄생한 테스트 접근 방식이다. 일반적으로 단위 테스트보다는 비교적 많은 환경을 포함해서 테스트하는 인수 테스트에서 사용하는 것이 적합하다고 알려져 있지만 단위 테스트에서도 유용하게 활용할 수 있다.
이 패턴은 간단한 테스트로 여겨지는 단위 테스트에서는 잘 사용하지 않는다. 그 이유 중 하나는 불필요하게 코드가 길어진다는 것이다. 하지만 이 패턴을 통해 테스트 코드를 작성한다면 '명세' 문서의 역할을 수행하는 측면에서 많은 도움이 된다.
F.I.R.S.T는 테스트 코드를 작성하는 데 도움이 될 수 있는 5가지 규칙을 의미한다. 이 규칙은 대체로 단위 테스트에 적용할 수 있는 규칙이며 간단하게 설명하면 다음과 같다.
테스트는 빠르게 수행되어야 한다. 테스트가 느리면 코드를 개선하는 작업이 느려져 코드 품질이 떨어질 수 있다. 테스트 속도에 절대적인 기준은 없지만 목적을 단순하게 설정해서 작성하거나 외부 환경을 사용하지 않는 단위 테스트를 작성하는 것 등을 빠른 테스트라고 할 수 있다.
하나의 테스트 코드는 목적으로 여기는 하나의 대상에 대해서만 수행되어야 한다. 만약 하나의 테스트가 다른 테스트 코드와 상호작용하거나 관리할 수 없는 외부 소스를 사용하게 되면 외부 요인으로 인해 테스트가 수행되지 않을 수 있다.
테스트는 어떤 환경에서도 반복 가능하도록 작성해야 한다. 이 의미는 앞의 Isolated 규칙과 비슷한 의미를 갖고 있다. 테스트는 개발 환경의 변화나 네트워크의 연결 여부와 상관없이 수행되어야 한다.
테스트는 그 자체만으로도 테스트의 검증이 완료되어야 한다. 테스트가 성공했는지 실패했는지 확인할 수 있는 코드를 함께 작성해야 한다. 만약 결괏값과 기댓값을 비교하는 작업을 개발자가 직접 확인한다면 좋지 않은 테스트 코드이다.
테스트 코드는 테스트하려는 애플리케이션 코드를 구현하기 전에 완성되어야 한다. 너무 늦게 작성된 테스트 코드는 정상적인 역할을 수행하기 어려울 수 있다. 또한 테스트 코드로 인해 발견된 문제를 해결하기 위해 소모되는 개발 비용도 커지기 쉽다. 다만, 테스트 주도 개발 기반인 애플리케이션이 아니라면 제외하고 진행하기도 한다.