본문 바로가기
Study/Server 심화

1주차: TDD와 테스트 코드(1)

by jisu-jeong0 2024. 4. 2.

테스트 코드?

    단위 테스트

    통합 테스트

좋은 테스트의 특징

TDD?

TDD를 사용해야 하는 이유

TDD 작성 방법

TDD의 장점

 

1️⃣ 테스트 코드?

: 소프트웨어의 기능과 동작을 테스트하는데 사용되는 코드

 

 

📌 일반적으로 개발자는 단위 테스트와 통합 테스트를 주로 다룸.

 

  • 단위 테스트(Unit Test) : 개별적인 코드 단위(함수, 메소드)가 의도한 대로 작동하는지 확인하는 과정. 테스트 케이스를 작성하여 각각의 코드 단위가 정확한 입력값과 출력값을 반환하는지 확인한다.
    • given-when-then 패턴
💡 given-when-then 패턴?
: 1개의 단위 테스트를 3가지 단계로 나누어 처리하는 패턴으로, 각각의 단계는 다음을 의미한다.

given(준비): 어떠한 데이터가 준비되었을 때
when(실행): 어떠한 함수를 실행하면
then(검증): 어떠한 결과가 나와야 한다.
verify 단계도 사용하는 경우가 있는데, 메소드의 호출 횟수가 중요한 테스트에서만 선택적으로 사용
💡 단위 테스트의 중요성

1. 개발 및 테스팅에 대한 시간과 비용 절감
2. 코드 변경 시 빠르게 검증 가능
3. 리팩토링 시 안정성 확보
4. 코드의 문서화

 

  • 통합 테스트(Integration Test) : 서로 다른 모듈 간의 상호작용을 테스트하는 과정. 통합된 모듈들이 올바르게 연계되어 동작하는지 검증한다.

 

2️⃣ 좋은 테스트의 특징

FIRST
  1. Fast: 테스트는 빠르게 동작하여 자주 돌릴 수 있어야 한다.
  2. Independent: 각각의 테스트는 독립적이며 서로 의존해서는 안된다.
  3. Repeatable: 어느 환경에서도 반복 가능해야 한다.
  4. Self-Validating: 테스트는 성공 또는 실패로 boolean 값으로 결과를 내어 자체적으로 검증되어야 한다.
  5. Timely: 테스트는 적시에 즉, 테스트하려는 실제 코드를 구현하기 직전에 구현해야 한다.
빠르게 독립적으로 어느 환경에서든 실행이 가능하고 검증할 수 있어야 한다

 

 

3️⃣ TDD?

💡 TDD란?
테스트 주도 개발(test-driven development, TDD)은 소프트웨어 개발 방법론
중의 하나로, 

선 개발 후 테스트 방식이 아닌 선 테스트 후 개발 방식의 프로그래밍 방법

 

4️⃣ TDD를 사용해야 하는 이유

  • 깔끔한 코드를 작성할 수 있다.
  • 장기적으로 개발 비용을 절감할 수 있다.
  • 개발이 끝나면 테스트 코드를 작성하는 것이 귀찮다.
TDD의 개발 단계에는 리팩토링이 있다. (하단 참고)

리팩토링 과정을 거치면서 중복된 코드들은 제거되고, 복잡한 코드들은 깔끔하게 정리하게 된다. 
테스트를 처음 작성할 때에는 귀찮고 개발을 느리게 한다는 느낌을 받을 수 있지만
장기적으로 보면 반드시 개발 비용을 아껴줄 것이다.

출처: https://mangkyu.tistory.com/182 [MangKyu's Diary:티스토리]

 

5️⃣ TDD 작성 방법

Red : 실패하는 테스트 코드를 먼저 작성한다. 
Green : 테스트 코드를 성공시키기 위한 실제 코드를 작성한다.
Blue : 중복 코드 제거, 일반화 등의 리팩토링을 수행한다.
💡 TDD 접근 방법

1️⃣ 가짜로 구현하기
변수를 사용하지 않고 상수를 반환하며, 답이 아닌 방법으로 가짜 구현하여 최대한 빨리 테스트를 통과하는 것이 가짜 구현 방법이다. 가짜 구현으로 연습을 많이 해두면, 복잡한 코드일 경우에 단계를 잘게 쪼개서 TDD로 문제없이 개발하는 능력을 갖출 수 있다. 

2️⃣ 삼각측량법
삼각 측량은 테스트 주도로 추상화된 과정을 일반화하는 과정이다. 삼각 측량 방법은 테스트 예시가 2개 이상일 때에만 추상화를 해야 한다. 

3️⃣ 명백하게 구현하기
다른 방법을 사용하지 않고 바로 정답을 구현하는 방법이다.

 

1. 테스트 케이스 작성: 만들고 싶은 기능을 점검할 테스트 코드를 작성한다. 이때, 아직 기능 코드를 구현하지 않았으므로 테스트 결과는 실패로 반환된다. 

2. 테스트 케이스를 통과하는 코드 작성: 테스트 코드를 만족시킬 수 있는 기능을 구현한다. 테스트 통과를 최우선으로 생각하며 작업한다. 즉, 단위 테스트를 통과할 수 있을 정도의 최소한의 코드만 작성한다.

3. 작성한 코드 리팩토링: 기능의 성능이 향상되며, 재사용성이 좋고, 가독성이 좋은 코드로 기능 코드를 개선한다. 테스트 코드를 통해 다시 기능 코드를 점검한다. → 기능 테스트가 완전해질 때까지 2, 3의 과정을 반복한다.

