박종훈 기술블로그

테스트 주도 개발 (TDD) 스터디 3-4회차 (18-32장)

테스트 주도 개발 - 켄트 벡

tdd-korean-book-cover


3회차 스터디는 다들 사정이 있어서 오늘 4회차에 3-4회차 내용을 같이 이야기 해보기로 하였다. 사실 2부 xUnit 예시는 크게 느낀것이 없었고, 그나마 3부에서 느낀것이 있었다.


25장 테스트 주도 개발 패턴

테스트할 시간이 없다 - “테스트 빈도” 와 “스트레스” 의 상관관계

test and stress

스트레스를 많이 받으면 테스트를 점점 더 뜸하게 한다. 테스트를 뜸하게 하면 당신이 만드는 에러는 점점 많아질 것이다. 에러가 많아지면 더 많은 스트레스를 받게 된다.

격리된 테스트

테스트는 순서에 영향을 받지 않아야 한다. (독립적이여야 한다.) 응집도는 높고, 결합도는 낮춰야 한다.

단언 우선

사고방식에 대한 이야기

결과를 먼저 정해두고, 그 결과를 얻으려면 어떻게 해야할까? 를 거슬러 올라감

실제로 업무할때 이 방식을 사용해보았는데 나는 좋았다.

명백한 데이터

수십 년 후 누군가 와서(혹은 자기가 예전에 만든 코드를 보며) 질문할 것이다. “대체 이 자식이 뭔 생각으로 이 코드를 만든거야?” 이 짜증 내는 사람이 여러분 자신이 될 수도 있다는 것을 생각하면 코드에 될 수 있는 한 많은 실마리를 남기고 싶을 것이다.

테스트에서는 입력으로 사용된 숫자와 예상되는 결과 사이의 관계를 읽어낼 수 있다.

테스트는 내가 작성한 코드의 첫번째 고객이 된다. 테스트는 개발 설계에 영향을 미친다.

26장 빨간 막대 패턴

설명 테스트

단순한 시작법은 테스트를 이용하여 묻고, 테스트를 이용하여 설명하는 것이다.

“당신이 설명한 걸 제가 제대로 이해했는지 한 번 얘기해보겠습니다. 예를 들어서 Foo를 이런 식으로 설정하고 Bar를 이런 식으로 설정하면 76이 나와야 한다 이거죠?”

실제로 이러한 방법을 사용한다. 이러한 방식을 통해 개발자가 아닌 비개발자(pm)과 특성 상황에서 발생할 수 있는 케이스에 대해서 이야기를 나눌 수 있었고 최종적으로 정책서를 개선할 수 있었다.

회귀 테스트

회귀 테스트란 사실 여러분에게 완벽한 선견지명이 있다면, 처음 코딩할 때 작성해야 하는 테스트다. 점점 케이스를 추가하고 그에 따라 리팩터링 해감 (설계를 개선해야할 필요가 있다는 것)

휴식

지쳤을 때는 쉬는 게 좋다.

다시하기

길을 잃은 느낌이 들 떈, 코드를 다 지워버리고 처음부터 다시 해보자.

27장 테스팅 패턴

자식 테스트

큰 테스트를 작은 테스트로 나눔

모의 객체

모의 객체는 설계에서 커플링이 감소하도록 한다.

하지만 모의 객체를 사용하면 프로젝트에 위험 요소가 하나 추가된다. 모의 객체가 진짜 객체와 동일하게 동작하지 않으면 어떻게 될까? 모의 객체용 테스트 집합을 진짜 객체가 사용 가능해질 때 그대로 적용해서 이러한 위험을 줄일 수 있다.

깨끗한 체크인

체크인하기 전에 항상 모든 테스트가 돌아가는 상태로 만들어 두어야 한다. 실행코드와 마찬가지로 테스트코드도 관리해야한다.

28장 초록 막대 패턴

명백한 구현

단순한 연산들을 어떻게 구현하는가? - (TDD를 거치지 말고) 그냥 구현해 버려라.

다만, 한번에 제대로 동작하는 깨끗한 코드를 만들기 어렵다면 우선 ‘제대로 동작하는 코드’로 되돌아 가서 제대록 동작하도록 해결하고, 그 후에 깨끗한 코드를 느긋하게 해결하라.

