글을 읽기에 앞서, 혹시나 수정이 필요한 부분이 있다면 지적해주시면 감사하겠습니다.
TDD?
Test Driven Development의 약자로 '테스트 주도 개발' 이라고 한다.
TDD가 테스트 주도 개발이라는 것은 알았으니, TDD의 본격적인 내용에 앞서 테스트의 종류와 단위 테스트의 중요성에 대해 알아보자.
1. 테스트의 종류?
1️⃣단위 테스트(Unit Test)
: 하나의 모듈을 기준으로 독립적으로 진행되는 가장 작은 단위의 테스트
여기서 말하는 모듈은 애플리케이션 내에 하나의 기능이나 메소드로 이해하면 된다
예시로 웹에서 로그인에 대한 독립 테스트가 하나의 단위 테스트로 볼 수 있는 것이다.
단위 테스트에서 테스트 대상의 크기는 엄격하게 정해져 있지는 않다. 일반적으로는 클래스나 메소드 수준으로 정해진다.
단위의 크기가 작을 수록 단위의 복잡성이 낮아지기 때문이다. 단위 테스트를 활용해 동작을 표현하기 쉬워지기에 테스트 단위의 크기를 작게 설정해 단위 테스트를 최대한 간단하고 디버깅하기 쉽게 작성해야한다.
SW를 개발할 때, SW 내부 구조, 구현 방법을 고려해 테스트 하기에 SW 내부 코드에 관련한 지식을 반드시 알고 있어야 하는 화이트박스 테스트이다. 단위 테스트는 TDD와 함께 사용하게 되면 더욱 효과적이다.
위에서 언급했던 화이트박스 테스트와 다른 테스트인 블랙박스 테스트에 대해 간략하게 설명하겠다. 화이트박스 테스트 : SW 나 제품의 내부 구조, 동작을 세밀하게 검사하는 테스트 방법으로, 외부에서 요구사항에 따른 예상 결과값을 테스트 하는 것과는 달리 내부 소스 코드를 테스트하는 것으로 사용자가 볼 수 없는 부분의 코드를 테스트하는 방법 블랙박스 테스트 : SW의 내부 구조나 작동 원리를 모르는 상태에서 SW의 동작을 검사하는 방법 |
또한 프로그래밍 언어별로 단위 테스트에서 사용하는 프레임워크가 다른데 Java에서는 주로 JUnit을 사용한다.
단위테스트에 대한 내용을 요약하자면, 단위테스트는 "어떤 기능을 테스트했을 때 어떤 결과가 나온다" 로 볼 수 있다.
2️⃣통합 테스트(Integration Test)
: 단위 테스트보다 큰 단위의 동작을 달성하기 위해 여러 모듈을 모아 기능들이 의도대로 협응하는지 확인하는 테스트
단위 테스트와 달리 개발자가 변경할 수 없는 부분까지 묶어 검증할 때 사용한다. DB에 접근하거나 전체 코드와 다양한 환경이 제대로 작동하는지 확인하는데 필요한 모든 작업을 수행하지만, 통합 테스트에서의 확인이 응용 프로그램의 완전한 작동을 무조건적으로 증명하지는 않는다.
통합 테스트의 장점은 단위 테스트에서 발견하기 어려운 버그를 찾을 수 있다는 점이다. 예를 들어, 통합 테스트에서는 환경 버그(ex. 싱글 코어 CPU에서는 잘 실행되나 쿼드 코어 CPU에서는 잘 실행되지 않음)이 발생할 수 있다.
단점은 장점의 반대되는 것들을 나열하면 된다. 단위 테스트보다 더 많은 코드를 테스트하기에 신뢰성이 떨어질 수 있으며, 에러 발생시 발생 위치가 확실하지 않아 유지보수가 힘들다는 것이 단점이다.
현재 내가 사용하고 있는 Spring에서는 클래스 상단에 @SpringBootTest 어노테이션을 붙임으로써 테스트를 수행할 수 있다.
3️⃣인수 테스트(Acceptance Test)
: 실제 사용자 환경에서 사용자의 입장으로 테스트를 수행하는 것
시스템 인수를 위해 기능적/비기능적 요구사항을 사용자가 직접 테스트해 개발의 완료를 증명하는 테스트이다.
단위 테스트와 통합 테스트와는 달리 비즈니스 쪽에 초점을 둔다.
즉, 에러를 잡는다기보단 고객의 니즈와 일치하는지 확인하기 위해 수행하는 것
기능을 테스트하며 완성도를 확인하여 확신을 얻을 수 있는 단계
개발자가 직접 시나리오를 제작할 수도 있으나, 다른 집단으로부터 시나리오를 인수받아 개발한다 는 의미가 더 강하다.
시나리오에서 요구하는 것은 누가, 어떤 목적으로, 무엇을 하는가 이며, 최종적으로 인수 테스트를 하는 목적은 SW 인수를 목적으로 하는 것이다.
Java에서는 RestAssured, MockMvc 같은 도구를 통해 인수 테스트를 작성할 수 있다.
2. 단위 테스트의 중요성과 좋은 테스트의 특징?
TDD는 반복 테스트를 통한 SW 방법론으로 작은 단위의 테스트 케이스를 작성해 이를 통과하는 코드를 추가하는 단계로 반복하여 구현한다. 짧은 개발 주기의 반복에 의존하는 개발 프로세스로, 애자일 방법론 중 하나인 extream Programming(XP)의 'Test - First' 개념에 기반을 둔 단순 설계를 중요시한다.
중요성 이전에 작성 이유에 대한 궁금증이 먼저 생길 수도 있다.
그렇다면 단위 테스트를 작성해야하는 이유에 대해 먼저 알아보자.
단위 테스트의 중요성
- 코드를 수정, 기능을 추가할 때 수시로 검증이 가능
- 리팩토링 시 안정성을 확보가능하다
- 개발 및 테스팅에 대한 시간, 비용을 절감 가능
좋은 테스트의 특징
- Fast : 테스트는 빠르게 동작하고, 자주 돌릴 수 있어야 한다
- Independent : 각각의 테스트는 독립적이며 서로 의존해서는 안된다
- Repeatable : 어느 환경에서도 반복 가능해야 한다
- Self-Validating : 테스트의 성공 또는 실패를 부울 값으로 결과를 내어 자체적으로 검증되게 한다
- Timely : 테스트는 적시에, 실제 코드 구현 직전에 구현해야 한다.
프로덕션 코드보다 테스트 코드를 먼저 작성해야한다.
(프로덕션 코드란, 프로그램을 구현하는 부분으로 사용자가 실제로 사용하는 소스 코드를 의미한다.)
😮테스트 코드를 먼저 작성해야 하는 이유
- 깔끔한 코드를 작성할 수 있다
- 장기적으로 개발 비용을 절감할 수 있다
- 개발이 끝나면 테스트 코드의 중요성이 줄어든다. 실패 케이스의 경우 더욱 그렇다
프로덕션 코드 작성 전에 테스트를 거치면 느리다는 느낌을 받을 수 있으나, 장기적으로 보면 개발 비용을 아낄 수 있다.
또한 프로덕션 코드를 우선적으로 작성하게 되면 이후에 테스트 코드를 작성하기가 매우 귀찮아진다.
특이 케이스가 아닌 이상 테스트 코드를 먼저 작성하는 것이 좋으며, 실패 테스트부터 작성해야한다. 순차적으로 실패하는 테스트를 우선 작성하며, 테스트가 실패할 경우에만 새로운 코드를 작성해야한다. 그 후 중복된 코드만 제거하면 되는 것이다.
🤔TDD는 어떤 상황에 해야할까?
해당 부분에 대한 코딩과 결과를 예상 가능하다면 TDD는 불필요하지만, 그 경우가 아니면 TDD가 필요하다.
다음과 같은 경우들이 TDD가 효과적인 경우들이다.
1. 처음해보는 프로그램 주제
- 본인에 대한 불확실성
2. 고객의 니즈가 바뀔 수 있는 프로젝트
- 외적인 불확실성이 높을 때
3. 개발 도중 코드를 많이 바꿔야 된다 예상되는 경우
4. 개발 후에 유지보수를 누가 할지 모르는 경우
- 외적인 불확실성이 높을 때 TDD를 하면 된다
TDD를 사용함으로써 피드백과 협력을 동시에 증진시킨다.
1. 피드백 - TDD를 통해 피드백이 증가한다. 이는 테스트 코드를 통해 GREEN/ RED를 자주 확인 가능하다
2. 협력(핵심)
test의 명사화
test는 보통 동사이다. " 테스트한다." , "테스트혀", "테스트하그라." 와 같이 말이다.
그런데 TDD를 사용하면 "test"는 명사가 된다. 동사는 그 순간에만 행하는 것이지만, 명사는 후에도 소유가 가능하기에 타인에게 테스트 코드를 보여주고, 코드를 직접 실행하게 할 수 있다.
🤔그럼 TDD를 행한다고 왜 협력이 증진될까?
다른 이들의 코드에 쉽게 접근이 가능해지고, 이해가 빨라지기에 코드에 내포된 의도를 파악할 수 있게 되는 것이다.
✔TDD 방식의 장점
튼튼한 객체 지향적인 코드 생산
- TDD는 코드의 재사용 보장을 명시하여 TDD를 통한 소프트웨어 개발시 기능 별로 모듈화가 이뤄진다.
이는 종속성과 의존성이 낮은 모듈로 조합된 SW 개발을 가능하게 하며 필요에 따라 모듈을 추가하거나 제거해도 SW 전체 구조에 영향을 미치지 않게 되는 것이다.
재설계 시간의 단축
- 테스트 코드의 작성이 우선시 되기에 개발자가 무엇을 해야하는지 확실히 정하고 개발을 시작한다.
또한 테스트 코드의 시나리오 작성을 통해 다양한 예외사항을 고려해볼 수 있다. 이를 통해 개발 진행 중 SW의 전반적인 설계가 변경되는 일을 방지할 수 있다.
디버깅 시간의 단축
- 유닛 테스팅을 하는 이점이기도 하다. 예로 사용자의 데이터가 잘못된 경우 DB의 문제인지, UI문제인지 등등 모든 레이어들을 전부 디버깅 해야하나, TDD의 경우 자동화 된 유닛테스팅이 전제하기에 쉽게 찾아낼 수 있다.
테스트 문서의 대체 가능
- 일반적으로 SI 프로젝트 진행 중에 어떤 요소들이 테스트 됐는지 테스트 정의서를 만든다.
보통은 단순 통합 테스트 문서에 지나지 않으나, TDD를 하게 될 경우 테스팅을 자동화 시킴과 동시에 보다 정확한 테스트 근거를 산출할 수 있게 된다.
추가 구현의 용이함
- 개발이 완료된 SW에 기능 추가시 이 기능의 추가로 인해 기존 코드에 문제가 생길까 우려하게 되지만, TDD를 통해 자동화된 유닛 테스팅이 전제되어 테스트 기간이 압도적으로 단축된다.
✔TDD 개발 방식의 단점
생산성의 저하가 제일 큰 단점이다. 쉽게 말해 느리다.
- 개발 속도가 느려진다. TDD 방식의 개발 시간은 개발 방식에 비해 대략 10~30% 늘어나기 때문이다.
그래서 SI 에서는 품질보다 납기일 준수가 중요해 TDD 방식이 지양된다고 한다.
TDD(Test-Driven Development, 테스트 주도 개발) 방법 및 순서
1. 실패하는 작은 단위 테스트를 작성한다. 처음에는 컴파일조차 되지 않을 수 있다.
2. 빨리 테스를 통과하기 위해 프로덕션 코드를 작성한다. 이를 위해 정답이 아닌 가짜 구현 등을 작성할 수 있다.
3. 그 다음의 테스트 코드를 작성한다. 실패 테스트가 없을 경우, 성공 테스트를 작성한다.
4. 새로운 테스트를 통과하기 위해 프로덕션 코드를 추가 또는 수정한다.
5. 1~4단계를 반복하여 실패/성공의 모든 테스트 케이스를 작성한다.
6. 개발된 코드들에 대해 모든 중복을 제거하며 리팩토링한다.
TDD 순서에 따라 개발을 진행하면 프로덕션 코드보다 테스트 코드를 우선 작성하게 된다.
Spring과 같은 프레임워크에 적용하는 것은 이와 다른 영역이기에, 이런 것을 ATDD(Application TDD)라고 부른다.
ATDD의 자세한 내용은 다음 글에서 다루도록 하겠다.
>> TDD 접근 방법
- 가짜 구현 : 최대한 빨리 테스트를 통과하기 위해 정답이 아닌 가짜 정답을 구현하는 방법
- 실패하는 테스트를 빠르게 구현하는 방법은 아무 값이나 반환하게 하는 것이다.
테스트를 통과하면 단계적으로 상수를 변수로 사용하도록 변형한다.
변수를 사용하지 않고 상수를 반환하며, 답이 아닌 방법으로 가짜 구현하여 최대한 빨리 테스트를 통과하도록 하는 것이 가짜 구현 방법이다. 가짜 구현을 통해 2가지 효과를 볼 수 있다.
- 심리학적 : 상태를 보고 그 위치부터 리팩토링한다
- 범위 조절 : 하나의 구체적인 예를 일반화하여, 불필요한 고민으로 혼동되는 일을 예방가능하다
- 실패하는 테스트를 빠르게 구현하는 방법은 아무 값이나 반환하게 하는 것이다.
- 삼각측량법 : 값이 다른 여러 테스트를 작성하고, 이를 일반화하여 정답을 구현하는 방법
- 테스트 주도로 추상화된 과정을 일반화하는 과정이다. 삼각 측량 방법은 테스트 예시가 2개 이상일 때에만 추상화해야한다.
- 명백한 구현 : 정답을 바로 구현하는 방법
- 가짜 구현이나 삼각 측량 방법 없이 바로 정답을 구현하는 방법
참고 자료 :
http://clipsoft.co.kr/wp/blog/tddtest-driven-development-%EB%B0%A9%EB%B2%95%EB%A1%A0/
https://hanamon.kr/tdd%EB%9E%80-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%A3%BC%EB%8F%84-%EA%B0%9C%EB%B0%9C/
https://mangkyu.tistory.com/182
https://tecoble.techcourse.co.kr/post/2021-05-25-unit-test-vs-integration-test-vs-acceptance-test/ .
'I LEARNED > 자료구조' 카테고리의 다른 글
[자료 구조] 프로세스 동기화 #1 critical section (0) | 2023.01.29 |
---|---|
[자료 구조] 교착상태 (0) | 2023.01.24 |
[자료구조] 객체 지향적 설계 원칙 (0) | 2023.01.19 |
[자료구조] 객체지향? 객체지향 프로그래밍? (0) | 2023.01.17 |
[자료 구조] 정규화(Normalization) (0) | 2022.08.18 |
댓글