Skip to content

Latest commit

 

History

History
450 lines (254 loc) · 23.9 KB

Effective-Unit-Testing.md

File metadata and controls

450 lines (254 loc) · 23.9 KB

왜 이 책을 읽어야 하는가?

  • 효과적인 테스트 코드를 작성해야 하기 때문에.

  • 클린 코드와 좋은 설계를 이끄는 단위 테스트를 작성하기 위해서

여기서 효과적인 테스트 코드란 무엇인지 이해하기 어렵다.

그러므로 이 책이 필요한게 아닐까?

아래 내용부터는 책 내용의 특정 부분을 갈무리함으로써 내용을 정리하고자 한다.

CHAPTER 2 좋은 테스트란?

  • 테스트 코드의 가독성과 유지보수성
  • 프로젝트 안에서, 그리고 소스 파일 안에서 코드는 적절히 구조화되어 있는가?
  • 테스트가 무엇을 검사하는가?
  • 테스트는 안정적이고 반복 가능한가?
  • 테스트가 테스트 더블을 잘 활용하는가?

코드가 좋다는건 보통 개인 취향에 좌우되고 나 또한 그런 개인 중 한 사람일 뿐이다.

1 읽기 쉬운 코드가 유지보수도 쉽다

  • 가독성과 결함 밀도는 반비례한다는 연구결과도 있다. 즉, 읽기 어려운 코드일수록 결함 수가 많다.
  • 자동화된 테스트는 결함을 효과적으로 막아주지만, 테스트 역시 코드인지라 가독성 문제에서 벗어날 수는 없다. 읽기 어려운 코드는 검증하기 어렵고, 결과적으로 테스트를 조금만 작성하는 사태로까지 이어진다.
  • 가독성...가독성... 읽기 좋은 코드라..

2 구조화가 잘 되어 있다면 이해하기 쉽다

  • 구조화해두면 좋다는 점뿐 아니라 제대로 구조화하지 않으면 역으로 피해를 본다는 사실도 기억해둘 필요가 있겠다.

  • 아래 그림과 같이 아무 구조나 다 구조를 이해하는 데 도움이 되는 건 아니다. 이해할 수 있는 구조가 필요한 것이다. 즉, 우리 두뇌와 사고 모델이 지지고 볶을 수 있을 정도로 정리된 구조라야 한다.
    image-20200530131900097

  • 끝나지 않는 통짜 소스와 마주쳤을 때의 가장 확실한 대처법은 작은 조각으로 나누고 코드 뭉텅이를 메서드로 뽑아내는 것. 500줄짜리 통짜 메서드라면 클래스 10개에 메서드 수십 개 정도로 재편할 수 있을거다.

  • 하지만, 코드가 도메인 모델이나 머릿속의 개념과 맞지 않아서 나눌 수 있는 명확한 경계를 찾을 수 없다면, 차라리 나누지 않느니만 못할 수도 있다.

  • 코드를 읽어보면 특히 코드 동작 방식을 구체적으로 보여주는 테스트 코드를 정독하면 도움이 된다. 다만, 테스트 코드가 제대로 구조화되어 있지 않다면 어디를 봐야하는지 찾아내기 어렵다는 게 함정이다.

  • 결국은 읽기 쉽고, 찾기 쉽고, 이해하기 쉽도록 한 가지 기능에 충실한 테스트가 필요한 것이다.

    • 현재 작업과 관련된 테스트 클래스를 찾을 수 있다.
    • 그 클래스에서 적절한 테스트 메서드를 고를 수 있다
    • 그 메서드에서 사용하는 객체의 생명주기를 이해할 수 있다.

3 엉뚱한 걸 검사하는 건 좋지 않다

  • 이때 가끔은 테스트의 이름을 너무 믿어버리는 실수를 저지르곤 한다. 보통은 테스트의 이름을 보면 그 테스트가 검사하는 내용을 알 수 있는데, 실제로는 이름과 전혀 관련 없는 것을 검사하는 경우가 있다.
  • 올바른 것을 검사하는 것 못지않게 올바른 것을 똑바로 검사하는 것도 중요하다. 특히 유지보수 관점에서는 어떻게 구현했느냐가 아니라 의도한 대로 구현했느냐를 검사하는게 중요하다.

