TDD 의 법칙 세 가지

 

1. 실패하는 단위 테스트를 작성할 때 까지 실제 코드를 작성하지 않는다

2. 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위테스트를 작성한다

3. 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성한다

 

 

위 규칙을 따르면 개발, 테스트가 대략 30초 주기로 묶인다

테스트 코드와 실제 코드가 함께 도출되고

테스트 코드가 실제 코드보다 불과 몇 초 전에 나온다

 

But 방대한 테스트 코드는 심각한 관리 문제를 유발하기도 한다

 

 

깨끗한 테스트 코드 유지하기

실제 코드가 진화하면, 테스트 코드 역시 변해야 한다

테스트 코드가 복잡할수록 실제 코드를 짜는 시간보다 테스트 케이스를 추가하는 시간이 더 걸리게 된다

 

테스트코드는 실제 코드만큼 중요하다

 

테스트는 유연성, 유지보수성, 재사용성을 제공한다

테스트가 있으면 변경이 두렵지 않다

>> 코드에 유연성, 유지보수성, 재사용성을 제공한다

 

 

 

깨끗한 테스트 코드

깨끗한 테스트 코드를 만들기 위해서는 가독성이 중요하다

테스트 코드에서 가독성을 높이려면 명료성, 단순성, 풍부한 표현력이 필요하다

 

 

 

public void testGetPageHierarchyAsXml() throws Exception {
  makePages("PageOne", "PageOne.ChildOne", "PageTwo");

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

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

public void testSymbolicLinksAreNotInXmlPageHierarchy() throws Exception {
  WikiPage page = makePage("PageOne");
  makePages("PageOne.ChildOne", "PageTwo");

  addLinkTo(page, "PageTwo", "SymPage");

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

  assertResponseIsXML();
  assertResponseContains(
    "<name>PageOne</name>", "<name>PageTwo</name>", "<name>ChildOne</name>");
  assertResponseDoesNotContain("SymPage");
}

public void testGetDataAsXml() throws Exception {
  makePageWithContent("TestPageOne", "test page");

  submitRequest("TestPageOne", "type:data");

  assertResponseIsXML();
  assertResponseContains("test page", "<Test");
}

BUILD_OPERATE_CHECK 패턴

테스트는 정확하게 세 부분으로 나눠진다

 

첫 부분은 테스트 자료를 만든다

두 번째 부분은 테스트 자료를 조작한다

세 번째 부분은 조작한 결과가 올바른지 확인한다

 

잡다한 코드 없이 진짜 필요한 자료 유형과 함수만 사용하여 읽는 사람이 빠르게 이해할 수 있도록 구성한다

 

 

 

테스트 당 assert 하나

JUnit 으로 테스트 코드를 짤 때는 함수마다 assert 문을 단 하나만 사용한다

 

 

@Test
public void turnOnLoTempAlarmAtThreashold() throws Exception {
  hw.setTemp(WAY_TOO_COLD); 
  controller.tic(); 
  assertTrue(hw.heaterState());   
  assertTrue(hw.blowerState()); 
  assertFalse(hw.coolerState()); 
  assertFalse(hw.hiTempAlarm());       
  assertTrue(hw.loTempAlarm());
}

이 코드를 개선한게 

 

@Test
public void turnOnCoolerAndBlowerIfTooHot() throws Exception {
  tooHot();
  assertEquals("hBChl", hw.getState()); 
}
  
@Test
public void turnOnHeaterAndBlowerIfTooCold() throws Exception {
  tooCold();
  assertEquals("HBchl", hw.getState()); 
}

@Test
public void turnOnHiTempAlarmAtThreshold() throws Exception {
  wayTooHot();
  assertEquals("hBCHl", hw.getState()); 
}

@Test
public void turnOnLoTempAlarmAtThreshold() throws Exception {
  wayTooCold();
  assertEquals("HBchL", hw.getState()); 
}

이 코드이다

하나의 테스트 당 하나의 assert 를 사용하여 한 눈에 알아보고 이해하기 쉽게 구현했다

But 리턴 값을 전부 비교해야 하는 테스트는 어쩔 수 없이 여러개의 assert 문을 사용해야된다

 

 

테스트 당 개념 하나

테스트 함수 마다 한 개념만 테스트 하라

 

 

F.I.R.S.T

깨끗한 테스트는 다음 다섯 규칙을 따른다

 

1. 빠르게 (Fast)

테스트는 빨라야 한다

테스트가 느리면 자주 돌릴 엄두를 못낸다

 

2. 독립적으로 (Independent)

각 테스트는 서로 의존하면 안된다

한 테스트가 다음 테스트가 실행 될 환경을 준비해서는 안된다

각 테스트는 독립적으로, 어떤 순서로 실행해도 괜찮아야 한다

 

3. 반복 가능하게 (Repeatable)

테스트는 어떤 환경에서도 반복 가능해야 한다

실제 환경, QA환경, 클라우드 환경 등 테스트가 돌아가지 않는 환경이 하나라도 있다면 테스트가 실패한 이유를 둘러댈 변명이 생긴다

 

4. 자가 검증하는 (Self_validating)

테스트는 bool 값으로 결과를 내야 한다

성공 아니면 실패

통과 여부를 알기 위해 로그를 읽어서는 안된다

 

 

5. 적시에 (Timely)

테스트는 적시에 작성해야 된다

단위 테스트는 테스트하려는 실제 코드를 구현하기 직전에 구현한다

실제 코드를 구현한 다음에 테스트 코드를 만들면 실제 코드가 테스트하기 어렵다는 사싱르 발견할지도 모른다

 

 

 

 

마지막으로

테스트 코드는 실제 코드의 유연성, 유지보수성, 재사용성을 보존하고 강화하기 때문에 지속적으로 깨끗하게 관리해야 한다

표현력을 높이고 간결하게 정리하자

테스트 API를 구현해 도메인 특화 언어를 만들자 (DSL) >> 그러면 그만큼 테스트 코드 짜기 쉬워진다

 

'끄적 > Clean Code' 카테고리의 다른 글

Clean Code -8 클래스  (0) 2023.08.14
Clean Code -6 오류 처리  (0) 2023.08.10
Clean Code -5 객체와 자료구조  (0) 2023.08.10
Clean Code -4 형식 맞추기  (0) 2023.08.10
Clean Code -3 주석  (0) 2023.08.10

+ Recent posts