본문 바로가기
Java

Junit_test

by 이농이능 2018. 8. 5.


Junit 


단위 테스트, 통합 테스트, 시스템 테스트, UI 테스트 등 모든 수준의 테스트를 만들 수 있는 가볍고 단순한 인터페이스 제공

클릭 몇 번으로 하나 또는 열 개의 테스트 셋을 실행할 수 있다. 

작은 변경 사항이 있어도 테스트가 통과하는지 매우 빠르게 알려준다.


JUnit 테스트하면 좋은 점


코드가 올바르게 작동하는 것을 확신할 수 있다. 

이는 서버 측 아키텍쳐를 개발할 때 지속적인 배포 모델을 구축할 수 있는 기반이 된다.

* 지속적인 배포 : 테스트 후 사람이 관여하지 않고 완벽하게 테스트 된 코드를 실제 서버에 자동으로 배포하는 것을 말한다.


Junit 테스트는 보통 TDD(Test-Driven Development)라는 개발 방법론에 기반을 둔다. 

코드가 어떻게 작동하길 바라는지에 관한 예상이나 가정을 기반으로 짧은 실행을 반복하는 테스트를 만드는 절차이다.


절차


코드가 원하는 대로 작동하는지에 관한 예상과 가정을 통해 테스트가 통과하도록 코드를 작성한다.

테스트가 통과하면 다른 기능에도 테스트에 관한 코드를 작성하는 절차를 반복한다.

테스트하려는 기능 모두에 테스트를 작성해다면 모든 테스트가 통과하는지 확인한다.

테스트가 성공하면 코드가 올바르게 작동하는 것으로 믿어도 된다.


작성하는 코드는 반드시 빌드에 통합되어야 하고 코드를 변경했을 때 테스트에 통과하지 못하면 빌드가 중지되어야 한다.

중지된 후에는 문제가 된 코드를 고치고 다시 빌드할 수 있어야 한다. 이렇게 해야 코드를 릴리스했을 때 버그에서 안전해질 수 있다.


JUnit 테스트 생명주기


JUnit 테스트를 실행시 일어나는 일.


테스트 셋은 대개 클래스에 한정된다.

테스트 셋을 일부 코드를 실행하려면 

void 타입 반환하는 public으로 정의한 정적 메소드를 지정하고 @BeforeClass 를 표시하면 된다.


그런데 정적 메서드는 인스턴스 변수가 인스턴스 메서드처럼 테스트 셋 클래스에서 생성된 인스턴스에는 접근할 수 없다.

이러한 사실을 반영해 모든 테스트가 완료된 후 실행할 수 있는 어노테이션은 @AfterClass다.


@BeforeClass 어노테이션으로 표시한 메서드의 테스트가 성공하면  다음 단계를 실행함.


1. 테스트 셋의 새로운 인스턴스가 생성됨. 생성자 코드가 실행되고 테스트 셋 클래스는 매개변수가 없는 단일 생성자를 선언한다.

2. 객체 생성 끝난 후에 @Before 어노테이션과 void 타입을 반환하는 모든 public 메서드가 실행된다. 각 테스트 이전에 이 단계가 실행된다. 

3. 테스트가 실행된다. @Test 어노테이션으로 정의된 테스트는 public이고 void 타입 값으로 유지할 수 있다.

4. 테스트가 성공하거나 실패한 후에 @After 어노테이션으로 선언한 메서드가 호출된다. 데이터베이스나 파일 시스템 또는 일부 테스트 후 로깅 같은 지저분한 메소드를 깔끔하게 정리한다.



코드는 두 개의 테스트를 가진 테스트 셋의 모든 수행 단계를 보여주는 예다.

모든 컴포넌트가 실행되는 순서를 증명하는 데는 카운터를 이용한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package basic.algorithm.test;
 
import static org.junit.Assert.*;
 
import java.util.Arrays;
 
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
 
public class JUnitLifecycle {
    private static int counter = 0;
    
    @BeforeClass
    public static void suiteSetup(){
        assertEquals(0,counter);
        counter++;
    }
    
    public JUnitLifecycle(){
        assertTrue(Arrays.asList(1,5).contains(counter));
        counter++;
    }
    
    @Before
    public void prepareTest(){
        assertTrue(Arrays.asList(2,6).contains(counter));
        counter++;
    }
    
    @Test
    public void performFirstTest(){
        assertTrue(Arrays.asList(3,7).contains(counter));
        counter++;
    }
 
    @Test
    public void perforeSecondTest() {
        assertTrue(Arrays.asList(3,7).contains(counter));
        counter++;
    }
    
