Notice
Recent Posts
Recent Comments
Link
«   2026/05   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
Tags
more
Archives
Today
Total
관리 메뉴

김쥬르에 개발일지

SpringBoot 테스트 코드 본문

Spring boot

SpringBoot 테스트 코드

김쥬르 2023. 12. 25. 12:53

테스트 코드?

테스트 코드는 작성한 코드가 의도대로 잘 동작하고 예상치 못한 문제가 없는지 확인할 목적으로 작성하는 코드입니다.

 

테스트 코드는 test 디렉터리에 위치해있으며 기본적으로 프로젝트 생성시 test 디렉터리가 존재합니다.

 

테스트 코드에는 다양한 패턴이 존재합니다.

그중 제가 사용할 패턴은 given-when-then 패턴으로

테스트 코드를 세 단계로 구분해 작성하는 방식을 말합니다.

 

given : 테스트 실행을 준비하는 단계

when : 테스트를 진행하는 단계

then : 테스트 결과를 검증하는 단계

 

스프링 부트는 코드를 테스트하기 위한 도구와 어노테이션을 제공합니다

build.gradle에 spring-boot-starter-test 에 테스트를 위한 도구가 모여있고

그중 Junit과 AssertJ를 가장 많이 사용합니다.

Junit과 AssertJ 가 뭔지 알아보겠습니다.

 

JUnit이란?

JUunit은 자바 언어를 위한 단위 테스트 프레임워크입니다.

단위 테스트란 작성한 코드가 의도대로 작동하는지 작은 단위로 검증하는 것을 의미합니다.

이때 단위는 보통 메서드가 됩니다.

 

이제 간단한 예제를 통해 알아보도록 하겠습니다.

 

 

test -> java 폴더에 JUnitTest.java 파일을 생성하고 아래 코드를 작성하겠습니다.

 

public class JUnitTest {
    @DisplayName("1+2는 3이다") // 테스트이름
    @Test // 테스트 메서드
     public void junitTest(){
        int a = 1;
        int b = 2;
        int sum = 3;

        Assertions.assertEquals(a + b, sum); // 값이 같은지 확인
    }
}

 

@DisplayName : 테스트 이름을 명시합니다.

@Test : 테스트를 수행하는 메서드를 지정합니다.

 

assertEquals() 메서드는 JUnit에서 제공하는 검증 메서드로 괄호 안에 식의 참 거짓을 판단합니다. 

 

이제 메서드 줄 좌측에 ▶ 버튼을 눌러 테스트를 실행해보겠습니다.

 

 

테스트가 끝나면 콘솔창에 테스트 결과가 출력되고 그림과 같이 성공여부를 확인할수 있습니다.

 

이번엔 실패에 경우를 보기 위해 테스트 케이스를 하나 더 추가해보겠습니다.

junitTest() 메서드 바로 아래에 코드를 추가하겠습니다.

 

    @DisplayName("1+3는 4이다") // 테스트이름
    @Test // 테스트 메서드
    public void junitFailedTest(){
        int a = 1;
        int b = 3;
        int sum = 3;

        Assertions.assertEquals(a + b, sum); // 값이 같은지 확인
    }
}

 

아래와 같이 실패했다는 표시와 함께 어디서 오류가 났는지 보여주며

에러문구를 통해 에러의 내용까지 확인할수있습니다.

 

 

테스트코드를 설명 드릴때 작은 단위로 진행한다고 하였습니다.

이번에 그 내용을 확인해보고 자주 사용되는 어노테이션도 알아보겠습니다.

 

방금 작성한 junitFailedTest() 메서드는 삭제하고

JUintCycleTest.java 파일을 만들어 코드를 입력해보겠습니다.

 

 

 

public class JUnitCycleTest {

    @BeforeAll // 전체 테스트를 시작하기 전에 1회 실행 메서드는 static으로 선언
    static void beforeAll() {
        System.out.println("@BeforeAll");
    }

    @BeforeEach // 테스트 케이스를 시작하기 전마다 실행
    public void beforeEach() {
        System.out.println("@BeforeEach");
    }

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

    @Test
    public void test2() {
        System.out.println("test2");
    }

    @Test
    public void test3() {
        System.out.println("test3");
    }

    @AfterAll // 전체 테스트를 마치고 종료하기 전에 1회 실행 메서드는 static으로 선언
    static void afterAll() {
        System.out.println("@AfterAll");
    }

