Notice
Recent Posts
Recent Comments
Link
«   2026/01   »
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
Archives
Today
Total
관리 메뉴

SSinsa

9. JUnit으로 테스팅하기 본문

Java/Java Programming

9. JUnit으로 테스팅하기

SSinsa 2020. 2. 18. 23:34
JUnit 테스트는 어떻게 실행하는가?

JUnit은 커맨드라인에서 직접 호출가능 -> JUnit 라이브러리의 JUnitCode 클래스

(*이 클래스는 커맨드라인에서 테스트를 시작하는 데 사용하는 main 메서드가 있음, 매개변수는 테스트하려는 클래스의 리스트

 

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>

나는 위의 의존성 추가 했다 (자동으로 추가되었지만...)

 

테스트 매개변수는 와일드카드를 사용할 수 있음

 

JUnit 테스트를 실행할 때 어떤 일이 일어나는가?

테스트 세트는 대개 클래스에 한정됨

JUnit 4에 어노테이션이 도입되기 전의 클래스에는 TestSuit 클래스를 확장해야했음

따라서 전체 테스트 세트를 실행하기 전에 한 번 실행되는 메서드나 메서드 집합을 정의할 수 있음

-> 대체로 시간이 오래 걸리는 계산을 정의하는 메서드를 정의할 때 테스트 세트를 사용하면 좋음

 

    @BeforeClass
    public void junitTestExample() {
        
    }

-> @BeforeClass 사용법

void 타입 반환, public, 정적 메서드

+ @AfterClass 는 테스트 세트 클래스에서 생성된 인스턴스에는 접근할 수 없기에, 모든 테스트가 완료된 후에 실행하도록 하는 어노테이션

 

※ @BeforeClass 어노테이션으로 표시한 메서드의 테스트가 성공하면 테스트 실행기는 테스트 세트에서 각 테스트에 다음 단계를 수행

  1. 테스트 세트의 새로운 인스턴스가 생성된다. 모든 자바 클래스처럼 생성자 코드가 실행된다. 테스트 세트 클래스는 매개변수가 없는 단일 생성자를 선언한다.
  2. 객체 생성이 끝난 후에 @Before 어노테이션과 void 타입을 반환하는 모든 public 메서드가 실행된다. 이는 대개 목객체나 상태를 갖는 객체처럼 모든 테스트에 공통으로 설정된다. 각 테스트 이전에 이 단계가 실행되므로 객체가 올바른 상태를 유지하게 하거나 테스트에서 기대하는 상태로 파일 시스템을 설정하는 데 이 메서드를 이용할 수 있다. 생성자와 @Before 메서드가 개별 테스트 이전에 실행된다는 것은 이 단계에서 모든 테스트를 준비할 수 있음을 의미한다. 즉, @Before 어노테이션으로 선언한 메서드에서 설정을 하고, @After 어노테이션으로 선언한 메서드를 이용해 대칭성을 유지할 수 있다.
  3. 테스트가 실행된다. @Test 어노테이션으로 정의된 테스트는 public이고 void 타입값으로 반환된다.
  4. 테스트가 성공하거나 실패한 후에 @After 어노테이션으로 선언한 메서드(public void 속성이다)가 호출된다. 데이터베이스나 파일 시스템 또는 일부 테스트 후 로깅같은 지저분한 데이터들을 깔끔하게 정리한다.

@Before, @After, @Test -> 각 메서드의 실행 순서는 보장하지 않는다

즉, 테스트는 독립적이고 원자적이어야만 한다. => JUnit의 핵심

 

package controller;

import org.junit.*;

import java.util.Arrays;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

public class JUnitLifecycle {
    private static int counter = 0;

    @BeforeClass
    public static void suiteSetup() {
        System.out.println("1");
        assertEquals(0, counter);
        counter++;
    }

    public JUnitLifecycle() {
        System.out.println("2");
        assertTrue(Arrays.asList(1, 5).contains(counter));
        counter++;
    }

    @Before
    public void prepareTest() {
        System.out.println("3");
        assertTrue(Arrays.asList(2, 6).contains(counter));
        counter++;
    }

    @Test
    public void peformFirstTest() {
        System.out.println("4");
        assertTrue(Arrays.asList(3, 7).contains(counter));
        counter++;
    }

    @Test
    public void peformSecondTest() {
        System.out.println("5");
        assertTrue(Arrays.asList(3, 7).contains(counter));
        counter++;
    }

    @After
    public void cleanupTest() {
        System.out.println("6");
        assertTrue(Arrays.asList(4, 8).contains(counter));
        counter++;
    }

    @AfterClass
    public static void suiterFinished(){
        System.out.println("7");
        System.out.println("last" + counter);
        assertEquals(9, counter); //값예상하고 다르면 에러나게 만들기!

    }
}

코드로 확인해보려고 짠 코드

 

결과값

1
2
3
4
6
2
3
5
6
7
last9

Process finished with exit code 0

보면 @Test를 만나면 새로 초기화하는 것을 알 수 있다 -> 이때 사용하는 것이 @Ignore

 

두번째 @Test부터 @Ignore을 붙이니

1
2
3
4
6

Test ignored.
7
last5

초기화하고 다시 시작하지 않았지만, 

@After랑 @AfterClass는 출력됨

 

테스트가 성공인지 어떻게 증명할 수 있는가?

JUnit 라이브러리의 핵심 클래스 중 하나는 Assert 클래스다. -> 이 클래스는 가정을 표현하는 데 사용하는 많은 정적 메서드가 있다. 

 

  • assertEquals 두 개의 객체가 자신들의 equals 메서드에 따라 같은지 비교한다.
  • assertTrue와 assertFalse 주어진 상태를 Boolean 예상치와 비교한다
  • assertNotNull 객체가 null이 아니다
  • assertArrayEquals 두 배열에 같은 값이 있다. Object 배열의 비교라면 equals 메서드로 동일성을 검사한다.

(실패단계에서 사용하는 메서드는 필요할때 fail 호출)

ex)

