TDD를 수행해보자

크리링·2024년 1월 14일
0

TDD 정리

목록 보기
2/5
post-thumbnail

이전의 글을 바탕으로 TDD의 장점을 상기하며 TDD를 수행해보자.

TDD의 장점
1. 지속적인 코드 정리
2. 빠른 피드백
3. 테스트를 통과할 만큼만 코드 작성
4. 설계대로 진행

이 예제는 켄트 백 - 테스트 주도 개발을 참고해 작성했습니다.
코드 보러가기


실행 환경

  • SpringBoot - 3.2.1
  • Junit5

(이후에 할 대역을 위해 미리 추가)

  • H2 Database
  • Spring Data JPA
  • Lombok

과정

달러 통화를 지원하는 Dollar 객체를 만들어보자

코드를 실제로 작성하기 전에 어떤 기능이 필요한지 알아야한다.

  • $5 * 2 = $10

일단 가장 필요한 기능을 먼저 작성했다.
다른 두개의 화폐를 덧셈했을때 환율을 고려해 기축통화인 달러($)로 결과가 나와야 하고, 곱셈이 가능해야한다.

쉬운 것에서 어려운 순서로 제품의 완성도를 높여라라는 테스트 주도 개발 시작하기의 내용을 지키기위해 $5 * 2 = $10를 먼저 단위 테스트 해보자.

단위 테스트 작성의 진행 순서는
1. 테스트를 작성한다. (원하는 로직을 순서대로 작성해서 빨간줄로 나온다.)
2. 초록불이 나오게 만든다. (실행 가능하게 만든다.)
3. 리팩토링 (올바르게 만든다.)

(assertJ를 사용하였고 static import한 상태이다.)

일단 작성하고 실행해보았다.

당연히 빨간불이다.
일단 초록불로 먼저 바꿔야하니까 Dollar 클래스를 만들어주자.

(테스트 폴더 내에 일단 만들고, 잘 실행되면 메인 소스 코드 폴더로 옮기자)

간단하게 클래스를 만들어주고 이전 테스트 코드를 import해보자

이제 코드를 실행할 수 있는 상태가 되었다. 바로 실행해보면

노란불이 발생한다.
노란불을 초록불로 바꾸어보자. 방법은 간단하다. 그냥 값을 때려넣자.

다시 실행해보자

드디어 초록불을 보았다.
이제 3. 리팩토링을 진행해보자.

위의 코드와 같이 코드를 리팩토링하고 다시 테스트를 실행해보자

초록불이 나온다. 하나의 요구사항을 만족시켰으니 다시 요구사항을 정리해보자.

  • $5 * 2 = $10

  • amount를 private로 만들기 (추가)

  • Dollar 부작용? (추가)

완료한 요구사항이 생겼고, 그 요구사항을 구현 중에 새로운 요구사항이 추가되었다. 요구사항을 처음부터 정리할 수는 없다. 일단 쉬운 요구사항부터 구현하면서 계속 추가하는 방식으로 진행한다.

다음으로는 Dollar 부작용?에 대해서 단위 테스트를 진행해보자.

뭐가 부작용일까? -> amount의 값이 변한다는 문제가 생긴다.

위의 단위 테스트를 일부 수정해보자

실행해보면

노란불 결과가 나온다.
일단 실행 가능하게 초록불로 만들어보자. 하지만 위의 방식으로는 도저히 바꿀 생각이 나지 않는다. 그래서 times(int times) 메서드의 리턴 타입을 변경해본다.

일단 빨간불이니까
Dollar 엔티티의 times 메서드를 변경해보자

단위 테스트의 빨간줄이 없어지니까 바로 실행해보니

초록불을 확인할 수 있다.

다시 요구사항을 보자.

  • $5 * 2 = $10
  • amount를 private로 만들기
  • Dollar 부작용?

$5의 객체와 $5의 객체가 같다는 equals 기능이 필요하다.
그래서 요구사항에 추가하자.

  • $5 * 2 = $10

  • amount를 private로 만들기

  • Dollar 부작용?

  • equals()

자 가장 쉬워보이는 equals()를 먼저 처리해보자

일단 단위테스트를 먼저 작성해보고

실행해보면

당연히 노란불
초록불로 만들어보자

원하는 답을 리턴시키고 단위 테스트를 다시 실행하면

