클린코드 핵심 정리 (9장 단위테스트)

김상운(개발둥이)·2022년 3월 28일
0

클린코드

목록 보기
8/12
post-thumbnail

테스트 코드의 중요성

  • 테스트 코드는 실수를 바로 잡아준다.
  • 테스트 코드는 반드시 존재해야하며, 실제 코드 못지 않게 중요하다.
  • 테스트 케이스는 변경이 쉽도록 한다. 코드에 유연성, 유지보수성, 재사용성을 제공하는 버팀목이 바로 단위테스트다. 테스트 케이스가 있으면 변경이 두렵지 않다. 테스트 케이스가 없다면 모든 변경이 잠정적인 버그다. 테스트 coverage가 높을수록 버그에 대한 공포가 줄어든다.
  • 지저분한 테스트 코드는 테스트를 안하니만 못하다.

Effective Unit Test 테스트의 중요성

💡 테스트는 실사용에 적합한 설계를 끌어내준다.

TDD 법칙 세 가지

TDD는 실제 코드를 짜기 전에 단위 테스트부터 짜라고 요구한다. 하지만 이 규칙은 빙산의 일각에 불과하다. 다음 세 가지 법칙을 살펴보자.

  • 첫째 법칙: 실패하는 단위 테스트를 작성할 때까지 실제 코드를 작성하지 않는다.
  • 둘째 법칙: 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성한다.
  • 셋째 법칙: 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성한다.

    위 세 가지 규칙을 따르면 개발과 테스트가 대략 30초 주기로 묶인다. 테스트 코드와 실제 코드가 함께 나올뿐더러 테스트 코드가 실제 코드보다 불과 몇 초 전에 나온다.
    이렇게 일하면 매일 수십 개, 매달 수백 개, 매년 수천 개에 달하는 테스트 케이스가 나온다. 실제 코드를 사실상 전부 테스트하는 테스트 케이스가 나온다. 하지만 실제 코드와 맞먹을 정도로 방대한 테스트 코드는 심각한 관리 문제를 유발하기도 한다.

💡 테스트를 작성해서 얻게 되는 가장 큰 수확은 테스트 자체가 아니다.
작성 과정에서 얻는 깨달음이다.

테스트의 종류

Test Pyramid

Just Say No to More End-to-End Tests

💡 구글의 제안:
70% unit tests, 20% integration tests, 10% end-to-end tests

  • Unit test: 프로그램 내부의 개별 컴포넌트의 동작을 테스트한다. 배포하기 전에 자동으로 실행되도록 많이 사용한다.
  • Integration Test: 프로그램 내부의 개별 컴포넌트들을 합쳐서 동작 테스트한다. Unit Test는 각 컴포넌트를 고립시켜 테스트하기 때문에 컴포넌트의 interaction을 확인하는 Integration Test가 필요하다.
  • E2E Test: End to End Test. 실제 유저 시나리오대로 네트워크를 통해 서버의 Endpoint를 호출해 테스트한다.

Unit Test 작성

Test Double

테스트에서 원본 객체를 대신하는 객체

  • Stub
    • 원래의 구현을 최대한 단순한 것으로 대체한다.
    • 테스트를 위해 프로그래밍된 항목에만 응답한다.
  • Spy
    • Stub의 역할을 하면서 호출에 대한 정보를 기록한다.
    • 이메일 서비스에서 메시지가 몇 번 전송되었는지 확인할 때
  • Mock
    • 행위를 검증하기 위해 가짜 객체를 만들어 테스트하는 방법
    • 호출에 대한 동작을 프로그래밍할 수 있다.
    • Stub는 상태를 검증하고 Mock은 행위를 검증한다.

given-when-then 패턴을 사용하자

public void testGetPageHierarchyAsXml() throws Exception {
	givenPages("PageOne", "PageOne.ChildOne", "pageTwo");
	
	whenRequestIsIssued("root", "type:pages");

	thenResponseShouldBeXML();
}

public void testGetPageHierarchyHasRightTags() throws Exception {
	givenPages("PageOne", "PageOne.ChildOne", "PageTwo");

	whenRequestIsIssued("root", "type:pages");

	thenResponseShouldContain(
		"<name>PageOne</name>", "<name>PageTwo</name>", "<name>ChildOne</name>"
	);
}

FIRST 원칙

  • Fast: 빠르게
    • 테스트는 빨리 돌아야 한다. 자주 돌려야 하기 때문이다.
  • Independent: 독립적으로
    • 각 테스트를 독립적으로 작성한다. 서로에게 의존하면 실패한 원인을 찾기 어려워진다. (다른 테스트의 실패로 인한건지, 코드 오류인지)
  • Repeatable: 반복가능하게
    • 테스트는 어떤 환경에서도 반복 가능해야 한다. 실제 환경, QA 환경, 모든 환경에서 돌아가야 한다.
  • Self-Validating: 자가검증하는
    • 테스트는 bool 값으로 결과를 내어야 한다.
  • Timely: 적시에
    - 테스트하려는 실제 코드를 구현하기 직전에 구현한다.

    참고

    해당 포스팅은 제로 베이스 클린코드 한달한권을 수강 후 정리한 내용입니다.

profile
공부한 것을 잊지 않기 위해, 고민했던 흔적을 남겨 성장하기 위해 글을 씁니다.

0개의 댓글