TDD

자바와 JUnit을 활용한 실용주의 단위 테스트 정리-1

Posted by Damin on January 21, 2021

이 정리는 자바와 JUnit을 활용한 실용주의 단위 테스트를 보고 개인적으로 정리한 글 입니다

테스트 구조 AAA

A : Arrange -> 준비 A : Act -> 실행 A : Assert -> 단언

위에서 아래의 순서대로 테스트 구조가 흘러간다

Before 어노테이션

각 Test 메서드 실행 전에 실행되는 메서드 각 Test 메서드 실행 전에 실행 되기 때문에 여러가지의 Test 메서드가 있다면

@Before -> @Test -> @Before -> @Test -> …

이런 순서로 흘러간다

Before 메서드를 여러개로 나눌 수 있다. 하지만, 실행 순서를 보장하지 않기 때문에 일정한 순서가 필요하다면 단일 @Before 메서드로 결합하여 순서대로 실행되도록 해야 한다

BeforeClass 는 클래스에 있는 어떤 테스트를 처음 실행하기 전에 단 한 번만 실행된다

@BeforeClass -> @Before -> @Test -> @Before -> @Test -> …

After 어노테이션

After 메서드는 각 테스트를 한 후에 실행된다 테스트가 실패하더라도 실행된다

ex) 들어보면 열려 있는 데이터베이스와의 연결을 종료

After 또한 Before 처럼 각 테스트 마다 실행이 된다

@Before -> @Test -> @After -> @Before -> @Test -> @After -> …

AfterClass 는 클래스에 있는 어떤 테스트를 처음 실행하기 전에 단 한 번만 실행된다

@Before -> @Test -> @After -> @Before -> @Test -> @After -> @AfterClass -> …

예외 기대 메서드

@Test(expected=CustomRuntimeException.class)

위와 같이 어노테이션을 사용하면 사용자가 커스터마이징한 예외를 기대할 수 있고, 해당 예외가 일어나면 테스트 성공, 예외가 일어나지 않는다면 테스트 실패 이다

기대 예외 초기화

1
2
3
4
5
6
7
8
9
10
@Rule
public ExpectedException thrown = ExpectedException.none(); // 필드 초기화

@Test
public void exceptionRule(){
    thrown.expect(CustomRuntimeException.class); // 기대하는 예외 설정
    thrown.expectMessage("balance only 0"); // 기대하는 메세지 설정

    account.withdraw(100);
}

내부 데이터 노출 vs 내부 동작 노출

테스트를 위해 내부 데이터를 노출하는 것은 테스트와 프로덕션 코드 사이에 과도한 결합을 초래한다

내부 행위를 테스트 하려는 충동이 든다?

-> 설계에 문제가 있는 것

가장 좋은 해결책은 테스트 하려는 private 메서드를 추출하여 다른 클래스로 public 메서드로 이동시킨다 이렇게 되면 그 클래스의 유용한 public 메서드로 된다 이를 통해 SRP 원칙을 지킬 수 있고, 테스트 또한 할 수 있다

다수의 케이스를 별도의 JUnit 테스트 메서드로 분리하자

  1. 단언이 실패하면 실패한 테스트 이름이 표시되기 때문에 어느 동작에서 문제가 있는지 빠르게 파악할 수 있다

  2. 별도의 JUnit 테스트 메서드로 분리되어 있기 때문에 실패한 테스트를 해독하는 데 필요한 시간을 줄일 수 있다. 현재 실패한 테스트에 대해 다른 테스트의 영향을 제거할 수 있다

  3. 모든 케이스가 실행되었음을 보장할 수 있다. 단언이 실패하면 현재 테스트 메서드는 중단한다. 단언 실패 이후의 테스트 케이스는 실행되지 않는다.

일관성 있는 이름으로 테스트 문서화

multipleDeposits -> multipleDepositsIncresaseBalanceBySumOfDeposits

다른 프로그래머가 보더라도, 이름만 보고 그 메서드 혹은 클래스가 무엇을 하는지 알 수 있게

양식 예

  1. doingSomeOperationGeneratesSomeResult

어떤 동작을 하면 어떤 결과가 나온다

  1. whenDoingSomeBehaviorThenSomeResultOccurs

어떤 일을 하면 어떤 결과가 나온다

테스트 제외

1
2
3
4
5
@Test
@Ignore("don't forget me!")
public void somethingWeCannotHandleRightNow(){

}

@Ignore 어노테이션을 이용하여 테스트를 제외시킬 수 있다 (설명 메세지는 생략 가능)