반응형

@SpringBootTest는 @SpringBootApplication 부터 시작하는 모든 빈을 스캔하고 등록해준다.

 

 

1. 시작은 spring-boot-starter-test 의존성 추가하는 것부터!

저는 스프링 이니셜라이져로 생성해서 자동으로 추가되었습니다.

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-test</artifactId>
	<scope>test</scope>
	<exclusions>
		<exclusion>
			<groupId>org.junit.vintage</groupId>
			<artifactId>junit-vintage-engine</artifactId>
		</exclusion>
	</exclusions>
</dependency>

pom.xml

 

 

 

2. main 코드

package com.example.springboottest.sample;

import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SampleController {

    @Autowired
    private SampleService sampleService;

    @GetMapping("/hello")
    public String hello(){
        return "hello" + sampleService.getName();
    }
}

SampleController.java

 

 

@Service
public class SampleService {
    public String getName() {
        return "naeun";
    }
}

SampleService.java

 

 

 

3. @SpringBootTest

  • @RunWith(SpringRunner.class)랑 같이 써야 함.
  • 빈 설정 파일은 설정을 안해주나? 알아서 찾습니다. (@SpringBootApplication)

 

4. webEnvironment

  • MOCK: mock servlet environment. 내장 톰캣 구동 안 함.
  • RANDON_PORT, DEFINED_PORT: 내장 톰캣 사용 함.
  • NONE: 서블릿 환경 제공 안 함.

 

 

 

 

여기서 잠깐! Mock란?

실제 객체를 만들기엔 비용과 시간이 많이 들거나 의존성이 길게 걸쳐져 있어 제대로 구현하기 어려울 경우, 가짜 객체를 만들어 사용하는데, 이를 Mocking 이라고 한다.

 

여기서 잠깐! Dispatcher-Servlet이란?

Servlet Container에서 HTTP프로토콜을 통해 들어오는 모든 요청을 프레젠테이션 계층의 제일앞에 둬서 중앙집중식으로 처리해주는 프론트 컨트롤러(Front Controller)이다. 클라이언트로부터 어떠한 요청이 오면 Tomcat(톰캣)과 같은 서블릿컨테이너가 요청을 받는데, 이때 제일 앞에서 서버로 들어오는 모든 요청을 처리하는 *프론트 컨트롤러를 Spring에서 정의하였고, 이를 Dispatcher-Servlet이라고 합니다. 

 

여기서 잠깐! Front Controller란?

Front Controller는 주로 서블릿 컨테이너의 제일 앞에서 서버로 들어오는 클라이언트의 모든 요청을 받아서

처리해주는 컨트롤러인데, MVC 구조에서 함께 사용되는 패턴이다.

 

여기서 잠깐! @Autowired란?

이 어노테이션을 부여하면 각 상황의 타입에 맞는 IoC컨테이너 안에 존재하는 빈을 자동으로 주입해준다.

 

 

 

 

1) WebEnvironment 가 MOCK 일 때,

MockMVC 라는 클라이언트를 사용하려면

 

-> mockup이 된 서블릿과 인터렉션 하려면 MockMVC라는 클라이언트가 필요하다.

@AutoConfigureMockMvc : 어노테이션 추가

@Autowired
MockMvc mockMvc; : 본문에 추가

 

package com.example.springboottest.sample;

import org.junit.Test;
import org.junit.runner.RunWith;
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.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import static org.junit.jupiter.api.Assertions.*;

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;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@AutoConfigureMockMvc
public class SampleServiceTest {

    @Autowired
    MockMvc mockMvc;

    @Test
    public void hello() throws Exception {
        mockMvc.perform(get("/hello"))
                .andExpect(status().isOk())
                .andExpect(content().string("hellonaeun"))
                .andDo(print());
    }
}

SampleControllerTest.java

 

 

이렇게 하고 hello를 run하면 ! 에러가 뜬다...

junit 버전이 12이상 필요하다고 해서 12로 고쳐주었더니 잘 작동된다.

 

-> 여러가지 정보들을 보여준다.

 

 

 

 

 

2) WebEnvironment 가 RANDOM_PORT 일 때, (내장 톰캣이 뜸)

test용 restTemplate나 test용 client를 사용해야 한다. 

 

먼저 restTemplate을 사용해보자.

테스트할 때마다 Service단위로 가져오는게 부담스럽기 때문에 가짜 객체를 만들어준다.

-> @MockBean

  • ApplicationContext에 들어있는 빈을 Mock으로 만든 객체로 교체 함.
  • 모든 @Test 마다 자동으로 리셋.
import org.junit.Test;
import org.junit.runner.RunWith;
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.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
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;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SampleControllerTest {

    @Autowired
    TestRestTemplate testRestTemplate;

    @MockBean
    SampleService mockSampleService;

    @Test
    public void hello() throws Exception {
        when(mockSampleService.getName()).thenReturn("whiteship");

        String result = testRestTemplate.getForObject("/hello",String.class);
        assertThat(result).isEqualTo("hellowhiteship");

    }
}

SampleControllerTest.java

 

둘 다 whiteship으로 변경하여 테스트해보니 정상적으로 작동한다.

 

 

 

 

다음으로 webTestClient를 사용해보자.

webTestClient 는 RestTemplate과 다르게 비동기 방식이다.

 

 

webflux 의존성 추가해준다.

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

 

 

test용 client 사용을 위해 restTemplate 대신,

@Autowired
WebTestClient webTestClient; 을 추가해준다.

package com.example.test2.sample;

import org.junit.Test;
import org.junit.runner.RunWith;
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.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.test.web.servlet.MockMvc;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
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;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SampleControllerTest {

    @Autowired
    WebTestClient webTestClient;

    @MockBean
    SampleService mockSampleService;

    @Test
    public void hello() throws Exception {
        when(mockSampleService.getName()).thenReturn("whiteship");

        webTestClient.get().uri("/hello").exchange()
                .expectStatus().isOk()
                .expectBody(String.class).isEqualTo("hellowhiteship");

    }
}

SampleControllerTest.java

 

 

 

 

 

 

 

슬라이스 테스트

  • 레이어 별로 잘라서 테스트하고 싶을 때
  • @JsonTest
  • @WebMvcTest
  • @WebFluxTest
  • @DataJpaTest
  • ...
반응형

+ Recent posts