[테스트] JUnit 이란?

노경준·2022년 2월 17일
0
post-thumbnail

글을 작성하게된 동기

최근 학교 친구들과 합동 프로젝트를 진행하던 도중 테스트코드에 대한 관심이 생겼어요.
프로젝트를 진행하면서 그냥 팀원들이 테스트 코드를 작성하길래
테스트 코드를 대충 공부하고 작성해봤던 경험이 있었는데,
테스트 코드에 대한 중요성을 모르고 작성하니 이게 잘 작성되고 있는건지도 모를정로 대충 작성한것 같았어요.

제가 프로젝트를 진행하면서 중요하다고 생각했던 부분은

  • 합동 프로젝트를 진행하면서 PR을 올리기 전 ./gradlew clean build 를 사용하여 빌드가 성공적으로 되는지 였는데 clean build를 하면서 통합 테스트를 진행 하더라구요. 그 과정에서 모든 서비스로직이 정상적으로 동작하는지 체킹하는 기능이 있어서 "테스트 코드 괜찮은데??" 라는 생각을 가졌어요.
  • 테스트 케이스를 작성했을때의 또 다른 이점은 aws에서 서버를 올리기 전에도 ./gradlew clean build를 진행할때 서비스로직에 문제점이 생기면 build failed가 떠서 신속히 대처했던 경험이 있었어요.

테스트 코드의 위력은 이것보다 훨씬 많은데 제 나약한 실력으로 인해 이정도의 이점을 못느낀것같아서 아쉬웠어요.

그래서 이번 공부를 통하여 테스트 코드에 대한 이해력이 더 늘었으면 좋겠고 잘 적용하여 프로젝트 품질 향상에 더 기여 하고싶어요.

우선 이번 편은 Java 진영의 대표적인 Test Framework인 JUnit 에 대해 알아보아요.

JUnit 에 대한 간단한 설명

  • 단위 테스트(Unit Test)를 위한 도구를 제공 합니다.

  • 단위 테스트란?
    코드의 특정 모듈이 의도된 대로 동작하는지 테스트 하는 절차를 의미
    모든 함수와 메소드에 대한 각각의 테스트 케이스(Test Case)를 작성하는 것

  • 어노테이션(Annotation)을 기반으로 테스트를 지원

  • 단정문(Assert) 으로 테스트의 기대값에 대해 수행 결과를 확인할 수 있음

  • Spring Boot 2.2버전부터 JUnit 5 버전을 사용

JUnit LifeCycle(생명주기) Annotation

@Test : 테스트용 메소드를 표현하는 어노테이션
@BeforeEach : 각 테스트 메소드가 시작되기 전에 실행되어야 하는 메소드를 표현
@AfterEach : 각 테스트 메소드가 시작된 후 실행되어야 하는 메소드를 표현
@BeforeAll : 테스트 시작 전에 실행되어야 하는 메소드를 표현 (static 처리 필요)
@AfterAll : 테스트 종료 후에 실행되어야 하는 메소드를 표현 (static 처리 필요 )

Junit Main Annotation

@SpringBootTest

  • 통합 테스트 용도로 사용됨
  • @SpriBootApplication을 찾아가 하위의 모든 Bean을 스캔하여 로드함
  • 그 후 Test용 Application Context를 만들어 Bean을 추가하고, MockBean을 찾아 교체

@WebMvcTest(Class명.class)

  • ()에 작성된 클래스만 로드하여 테스트 진행
  • 매개변수를 지정해주지 않으면 @Controller, @RestController, @RestControllerAdvice 등 컨트롤러와 연관된 Bean이 모두 로드됨
  • 스프링의 모든 Bean을 로드하는 @SpringBootTest 대신 컨트롤러 관련 코드만 테스트할 경우 사용

@Autowired about Mockbean

  • Controller의 API를 테스트하는 용도인 MockMvc 객체를 주입 받음

