본문 바로가기
Book

[독서 기록] 자바 Junit을 활용한 실용주의 단위 테스트, 제프 랭어, 앤디 헌트, 에이브 토마스 지음, 유동환 옮김, 길벗

by Renechoi 2022. 11. 4.
 
자바와 JUnit을 활용한 실용주의 단위 테스트
『실용주의 프로그래머』의 앤디 헌트와 데이브 토마스가 알려주는 실용주의 단위 테스트! 클린 코드의 핵심인 단위 테스트, 어디서 어떻게 시작해야 할까? 책에서는 단위 테스트의 개념과 작성 이유부터 테스트 가이드라인, 목 객체 사용법, 자동화된 단위 테스트, 리팩토링까지 단위 테스트의 핵심 내용을 설명한다. 또한, 자바와 JUnit으로 단위 테스트를 단계별로 실습할 수 있게 구성했다. 단위 테스트가 처음이거나, 단위 테스트를 좀 더 깊게 이해하고 싶은 분들에게 추천한다.
저자
제프 랭어, 앤디 헌트, 데이브 토마스
출판
길벗
출판일
2019.06.30

단위 테스트를 작성하는 이유

- 26p 

 

 

assertTrue 사용예 

 

@Test
public void hasPositiveBalance(){
	account.deposit(50);
    assertTrue(account.hasPositiveBalance());
}

- 61p

 

 

 

assertThat은 명확한 값을 비교 

- 62p

 

 

assertThat(account.getBalance(), equalTo(100));

-62p

 

 

어떤 값을 부정하는 단언을 만든다면 not 매처를 사용합니다.

 

assertThat(account.getName(), not(equalTo("plunderings")));

-66p

 

 

 

예외를 기대하는 세 가지 방법 

1. 단순한 방식 : 애너테이션 사용

@Test(expected=InsufficientFundsException.class)

 

2. 옛 방식 : try/catch와 fail 

try {
	account.withdraw(100);
    fail();
    }
    catch (InsufficientFundsException expected) {
    }

 

 

3. 새로운 방식 : ExpectedException 규칙 

 

새로운 계좌(즉, 돈이 없는 계좌)에서 돈을 인출하는 테스트를 설계한다고 합시다. 그 계좌에서 돈을 찾으면 예외가 발생합니다.

 

ExpectedException 규칙을 사용하려면 테스트 클래스에 ExpectedException 인스턴스를 public으로 선언하고 @Rule 애너테이션을 부착해야 합니다. 

 

@Rule
public ExpectedException thrown = ExpectedException.none();

@Test
publci void exceptionRule(){
	thrown.expect(InsufficientFundsException.class);
    thrown.expectMessage("balance only 0");
    
    account.withdraw(100);
    }

 

테스트의 셋업 단계에서 나머지 테스트를 실행할 때 발생할 수 있는 일을 규칙에 알립니다. thrown 규칙 인스턴스는 InsufficientFundsException 예외가 발생함을 알려줍니다(08행) 

 

- 72 ~ 73p

 

 

검증된 예외를 처리하려고 테스트 코드에 try/catch 블록을 넣지 마세요. 그 대신 발생하는 예외를 다시 던지세요. 

 

@Test

public void readsFromTestFile() throws IOExceprtion 

 

- 74 ~ 75p

 

 

 

테스트를 작성할 때는 클래스 동작에 집중해야 하며 개별 메서드를 테스트한다고 생각하면 안 됩니다. 

 

그 의미를 위해 지루하지만 오랜 시간 검증된 예인 은행의 ATM 클래스를 생각해 봅시다. 그 클래스의 메서드에는 deposit(), withdraw(), getBalance()가 있습니다. 다음 테스트로 시작합시다. 

 

- makeSingleDeposit

- makeMultipleDeposits

 

각 테스트 결과를 검증하려면 getBalance() 메서드를 호출해야 합니다. 하지만 getBalance() 메서드만 검사하는 테스트는 만들고 싶지 않을 것입니다. 그 메서드는 단지 객체의 필드만 리턴하므로 의미가 없기 때문입니다. 테스트 대상이 될만한 흥미로운 동작에는 입금과 출금 같은 다른 동작이 먼저 나와야 합니다. 

 

withdraw() 메서드로 옮기면 다음과 같습니다. 

 

- makeSingleWithdrawal

- makeMultipleWithdrawals

- attemptToWithdrawTooMuch

 

모든 출금 테스트를 위해서는 먼저 입금(잔고가 있는 ATM 객체를 초기화 하려면 입금을 해야함)할 필요가 있습니다. 그렇지 않으면 테스트를 효과적으로 작성하기가 쉽지 않습니다.

 

단위 테스트를 작성할 때는 먼저 전체적인 시각에서 시작해야 합니다. 개별 메서드를 테스트하는 것이 아니라 클래스의 종합적인 동작을 테스트해야 합니다.

 

- 80p 

 

 

@Before 메서드는 매번 테스트 메서드 실행에 앞서 실행됩니다. 

- 91p 

 

 

테스트 제외 

- 96p

(@Ignore 애터네이션을 사용하기)

 

 

 

성능 염려 : 그러지 않아도 된다

 

어떤 독자는 혼란스러울 수 있습니다. matches() 메서드를 리팩토링한 결과 anymatches()), calculateScore(), doesNotMeetAnyMustMatchCrieterion() 메서드 각각에 criterion 조건에 대한 반복문을 갖게 되었습니다. 새로운 반복문 세  개로 matches() 메서드는 잠재적으로 실행 시간이 네 배가 되었습니다.

 

우리 답변은 "그래서 어쨌다는 겁니까?"입니다. 

 

- 178p

 

 

 

명령-질의 분리 

 

어떤 값을 반환하고 부작용을 발생시키는 메서드는 명령-질의 분리(command-query separation) 원칙을 위반합니다. 이 원칙에 따르면 어떤 메서드는 명령을 실행하거나 질의에 대답할 수 있으며, 두 작업을 모두 하면 안 됩니다. 

 

- 192p

 

 

반응형