자 이제 리팩토링을 진행하고

추가적인 assert 문을 단위 테스트에 추가해보고 실행하면

똑같이 초록불을 확인할 수 있다.

단위 테스트를 통과했으니 전체 테스트를 실행해보자

모두 통과했으니 업데이트된 요구사항을 확인해보자.

  • $5 * 2 = $10
  • amount를 private로 만들기
  • Dollar 부작용?
  • equals()

자 그러면 위의 equals의 동치성을 일반화해보자

그리고 바로 다음 요구사항인 amount를 private를 진행하고

모든 테스트를 실행해보면

초록불의 결과를 확인해 볼 수 있다.

모든 요구사항을 만족했다면 이전에 test폴더에 만들어둔 entity를 메인 코드로 올리자.






정리

TDD의 과정을 간단하게 요약하고 설명하기 위해 책의 내용에서 많은 부분을 생략했다. 실제 기능 구현을 하는데에 미리 계획을 가지고 구현하고, 필요한 내용만 구현하는 것은 굉장히 효과적이라고 생각한다.

나는 실무에서 도움이 되는 내용을 공부하고 사용하고 싶다. 하지만 당장 실무에서 사용하기에 TDD의 문제가 없다고 생각하지 않는다. 나 뿐만 아니라 많은 TDD를 실행하지 않는 개발자들이 말하는 시간이 있다면 해야지, 필요한건 알겠는데 그냥 테스트 없이 하는게 빠르고 효율적이다.라는 말로 기존에 해오던 방식을 고수한다. 당장의 업무에서 일정을 지키는게 우선이기에 그렇게 생각했다. 맞는 말이긴하다. 일정을 지키는게 가장 우선이 되어야한다.

최근에 본 책 함께 자라기 - 애자일로 가는 길에서 나온 말들은 이런 나의 뼈를 때려주었다.
인상깊은 세문장을 공유하고 싶다.

  • 실수는 할 수 밖에 없다. 대신 그 실수가 나쁜 결과로 되기 전에 일찍 발견하고 빨리 고쳐야 한다.

  • 학습과 일을 굳이 구분하지 마라

  • 두려워도 필요하다면 시도해야 한다.

모두 현재 내가 TDD를 대해야 하는 상황과 연관이 있다.
처음 왜 TDD를 공부했고, 필요하다고 생각했는가? 라는 물음에는 실무를 하는 도중 단위 테스트 코드가 없어 하나의 오류를 고쳤을때 나오는 다른 오류를 자동으로 확인할 방법이 없다. 였고, 개인적인 공부인 클린코드 학습에서 TDD의 중요성을 강조한다.

삼위일체의 상황이 아니던가?
실제 TDD를 공부하며 봤던 두권의 책의 저자 모두 TDD는 수련이 필요하다., 단기간에 잘할 수 없는 일이다. 라고 얘기한다. 지금은 부정적인 생각이 있을지 몰라도 필요한 일이고, 내 코드 품질을 높이기 위해서는 공부해야되는 것이기 때문에 계속 수련해보려고 한다.






예고

TDD를 실무에서 연습하고 있는데 새로운 기능 개발에서는 참 효과적이고, 좋은 것 같다. 하지만 내가 고민이 되는 것은 어떻게 실시간과 연관된 데이터는 테스트 DB를 만들어서 해결할 문제가 아닌 것 같다는 생각이든다. 그래서 @BeforeEach 어노테이션을 사용해서 실제 Repository에 데이터를 save하고 테스트를 돌리면 시간이 오래 걸릴 뿐더러 id 값을 autoIncrement 전략을 사용한다면 ID의 공백이 발생한다.
그리고 추가적으로 새로운 기능 개발이 아닌 원래의 목표인 기존의 레거시 코드에서는 어떻게 TDD를 전략적으로 사용해야 할 것인가? 에 대한 고민이 생겼다.

그래서 문제를 정리하자면
1. 어떻게 테스트 데이터를 사용할까?라는 문제
2. 레거시 코드에 어떻게 TDD를 적용할까?라는 문제

인데, 다음 시간에는 1번 문제를 공부하다가 찾게된 대역에 대해 정리해보고자한다.






부족한 부분은 댓글로 피드백 남겨주시면 겸허히 받아들이겠습니다.
읽어주셔서 감사합니다.

0개의 댓글