[TDD] 테스트 주도 개발
in Development on Server, Tdd, 개념
“해당 포스팅은 드림코딩의 테스트 코드와 TDD 🧪(feat. 프론트엔드, 백엔드를 위한 테스트 코드)을 참고하여 포스팅하였습니다. 영상을 제작해주신 드림코딩의 엘리님에게 감사드립니다.”
#목차
TDD(Test-Driven Development)
Test란?
- 개발자들이 말하는 테스트란?
- 소프트웨어 테스트를 말하며, 애플리케이션 제품이나, 서비스의 품질을 확인하고, 버그들을 찾는데 사용하고 있다.
- 한마디로 소프트웨어 테스트란, 제품이 원하는 데로 동작하는지 확인하는 것과 애플리케이션이 우리가 원하는 데로 동작하는지 검증하고 확인하는 것이다.
- 여기서 제품이란, 우리의 메서드, 기능, UI, 성능, API 스펙이 우리가 원하는 데로 동작하는지 확인하는 것이다.
Software Test란?
- 우리의 목표가 무엇이냐에 따라서, 우리의 플랫폼과, 환경이 무엇이냐의 따라서 다양한 테스트가 있다.
- 많은 개발자들이 정말 많이 사용하는
Unit Test
부터Functional Test
,Integration Test
,Component Test
,Contract Test
,E2E Test
,Performance Test
등등 정말 많은 테스트가 있다. - 우리가 뭘 원하느냐, 어떤 걸 확인하고 싶냐에 따라 다양한 테스트들이 있지만 이 테스트들의 프로세스는 딱 하나로 정의할 수 있다.
Software Test Process
- 특정한 기능을 수행하는 비즈니스 로직을 가지고 있는 소스코드가 있다면, 그에 해당하는 테스트 코드를 작성한다.
- 이때, 이 테스트 코드는 우리의 코드가 우리가 예상하고 원하는 요구사항에 맞는지 확인할 수 있어야 한다.
API 스펙
,Query
,메서드
,특정한 기능
,성능
,UI
등이 어떻게 돼야 하는지 이러한 정의에 따라서 다양한 테스트 프레임워크나 라이브러리를 사용할 수 있다.- 이렇게 특정한 상황에 우리가 원하는 데로, 예상한 데로 동작하는 것을 검증하는 테스트 코드를 작성해두었다면 이 테스트 코드를 수행해서 모든 테스트가 성공하는지 확인해야 한다.
- 만약 테스트가 실패하게 된다면 우리 코드가 어떤 부분이 잘못되었는지 확인하고 수정해야 한다.
- 테스트가 다시 통과할 때까지 이 부분(
pass
)을 계속 반복해 줘야 한다. - 여기서 테스트의 포인트는 우리가 예상하는 요구사항에 맞게 우리 코드가 동작하는지 검증하는 것이다.
- 많은 개발자들과 기업들이 TDD 방법론을 중요시하는 곳이 굉장히 많은 것을 볼 수 있다.
- 그렇다면 TDD란 과연 무엇일까?
TDD(Test-Driven Development)란?
Test-Driven Development
의 약자이며, 테스트 주도 개발이라 한다.- 조금 풀어서 얘기하면 개발하기 전에 즉, 코드를 작성하기 전에 테스트 코드를 먼저 작성하는 방식. 이렇게 개발하는 방식을 TDD라고 한다.
- TDD는 특정한 기술 프레임워크나 라이브러리를 말하는 것이 아니라 우리가 어떻게 개발해 나갈 것인가를 정의하는 개발 방식, 개발 방법론 중에 하나이다.
TDD전 기존 개발 프로세스
- TDD를 적용하기 전 개발 프로세스는 설계 및 디자인 -> 코드 개발 -> 해당 코드를 테스트 실행하게 된다.
- 테스트를 진행 후 버그나 또는 변경사항이 발견된다거나 하게되면 다시 코드를 수정한다거나, 수정된 설계를 통해 다시 개발 코드를 수정하게 된다. 좀더 세분화해서 보자면..
- 코드를 작성하고
- 프로그램(Tomcat)을 실행한 뒤
- Postman과 같은 API 테스트 도구로 HTTP 요청을 하고
- 요청 결과를
System.out.println()
또는log.debug()
로 눈으로 검증하게 된다. - 결과가 다르다면 다시 프로그램(Tomcat)을 중지하고 코드를 수정하게 된다.
- 만약 수정할 코드들이 있다면 2 ~ 5번의 작업을 반복적으로 계속 수행해야 한다.
- 또한 테스트를 실행하려면 프로그램(Tomcat)을 켜는데 시간도 상당히 소모되게 된다.
TDD Process
- 코드를 작성하기 전에 특정한 기능에 한에서, 기능도 조금 더 세분화해서 딱 하나의 케이스에 대해서 테스트 코드를 먼저 작성한다.
- 그리고 테스트를 실행하는데 당연히 실패하게 된다. 왜냐하면 기능을 구현하지 않았기 때문이다.
- 그래서 이 실패한 테스트가 성공할 정도의 조금의 양만, 딱 그만큼의 기능만 하는 코드를 작성해서 다시 테스트를 진행한다.
- 작성한 테스트를 성공하게 만든다.
- 이렇게 하나의 테스트가 완성이 되면 이제 그다음 기능으로 넘어가서, 그 기능에 해당하는 테스트를 작성하고, 테스트를 수행해서 실패하면 이 실패한 코드가 성공할 수 있을 만큼의 코드만 작성해서 다시 테스트를 수행해서 성공하면 다시 그다음의 테스트를 진행한다.
- 이렇게 테스트 코드를 조금 작성하고, 기능을 조금 구현하고 다시 테스트 코드를 조금 작성하고, 기능을 조금 구현하고 이런 식으로 개발해 나가는 것을 TDD라고 한다.
- 이렇게 TDD 방법을 이용해서 모든 기능이 다 구현이 완료되었다면 그동안 작성해왔던 테스트 코드들이 성공적으로 통과되어야 한다.
- 여기까지는 기능을 구현하는데 만 조금 더 집중해서 빠르게 코드를 작성했다면…
TDD(Test-Driven Development) Refactoring
- 이제 작성해둔 테스트 코드들을 기반으로 해서 조금 더 자신감 있게 코드에 퀄리티를 향상하고, 아키텍처를 개선하고, 리팩토링을 해나갈 수 있다.
- 이렇게 실패하는 테스트 코드를 먼저 작성하고, 그에 해당하는 기능을 구현해나가는 방식 이것이 TDD인데…
오히려 코드량이 늘어나고 처리할 작업들이 많아지는데 왜 TDD를 지향해야 할까?
- 그렇다면 오히려 코드량이 늘어나고 처리해야할 작업들이 더 많아질텐데 왜 많은 사람들이 TDD… TDD… 하는 것일까?
TDD의 장점
- 작성하고자 하는 모든 요구사항에 대한 철저한 분석과 명확한 이해가 필요하기 때문이다.
- 명확한 요구 사항을 기반으로 해서 설계자의 관점에서 코드를 작성해 나갈 수 있기 때문이다.
- 그래서 TDD를 이용하면 우리가 원하는 모든 요구 사항(목표)에 대해서 점검할 수 있다.
- 또한, 사용자 입장에서 코드를 작성할 수 있다.
- 이를 기반으로 테스트 코드에서 이런 식으로 우리 코드를 사용하면 되겠구나.. 라고 생각하게 되는데 조금 더 개발자스럽게 얘기해 보자면..
- 구현보다는 인터페이스에 조금 더 집중해서 코드를 작성해 나갈 수 있다. =>
구현 < 인터페이스 -> 코드의 퀄리티 향상
- 이렇게 작성하면 당연히 코드의 퀄리티가 향상이 되고, 시스템 전반적인 설계를 향상할 수 있다.
- 그리고 실패한 테스트 -> 기능구현, 실패한 테스트 -> 기능구현 이렇게 지속적으로 개발을 게임하듯이 해나갈 수 있기 때문에 개발 집중력도 향상할 수 있다.
결론
- 무조건 TDD가 옳은 건 아니다. 하지만 개발에 있어 장점이 굉장히 많다.
- 위 내용은 TDD에 관해 주로 장점을 설명하였다. 하지만 아래는 무조건 TDD를 사용하자! 가 아닌 적절하게, 꼭 필요한 곳에서 TDD를 사용해야 한다는 내용이다.
- 아래는 포프TV - 효율적인 테스트 코드 작성법을 잘 요약한 설명이니 위 내용과의 차이점을 느끼고 생각해 보는 계기가 되었으면 한다.
효율적인 테스트 코드 작성법 - 요약
- 소프트웨어 개발, 테스팅 또한 경제적인 활동이다. 자원(시간, 인력)을 적게 투입하여 최대한의 효용을 뽑아내어야 한다.
- 코드에 따라 유닛 테스트는 필요할 때도 있고 필요하지 않을 때도 있다. 유닛 테스트가 필요한 경우는 다음과 같다.
- 알고리즘이 매우 복잡하지만 수학적으로 잘 정의된 경우, 구현 상의 명백한 버그를 없애기 위해 필요하다.
- 제품이 실제로 사용되고 발전하면서 자꾸 변하거나 가정이 틀리는 부분의 버그를 없애기 위해 필요하다.
- 1에서는 TDD가 어느 정도 유용할 수 있으나 2에서는 쓸모가 없다. 코드의 어떤 부분이 변경될지 예측하는 것은 어렵기 때문이다.
- 1은 애초에 안 변하고, TDD 방식으로 모든 코드에 대해 테스트를 짤 경우, 특히 2에서 코드를 변경해야 하는데 테스트가 발목을 잡는다.
- 그러므로 (포프는) 제품 코드 전에 테스트 코드를 짜자는 TDD 방식을 쓰지 않는다.
- 일단 코드를 그냥 짜고, 실제로 버그가 일어나고 가정이 틀리는 시점에서 그에 대한 테스트 코드를 작성한다