    @After
    public void cleanupTest(){
        assertTrue(Arrays.asList(4,8).contains(counter));
        counter++;
    }
    
    @AfterClass
    public static void suiteFinished(){
        assertEquals(9,counter);
    }
 
}
 
cs

 

이 테스트 셋 실행을 담당하는 테스트 실행기는 

@Test 어노테이션이 선언된 메서드를 한 번씩 실행할 때마다 

JUnitLifecycle 인스턴스를 두 번 초기화 한다.


@Ignore 어노테이션을 선언한 모든 테스트 메서드는 무시된다. 

테스트에 문제가 있거나 지속적인 통합 빌드에 문제를 발생시키는 테스트에 자주 사용된다.



JUnit 사용의 좋은 예


테스트가 성공인지 증명하는 법.


JUnit 라이브러리의 핵심 클래스 중 하나는 Assert 클래스이다. 

- assertEquals 두 개의 객체가 자신들의 equals 메서드에 따라 같은지 비교한다.

- assertTrueassertFalse 주어진 상태를 Boolean 예상치와 비교한다.

- assertNotNull 객체가 null이 아니다.

- assertArrayEquals 두 배열에 같은 값이 있다. Object 배열의 비교라면 equals 메서드로 동일성을 검사한다.



모든 assertXXX 메서드들은 추가 String 매개변수와 짝을 지어 오버로드 된다.


public static void assertTrue(String message, boolean condition)

public static void assertTrue(boolean condition)


message 매개변수를 통해서 문제 발생시 나타낼 메시지를 표시할 수 있다.




특정 예외 예상하기


코드에 문제가 있어 예외가 발생하는 상황을 테스트하는 중이라면 해당 테스트에 예상되는 예외 종류를 알려줄 수 있다. 

그리고 테스트에서 해당 예외가 발생하면 이 예외를 처리하게 된다.  

해당 예외를 처리하지 않은 채 테스트가 종료되면 문제가 있다는 의미이다. 


1
2
3
4
    @Test(expected=NoSuchFileException.class)
    public void expectException() throws IOException {
        Files.size(Paths.get("/tmp/non_exist_file.txt"));
    }

cs


@Test 어노테이션의 expected 매개변수는 이 테스트가 예외를 처리해야만 한다고 테스트 실행기에 알려준다.  

IOException이 확인되어야 하는 예외이므로 이 메서드는 여전히 throws IOException을 선언해야 한다. 


그런데 테스트가 한 줄 이상이고 예상되는 예외가 Runtime Exception이나 Throwable처럼 일반적일 때 

예상되는 예외와 다른 경우의 문제를 구분하기가 매우 어렵다.

@Test 어노테이션에서는 expected 매개변수를 많이 사용하지 않는 것이 좋다. 



테스트가 예상했던 시간 안에 완료되지 않으면 테스트가 실패하게 만들기.


@Test 어노테이션은 두 개의 매개변수

1.예외가 발생했을 때 테스트를 통과하게 하는 expected

2. timeout   // 값은 밀리세컨드 단위이고 테스트가 지정된 시간보다 오래 실행하면 실패하게 된다.


예시)

@Test(timeout=1000L)   // 테스트가 1초 안에 완료되지 않으면 예외를 발생시키고 타임아웃 발생 했다는 것을 알려줌.





@RunWith 어노테이션은 어떻게 작동하는가?


@RunWith 어노테이션은 클래스 수준의 어노테이션이고 테스트 실행기의 기본 동작을 변경할 수 있게 해준다.

Runner 클래스의 하위 클래스이다.


JUnit 테스트에 @RunWith(Parameterized.class) 어노테이션을 선언하면 테스트 생명주기에 변화가 일어난다.

  @RunWith는 JUnit 프레임워크의 테스트 실행 방법을 확장할 때 사용하는 애노테이션이다.

@RunWith에 Runner클래스를 설정하면 JUnit에 내장된 Runner대신 그 클래스를 실행한다. 여기서는 스프링 테스트를 위해서 SpringJUnit4ClassRunner라는 Runner 클래스를 설정해 준 것이다.

한 클래스내에 여러개의 테스트가 있더라도 어플리케이션 컨텍스트를 초기 한번만 로딩하여 사용하기 때문에, 여러개의 테스트가 있더라도 처음 테스트만 조금 느리고 그 뒤의 테스트들은 빠르다.



출처: http://countryxide.tistory.com/17 [배워서 남주자]

[자바 프로그래밍 면접 이렇게 준비해라] chapter09. Junit으로 테스팅하기