개발/java

JUnit

ebang 2023. 11. 3. 16:20
반응형

#개발 #java  #테스트코드
정의: Java 생태계에서 제공하는 단위 테스트 프레임워크

(추가적으로 보고 싶은: - [Using Gradle in the Eclipse IDE](https://www.vogella.com/tutorials/EclipseGradle/article.html))

Junit


Junit 테스트는, 테스트 목적으로 만들어진 클래스 내에서 @Test 어노테이션이 붙은 메소드이다. 
기대값과 실제 값을 비교하는 assert 구문을 이용하여 테스트를 할 수 있다.
특히 실패했을 경우 @DisplayName 어노테이션을 통해, 출력하는 메시지를 정하여 보다 수월하게 확인할 수 있다.

예시 코드

package com.vogella.junit5;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;

class CalculatorTest {

    Calculator calculator;

    @BeforeEach                                         
    void setUp() {
        calculator = new Calculator();
    }

    @Test                                               
    @DisplayName("Simple multiplication should work")   
    void testMultiply() {
        assertEquals(20, calculator.multiply(4, 5),     
                "Regular multiplication should work");  
    }

    @RepeatedTest(5)                                    
    @DisplayName("Ensure correct handling of zero")
    void testMultiplyWithZero() {
        assertEquals(0, calculator.multiply(0, 5), "Multiple with zero should be zero");
        assertEquals(0, calculator.multiply(5, 0), "Multiple with zero should be zero");
    }
}






static import : 클래스에서 public static으로 선언된 필드 및 메소드인 자바 기능. 
다음과 같은 차이가 있다.

// without static imports you have to write the following statement
import org.junit.jupiter.api.Assertions;
// more code
Assert.assertEquals("10 x 5 must be 50", 50, tester.multiply(10, 5));


// alternatively define assertEquals as static import
import static org.junit.jupiter.api.Assertions.assertEquals;
// more code
// use assertEquals directly because of the static import
assertEquals(calculator.multiply(4,5), 20, "Regular multiplication should work");



간단한  assert 문

`org.junit.jupiter.api.Assertions.*` package. 에 있는 static method

오버헤드 방지를 위해서 람다 함수 형식으로 메시지를 작성하기도 한다.

assertTrue('a' < 'b', () -> "Assertion messages can be lazily evaluated -- " + "to avoid constructing complex messages unnecessarily.");



## 예외를 위한 테스트
org.junit.jupiter.api.Assertions.expectThrows()

import static org.junit.jupiter.api.Assertions.assertThrows; 
@Test void exceptionTesting() { 
	// set up user 
	Throwable exception = assertThrows(IllegalArgumentException.class,
							() -> user.setAge("23")); 
    assertEquals("Age must be an Integer.", exception.getMessage()); 
    
}


여러개의 assert 문을 사용하려고 할 때

@Test
void groupedAssertions() {
    Address address = new Address();
    assertAll("address name",
        () -> assertEquals("John", address.getFirstName()),
        () -> assertEquals("User", address.getLastName())
    );
}


시간 제한 두기

assertTimeout()

import static org.junit.jupiter.api.Assertions.assertTimeout;
import static java.time.Duration.ofSeconds;
import static java.time.Duration.ofMinutes;

@Test
void timeoutNotExceeded() {
    assertTimeout(ofMinutes(1), () -> service.doBackup());
}

// if you have to check a return value
@Test
void timeoutNotExceededWithResult() {
    String actualResult = assertTimeout(ofSeconds(1), () -> {
        return restService.request(request);
    });
    assertEquals(200, request.getStatus());
}



advance: dynamic test


컴파일 시점에만 돌아가는 테스트 코드와 달리, 
다이나믹 테스트는 런타임 동안에 테스트가 생성되고 수행된다.
래서 프로그램이 수행되는 도중에도 동작을 변경할 수 있는 특징이 있다. 


이 다이나믹 테스트는 `@Test` 어노테이션을 사용하지 않고, `@TestFactory` 어노테이션을 통해 팩토리 메서드로 생성된다.

장점:
- 정적 테스트는 지정해놓은 데이터만으로 테스트해야한다.
- 반면 다이나믹 테스트를 사용하면 데이터셋을 런타임 시점에 동적으로 가져와서 테스트를 수행할 수 있다. (getNumberFromDatatbase.. )
- 하나의 메소드 안에서 사용자 시나리오를 작성하는 경우, 가독성이 약해지고 BDD (행위 주도 개발)을 하는 의미가 약해진다.
- 다이나믹 테스트 같은 경우, 첫번째 인자로 테스트 제목을 붙일 수 있어서 가독성을 높일 수 있다고 한다.

방법
- @TestFactory 어노테이션 사용: 테스트 케이스를 생성하는 팩토리
  private, static은 안된다.
- 컬렉션 반환
@TestFactory 메소드는 Stream, Collection, Iterable or Iterator를 return해야한다. (그렇지 않으면 JUnitException 발생)
- 첫번째 이름으로 테스트 이름 작성

기본 형식

@TestFactory
Stream<DynamicTest> exampleDynamicTest() {
	return Stream.of(
		dynamicTest("First Dynamic Test", () -> {
			//test code
       }),
		dynamicTest("Second Dynamic Test", () -> {
			//test code
	}));
}


다이나믹 테스트는 생명주기 콜백함수를 지원하지 않기 때문에, @BeforeEach, @AfterEach 와 같은 테스트 생명 주기와 관련된 요소들을 사용할 수 없다.

반응형