1. TDD에 관한 조사
A. 테스트 주도 개발이란?
테스트 주도 개발(test-driven development, TDD)은 소프트웨어 개발 방법론 중의 하나로, 선 개발 후 테스트 방식이 아닌 선 테스트 후 개발 방식의 프로그래밍 방법을 말한다. 다시 말해 먼저 자동화된 테스트 코드를 작성한 후 테스트를 통과하기 위한 코드를 개발하는 방식의 개발 방식을 말한다.[1] TDD에서는 제품의 기능 구현을 위한 코드와 별개로, 해당 기능이 정상적으로 움직이는지 검증하기 위한 테스트 코드를 작성한다. 이를 통해 테스트가 실패할 경우, 테스트를 통과하기 위한 최소한으로 코드를 개선한다. 최종적으로 테스트에 성공한 코드를 리팩토링 하는 과정을 거친다.[2]TDD를 잘 사용하면, 전체 코드를 완성하기 전에 기능 단위로 문제를 개선할 수 있게끔 피드백이 오기 때문에, 버그를 보다 빠르고 효과적으로 개선할 수 있다.
B. TDD 개발의 장단점
TDD는 객체지향적인 코드 개발이 가능하다. TDD는 모듈테스트 기반으로 개발해 나가므로 각 기능별로 모듈화가 이루어진다. 각 테스트 코드를 작성하기 위해서 각 모듈들은 의존성과 종속성이 낮아지는 모듈로 구성되게 된다. TDD는 설계 수정시간 또한 단축된다. 테스트 코드를 먼저 작성하기 때문에, 최초의 설계안을 만족하게 되며, 입출력의 구조와 기능을 보다 명확하게 정의하게 된다. 이에 따라 계획하지 않았던 코드가 추가 되는 오버 엔지니어링을 방지한다. TDD는 테스트를 통과할 최소한의 기능만 요구하기 때문이다. 이렇게 단위 테스트 기반으로 테스트 코드를 작성하게 되면 리팩토링이 용이하다. 또한, 테스트 과정이 모두 남기때문에 테스트 문서를 대체할 수 있다는 장점이 있다.
C. TDD와 전통적인 테스팅의 차이
TDD와 전통적인 테스트 모두 테스트에서 하나이상의 결함을 찾아 문제를 발견한다는 점에서 동일하지만, TDD는 테스트가 제대로 작동하는지 확인하는 코드에 더 중점을 두게 되고, 기존의 테스트는 테스트 케이스 테스트가 정상적으로 작동하는지 안하는지에 관해서 테스트 케이스 디자인에 더 초점을 맞춘다. 또한, TDD는 모든 테스트를 달성해야 하고, 기존 테스트는 단일 코드별로 테스트가 진행된다는 점에서 차이가 있다.
D. TDD의 세가지 법칙
TDD를 만족하기 위해서는 다음 세가지 법칙을 만족해야 한다.
1. 실패한 단위 테스트를 통과하기 위한 경우를 제외하고는 코드를 작성해서는 안된다.
2. 실패할 때까지 충분한 테스트 코드를 작성해야 한다. 컴파일 오류도 실패이다.
3. 단위 테스트를 통과하기 위한 코드이외의 추가 코드는 작성해서 안된다.
E. TDD 개발 과정
TDD를 개발하기 위해서는 테스트를 만들고 그에 맞는 코드를 쓰기 위해서 반복해야 한다. 이를 간단하게 도식화 하여 나타내면 다음과 같다.
1. 테스트를 만든다.
2. 실패할때까지 모든 테스트를 실행한다.
3. 실패하면 코드를 작성한다.
4. 반복한다.
이러한 과정을 흔히 TDD 주기라고 부르며 세가지의 단계로 나눈다. Red는 테스트 실패를 의미하고, Green은 테스트 성공, Refactor은 리팩토링이라고 부른다.
Red의 경우 테스트 실패를 의미한다. TDD에서는 실패하는 것이 확인 되어야, 테스트가 검증력을 가진다고 신뢰할 수 있다. 실패의 이유는 아직 코드가 변경되지 않았기 때문이다. 이때는 구체적인 하나의 요구사항을 검증하는 하나의 테스트를 추가하고 추가된 테스트가 실패하는지 확인한다. Green의 경우 테스트 성공을 의미한다. TDD에서 추가된 테스트를 포함하여 모든 테스트가 성공하게끔 운영코드를 변경한다. 테스트 성공은 모든 요구사항 만족을 의미한다. 테스트를 성공하기 위한 코드만 작성하여 오버엔지니어링을 방지한다. Refactor의 경우 코드 베이스를 정리하고 인터페이스 뒤에 숨어있는 구현 설계를 개선하게 된다. 또한, 가독성, 적용성, 성능등을 고려하여 코드를 수정한다. 세부흐름으로 보면 아래와 같다.[3]
[TDD의 상세 흐름]
F. TDD 테스트 기법
i. 수동 테스트
회사에서는 보통 QA라고 부르는 전문 담당자들이 UI를 활용해 기능을 검증한다. 사람이 검증하기 때문에, 사용자와 가장 가까운 관점에서 테스트가 가능하며, 단위 테스트 보다는 전체 코드를 검증할때 주로 이용된다. 하지만, 비용이 높고 결과 변동이 크다.
ii. 테스트 자동화
사람이 직접 테스트 하지 않고, 기능을 검증하는 코드를 작성하여 이용하는 방식이다. 실행비용이 낮고 결과의 신뢰도가 높다. 하지만, 테스트 코드를 작성하는 프로그래머의 역량에 따라 신뢰도가 달라진다.
iii.단위 테스트
하위 시스템을 대상으로 기능을 검증하는 테스트이다. 일반적으로 클래스 또는 메소드, 함수 수준으로 정해진다. 전체 시스템을 배치해놓고 진행하지 않으므로, 비용이 상대적으로 낮은 편이다. 단위 안에서 버그가 있다는 걸 상대적으로 자세히 알 수 있다. 따라서 프로그래머 입장에서는 문제 해결을 위해 필요한 피드백을 적절하게 받을 수 있다. 하지만 전체 시스템의 이상 여부를 판단하는 신뢰도는 낮아진다.
iv.통합 테스트
단위 테스트와 달리 외부 라이브러리와 같이 개발자가 변경할 수 없는 부분까지 묶어 검증할 때 사용한다. 이는 DB에 접근하거나 전체 코드와 다양한 환경이 제대로 작동하는지 확인하는데 필요한 모든 작업을 수행할 수 있다. 단위 테스트보다 테스트 단위가 커지므로 어디서 에러가 발생했는 지 확인하기는 어렵다.
v.인수 테스트
인수 테스트는 비즈니스 관점에서의 테스트이다. 배치된 시스템을 대상으로 검증하는 방식으로, 주로 클라이언트가 의뢰한 소프트웨어를 최종적으로 사용할 수 있는 수준인지 점검하는 테스트이다. 전체 시스템의 이상 여부가 없는지 확인하며, 사용자 관점으로 체크하기 때문에 신뢰도가 높은 테스트 방법이다. 하지만, 비용이 높고 개발자 입장에서 피드백을 받기 어렵다.[4]
G.TDD 활용 툴
xUnit이름 | 해당 언어 | 관련 사이트 |
CUnit | C | http://cunit.sourceforge.net/ |
CppUnit | C++ | https://sourceforge.net/projects/cppunit/ |
PyUnit | Python | http://pyunit.sourceforge.net/ |
JUnit | Java | http://junit.org/ |
H.TDD는 옳은가?
2014년 Ruby on Rails의 개발자로 유명한 David Heinemeier Hansson는 ‘TDD is dead. Long live testing.' 관한 논쟁이 제기되었다. 주요 쟁점을 정리해보면, TDD가 설계를 망친다는 것이다. 테스트를 먼저 작성하고 코드를 작성하는 것은 시간에 쫓기는 개발자에게, 단순히 유닛 테스트를 통과하기 쉬운 설계를 하게 만든다. Mock이란 TDD에서 비용과 시간이 많이 들거나 의존성이 높아 실제 객체를 만들기 어려울떄 사용하는 가상 객체이다. 또한, TDD에서 유닛 테스트만 너무 강조되는 나머지, mock에만 의존한, 형식적인 테스트로 이용된다는 것이다. 유닛테스트 외에도 통합 테스트나 시스템 테스트가 필요하다고 이야기 한다.
I. TDD와 BDD
BDD는 "Behaviour Driven Development" 이다. BDD는 시나리오를 기반으로 테스트 케이스를 작성하며 함수 단위 테스트를 권장하지 않는다. 이 시나리오는 개발자가 아닌 사람이 봐도 이해할 수 있을 정도의 레벨을 권장한다.[6] 두 방식의 차이를 간단하게 표로 정리하면 다음과 같다.
구분 | TDD(테스트 주도 개발) | BDD(행동 주도 개발) |
중점 | 소프트웨어 기능이 어떻게 작동해야 하는지에 대한 개발자의 의견에 중점 | 애플리케이션이 어떻게 작동하기를 원하는지에 대한 사용자의 의견에 중점 |
관점 | 프로그래머의 관점 | 고객의 관점 |
접근 | 저수준 접근 | 고수준 접근(사용자 접근 방식) |
확인사항 | 기능 구현이 올바른지 확인 | 원하는 방식으로 작동하는지 확인 |
J. TDD에 관한 고찰
TDD 방법론에 대해서 반대하는 입장에서는 검증하기 위해 테스트 코드를 짰는데, 테스트 코드를 검증하는 테스트 코드는 필요하지 않느냐의 순환 논리를 지적한다. 테스트도 사람이 만드는 것이기에 다양한 환경에서의 아웃풋은 모두 동일하지 않을 것이다. 하지만 TDD를 이용하게 되면, 전체 코드를 완성하기 전에 기능 단위로 문제를 개선할 수 있게끔 빠른 피드백을 받을 수 있어, 특정상황에서는 좋은 전략이 될 수 있을 것이라 생각한다.
참고자료
[1]'http://www.incodom.kr/%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%A3%BC%EB%8F%84_%EA%B0%9C%EB%B0%9C?openLinerExtension=true’ 2021. 10. 11. 확인함
[2] ‘https://media.fastcampus.co.kr/knowledge/dev/tdd/?openLinerExtension=true’ 2021. 10. 11. 확인함
[3] ‘https://fastcampus.co.kr/story_article_tdd’ 2021. 10. 11. 확인함
[4] ‘https://fastcampus.co.kr/story_article_tdd’ 2021. 10. 11. 확인함
[5] ‘https://nesoy.github.io/articles/2017-02/JUnit#3-junit-function-flow’ 2021. 10. 11. 확인함
[6] ‘https://www.popit.kr/bdd-behaviour-driven-development에-대한-간략한-정리/’ 2021. 10. 11. 확인함
'Computer Science > Software Engineering' 카테고리의 다른 글
MDE, MBD: Model-Based Development)의 사례 및 지원도구 (1) | 2021.12.26 |
---|---|
ISO/IEC 9126-1 - Software Product Quality 표준 (1) | 2021.12.26 |
Cunit Test Code 작성하기 (0) | 2021.12.26 |
C Unit Test Automation(Framework) - TDD (1) | 2021.12.26 |
CMMI와 유사한 국내외 평가모델-SP인증 (1) | 2021.12.26 |