Back-end/테스트

JUnit 테스트 - Assertions

javapp 자바앱 2022. 9. 24. 00:00
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