29장 xUnit 패턴

p 255

이 부분은 신기해서 정리해두었다. 지금 생각하면 ‘어떻게 이런 생각을 할 수 있지?’ 싶은데 그 때는 의견이 나누어졌었나보다. public 만 하는 것이 맞다고 생각하고 그것이 지금은 정석이라고 생각된다.

내가 public api 만 이용해서 모든 테스트를 작성해야 한다고 주장하는 것이 흐름에 거슬릴 수 있다. private로 선언한 것까지 테스트할 수 있도록 JUnit을 확장한 JXUnit이라는 패키지도 존재한다.

화이트 박스 테스트와 블랙박스 테스트

요즘 많이 하고 있는 고민 중 하나이다. 두 가지의 개념을 알고 있으나 화이트 박스 테스트를 써야할 때가 구체적으로 언제인지 잘 모르겠다. 이 부분은 같이 이야기 해보면 좋을 것 같아서 남겨본다.

블랙 박스 테스트로 커버가 되지 않을까 싶다.

일반적으로 화이트 박스 테스트는 깨지기 쉽다고 이야기 한다. 화이트 박스 테스트로 진행하는 부분을 메소드로 묶어서 블랙 박스 테스트로 진행하면 안되는건가?

픽스처

setup / teardown

beforeAll afterAll beforeEach afterEach

테스트 이름 규칙

관습적으로 메소드 명이 test로 시작한다.

요즘은 한글로도 테스트 메소드를 작성하기도 한다.

참고 : https://cheese10yun.github.io/spring-about-test/

public void 만료일이지난_쿠폰_사용_불가() { ... }
public void 이미_사용한_쿠폰은_쿠폰_사용_불가() { ... }
public void 사용가능_쿠폰_사용시_used_is_true() { ... }

테스트 메서드는 의미가 그대로 드러나 읽기 쉬워야한다.

@DisplayName 어노테이션을 사용하면 좋다.

BDD 패턴을 사용해도 좋다. 참고 : https://johngrib.github.io/wiki/junit5-nested/

키워드설명
Describe설명할 테스트 대상을 명시한다.
Context테스트 대상이 놓인 상황을 설명한다.
It테스트 대상의 행동을 설명한다.

예외 테스트

예외 테스트는 책에서는 try catch를 사용하였지만 최근에는 assertThrows메소드로 깔끔하게 단언할 수 있다.

assertThrows(Exception.class, () -> doSomething());

31장 리팩터링

관측상의 동치성이 성립되려면 충분한 테스트를 가지고 있어야한다. 충분한 테스트란 현재 가지고 있는 테스트들에 기반한 리팩터링이 추측 가능한 모든 테스트에 기반한 리펙터링과 동일한 것으로 여겨질 수 있는 상태를 말한다.

차이점 일치시키기

비슷해 보이는 두 코드 조각을 합치려면 어덯게 해야할까? 먼저 동일하게 만드고서 하나로 합친다.

변화 격리하기

바꿀 부분을 격리하자.

개방 폐쇄 원칙 - OCP (Open Closed Principle)

개방 폐쇄의 원칙(OCP)이란 기존의 코드를 변경하지 않으면서, 기능을 추가할 수 있도록 설계가 되어야 한다는 원칙을 말한다. 보통 OCP를 확장에 대해서는 개방적(open)이고, 수정에 대해서는 폐쇄적(closed)이어야 한다는 의미로 정의한다.

JDBC Driver - 각 DB 별로 확장해서 사용 Java Application 입장에서는 JDBC Driver를 바라보기 때문에 수정에 대해서는 폐쇄적임. 하위 JDBC Driver에서 무엇인가를 더 추가한다고 해서 Application 입장에서는 상관없음.

프로젝트 중반에 TDD 도입할 수 있을까?

문제 : 테스트를 염두에 두지 않고 만든 코드는 테스트 하기가 쉽지 않다. 테스트가 없기 때문에 에러가 생겼을 때 알아낼 수 없다.

우선은 변경의 범위를 제한하라. 그리고 점차 확장해나가라