    @AfterEach // 테스트 케이스를 종료하기 전마다 실행
    public void afterEach() {
        System.out.println("@AfterEach");
    }

}

 

@BeforeAll

전체 테스트를 시작하기 전에 처음으로 한번만 실행합니다.

예를 들어 데이터베이스를 연결해야하거나 테스트 환경을 초기화할 때 사용됩니다.

@BeforeEach

테스트 케이스를 시작하기 전에 매번 실행합니다.

예를 들어 테스트 메서드에서 사용하는 객체를 초기화하거나 테스트에 필요한 값을 미리 넣을때 사용할 수 있습니다.

@AfterAll

전체 테스트를 마치고 종료하기 전에 한 번만 실행합니다.

예를 들어 데이터베이스 연결을 종료할때나 공통적으로 사용하는 자원을 해제할 때 사용할 수 있습니다.

@AfterEach

각 테스트 케이스를 종료하기 전 매번 실행합니다.

예를 들어 테스트 이후에 특정 데이터를 삭제해야 하는 경우 사용합니다.

 

어노테이션을 중심으로 실행 흐름을 살펴보면

@BeforeEach 부터 @AfterEach까지 테스트 개수만큼 반복합니다.

 

Junit 순서도

출력 결과를 확인해보겠습니다.

 

 

위에 Junit 순서도 그림과 같이

어노테이션에 의한 실행 순서대로 실행 -> 반복 -> 종료 가 되는것을 확인할수있었습니다.

이번에는 함께 사용하면 좋은 AssertJ를 알아보겠습니다.

 

AssertJ란?

JUnit과 함께 사용해 검증문의 가독성을 높여주는 라이브러리입니다.

앞서 작성했던 Assertion.assertEquals 의 경우 기댓값과 비교값이 잘 구분되지 않습니다. 

현재는 코드가 간단하기에 와닿지 않겠지만 코드가 복잡해지고 많아질수록

가독성은 매우 중요한 요소입니다.

 

앞서 작성했다 Assertion코드를 AssertJ 표현으로 바꿔보겠습니다.

assertThat(a+b).isEqualTo(sum);

 

a  와 b 를 더한 값이 sum과 같아야한다 라고 정확히 명시해주기에

코드를 읽는 입장에서 헷갈리지 않습니다.

AssertJ에는 값이 같은지 비교하는 다양한 메서드를 제공합니다.

 

메서드 이름 설명
isEqualTo(A) A 값과 같은지 검증
isNotEqualTo(A) A 값과 다른지 검증
contains(A) A 값을 포함하는지 검증
doesNotContain (A) A 값을 포함하지 않는지 검증
startsWith(A) 접두사가 A인지 검증
endsWith(A) 접미사가 A인지 검증
isEmpty() 비어있는 값인지 검증
isNotEmpty() 비어있지 않은 값인지 검증
isNegative() 양수인지 검증
isGreaterThan(1) 음수인지 검증
isLessThan(1) 1보다 큰 값인지 검증
isLessThan(1) 1보다 작은 값인지 검증

 

이제 본격적으로 테스트 코드를 작성해보겠습니다.

TestController.java 파일을 열고 클래스 이름을 클릭 후 Alt + Enter 을 누르고

Create Test 을 누릅니다 그러면 Create Test 창이 열리고 OK를 누르면 해당 클래스에 Test파일이

test/java/패키지 아래에 생성됩니다.

생성이 되었다면 아래 코드를 작성해보겠습니다.

 

@SpringBootTest // 테스트용 애플리케이션 컨텍스트 생성
@AutoConfigureMockMvc //MockMvc 생성
class TestControllerTest {

    @Autowired
    protected MockMvc mockMvc;

    @Autowired
    private WebApplicationContext context;

    @Autowired
    private MemberRepository memberRepository;

    @BeforeEach
    public void mockMvcSetup() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(context)
                .build();
    }

    @AfterEach
    public void cleanUp() {
        memberRepository.deleteAll();
    }

    @DisplayName("getAllMembers: 아티클 조회에 성공한다.")
    @Test
    public void getAllMembers() throws Exception {
        // given
        final String url = "/test";
        Member savedMember = memberRepository.save(new Member(1L, "홍길동"));

        // when
        final ResultActions result = mockMvc.perform(get(url) // 1
                .accept(MediaType.APPLICATION_JSON)); // 2

        // then
        result
                .andExpect(status().isOk())
                // 응답의 0번째 값이 DB에서 저장한 값과 같은지 확인
                .andExpect(jsonPath("$[0].id").value(savedMember.getId()))
                .andExpect(jsonPath("$[0].name").value(savedMember.getName()));
    }


}

 

