no image
[TestCode] AssertJ에 대하여(JUnit5)
💻AssertJ란 AssertJ는 많은 assertion을 제공하는 자바 라이브러리이다. 오류 메세지와 테스트 코드의 가독성을 높이고 자신이 사용하는 IDE에서 사용하기에 용이하다. AssertJ는 사이드 프로젝트로 만들어졌다. 만약 무엇인가 잘못된것이 있다면 언제든지 피드백을 할 수 있다고 원작자가 말하였다. 가독성 이야기를 해보자면 //JUnit assertEquals(expected, actual); //AssertJ assertThat(actual).isEqualTo(expected); 두 예제가 있는데 첫번째가 JUnit에서 제공하는 assertEquals이다. 아래는 AssertJ의 AssertThat이다. AssertThat이 확실히 직관적으로 보이고 가독성이 올라간다. 가장 기본적인 예제 ..
2021.12.07
no image
[TestCode] JUnit5 기본 메뉴얼
프로젝트가 작을 때는 그냥 테스트 코드는 선택인 줄 알고 그냥 소홀히 했다. 그러나 하면 할 수록 테스트 코드가 중요하다는 걸 몸으로 느끼고 많은 개발자들이 테스트 코드에 대해서 강조하신다. 그래서 그냥 공부만 하려고 했으나 정리를 해놓으면 더 깔끔하게 머릿속에 들어올 거 같아서 정리하려고 한다. 🤖테스트 코드와 테스트 메서드 테스트 클래스란 최상위 클래스 , static member class, @Nested 클래스에 적어도 한 개의 @Test 어노테이션이 달린 테스트 메서드가 포함돼있는 걸 말한다. 테스트 클래스는 추상 클래스면 안되고 하나의 생성자가 있어야 한다. 테스트 메서드란 @Test @RepeatTest @ParamterizedTest @TestFactory @TestTemplate 같은 메..
2021.12.05
728x90

💻AssertJ란

AssertJ는 많은 assertion을 제공하는 자바 라이브러리이다. 오류 메세지와 테스트 코드의 가독성을 높이고 자신이 사용하는 IDE에서 사용하기에 용이하다.

AssertJ는 사이드 프로젝트로 만들어졌다. 만약 무엇인가 잘못된것이 있다면 언제든지 피드백을 할 수 있다고 원작자가 말하였다.


가독성 이야기를 해보자면 

//JUnit
assertEquals(expected, actual); 

//AssertJ
assertThat(actual).isEqualTo(expected);

두 예제가 있는데 첫번째가 JUnit에서 제공하는 assertEquals이다. 아래는 AssertJ의 AssertThat이다.

AssertThat이 확실히 직관적으로 보이고 가독성이 올라간다.

 

가장 기본적인 예제

@Test 
void simple_case() { 
	assertThat("ABCD").isNotNull() 
    	    .startsWith("A")
            .contains("BC") 
            .endsWith("D"); 
         
}

봐도 어느정도는 어떤말인지 감은 온다. "ABCD"라는 문자열이 NULL이 아니고 "A"로 시작하고 "BC"가 포함되어 있고 "D"로 끝난다는 테스트 예제이다.

 

이제 다양한 예제를 보자


💻Filtering assertions

@Test
void filter_test1(){

    List<Human> list = new ArrayList<>();
    Human k = new Human("Kim",22);
    Human a = new Human("Aim",23);
    Human p = new Human("Park",42);
    Human j = new Human("Jin",12);
    Human y = new Human("yun",32);

    list.add(k);
    list.add(a);
    list.add(p);
    list.add(j);
    list.add(y);

    Assertions.assertThat(list).filteredOn(human ->
                human.getName().contains("i"))
                .containsOnly(a,j,k);

}

예를 보면 Human클래스에는  이름과 나이가 있다. filteredOn은 직관적으로 걸러낸다?이렇게 생각하면 쉬울것이다.

이름을 모두 가져와서 이름중에 i가 포함되는 이름을 걸러낸다. 그 다음 containOnly로 a,j,k 가 맞는지 검증한다.

 

💻객체의 property를 검증 예제

@Test
void filter_test2() {
   
     List<Human> list = new ArrayList<>();
     Human k = new Human("Kim",22);
     Human a = new Human("Aim",23);
     Human p = new Human("Park",42);
     Human j = new Human("Jin",12);
     Human y = new Human("yun",32);

    
     list.add(k);
     list.add(a);
     list.add(p);
     list.add(j);
     list.add(y);

     Assertions.assertThat(list).
                filteredOn("age", 22)
                .containsOnly(k);
}

위와 세팅은 같다. assertThat 구문에서 프로퍼티에 값에 접근하여 값을 검증한다.

 

값이 포함되지 않은 경우도 검증을 할 수 있다.

@Test
void filter_test3() {

        List<Human> list = new ArrayList<>();
        Human k = new Human("Kim",22);
        Human a = new Human("Aim",23);
        Human p = new Human("Park",42);
        Human j = new Human("Jin",12);
        Human y = new Human("yun",32);

        list.add(k);
        list.add(a);
        list.add(p);
        list.add(j);
        list.add(y);

        Assertions.assertThat(list)
                .filteredOn("age", notIn(22))
                .containsOnly(k);
}

