이 정리는 자바와 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 테스트 메서드로 분리하자
-
단언이 실패하면 실패한 테스트 이름이 표시되기 때문에 어느 동작에서 문제가 있는지 빠르게 파악할 수 있다
-
별도의 JUnit 테스트 메서드로 분리되어 있기 때문에 실패한 테스트를 해독하는 데 필요한 시간을 줄일 수 있다. 현재 실패한 테스트에 대해 다른 테스트의 영향을 제거할 수 있다
-
모든 케이스가 실행되었음을 보장할 수 있다. 단언이 실패하면 현재 테스트 메서드는 중단한다. 단언 실패 이후의 테스트 케이스는 실행되지 않는다.
일관성 있는 이름으로 테스트 문서화
multipleDeposits -> multipleDepositsIncresaseBalanceBySumOfDeposits
다른 프로그래머가 보더라도, 이름만 보고 그 메서드 혹은 클래스가 무엇을 하는지 알 수 있게
양식 예
- doingSomeOperationGeneratesSomeResult
어떤 동작을 하면 어떤 결과가 나온다
- whenDoingSomeBehaviorThenSomeResultOccurs
어떤 일을 하면 어떤 결과가 나온다
테스트 제외
1
2
3
4
5
@Test
@Ignore("don't forget me!")
public void somethingWeCannotHandleRightNow(){
}
@Ignore 어노테이션을 이용하여 테스트를 제외시킬 수 있다 (설명 메세지는 생략 가능)