4 독립적인 테스트는 혼자서도 잘 실행된다

  • 예컨데 개인적으로는 낯선 코드를 처음 접했을 때 가장 먼저 메서드의 길이부터 살펴본다.
  • 테스트 코드라면, 테스트가 얼마나 독립적인가? 를 살펴야 한다. 이때 아키텍처의 경계부분이 특히 중요하다. 경계에서 일어나는 일을 관찰하면서 수많은 코드 냄새를 맞을 수 있는데, 다음 요소와 관련이 있다면 각별한 주의가 필요하다.
    • 시간(time)
    • 임의성(Randomness)
    • 동시성(Concurrecy)
    • 인프라(Infrastructure)
    • 기존 데이터(Pre-existing Data)
    • 영속성(Persistency)
    • 네트워킹(Networking)
  • 격리와 독립성이 중요한 이유는 그것이 없다면 테스트를 실행하고 관리하기가 휠씬 어렵기 때문이다.
  • 같은 테스트 클래스에 속한 테스트 메서드끼리도 순서를 가정하면 안 된다.

실전에서는 아래와 같이 하는 것이 좋다.

  • 테스트 더블로 서드파티 라이브러리와의 종속성을 제거한다. 손수 만든 어탭터(adapter)로 적절히 감싸주는 것이다. 성가신 부분이 어탭터 안으로 감춰지므로 나머지 애플리케이션 로직과 분리해서 검사할 수 있다.
  • 테스트에 필요한 자원을 테스트 코드와 같은 위치에 둔다. 자바 프로젝트라면 같은 패키지에 두면 된다.
  • 테스트가 사용할 자원을 직접 만들도록 한다.
  • 테스트가 필요한 문맥을 직접 설정하게 한다. 절대 다른 테스트에 의존하지 말자.
  • 영속성이 필요한 통합 테스트라면 인메모리 DB를 활용한다. 테스트를 위한 꺠끗한 데이터를 휠씬 간단하게 준비할 수 있다. 덤으로 초기화 시간도 상당히 단축
  • 스레드를 사용하는 코드는 동기식과 비동기식을 구분 지어서 골치 아픈 동시성 문제는 소규모의 전문 테스트 그룹에 맡긴다. 평범한 동기식 코드로 작성된 나머지 로직 대부분을 별다른 어려움 없이 검사할 수 있다.

5 믿음직한 테스트라야 기댈 수 있다

아무것도 검사하지 않는 테스트 => 행복한 테스트

assert 문은 단 한 줄도 실행하지 않지만, 어쨌든 제품 일부를, 어쩌면 가능한 실행 경로 전부를 신이 나게 휘젓고 간다는 이유에서- 코드 구석구석을 샅샅이 실행한 덕분에 테스트 커버리지는 나무랄 데 없이 높아진다. 다만, 대상 코드가 예외를 던지지 않는 한 테스트가 절대 실패하지 않는다는 게 문제다.

  • 테스트를 믿고 의지하려면 반복할 수 있게 만들어야 한다. 열 번 실행하면 열 번 모두 반드시 같은 결과가 나와야 한다.
  • 애플리케이션이 비동기적 요소나 현재 시각에 종속된 코드를 포함한다면 그 부분을 인터페이스로 감싸 격리해야 한다. 그렇게하면 테스트 더블 로 대체 할 수 있어 반복 가능한 테스트를 만ㄷㄹ 수 있다.

6 모든 일이 그렇듯 테스트에도 도구가 쓰인다

tip) 테스트 더블?

Stub, 가짜 객체, Mock객체 등으로 알고 있는 개념들을 통칭하는 용어.

  • 테스트 더블은
    • 원래의 로직을 간소화된 코드로 대체하여 테스트 속도를 개선한다.
    • 만들어내기 어려운 특수한 상황을 시뮬레이션한다.
    • 대상 객체의 내부 상태나 동작 등 테스트가 접근할 수 없던 정보를 얻어낸다.

JUnit과 같은 테스트 프레임워크, 테스트 더블, 빌드 도구 중요하다!

7 요약