notIn안에 들어간 값이 없는 객체만 검증하는것이다. 

나머지로는 In,not등이 있다. not과 notIn은 거의 동일하다.

 

💻property 추출하기 

extracting을 사용하면 테스트를 할때  객체 이름을 검증하기 위해 반복문에서 이름을 꺼내고 또 다른 리스트에 담고 비교하는 불편한 과정을 간편하게 해결할 수 있다.

 

@Test
void filter_test4() {

      List<Human> list = new ArrayList<>();
      Human k = new Human("Kim",22);
      Human a = new Human("Aim",23);
      Human p = new Human("Park",42);
      Human j = new Human("Jin",12);
      Human y = new Human("yun",32);

      list.add(k);
      list.add(a);
      list.add(p);
      list.add(j);
      list.add(y);

      Assertions.assertThat(list).extracting("name")
                .contains("Kim","Aim","Park","Jin","yun");
}

list를 넘겨도 list에서 어떤 함수를 부르고 걸러진 값들에 대한 필드를 추출(extracting)해서 검증할 수 있다.

 

또, 필드명뿐만 아니라 클래스 타입을 명시하여 검증을 강하게 할 수 있다.

@Test
void filter_test5() {

      List<Human> list = new ArrayList<>();
      Human k = new Human("Kim",22);
      Human a = new Human("Aim",23);
      Human p = new Human("Park",42);
      Human j = new Human("Jin",12);
      Human y = new Human("yun",32);

      list.add(k);
      list.add(a);
      list.add(p);
      list.add(j);
      list.add(y);

      Assertions.assertThat(list).extracting("name",String.class)
                .contains("Kim","Aim","Park","Jin","yun");
    }

 

그리고 튜플로도 추출이 가능하다. 여러개의 필드를 검증할 때 유용하다.

@Test
void filter_test6() {
     
      List<Human> list = new ArrayList<>();
      Human k = new Human("Kim",22);
      Human a = new Human("Aim",23);
      Human p = new Human("Park",42);
      Human j = new Human("Jin",12);
      Human y = new Human("yun",32);

      list.add(k);
      list.add(a);
      list.add(p);
      list.add(j);
      list.add(y);

     Assertions.assertThat(list).extracting("name","age")
                .contains(tuple("Kim",22)
                        ,tuple("Aim",23)
                        ,tuple("Park",42)
                        ,tuple("Jin",12)
                        ,tuple("yun",32));
    }

 

💻String assertions

문자열 검증 예시이다.

@Test
void stringAssertions(){
      String s = "ABCDE";

      Assertions.assertThat(s).startsWith("A").contains("BCD").endsWith("E");

}

 

💻DBB 스타일

@Test
void DBB_st()throws Exception{
        //given
        
        //when
        Throwable t = catchThrowable(()-> {
            throw new Exception("Exception");
        });
        
        //then
        Assertions.assertThat(t).isInstanceOf(Exception.class)
                .hasMessageContaining("Exception");
        
    
}

given.when.then 주석으로 가독성이 높고 순차적으로 어디서 어떤 작업을 하는지 알기 용이하다.

 

 

💻Exception test(테스트 예외 처리)

@Test 
public void exception_assertion() { 
	assertThatThrownBy(() -> { 
    		throw new Exception("exception"); 
            	}).isInstanceOf(Exception.class) 
                .hasMessageContaining("exception"); };

assertThatThrownBy()는 Trowable보다 가독성이 높게 작성할 수 있다.

 

예외 처리 문법 예제

@Test 
public void exception_assertion() { 
    assertThatIOException().isThrownBy(() -> {
    	throw new IOException("exception"); 
        }) 
        .withMessage("exception") 
        .withMessageContaining("exception") 
        .withNoCause(); 
 }
@Test 
public void testException() { 
    assertThatExceptionOfType(IOException.class).isThrownBy(() -> { 
    	throw new IOException("exception"); 
       }) 
        .withMessage("exception") 
        .withMessageContaining("exception") 
        .withNoCause(); 
}

 

🧑🏻‍💻예제 코드 : https://github.com/ryudongjae/blog-ex

 

GitHub - ryudongjae/blog-ex: 📁블로그 예제 코드

📁블로그 예제 코드 . Contribute to ryudongjae/blog-ex development by creating an account on GitHub.

github.com


⌨️REFERENCE

https://pjh3749.tistory.com/241

728x90

'Dev > TestCode' 카테고리의 다른 글

[TestCode] JUnit5 기본 메뉴얼  (0) 2021.12.05
728x90

프로젝트가 작을 때는 그냥 테스트 코드는 선택인 줄 알고 그냥 소홀히 했다.

그러나 하면 할 수록 테스트 코드가 중요하다는 걸 몸으로 느끼고 많은 개발자들이 테스트 코드에 대해서 강조하신다. 그래서 그냥 공부만 하려고 했으나 정리를 해놓으면 더 깔끔하게 머릿속에 들어올 거 같아서 정리하려고 한다.

 