public static void assertTrue(String message, boolean condition)
public static void assertTrue(boolean condition)

 

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

@Test 어노테이션은 두 개의 매개변수를 받을 수 있음

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

2. timeout //long 타입임, 밀리세컨드 단위

 

@Test(timeout = 1000L)
public void serviceResponseTime() {
	...
}

특정 메서드 시간을 확인하고 싶다면

new Thread(highScoreRunnable).start();
assertTrue(latch.await(1, TimeUnit.SECONDS));

 

 

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

@RunWith 어노테이션은 Runner 클래스의 하위 클래스

JUnit은 기본적으로 몇 가지 실행기가 있으며, 일반적으로 선택하는 것은 Parameterized 클래스다

 

==> 여기 헬이다 공부가 필요할 듯

 

행위 주도 개발이란 무엇인가?

BDD(Behavior-Driven Development) : 가능한 한 자연 언어에 가깝게 자연 언어에 가깝게 작성된 테스트 스크립트와 테스트 스크립트 뒤에서 실행되는 코드라는 두 개의 요소로 이루어져있다.

 

이 테스트들의 기반이 되는 동기는 구현 코드에 독립적인 고수준의 테스트를 제공하는 것이다. 기본적으로 시스템을 블랙박스로 취급하며, 이 테스트들은 '시스템 테스트'라고 부른다.

 

스텝 : 미리 지정한 명령어 집합 -> Given, When, Then

 

  • Given 스텝은 다음 스텝을 따라야 하는 시스템을 확인할 수 있는 상태로 만든다
  • When 스텝은 테스트의 행위를 수행한다. 테스트할 때 시스템의 측정 가능한 효과가 있어야만 한다
  • Then 스텝은 When 스텝이 성공적으로 수행됐는지 확인한다

(순서가 매우 중요)

 

public class CucumberSteps {
    private int a;
    private int b;
    private int calculation;
    
    @Given("^the numbers (.*) and (.*)$")
    public void captureNumbers(final int a, final int b){
    	this.a = a;
        this.b = b;
    }
    
    @When("^the numbers are added together$")
    public void addNumbers() {
    	this.calculation = a+b;
    }
    
    @Then("^the result is (.*)$")
    public void assertResult(final int expectedResult) {
    	assertEquals(expectedResult, calculation);
    }
}

@RunWith(Cucumber.class)
public class CucumberRunner {}

 

 

 

 

'Java > Java Programming' 카테고리의 다른 글

5. 어노테이션 이용하기  (0) 2020.02.05
4. 오토박싱과 언박싱 이해하기  (0) 2020.02.05
3. 제네릭 이해하기  (0) 2020.01.15
2. String 이용하기  (0) 2020.01.15
1. 배열과 리스트의 관계  (0) 2020.01.15