이들 대부분은 좋은 테스트를 만드는 절대적인 진리라기보다는 처한 상황에 따라 달라짐을 알게 되었다.

  • 테스트의 필수 미덕 중 하나인 가독성부터 시작해보았다. 아무리 애를 써도 이해할 수 없는 테스트 코드는 그 자체가 곧 큰 골칫거리가 되어 유지보수하기 어렵게 한다. 이렇게 되면 유지 비용이 너무 커져서 차라리 지워버리는 길을 선택하곤 한다.
  • 잘 구조화된 테스트라면 원하는 코드를 빠르게 찾을 수 있고 논리 흐름도 쉽게 이해할 수 있다. 가독성과 직결되는 특성이기도 하다.
  • 엉뚱한 테스트는 개발자를 잘못된 길로 안내하거나 본질을 흐려버려서 테스트가 의도했던 진짜 논리를 감추고 가독성을 떨어뜨리는 결과를 낳는다.
  • 가끔 의심스러운 동작을 하는 테스트도 큰 문제 - 이런 불신을 키우는 공통 원인을 찾아내고 반복할 수 있게 만드는 것이 테스트에 얼마나 중요한가를 강조했다.
  • 마지막으로, 자동화된 테스트 작성을 보조해주는 테스트 프레임웤, 빌드 도구, 테스트 더블

CHAPTER 3 테스트 더블

스텁과 더미가 왜 존재할까?
클래스와 메서드 단위로 구조화하기 시작했던 시기부터 사용되던 개념.

테스트 더블의 득은 무엇인가?

1 테스트 더블의 위력

종종 어떤 코드 조각이 원하는 동작을 올바로 수행하는지 검증하려 할 때, 주변 코드를 모두 교체하여 테스트 환경 전반을 통제할 수 있다면 가장 좋다. 이렇게 테스트 대상 코드와 협력 객체를 잘 분리하면 아래와 같다.

테스트하려는 코드를 주변에서 분리하는 것이 테스트 더블을 활용하는 가장 기본적인 이유.

  • 테스트 대상 코드를 격리
  • 테스트 속도 개선
  • 예측 불가능한 실행요소를 제거
  • 특수한 상황을 시뮬레이션
  • 감춰진 정보를 얻어냄

1.1 테스트 대상 코드를 격리한다

OOP에서 테스트 대상 코드를 격리한다는 것은 세상의 모든 것을 두가지로 분류한다는 것.

  • 테스트 대상 코드
  • 테스트 대상 코드와 상호작용하는 코드

1.2 테스트 속도를 개선한다

성능 개선은 언제라도 환영할 일이다. 다만, 가장 중요한 요소는 아닐 수 있다.

1.3 예측 불가능한 실행 요소를 제거한다

  • 이처럼 예측할 수 없는 요인을 다뤄야 할 때에는 역시나 테스트 더블이 해결책이 될 수 있다.

1.4 특수한 상황을 시뮬레이션한다

1.5 감춰진 정보를 얻어낸다

테스트 더블의 존재 이유중 마지막은 테스트가 얻을 수 없었던 정보에 접근하기 위해서다.

2 테스트 더블의 종류

총 네 종료의 객체를 포괄하는 통칭

  • 테스트 스텁
  • 가짜 객체
  • 테스트 스파이
  • Mock 객체

2.1 테스트 스텁은 유난히 짧다(STUB)

Stub은?

  • 끝이 잘렸거나 유난히 짧은 것.
  • 스텁의 목적은 원래의 구현을 최대한 단순한 것으로 대체하는 것.

Stub을 사용하는 이유?

  • 테스트는 대상 코드가 로깅하는 내용에는 전혀 관심없다.
  • 가동중인 로그 서버가 없으니 로깅은 어차피 실패했을 것이다
  • 테스트 스위트가 콘솔로 대량의 정보를 쏟아내는 건 바라지 않는다.

2.2 가짜 객체는 뒤끝 없이 처리한다(FAKE)

  • 가짜 객체는 진짜 객체의 행동을 흉내 내지만, 진짜 객체를 사용할 때 생기는 부수효과나 연쇄 동작이 일어나지 않도록 경량화하고 최적화한 것이라 볼 수 있다.

2.3 테스트 스파이는 기밀을 훔친다(SPY)

  • give(...).then()...willReturn()
  • 테스트 스파이는 목격한 일을 기록해두었다가(write()) 나중에 테스트가 확인할 수 있게끔 만들어진 테스트 더블이다.

2.4 Mock 객체는 예기치 않은 일을 막아준다

  • Mock 객체는 특수한 형태의 테스트 스파이. 특정 조건이 발생하면 미리 약속된 행동을 취한다.
  • UserRepo 인터페이스를 예로 Mock객체를 설명하자만, findByUd()의 파라미터로 123을 주면 null을 반환하고 124를 주면 앞서 저장한 User객체를 반환하는 식.

3 테스트 더블 활용 지침

테스트 더블 = 목수의 못과 망치같은 존재

3.1 용도에 맞는 더블을 선택하라

