본문 바로가기
springboot

[springboot] 컨트롤러 JUnit 테스트

by 개발LOG 2024. 2. 14.

Controller JUnit 테스트할 때의 어노테이션 정리

 

@ExtendWith(SpringExtension.class) //JUnit5 버전, JUnit5 버전은 @RunWith

- 스프링 부트 테스트와 JUnit 사이에 연결자 역할

 

@AutoConfigureMockMvc //@WebMvcTest(@Service, @Repository   테스트 불가능, 컨트롤러 테스트만 가능) 비슷한 의미

- MockMvc 제어하는 어노테이션

- @Controller 뿐만 아니라 @Service, @Repository 모두 테스트 가능

 

@SpringBootTest

- 테스트에 필요한 거의 모든 의존성 제공

- Autowired 허용하여 객체 의존성 주입

- 사용 시 @ExtendWith(SpringExtension.class) 이미 포함하고 있기 때문에 @ExtensionWith을 사용하지 않아도 됨

 

@Autowired

private MockMvc mvc;

- 스프링이 관리하는 빈(Bean) MockMvc 객체 의존성 주입 받음

- @SpringBootTest 어노테이션이 없다면 의존성 주입이 되지 않아 값이 null로 처리됨

 

@Test

- 테스트할 메서드

 

테스트 내용 예시:

	@Test
	public void hello(){
	//given
        String hello = "hello";

        //when, then
        mvc.perform(get("/hello")) //get매핑으로 /hello 요청
                .andExpect(status().isOk()) // 200번 OK상태인지 확인
                .andExpect(content().string(hello)); //hello 리턴하는지 확인
              }

 

 

 

참고소스:

package com.jojoldu.book.springboot.web;


import com.jojoldu.book.springboot.config.auth.SecurityConfig;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;


import static org.hamcrest.Matchers.is;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

//@RunWith(SpringRunner.class) // JUnit4 버전
@ExtendWith(SpringExtension.class) //JUnit5 버전
@WebMvcTest(controllers = HelloController.class,
        excludeFilters = {
                @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = SecurityConfig.class)
        }
) //웹(컨트롤러)만 테스트 가능 , 서비스or레포지토리 테스트 안됨
public class HelloControllerTest {
    @Autowired
    private MockMvc mvc; //개발한 웹 프로그램을 실제 서버에 배포하지 않고도 테스트를 위한 요청을 제공 즉, 웹 API 테스트 할 때 사용, 이 클래스를 통해 HTTP GET, POST등에 대한 API테스트

    @Test
    @WithMockUser(roles = "USER")
    public void hello가_리턴된다() throws Exception {
        //given
        String hello = "hello";

        //when, then
        mvc.perform(get("/hello")) //get매핑으로 /hello 요청
                .andExpect(status().isOk()) // 200번 OK상태인지 확인
                .andExpect(content().string(hello)); //hello 리턴하는지 확인
    }

    //@WithMockUser(roles="USER")
    @Test
    @WithMockUser(roles = "USER")
    public void helloDto가_리턴된다() throws Exception {
        //given
        String name = "hello";
        int amount = 1000;

        //when, then
        mvc.perform(
                        get("/hello/dto")
                                .param("name", name)
                                .param("amount", String.valueOf(amount)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.name", is(name))) //json 응닫값이 name과 같은지
                .andExpect(jsonPath("$.amount", is(amount))); //json 응답값이 amount와 같은지
    }


}
package com.jojoldu.book.springboot.web;


import com.jojoldu.book.springboot.web.dto.PostsSaveRequestDto;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jojoldu.book.springboot.domain.posts.Posts;
import com.jojoldu.book.springboot.domain.posts.PostsRepository;
import com.jojoldu.book.springboot.web.dto.PostsUpdateRequestDto;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.http.*;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@ExtendWith(SpringExtension.class) //JUnit5 버전
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) //컨트롤러,서비스,레포지토리사용할때
public class PostsApiControllerTest {
    @LocalServerPort
    private int port;

