본문 바로가기
Back-end/테스트

JUnit 테스트 - Assertions

by javapp 자바앱 2022. 9. 24.
728x90

테스트

 

 

단위 테스트

 

Automated tests

Better code design

Fewer bugs and higher reliability

Increases confidence for code refactoring

DevOps and Build Pipelines

CI/CD

 

 

 

통합 테스트

하향식 통합 테스트

    깊이 우선, 너비 우선

    Stub (가짜 모듈) 사용

 

 

상향식 통합 테스트

    클러스터 : 하위 모듈 그룹

    드라이버 : 더미 모듈

    순서

        낮은 수준 모듈들을 클러스터로 결합

        드라이버 작성

        클러스터 검사/테스트

        드라이버 제거하고 클러스터를 상위로 결합

 

유닛테스트 프레임워크

JUnit

 

Mockito

 

 

 


 

Unit Test

Process

  • Set Up
  • Execute
  • Assert

 

class DemoUtilsTest
{
	@Test
    void testEqualsAndNotEquals()
    {
    	// set up
        DemoUtils demoUtils = new DemoUtils();
        int expected= 6;
        
        // execute
        int actual= demoUtils.add(2,4);
        
        // assert
        Assertions.assertEquals(expected, actual, "2+4 는 6이다.");
    }
}

 

 


 

Execution Sequence

 

@BeforeAll (static method)

 

  @BeforeEach

    @Test Method One

  @AfterEach

 

  @BeforeEach

    @Test Method Two

  @AfterEach

 

@AfterAll  (static method)

 

 

 


 

 

Custom Display Names

현재 테스트를 할 때 그 결과는 단순히 클래스명과 테스트한 메소드 명을 보여주고 있다.

 

그래서 애노테이션을 추가하여

커스텀된 테스트 결과 리스트를 보여주려고 함.

 

 

@DisplayName("..")

각 메소드마다 애노테이션을 추가하여 테스트에 대한 설명을 적을 수 있음.

사용해본 결과 : 번거로운 점이 있음

    @Test
    @DisplayName("Equals and Not Equals")
    void testEqualsAndNotEquals(){
        DemoUtils demoUtils = new DemoUtils();
        assertEquals(6,demoUtils.add(2,4), " 2 +4 = 6");
        assertNotEquals(6,demoUtils.add(2,7), " 2 +4 = 6");
    }

    @Test
    @DisplayName("Null and Not Null")
    void testNullAndNotNull(){
        DemoUtils demoUtils = new DemoUtils();

        String str1= null;
        String str2 = "javapp";

        assertNull(demoUtils.checkNull(str1), "Object should be null");
        assertNotNull(demoUtils.checkNull(str2), "Object should be null");
    }

 

 

제너레이터를 둔다.

DisplayNameGenerator.ReplaceUnderscores.class --> 밑줄을 공백으로 대체해줌.

 

@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)

@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
public class DemoUtilsTest {

    @Test
    void test_Equals_And_Not_Equals(){
        DemoUtils demoUtils = new DemoUtils();
        assertEquals(6,demoUtils.add(2,4), " 2 +4 = 6");
        assertNotEquals(6,demoUtils.add(2,7), " 2 +4 = 6");
    }

    @Test
    void test_Null_And_Not_Null(){
        DemoUtils demoUtils = new DemoUtils();

        String str1= null;
        String str2 = "javapp";

        assertNull(demoUtils.checkNull(str1), "Object should be null");
        assertNotNull(demoUtils.checkNull(str2), "Object should be null");
    }
}

단 한번 애노테이션을 써서 사용할 수 있으며

메소드 명을 통해 테스트를 설명할 수 있음.

사용해본 결과 : 스네이크 표기법을 쓰면서 "_" 사용에 부자연스러움

DisplayName 보다는 효율적임

 

 

 

Simple 일 경우 단순히 메소드 마지막 소괄호 제거

@DisplayNameGeneration(DisplayNameGenerator.Simple.class)

 

 

IndicativeSentences

어떤 클래스에서 어떤 메소드를 사용했는지 제공해줌.

@DisplayNameGeneration(DisplayNameGenerator.IndicativeSentences.class)

 

 


 

 

Assertions

 

assertEquals , assertNotEquals

assertNull , assertNotNull

assertSame

assertNotSame

 

assertTrue

assertFalse

 

assertArrayEquals

assertIterableEquals

 

assertLinesMatch

 

assertThrows

assertDoesNotThrow

assertTimeoutPreemptively

 

 

JUnit 메이븐 의존성 추가

 

 

단위 테스트

 

assertEquals , assertNotEquals(기대값, 테스트값, message);

결과

assertEquals 성공

assertNotEquals 실패

 

 

 

assertNull , assertNotNull(테스트값, message);

    public Object checkNull(Object obj) {
        return null;
    }

 

 

    public Object checkNull(Object obj) {
        if (obj != null) {
            return obj;
        }
        return null;
    }

null 일때 파라미터 타입으로 반환

 

 

 


 

 

assertSame

assertNotSame

 

assertTrue