🔥 Spring에서의 TDD 프로그래밍 방법
Repository -> Service -> Controller 순서로 개발을 진행한다. Repository 계층의 테스트는 H2와 같은 인메모리 데이터베이스 기반의 통합 테스트로 진행한다. Service 계층의 테스트는 Mockito를 사용해 Repository 계층을 Mock하여 진행한다. Controller 계층의 테스트는 SpringTest의 MockMvc를 사용해 진행한다.  

참고: Controller -> Service -> Repository 순서로 TDD 개발을 하는 경우도 있으나, Repository 계층은 다른 계층에 대한 의존성이 거의 없기 때문에 먼저 작성하기가 편리함.
🔥 JUnit?
: 가장 널리 사용되는 JAVA 단위 프레임워크

 


#️⃣ ATDD와 BDD?

더보기
ATDD(Acceptance Test Driven Develpment)

: 인수 테스트를 먼저 작성한 다음 기능 개발을 하는 개발 방법론

💡 인수 테스트?
: 클라이언트가 제품을 인수하기 전, 명세나 계약의 요구사항이 모두 충족되었는지 확인하기 위해 수행되는 테스트
마지막 단계에서 수행되는 테스트를 의미하며, 이 테스트가 성공한다면 작업이 끝났다는 것을 의미하기도 한다.

ATDD는 다음과 같이 정의할 수 있다.

▪ 개발 이전에 사용자, 테스터 및 개발자가 인수조건(Acceptance Creteria)을 정의하는 협업 실천법
▪ 모든 프로젝트 구성원이 수행해야 할 작업과 요구사항을 정확히 이해할수 있도록 도와줌
▪ 테스트는 비지니스 도메인 용어로 기술됩니다.
▪ 인수 테스트(Acceptance Test)의 요구사항을 작성하는 데에 집중(인수 테스트 주도 개발)

 

BDD(Behavioral Deiven Development)

: 사용자의 행위를 미리 예상하고 결과를 테스트 해보는 행위 주도 방법론

코드를 작성하기 전에 코드가 수행할 행위에 대한 명세를 먼저 작성해야 한다고 하면 다들 쉽게 이것이 좋은 습관이라고 수긍하게 되지 않을까?

아직 존재하지 않은 코드에 대해 테스트를 작성하기 보다는, 행위에 대한 명세를 작성하는 것이라고 생각하면 직관적으로 쉽게 이해가 된다. 이것이 BDD의 핵심이다.

 

-> BDD 개발자 관점에서 기능의 동작에 더 중점을 두는 반면 ATDD 사용자 시나리오 관점에서 정확한 요구 사항을 캡처하는 데 중점을 둔다.


6️⃣ TDD의 장점

 

1. 디버깅 시간을 단축 할 수 있다. ( = 단위 테스트의 이점)

TDD의 경우 자동화 된 단위 테스트를 전제하므로 특정 버그를 손 쉽게 찾아낼 수 있다. 

2. 코드가 내 손을 벗어나기 전에 가장 빠르게 피드백 받을 수 있다.

개발 프로세스에서는 보통 ‘인수 테스트’를 한다. 이미 배치된 시스템을 대상으로 클라이언트가 의뢰한 소프트웨어가 사용자 관점에서 사용할 수 있는 수준인지 체크하는 과정이다. 이미 90% 이상 완성된 코드를 가지고 테스트하기 때문에 문제를 발견해도, 정확하게 원인이 무엇인지 진단하기는 힘들다.

 

하지만 TDD를 사용하면 기능 단위로 테스트를 진행하기 때문에 코드가 모두 완성되어 프로그래머의 손을 떠나기 전에 피드백을 받는 것이 가능하다.

 

3. 작성한 코드가 가지는 불안정성을 개선하여 생산성을 높일 수 있다.

TDD를 사용하면, 코드가 내 손을 떠나 사용자에게 도달하기 전에 문제가 없는지 먼저 진단 받을 수 있다. 그러므로 코드가 지닌 불안정성과 불확실성을 지속적으로 해소해준다.

 

4. 재설계 시간을 단축 할 수 있다.

테스트 코드를 먼저 작성하기 때문에 개발자가 지금 무엇을 해야하는지 분명히 정의하고 개발을 시작하게 된다. 또한 테스트 시나리오를 작성하면서 다양한 예외사항에 대해 생각해볼 수 있다. 이는 개발 진행 중 소프트웨어의 전반적인 설계가 변경되는 일을 방지할 수 있다.

 

5. 추가 구현이 용이하다.

개발이 완료된 소프트웨어에 어떤 기능을 추가할 때 가장 우려되는 점은 해당 기능이 기존 코드에 어떤 영향을 미칠지 알지 못한다는 것이다. TDD의 경우 자동화된 유닛 테스팅을 전제하므로 테스트 기간을 획기적으로 단축시킬 수 있다.

 

 

 

 

 

 

 

 

참고

 

 

'Study > Server 심화' 카테고리의 다른 글

6주차: 동시성 처리(2)  (0) 2024.05.28
5주차: 동시성 처리(1)  (1) 2024.05.21
4주차: 스프링 시큐리티 + JWT(2)  (1) 2024.05.14
3주차: 스프링 시큐리티 + JWT(1)  (0) 2024.05.07
2주차: TDD와 테스트 코드(2)  (0) 2024.04.09