선택할 수 있는 테스트 더블은 많고 서로 조금씩 다르다. 각각의 장점은 무엇이고 어떤 걸 골라야 할까?

= 어떤 것을 선택하든, 가장 명확한 원칙은 테스트를 가장 읽기 쉽게 만들어주는 선택을 하라는 것

그럼에도 결정이 어렵다면 아래방법을 시도해보기

  • 두 객체 간 상호작용의 결과로 특정 메서드가 호출되었는지 확인하고 싶다면 Mock 객체를 써야 할 가능성이 높다.
  • Mock객체를 사용하기로 했는데, 테스트 코드가 생각만큼 깔끔하게 정리되지 않는다면 더 단순한 테스트 스파이를 손수 작성해서도 똑같은 마술을 부릴 수 있는지 생각해보자.
  • 협력 객체는 자리만 지키면 되고 협력 객체가 대상 객체에 넘겨줄 응답도 테스트에서 통제할 수 있다면 스텁이 정답이다.
  • 필요한 서비스나 컴포넌트를 미처 준비하지 못해 스텁을 대용품으로 사용하고 있는데, 시나리오가 너무 봊갑해서 벽에 부딪쳤거나 테스트 코드가 관리하기 어려울 만큼 복잡해졌다면 가짜 객체를 구현하는 걸 고려해보자.
  • 이도 저도 아니라면 동전을 던져보자. 앞면이 Mock, 뒷면이 스텁. 어쩌다 똑바로 서버리면 가짜 객체를 써도 뭐라 하지 하지 않겠다.

🔴스텁은 질문하고 Mock은 행동한다.🔴

3.2 준비하고, 시작하고, 단언하라

  • AAA(arrange - act - assert)
    필요한 객체들을 준비하고, 실행하고, 결과를 단언하는 총 세 단계로 테스트를 구성
  • 또는 BDD에서는 Given-When-Then
  • 혹 세 영역 중 하나가 비대하다 고 느껴진다면, 너무 많은 것을 한꺼번에 검사하려는 테스트일 가능성이 높다. 더 작은 단위의 기능을 집중적으로 검사하는 테스트로 나눌 필요가 있다는 신호다.

3.3 구현이 아니라 동작을 확인하라

사람은 누구나 실수한다. Mock 객체에 예상을 너무 상세히 설정하는 프로그래머를 종종 볼 수 있는데, Mock 객체 라이브러리에 갓 입문했을 때 흔히 저지르는 실수의 하나다. 테스트와 관련된 모든 것을 Mock 객체로 만들고, 객체 간의 사소한 메서드 호출 하나까지 깐깐하게 정의하는 걸 말한다.

  • 검증 목적과 관련 없는 지극히 사소한 변경마저도 테스트를 실패하게 한다면 마치 못집을 너무 많이 해서 구멍이 송송 뚫린 불쌍한 목판처럼 되어 버린다.
  • 테스트는 오직 한 가지만 검사해야 하고 그 의도를 명확히 전달하도록 작성되어야 한다. 그러니 대상 객체를 지긋이 바라보며 검사하려는 동작은 무엇이고 굳이 확인할 필요없는 부수적인 구현은 무엇인지 자문해볼 필요가 있다.
  • Mock에는 정말 바라고 의도한 핵심 동작만 설정하면 된다. 부수적인 구현은 호출 횟수에 전혀 개의치 않는 관대한 Mock객체나 스텁만으로도 충분하다.
  • 구현이 아니라 동작을 검증하자. Mock객체 라이브러리를 사용할 때 항시 명시하길 바란다.

3.4 자신의 도구를 선택하라

많은 라이브러리들이 대동 소이하지만, API모습이 다소 다르고 특정 용도로 굉장히 유용한 독특한 기능을 제공.

그 중에서도 Stubbing과 Verification을 구분 하는 Mockito

  • API만 놓고 보면 어떤 Mock 객체 라이브러리를 선택할지는 거의 개인 취향. 단, 스텁을 주로 사용하는 테스트에서라면 Mockito가 확실히 유리하다. 가장 중요한 것은, 결국 테스트 코드는 지금이나 앞으로나 읽기 쉽고 간결하고 관리하기 쉬워야 한다는 것.

레인스버거의 JMock과 Mockito의 지향 방향이 다른 점?

나는 레거시 코드를 구원할 때는 Mockito를, 새로운 기능을 설계할 때는 JMock을 사용한다.