🤖테스트 코드와  테스트 메서드

  • 테스트 클래스란
    • 최상위 클래스 , static member class, @Nested 클래스에 적어도 한 개의 @Test 어노테이션이 달린 테스트 메서드가 포함돼있는 걸 말한다. 테스트 클래스는 추상 클래스면 안되고 하나의 생성자가 있어야 한다.
  • 테스트 메서드란 
    • @Test @RepeatTest @ParamterizedTest @TestFactory @TestTemplate 같은 메타 어노테이션이 메서드에 붙여진 메서드를 말한다.
    • 테스트 메서드와 라이프사이클 메서드는 테스트를 진행할 클래스, 상속한 부모 클래스 또는 인터페이스에 선언된다. 그리고 테스트 메서드와 라이프 사이클 메서드는 추상 클래스 선언을 하면 안 되고, 어떠한 값도 리턴되어선 안된다.

 

 

 

🔬JUnit 

JUnit은 단위 테스트를 위한 테스트용 프레임워크이다.  JUnit 홈페이지에 JUnit5는 JUnit Platform, JUnit Jupiter, JUnit Vintage가 합쳐진 것이라고 한다.

 

  • JUnit Platform
    • JUnit Platform은 JVM에서 테스트 프레임워크를 실행하는데 기초를 제공하고, TestEngine API를 제공해 테스트 프레임워크를 개발할 수 있다.
  • JUnit Jupiter
    • JUnit Jupiter는 JUnit 5에서 테스트를 작성하고 확장을 하기 위한 새로운 프로그래밍 모델과 확장 모델의 조합이다.
  • JUnit Vintage
    • JUnit Vintage는 하위 호환성을 위해 JUnit 3 ,JUnit 4를 기반으로 돌아가는 플랫폼에 테스트 엔진을 제공해준다.

 

JUnit 5 사용 시 Java 8부터 지원하기 때문에 그 이상의 버전으로 진행해야 한다.

 


🔬테스트 코드 작성

위 예제는 테스트 코드 작성 예시로 최소 조건으로 작성한 것이다.

테스트 코드는 테스트를 구성하고 프레임워크를 상속하기 위해서 다양한 어노테이션을 제공한다.

 

  • @DisplayName : 테스트 클래스 또는 메서드에 이름을 붙여줄 때 사용한다. 테스트 코드에서는 메서드명이 한국어로 가능하지만 이 어노테이션으로 작성하면 내가 생각하기에는 깔끔하다고 생각한다.

 

이런 식으로 이름이 자신이 @DisplayName으로 설정한 값이 따라온다.

  • @DisplayNameGeneration : @Test 메서드 이름에 언더 바로 표시된 부분은 공백으로 처리된다.
  • @BeforeEach : 각 테스트 메서드가 실행되기 전에 실행되어야 하는 메서드를 명시해준다. 테스트 전에 필요한 데이터를 셋업 할 때 많이 사용한다. 

이처럼 메서드에 미리 데이터를 넣어 값을 미리 세팅한 다음 테스트를 진행할 수 있다.

  • @BeforeAll : @BeforeEach는 각 메서드 실행 전 실행되지만 이 메서드는 테스트 시작 전 딱 한 번만 실행된다.
  • @AfterEach : @BeforeEach와 원리는 동일하다 테스트가 끝날 때마다 실행된다. 이 메서드는 혹여나 데이터를 삽입하는데 중복되거나 하는 우려를 해결하기 위해 테스트 끝나면 데이터를 삭제해줄 때 사용한다.

  • @AfterAll : @BeforeAll가 원리가 같다. 테스트가 완전히 끝난 후 한번 실행된다.
  • @Disable :  테스트 클래스나, 테스트 메서드를 비활성화한다. JUnit 4에서는 @Ignore과 같은 역할이다.
  • @Tag : 테스트를 필터링할 때 사용한다. 클래스 또는 메서드 레벨에 사용한다.
  • @ExtendWith : extension을 등록한다. 이 어노테이션은 상속이 가능하다.
  • @RegisterExtension : 필드를 통해 extension을 등록한다. private이 아니라면 상속된다.
  • @TimeOut : 주어진 시간 안에 테스트가 끝나지 않으면 테스트에 실패한다.

이런 식으로 메서드 시간제한을 둘 수 있다. 위 메서드는 2초 안에 테스트가 끝나지 않으면 실패한다.

 

 

🧑🏻‍💻예제 코드 : https://github.com/ryudongjae/blog-ex

 

GitHub - ryudongjae/blog-ex: 📁블로그 예제 코드

📁블로그 예제 코드 . Contribute to ryudongjae/blog-ex development by creating an account on GitHub.

github.com


👍🏻REFERENCE

https://donghyeon.dev/junit/2021/04/11/JUnit5-완벽-가이드/

 

JUnit5 완벽 가이드

시작하기전

donghyeon.dev

 

728x90

'Dev > TestCode' 카테고리의 다른 글

[TestCode] AssertJ에 대하여(JUnit5)  (0) 2021.12.07