    @Autowired
    private PostsRepository postsRepository;
    /*
    --- 아래 context, mvc, setup() 해줘야 mvc를 @SpringBootTest로 사용할 수 있음(컨트롤러,서비스,레포지토리 테스트하려면)
    --- 웹API(컨트롤러)만 테스트 하려면
        @WebMvcTest(controllers = HelloController.class,
             excludeFilters = {
                     @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = SecurityConfig.class)
             }) 랑
        @Autowired
        private MockMvc mvc; 이거써서 테스트 가능

    */

    @Autowired
    private WebApplicationContext context;

    private MockMvc mvc;
    @BeforeEach
    public void setup() {
        mvc = MockMvcBuilders.webAppContextSetup(context).build();
    }

    @AfterEach
    public void tearDown() throws Exception {
        postsRepository.deleteAll();
    }

    @Test
    @WithMockUser(roles = "USER")
    public void Posts_등록된다() throws Exception {
        //given
        String title = "title";
        String content = "content";
        PostsSaveRequestDto requestsDto = PostsSaveRequestDto.builder()
                .title(title)
                .content(content)
                .author("author")
                .build();

        String url = "http://localhost:" + port + "/api/v1/posts";

        //when
        mvc.perform(post(url)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(new ObjectMapper().writeValueAsString(requestsDto)))
                .andExpect(status().isOk());

        //then
        List<Posts> all = postsRepository.findAll();
        assertThat(all.get(0).getTitle()).isEqualTo(title);;
        assertThat(all.get(0).getContent()).isEqualTo(content);
    }


    @Test
    @WithMockUser(roles = "USER")
    public void Posts_수정된다() throws Exception {
        //given
        Posts savedPosts = postsRepository.save(Posts.builder().title("title").content("content").author("author").build());

        Long updateId = savedPosts.getId();
        String expectedTitle = "title2";
        String expectedContent = "content2";

        PostsUpdateRequestDto requestDto = PostsUpdateRequestDto.builder().title(expectedTitle).content(expectedContent).build();

        String url = "http://localhost:" + port + "/api/v1/posts/" + updateId;


        //when
        mvc.perform(put(url)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(new ObjectMapper().writeValueAsString(requestDto)))
                .andExpect(status().isOk());

        //then
        List<Posts> all = postsRepository.findAll();
        assertThat(all.get(0).getTitle()).isEqualTo(expectedTitle);
        assertThat(all.get(0).getContent()).isEqualTo(expectedContent);
    }


}

 

 

 

 

참고링크:

https://velog.io/@gale4739/Spring-Boot-Controller-test-with-JUnit5

 

Spring Boot Controller test (with JUnit5)

안녕하세요 오늘은 Spring Boot에서 Controller를 생성해보고 이를 테스트해보는 방법에 대해서 포스팅하려고 합니다. 출처 : https://junit.org/junit5/docs/current/user-guide/ 우선 저는 어노테이션으로 간단하

velog.io

https://www.inflearn.com/questions/834733/springboottest%EC%99%80-extendwith-contextconfiguration-%EC%B0%A8%EC%9D%B4%EA%B0%80-%EA%B6%81%EA%B8%88%ED%95%A9%EB%8B%88%EB%8B%A4

 

@SpringBootTest와 @ExtendWith + @ContextConfiguration 차이가 궁금합니다. - 인프런

안녕하세요. 강의 잘 듣고 있습니다!일반적으로 사용하는 스프링 컨테이너를 포함하는 @SpringBootTest와 강의에서 사용하신 @ExtendWith + @ContextConfiguration의 차이점이 궁금합니다.@ExtendWith(SpringExtension

www.inflearn.com

 

 

https://www.inflearn.com/questions/834733/springboottest%EC%99%80-extendwith-contextconfiguration-%EC%B0%A8%EC%9D%B4%EA%B0%80-%EA%B6%81%EA%B8%88%ED%95%A9%EB%8B%88%EB%8B%A4