JMock과 Mockito는 기본 가정이 서로 달라서 각자의 목적이 더 유리하도록 진화되었다. 기본적으로 JMock의 테스트 더블(Mock객체)은 대상 코드가 그 어떤 것도 자기 마음대로 호출하면 안된다고 믿는다. 이 가정을 완화하려면 스텁을 사용해야 한다. 이와 반대로 Mockito의 테스트 더블(안타깝지만, 이번에도 Mock객체)은 대상 코드가 언젠건 아무것이나 호출해도 된다고 믿는다. 이 가정을 더 강화하려면 우리가 직접 메서드 호출 여부를 확인해야 한다. 이 가정을 더 강화하려면 우리가 직접 메서드 호출 여부를 확인해야 한다. 이것이 모든 차이을 만들어낸다.

3.5 종속 객체를 주입하라

진짜 객체를 다른 것과 교체할 방법이 없다면 테스트 더블도 무용지물이다.

4 요약

테스트 대상 코드를 격리해야지만 모든 시나리오를 시뮬레이션하고 모든 동작을 검증할 수 있다는 것.

PART 2 테스트 냄새

CHAPTER 4 가독성

테스트란 코드에 바라는 동작과 가정을 프로그래머 식으로 표현한 것

따라서, 테스트를 읽은 프로그래머는 코드가 해야할 일 을 이해할 수 있어야 한다. 테스트를 실행한 후에는 코드가 실제로 한 일 이 무엇인지 말할 수 있어야 한다.

  • 테스트의 핵심인 단언문은 대상 코드의 올바른 동작을 규정한다.

1 기본 타입 단언

단언문은 가정이나 의도를 명시해야 한다.

  • 단언하려는 이유나 의도가 의미를 알 수 없는 단어나 숫자에 가려진 상황을 말한다. 이 경우 이해하기도 어렵고 단언을 올바로 기술한 것인지도 파악하기 쉽지 않다는 문제가 발생.
  • 기본 타입 선언이란 검사해야 할 동작보다 더 기초적인 요소에 집착하는 것을 말한다.

1.1 예시

Grep 유틸리티 테스트 하는 코드

@Test
public void outputHasLineNumbers(){
  String content = "1st match on #1\nand\n2d match on #3";
  String out = grep.grep("match", "test.txt", content);
  assertTrue(out.indexOf("test.txt:1 1st match") != -1);
  assertTrue(out.indexOf("test.txt:3 2st match") != -1);
}

단언문이 너무 원시적이라 확인하려는 것이 무엇인지 분명치가 않다. 마치 나머지 코드와는 다른 외계어로 쓰인 것 같다.

1.2 개선 방법

위 코드의 문제는 단언 대상의 추상화 수준이 너무 낮다는 점.

