Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- jpa회원가입
- REST API 규칙
- 스프링 부트 공식 문서
- Unsatisfied dependency
- 스프링 부트 기능
- 복합키
- json
- json gson 차이
- JoinColumn
- JPA주의사항
- Error creating bean with name
- 빈생성안됨
- REST란
- JPA
- uncheck Exception
- 1차캐시
- 최종 프로젝트
- Filter
- jpa에러
- ERD 작성
- github
- Q 클래스
- @IdClass
- 인텔리제이
- jwt메서드
- spring서버
- queryDSL
- 스프링부트오류
- Spring Spring boot 차이
- git
Archives
- Today
- Total
Everyday Dev System
스프링 부트에서 MockMvc를 사용하여 HTTP API 테스트하기 본문
먼저, MockMvc는 SpringBoot 프레임워크에서 내부적으로 자동으로 생성해주어 주입받아 사용할 수 있습니다.
MockMvc를 만들고 테스트하는 방법을 알아보도록 하겠습니다.
1. MockMvc란?
테스트에 필요한 기능만 가지는 가짜 객체를 생성하여 애플리케이션을 실행하지 않고 Test코드만을 활용하여
스프링 MVC 동작을 재현할 수 있도록 돕는 클래스입니다.
[build.gradle]에 의존성 추가를 합니다.
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
2. MockMvc의 메소드
1) perform()
mvc.perform(post("/api/products")
.content(postInfo)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.principal(mockPrincipal) // 토큰
)
.andExpect(status().isOk())
.andDo(print());
- 요청을 전송하는 역할을 합니다.
- 결과로 ResultActions 객체를 반환합니다.
- ResultActions 객체는 반환 값을 검증하고, 확인할 수 있는 andExcpect() 메소드를 제공합니다.
- .andExpect(status().isOk()) → 상태 코드가 isOk()일 것이다 라는 예측을 하는 코드입니다.
- andDo() → 요청/응답 전체 메시지 확인 가능합니다.
mvc.perform(get("/api/user/login"));
HTTP 메소드를 결정할 수 있습니다. ( get(), post(), put(), delete() )
인자로는 uri를 넣어주어야 합니다.
2) param() , params()
MultiValueMap<String, String> signupRequestForm = new LinkedMultiValueMap<>();
signupRequestForm.add("username", "sollertia4351");
signupRequestForm.add("password", "robbie1234");
signupRequestForm.add("email", "sollertia@sparta.com");
signupRequestForm.add("admin", "false");
// when - then
mvc.perform(post("/api/user/signup")
.params(signupRequestForm)
)
.andExpect(status().is3xxRedirection())
.andExpect(view().name("redirect:/api/user/login-page"))
.andDo(print());
}
Key , Value 값의 형태의 파라미터를 전달할 수 있습니다.
여러 개일 때는 params()를, 하나일 때에는 param()을 사용합니다.
.andExpect(status().is3xxRedirection())
→ 반환하는 타입이 redirect 하는 코드인지를 예측합니다.
.andExpect(view().name("redirect:/api/user/login-page"))
→ 성공할 때 반환하는 view name인지를 예측합니다.
빌드업 코드들
package com.sparta.myselectshop.mvc;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sparta.myselectshop.config.WebSecurityConfig;
import com.sparta.myselectshop.controller.ProductController;
import com.sparta.myselectshop.controller.UserController;
import com.sparta.myselectshop.dto.ProductRequestDto;
import com.sparta.myselectshop.entity.User;
import com.sparta.myselectshop.entity.UserRoleEnum;
import com.sparta.myselectshop.security.UserDetailsImpl;
import com.sparta.myselectshop.service.FolderService;
import com.sparta.myselectshop.service.KakaoService;
import com.sparta.myselectshop.service.ProductService;
import com.sparta.myselectshop.service.UserService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.context.WebApplicationContext;
import java.security.Principal;
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
// Security 를 같이 테스트할 때는 아래와 같이 설정하면 됩니다.
@WebMvcTest(
controllers = {UserController.class, ProductController.class},
excludeFilters = {
@ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = WebSecurityConfig.class
)
}
)
class UserProductMvcTest {
private MockMvc mvc;
private Principal mockPrincipal;
@Autowired
private WebApplicationContext context;
@Autowired
private ObjectMapper objectMapper;
@MockBean
UserService userService;
@MockBean
KakaoService kakaoService;
@MockBean
ProductService productService;
@MockBean
FolderService folderService;
@BeforeEach
public void setup() {
mvc = MockMvcBuilders.webAppContextSetup(context)
.apply(springSecurity(new MockSpringSecurityFilter()))
.build();
// 우리가 생성한 가짜 Filter 가 가짜 SecurityFilter 로서 사용됨.
}
private void mockUserSetup() {
// Mock 테스트 유져 생성
String username = "sollertia4351";
String password = "robbie1234";
String email = "sollertia@sparta.com";
UserRoleEnum role = UserRoleEnum.USER;
User testUser = new User(username, password, email, role);
UserDetailsImpl testUserDetails = new UserDetailsImpl(testUser);
mockPrincipal = new UsernamePasswordAuthenticationToken(testUserDetails, "", testUserDetails.getAuthorities());
}
@Test
@DisplayName("로그인 Page")
void test1() throws Exception {
// when - then
mvc.perform(get("/api/user/login-page"))
.andExpect(status().isOk())
.andExpect(view().name("login"))
.andDo(print());
}
@Test
@DisplayName("login")
void test111() throws Exception {
mvc.perform(get("/api/user/login-page"))
.andExpect(status().isOk())
.andExpect(view().name("login"))
.andDo(print());
}
@Test
@DisplayName("회원 가입 요청 처리")
void test2() throws Exception {
// given
MultiValueMap<String, String> signupRequestForm = new LinkedMultiValueMap<>();
signupRequestForm.add("username", "sollertia4351");
signupRequestForm.add("password", "robbie1234");
signupRequestForm.add("email", "sollertia@sparta.com");
signupRequestForm.add("admin", "false");
// when - then
mvc.perform(post("/api/user/signup")
.params(signupRequestForm)
)
.andExpect(status().is3xxRedirection())
.andExpect(view().name("redirect:/api/user/login-page"))
.andDo(print());
}
@Test
@DisplayName("신규 관심상품 등록")
void test3() throws Exception {
// given
this.mockUserSetup();
String title = "Apple <b>아이폰</b> 14 프로 256GB [자급제]";
String imageUrl = "https://shopping-phinf.pstatic.net/main_3456175/34561756621.20220929142551.jpg";
String linkUrl = "https://search.shopping.naver.com/gate.nhn?id=34561756621";
int lPrice = 959000;
ProductRequestDto requestDto = new ProductRequestDto(
title,
imageUrl,
linkUrl,
lPrice
);
// Class 를 Json Type String 으로 변환하는 코드
String postInfo = objectMapper.writeValueAsString(requestDto);
// when - then
mvc.perform(post("/api/products")
.content(postInfo)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.principal(mockPrincipal) // 토큰
)
.andExpect(status().isOk())
.andDo(print());
}
}
'나의 호기심' 카테고리의 다른 글
SimpleJpaRepostory 내부 뜯어보기 (0) | 2023.07.26 |
---|---|
JPA의 엔티티는 왜 기본 생성자가 있어야 할까? (0) | 2023.07.18 |
HttpHeaders는 MultiValueMap의 구현체이다? (0) | 2023.07.11 |
Local Storage 와 Session Storage (0) | 2023.06.22 |
왜 HTTP 통신에서 Body에 Json을 주로 활용하는가? (0) | 2023.06.21 |