Java/Spring

[Java Spring] 프로젝트 생성 후 테스트 코드

씬프 2021. 5. 30. 19:09
반응형

테스트 주도 개발은 아니여도 단위 테스트는 작성하는 것이 좋다.

 

Testing the Web Layer

this guide is designed to get you productive as quickly as possible and using the latest Spring project releases and techniques as recommended by the Spring team

spring.io

 

간단한 index 페이지를 불러오는 Controller 작성 후 테스트 코드

1. 웹 애플리케이션이 동작하는지 확인하는 테스트

package kr.scene.board;

import kr.scene.board.controller.BoardController;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.assertj.core.api.Assertions.*;

@SpringBootTest
class BoardApplicationTests {

    @Autowired
    private BoardController boardController;

    @Test
    public void 컨트롤러_확인() throws Exception {
        assertThat(boardController).isNotNull();
    }
    
}

@SpringBootTest 애너테이션은 해당 클래스가 스프링 애플리케이션을 동작시킨다는 것과 @SpringBootApplication이 붙은 메인 클래스를 찾아 실행한다는 것을 의미한다.

 

@Autowired 애너테이션은 해당하는 인스턴스가 스프링 컨테이너에 자동 주입되도록 한다. 현재 BoardController의 인스턴스를 생성해 스프링 컨테이너에 자동 주입한다.

 

assertThat() 메서드는 파라미터로 전달되는 인스턴스에 대해 테스트한다. 현재 controller 인스턴스에 대해 테스트하는데, isNotNull() 메서드를 통해 해당 컨트롤러가 Null인지 확인한다. (Null이 아니면 테스트 OK)

 

2. 애플리케이션이 동작하면서 연결 대기를 하는지, 요청에 응답하는지 확인하는 테스트

package kr.scene.board.controller;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;


import static org.assertj.core.api.Assertions.*;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class BoardControllerTest {

    @LocalServerPort
    private int port;

    @Autowired
    private TestRestTemplate testRestTemplate;

    @Test
    public void httpTest() throws Exception {
        assertThat(this.testRestTemplate
                .getForObject("http://localhost:" + port + "/", String.class)
                .contains("not contains")
        );
    }

}

@SpringBootTest 애너테이션에 webEnvironment = WebEnvironment.RANDOM_PORT가 파라미터로 전달되었다. 이는 애플리케이션이 실행될 때, 임의의 값으로 PORT를 설정하게 된다. 그리고 @LocalServerPort 애너테이션이 붙은 변수에 값을 주입한다.

 

TestRestTemplate 클래스를 통해 인스턴스를 생성했다. (@Autowired 를 통해 스프링 컨테이너에 자동 주입)

TestRestTemplate는 RestTemplate를 테스트하기 위한 클래스이다. getForObject() 메서드는 파라미터로 전달된 URI의 템플릿에 GET 방식으로 접근해 대표? 설명?을 검색한다. (retrieve a representation) 그리고 지정된 클래스 타입으로 반환한다. (현재 String.class)

주어진 String 타입에 대해 contains() 메서드를 통해 문자열이 포함되어 있는지 확인한다.

 

3. 또 다른 테스트 방법 (MockMvc)

TestRestTemplate는 서버를 실행시켜야 한다.  서버를 실행시키지 않고도 테스트할 수 있는 MockMvc를 사용한다.

package com.example.testingweb;

import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;

@WebMvcTest
public class WebLayerTest {

	@Autowired
	private MockMvc mockMvc;

	@Test
	public void shouldReturnDefaultMessage() throws Exception {
		this.mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk())
				.andExpect(content().string(containsString("Hello, World")));
	}
}

@WebMvcTest 에 특정 컨트롤러를 파라미터로 전달하면 특정 컨트롤러에 대한 테스트가 가능하다.

MockMvc 자세히 따로 살펴볼 필요가 있다. 컨트롤러가 많아지면 서버 실행하지 않고 테스트하는 것이 필요함.

 

perform() 메서드는 파라미터로 URI를 담은 HTTP method를 받는다. 해당 URI에 지정된 방식으로 접근을 요청한다. ResultActions 타입을 반환한다. ResultActions는 인터페이스로 실행된 요청의 결과를 담는다.

andDo()와 andExpect(), andReturn() 메서드를 갖는다.

andDo()는 ResultHandler를 파라미터로 전달받아 요청에 대해 처리한다. 일반적으로 print()

andExpect()는 ResultMatcher를 파라미터로 전달받아 예상 값을 검증한다. 현재 status().isOk() HTTP 연결 상태가 OK (상태코드 200)을 예측하고, content().string(containsString("Hello, World")로 내용에 문자열로 "Hello, World"를 포함하는지 예측하고 검증한다.

 

주의

HTTP Response Body에 담긴 내용을 검증한다.