@Test
public void outputHasLineNumbers(){
  String content = "1st match on #1\nand\n2d match on #3";
  String out = grep.grep("match", "test.txt", content);
  assertThat(out.indexOf("test.txt:1 1st match") is(not(-1));
  assertThat(out.indexOf("test.txt:3 2st match") is(not(-1));
}

목적은 프로그래머의 인지 부하를 줄이는 것.!!!

@Test
public void outputHasLineNumbers(){
  String content = "1st match on #1\nand\n2d match on #3";
  String out = grep.grep("match", "test.txt", content);
  assertThat(out.contains("test.txt:1 1st match"));
  assertThat(out.contains("test.txt:3 2st match"));
}

테스트 코드에서 어떤 방식으로 의도를 표현할지 결정할 때, 코드 중복이나 성능보다 가독성과 명료성이 더 중요함을 기억해두자.

어떤 것을 선택하건 검사하려는 기능과 단언문을 같은 언어와 어휘로 표현하길 바란다.

1.3 정리

!=, == 등의 비교문을 사용하는 단언문을 발견하면 주저하지 말고 리팩토링!

테스트를 작성할 때는 이들 타입(전화번호 = String, 부가서비스사용여부 = Byte, 약정기간 = Date)과 표현하려는 개념의 추상화 수준과 같은지 신경써야 한다.

2 광역 단언

어떤 것을 광역 단언이라 하는가? 단언문은 2개밖에 없지만, 그 2개가 단언하고자하는 범위가 너무 광범위한 것을 말한다.

이는 검사하려는 동작의 아주 작은 하나까지도 놓치지 않으려는 집착의 산물이다.

그러므로,

  • 테스트가 실패하는 이유는 오직 하나뿐이어야 한다.
  • 결과를 보고 감지해낼 수 있는 변화가 많다는 건 좋다. 하지만 실패한 테스트를 봤을 때 우리가 가장 궁금한 건 실패했는가다.

개선방법은

테스트 목적을 이룰 수 있는 만큼의 정보만 담아두면 된다.

지금까지의 리팩토링으로 각 테스트는 자신과 관련 없는 세부 정보를 숨기고 한 가지 일에만 충실한 모습이 되었다. 다만, 세부 정보를 숨긴다는 게 어찌 보면 부정적일 수도 있느니, 어느쪽 가치가 더 큰지 숙고해본 후 적용하는 것이 좋다. 한번에 전체를 볼 것인가?아니면 핵심을 빠르게 파악할 수 있는 테스트를 만들 것인가의 문제이다.

그러므로, 큰 그림에 관심을 두는 건 좋다. 하지만 자칫 너무 광범위한 단언문을 만드는 실수를 할 수 있다. 광역 단언은 대상을 너무 크게 묶어서 모든 걸 비교하려다 보니 너무 쉽게 망가져 버린다. 단언문은 테스트의 주된 관심사와 상관없는 극히 사소한 변경에도 실패할 것이다.

광역 단언은 프로그래머가 테스트의 의도와 핵심을 파악하는 데도 방해가 된다.

3 비트 단언

비트연산에 대한 단언문을 작성하는 것.

예를 들면 assertTrue(Plactform.IS_32_BIT ^ Platform.IS_64_BIT) 와 같은 부분을 말한다. 이 단언문이 말하고자하는 것은 무엇일까?

해결방법은 단순히 부울연산자로 대체하면 된다.

4 부차적 상세정보

  • 핵심이 아닌 설정은 private 메서드나 셋업 메서드로 추출하라.
  • 적절한 인자와 서술형 이름을 사용하라.
  • 한 메서드 안에서는 모두 같은 수준으로 추상화하라.

테스트를 하나 작성할때마다 자문하라.

'테스트가 하려는 일이 진짜 명백한가? 당연하다는 대답이 선뜻 나오지 않는다면 아직 다 끝난게 아니다.'

문제 상황을 대처하려면 핵심이 아닌 코드나 정보를 도우미 메서드나 셋업 메서드로 내몰아야 한다. 특히 '한 메서드 안에서는 모두 같은 수준으로 추상화하라' 라는 말을 항시 기억하면 좋다.

5 다중 인격

다중인격?

여러 개의 영혼(테스트 목적)이 한 몸(테스트 메서드)을 공유하는 걸 말한다.

해결방안

너무 많은 것을 시도해서, 나중에 수정하려 할 때 애를 먹게 한다. 그러므로 차라리 중복을 먼저 제거하면 문제의 핵심을 더 뚜렷이 드러날 듯싶다.

읽기 쉬운 코드는 프로그래머에게 자신의 목적을 명확히 전해준다. 다중 인격은 시야를 뿌옇게 흐리는 테스트 냄사다. 여러 논점을 하나의 테스트에 뒤섞여서, 혼란스러운 코드 속에 테스트의 세부 정보와 큰 그림 모두를 감춰버린다.

6 쪼개진 논리

여러 곳으로 논리가 흩어진 코드를 분석하느라 프로그래머의 인지능력에 과부하가 걸린다.

Note

나눔의 심리학

가독성을 높이려면 긴 메서드를 짫은 덩어리로 나누라는 뜻으로 들릴 것이다. 하지만 성급한 결론이다. 반드시 의미 있는 조각이어야만 인지능력에 도움이 되는 건 아니지만, 이왕이면 의미가 있을 때 효과도 배가 된다.

무작정 작은 메서드로 추출하는 건 곤란하다. 그보다는 같은 속성을 공유하는 의미 있는 조각이 어디까지인지 신경 쓰면서 나눠주는 세심함이 필요하다.

Note

데이터나 로직을 언제 통합(inline)해야 할까?

\1. 짫다면 통합하라.

\2. 통합하기에 너무 길다면 팩토리 메서드나 테스트 데이터 생성기를 통해 만들어라.

\3. 이마저도 쉽지 않다면 그냥 독립 파일로 남겨둬라.

7 매직 넘버

8 셋업 설교

9 과잉보호 테스트

과잉보호의 대표적인 에로 NullPointException이 있다. assertNull 을 체크하고 assertEuqals 두번 반복하는 행위. 만약에 null이라면, assertEuals에서 예외를 던질 것이다.

10 요약