@MockBean

  • 테스트할 클래스에서 주입 받고 있는 객체에 대해 가짜 객체를 생성해주는 어노테이션
  • 해당 객체는 실제 행위를 하지 않음
  • given() 메소드를 활용하여 가짜 객체의 동작에 대해 정의하여 사용할 수 있음

@AutoConfigureMockMvc

  • spring.test.mockmvc 의 설정을 로드하면서 MockMvc의 의존성을 자동으로 주입
  • MockMvc 클래스는 REST API 테스트를 할 수 있는 테스트

@Import

  • 필요한 Class들을 Configuration으로 만들어 사용할 수 있음
  • Configuration Componet 클래스도 의존성 설정할 수 있음
  • Import된 클래스는 주입으로 사용 가능

통합 테스트

통합 테스트는 여러 기능을 조합하여 전체 비즈니스 로직이 제대로 동작하는지 확인하는 것을 의미합니다.

통합 테스트의 경우, @SpringBootTest를 사용하여 진행합니다.

  • @SpringBootTest는 @SpringBootApplication을 찾아가서 모든 Bean을 로드하게 됩니다.
  • 이 방법을 대규모 프로젝트에서 사용할 경우, 테스트를 실행할 때마다 모든 빈을 스캔하고 로드하는 작업이 반복되어 매번 무거운 작업을 수행해야 합니다.

단위 테스트

  • 단위 테스트는 프로젝트에 필요한 모든 기능에 대한 테스트를 각각 진행하는 것을 의미합니다.

  • 일반적으로는 스프링 부트에서는 'org.springframework.boot:spring-boot-starter-test' 디펜던시만으로 의존성을 모두 가질 수 있어요.

F.I.R.S.T 원칙

  • Fast : 테스트 코드의 실행은 빠르게 진행되어야 함
  • Independent : 독립적인 테스트가 가능해야 함
  • Repeatable : 테스트는 매번 같은 결과를 만들어야 함
  • Self-Validating : 테스트는 그자체로 실행하여 결과를 확인할 수 있어야 함
  • Timely : 단위 테스트는 비즈니스 코드가 완성되기 전에 구성하고 테스트가 가능해야 함
    ( 코드가 완성되기 전부터 테스트가 따라와야 한다는 TDD의 원칙을 담고 있음 )

단위 테스트도 알아봤으니 간단하게 LifeCycle 을 테스트⌨️ 해볼까요??

Junit LifeCycle 테스트

package com.project.library.test;

import org.junit.jupiter.api.*;

public class TestLifeCycle {

    @BeforeAll // 테스트 시작 전 제일 우선으로 실행되는 어노테이션
    static void beforeAll(){
        System.out.println("beforeAll Annotation 호출");
        System.out.println();
    }

    @AfterAll // 테스트 종료 후 제일 마지막으로 실행되는 어노테이션
    static void afterAll(){
        System.out.println("afterAll Annotation 호출");
        System.out.println();
    }

    @BeforeEach // 테스트 시작 전 실행되는 어노테이션 ( 실행순서 BeforeAll -> BeforeEach )
    void beforeEach(){
        System.out.println("beforeEach Annotation 호출");
        System.out.println();
    }

    @AfterEach // 테스트 종료 후 실행되는 어노테이션 ( 실행순서 afterEach -> afterAll )
    void afterEach(){
        System.out.println("afterEach Annotation 호출");
        System.out.println();
    }

    @Test
    void test1(){
        System.out.println("test1 시작");
        System.out.println();
    }

    @Test
    @DisplayName("DisplayName Use : test2") // 테스트의 이름을 설정하는 어노테이션
    void test2(){
        System.out.println("test2 시작");
        System.out.println();
    }

    @Test
    @Disabled // 통합 테스트를 무시하는 어노테이션
    void test3(){
        System.out.println("test3 시작");
        System.out.println();
    }
}

LifeCycleTest 결과

이처럼 위와 같은 순서로 결과가 출력되는걸 확인할 수 있었어요 😊

참고한 자료

profile
커뮤니케이션을 좋아하는 개발자

0개의 댓글