@SpringBootTest

@SpringBootApplication이 있는 클래스를 찾고 그 클래스에 포함되어 있는

빈을 찾은 다음 테스트용 애플리케이션 컨텍스트라는 것을 만듭니다.

@AutoConfigureMockMvc

MockMvc를 생성하고 자동으로 구성하는 어노테이션입니다.

MockMvc는 어플리케이션을 서버에 배포하지 않고도 테스트용 MVC환경을 만들어

요청 및 전송,응답 기능을 제공하는 유틸리티 클래스입니다.

 

이제 코드를 순서대로 풀이 해보겠습니다.

1.@Autowired 어노테이션을 통해 빈으로 등록된 각각에 필드들을 주입합니다.

 

2.@BeforEach를 통해 테스트를 실행하기 전에 해당 메서드를 실행합니다.

MockMvcSetUp() 메서드를 실행해 MockMvc를 설정해줍니다.

MockMvcBuilders : MockMvc를 설정하기 위해 사용됩니다.

webAppContextSetup() : 구성된 컨트롤러 한 개 이상을 포함하는

스프링 애플리케이션 컨텍스트를 사용하여 Mock MVC를 만듭니다.

(자세한 내용은 링크를 참조해주세요)

https://velog.io/@hanblueblue/Spring-mvc-standaloneSetup-vs-webAppContextSetup

 

3.@DisplayName를 통해 "~아티클 조회에 성공한다" 라는 테스트 이름을 정해줍니다.

@Test를 통해 해당 메서드가 Test 목적임을 정해줍니다.

//Given

/test 라는 문자열 데이터를 url 이라는 상수(final)에 넣어줍니다.

new Member객체를 생성하여 인자값을 전달하고 

memberRepository.save() 메서드를 사용하여 해당 엔티티를 데이터베이스에 저장합니다.

메서드의 변환 값을 savedMember 변수에 할당합니다.

 

//When

perform()메서드는 요청을 전송하는 역할을 하는 메서드입니다.

결과로 ResultActions객체를 받으며 ResultActions객체는 반환값을 검증하고

확인하는 andExpect() 메서드를 제공합니다.

andExpect()는 아래에서 다시 다루겠습니다.

get(url)은 "get" HTTP GET 요청을 나타내며 "(url)"은 요청이 전송되는 경로를 나타냅니다.

즉 /test라는 url로 GET요청을 보내게됩니다.

.accpt(MediaType.APPLICATION_JSON)은

요청을 보낼때 무슨 타입으로 받을지 결정하는 메서드입니다.

여기서는 JSON 형식임을 나타내며 JSON,XML,PDF 등등 많은 타입이 존재합니다.

 

//Then

.andExpect(status().isOk) 메서드는 응답을 검증합니다.

TestController에서 만든API는 응답으로 OK(200)을 반환하므로

이에 해당하는 메서드인 isOk를 사용해 응답코드가 OK(200)인지 확인합니다

.andExpect(jsonPath("$[0].id").value(savedMember.getId()))

메서드는 JSON 응답에서 특정 필드의 값을 검증합니다.

("$[0].id")는 JSON 배열의 첫번째 요소의 id필드를 나타냅니다

.value(savedMember.getId())는 id 필드의 값이 savedMember.getId()와 일치하는지 확인합니다.

name 또한 id와 동일한 기능입니다.

 

4.@AfterEach를 통해 테스트를 실행한 이후에 해당 메서드를 실행합니다.

cleanUp() 메서드를 실행해 member 테이블에 있는 데이터들을 모두 삭제합니다.

 

HTTP 주요 응답 코드

 

이제 테스트가 잘 동작하는지 확인해보겠습니다.

 

다음 포스팅은 ORM에 대해 포스팅하겠습니다!

'Spring boot' 카테고리의 다른 글

Spring Boot REST API  (2) 2023.12.26
SpringBoot ORM  (0) 2023.12.25
Spring Boot 어노테이션 모음  (0) 2023.12.25
SpringBoot 구조 이해하기  (0) 2023.12.23
SpringBoot 코드 이해하기  (0) 2023.12.22