assertFalse

    @Test
    @DisplayName("Same and Not Same")
    void testSameAndNotSame()
    {
        String str= "code";

        assertSame(demoUtils.getAcademy(), demoUtils.getAcademyDuplicate(),"같은 값을 가진다.");
        assertNotSame(str,demoUtils.getAcademy());
    }

    @Test
    @DisplayName("True and False")
    void testTrueFalse()
    {
        int gradeOne= 10;
        int gradeTwo = 5;

        assertTrue(demoUtils.isGreater(gradeOne, gradeTwo), "this should return true");
        assertFalse(demoUtils.isGreater(gradeTwo, gradeOne), "this should return false");
    }

 

 


 

 

 

 

 

assertArrayEquals

assertIterableEquals

  • 예상 반복 가능 항목과 실제 반복 가능 항목이 동일한지 확인
  • LinkedList 및 ArrayList 의 값 비교 가능
    @DisplayName("Array Equals")
    @Test
    void testArrayEquals(){
        String [] stringArray={"A","B","C"};
        assertArrayEquals(stringArray, demoUtils.getFirstThreeLettersOfAlphabet(),"배열의 값이 같다.");
    }

    @DisplayName("Iterable equals")
    @Test
    void testIterableEquals(){
        List<String> theList = List.of("academy","In","List");
        assertIterableEquals(theList,demoUtils.getAcademyInList(),"리스트의 요소들이 같다.");
    }

 

 

assertLinesMatch

  • 예상 목록이 실제 목록과 일치하는지 확인
    @DisplayName("Iterable equals")
    @Test
    void testLinesMatch(){
        List<String> theList = List.of("academy","In","List");
        assertLinesMatch(theList,demoUtils.getAcademyInList(),"리스트의 요소들이 같다.");
    }

 


 

Throws Test

예외 처리 테스트

 

assertThrows

assertDoesNotThrow

public class DemoUtils {

	public String throwException(int a) throws Exception {
        if (a < 0) {
            throw new Exception("0 보다 같거나 커야 됩니다.");
        }
        return "값이 0보다 크거나 같습니다.";
    }
    ...
}
    @DisplayName("예외 테스트")
    @Test
    void testThrowsAndDoesNotThrow(){
        assertThrows(Exception.class, ()->{demoUtils.throwException(-1);}, "예외 발생");

        assertDoesNotThrow(()->demoUtils.throwException(-1), "예외가 발생하면 안됨.");
    }

assertDoesNotThrow 의 에러 메시지와

메소드에 의한 에러 메시지 출력

 

 

타임아웃 테스트

assertTimeoutPreemptively

    @DisplayName("타임 아웃 테스트")
    @Test
    void test3secTimeout(){
        assertTimeoutPreemptively(Duration.ofSeconds(3), ()->{
            demoUtils.checkTimeout(); // 2초간의 작업
        }, "메소드는 3초안에 처리되어야 한다.");
    }

 

 

 


 

 

 

테스트 순서

 

@TestMethodOrder(MethodOrderer.MethodName.class) // 메소드명 순서

@TestMethodOrder(MethodOrderer.DisPlayName.class) // 디스플레이 명 순서

@TestMethodOrder(MethodOrderer.OrderAnnotation.class) + @Order(n) // 음수 가능

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class DemoUtilsTest
{ 
	@Order(1)
	@Test
    @DisplayName("...")
    method()
}

 

 

 


 

 

 

 

파라미터를 이용한 테스트 반복

 

@ParameterizedTest    // 파라미터를 이용하여 테스트를 할 수 있음.

어떤 데이터 자원 포맷을 사용할 것인지 애노테이션을 작성

@ValueSource(strings = {""," "})

 

@NullSource   // primitive 타입은 불가

@EmptySource

@NullAndEmptySource

 

@EnumSource(Month.class)

 

@MethodSource    // 복잡한 인수 전달

 

 

사용예시)

@ParameterizedTest    // 파라미터를 이용하여 테스트를 할 수 있음.
@ValueSource(strings = {""," "})

 

 

실습) CSV 에서 (값 , 예상값) 을 파라미터로 가져와서 반복 단위 테스트

FizzBuzzTest.java

// csv 파일을 활용한 반복 테스트
@DisplayName("csv 파일을 활용한 반복 테스트")
@ParameterizedTest(name="value={0}, expected={1}")
@CsvFileSource(resources="/small-test-data.csv")
@Order(5)
void testCsvDataFile(int value, String expected){

    assertEquals(expected, FizzBuzz.compute(value), "1 리턴");
}

 

JUnit 은 실제로 해당 테스트를 호출합니다. 백그라운드에서

CSV 파일을 통해 데이터를 여러번 생성하며 모든 반복 작업을 처리합니다.

 

 

 

 

 

https://www.jetbrains.com/help/idea/junit.html

 

JUnit 5 | IntelliJ IDEA

 

www.jetbrains.com

 

 

https://junit.org/junit5/docs/current/user-guide/#writing-tests

 

JUnit 5 User Guide

Although the JUnit Jupiter programming model and extension model do not support JUnit 4 features such as Rules and Runners natively, it is not expected that source code maintainers will need to update all of their existing tests, test extensions, and custo

junit.org

 

댓글