4์ฃผ์ฐจ
์นด์นด์ค ํ ํฌ ์บ ํผ์ค 2๋จ๊ณ - BE - 4์ฃผ์ฐจ ํด๋ก ๊ณผ์
๊ณผ์ ๋ช
1. ์ปจํธ๋กค๋ฌ ๋จ์ ํ ์คํธ
๊ณผ์ ์ค๋ช
1. ์ปจํธ๋กค๋ฌ ๋จ์ํ ์คํธ๋ฅผ ์์ฑํ๋ค ์์ค์ฝ๋๋ฅผ ์ ๋ก๋ํ์์ค.
2. stub์ ๊ตฌํํ์์ค.
๊ณผ์ ์์ธ : ๊ณผ์ ๋ฅผ ์งํํ ๋, ์ ๋ ํด์ผํ ๊ฒ
์ปจํธ๋กค๋ฌ ๋จ์ํ ์คํธ๊ฐ ๊ตฌํ๋์๋๊ฐ?
Mockito๋ฅผ ์ด์ฉํ์ฌ stub์ ๊ตฌํํ์๋๊ฐ?
์ธ์ฆ์ด ํ์ํ ์ปจํธ๋กค๋ฌ๋ฅผ ํ ์คํธํ ์ ์๋๊ฐ?
200 ok๋ง ์ฒดํฌํ ๊ฒ์ ์๋๊ฐ? (ํด๋น ์ปจํธ๋กค๋ฌ์์ ์ ์ผ ํ์ํ ๋ฐ์ดํฐ์ ๋ํ ํ ์คํธ๊ฐ ๊ตฌํ๋์๋๊ฐ?)
๋ชจ๋ ์์ฒญ๊ณผ ์๋ต์ด json์ผ๋ก ์ฒ๋ฆฌ๋์ด ์๋๊ฐ?
1. ์ปจํธ๋กค๋ฌ ๋จ์ ํ ์คํธ
01) ์ปจํธ๋กค๋ฌ ๋จ์ํ ์คํธ๋ฅผ ์์ฑํ๋ค ์์ค์ฝ๋๋ฅผ ์ ๋ก๋ํ์์ค.
๐ ๊ธฐ์กด ์ฝ๋ ๋ถ์
GlobalExceptionHandler
@RequiredArgsConstructor
@Component
public class GlobalExceptionHandler {
private final ErrorLogJPARepository errorLogJPARepository;
public ResponseEntity<?> handle(RuntimeException e, HttpServletRequest request){
if(e instanceof Exception400){
Exception400 ex = (Exception400) e;
return new ResponseEntity<>(
ex.body(),
ex.status()
);
}else if(e instanceof Exception401){
Exception401 ex = (Exception401) e;
return new ResponseEntity<>(
ex.body(),
ex.status()
);
}else if(e instanceof Exception403){
Exception403 ex = (Exception403) e;
return new ResponseEntity<>(
ex.body(),
ex.status()
);
}else if(e instanceof Exception404){
Exception404 ex = (Exception404) e;
return new ResponseEntity<>(
ex.body(),
ex.status()
);
}else if(e instanceof Exception500){
ErrorLog errorLog = ErrorLog.builder()
.message(e.getMessage())
.userAgent(request.getHeader("User-Agent"))
.userIp(request.getRemoteAddr())
.build();
errorLogJPARepository.save(errorLog);
Exception500 ex = (Exception500) e;
return new ResponseEntity<>(
ex.body(),
ex.status()
);
}else{
ErrorLog errorLog = ErrorLog.builder()
.message(e.getMessage())
.userAgent(request.getHeader("User-Agent"))
.userIp(request.getRemoteAddr())
.build();
errorLogJPARepository.save(errorLog);
return new ResponseEntity<>(
"unknown server error",
HttpStatus.INTERNAL_SERVER_ERROR
);
}
}
}
์์ธ ์ฒ๋ฆฌ๋ฅผ ๋ด๋นํ๋ GlobalExceptionHandler ํด๋์ค์ด๋ค. ํน์ ์์ธ ์ข ๋ฅ์ ๋ฐ๋ผ ์ ์ ํ HTTP ์ํ ์ฝ๋์ ์๋ต์ ์์ฑํ๋ค. ๊ฐ ์์ธ์ ๋ํ ์ฒ๋ฆฌ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ๋ค.
handle ๋ฉ์๋๊ฐ RuntimeException๊ณผ HttpServletRequest๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ๋ฐ๋๋ค. RuntimeException์ ์ฒ๋ฆฌํ๊ณ ResponseEntity๋ฅผ ๋ฐํํ๋ ์ญํ ์ ํ๋ค.
- Exception400~404์ ๊ฒฝ์ฐ, ์์ธ ๊ฐ์ฒด์ธ ex์์ ์๋ต ๋ฐ์ดํฐ์ ์ํ ์ฝ๋๋ฅผ ๊ฐ์ ธ์ ResponseEntity๋ฅผ ์์ฑํ๋ค.
- Exceotion500์ด ๊ฒฝ์ฐ์๋, ์์ธ ๊ฐ์ฒด์ธ ex์์ ์๋ต ๋ฐ์ดํฐ์ ์ํ ์ฝ๋๋ฅผ ๊ฐ์ ธ์จ ๋ค, ์๋ฌ ๋ก๊ทธ๋ฅผ ์์ฑํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅํ ๋ค, ResponseEntity๋ฅผ ์์ฑํ๋ค.
- ๊ทธ ์ธ์ ์์ธ๊ฐ ๋ฐ์ํ๋ฉด, "unknown server error" ๋ฉ์์ง์ HttpStatus.INTERNAL_SERVER_ERROR ์ํ ์ฝ๋๋ฅผ ๋ฐํํ๋ฉฐ, ๋์์ ์๋ฌ ๋ก๊ทธ๋ฅผ ์์ฑํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅํ๋ค.
UserRestControllerTest
// GlobalExceptionHandler์ UserRestController๋ฅผ SpringContext์ ๋ฑ๋กํฉ๋๋ค.
@Import({
SecurityConfig.class,
GlobalExceptionHandler.class
})
@WebMvcTest(controllers = {UserRestController.class})
public class UserRestControllerTest {
// ๊ฐ์ฒด์ ๋ชจ๋ ๋ฉ์๋๋ ์ถ์๋ฉ์๋๋ก ๊ตฌํ๋ฉ๋๋ค. (๊ฐ์ง๋ก ๋ง๋ค๋ฉด)
// ํด๋น ๊ฐ์ฒด๋ SpringContext์ ๋ฑ๋ก๋ฉ๋๋ค.
@MockBean
private UserService userService;
@MockBean
private ErrorLogJPARepository errorLogJPARepository;
// @WebMvcTest๋ฅผ ํ๋ฉด MockMvc๊ฐ SpringContext์ ๋ฑ๋ก๋๊ธฐ ๋๋ฌธ์ DIํ ์ ์์ต๋๋ค.
@Autowired
private MockMvc mvc;
// @WebMvcTest๋ฅผ ํ๋ฉด ObjectMapper๊ฐ SpringContext์ ๋ฑ๋ก๋๊ธฐ ๋๋ฌธ์ DIํ ์ ์์ต๋๋ค.
@Autowired
private ObjectMapper om;
@Test
public void t1(){}
@Test
public void join_test() throws Exception {
// given
UserRequest.JoinDTO requestDTO = new UserRequest.JoinDTO();
requestDTO.setEmail("ssarmango@nate.com");
requestDTO.setPassword("meta1234!");
requestDTO.setUsername("ssarmango");
String requestBody = om.writeValueAsString(requestDTO);
// when
ResultActions result = mvc.perform(
MockMvcRequestBuilders
.post("/join")
.content(requestBody)
.contentType(MediaType.APPLICATION_JSON)
);
String responseBody = result.andReturn().getResponse().getContentAsString();
System.out.println("ํ
์คํธ : "+responseBody);
// then
result.andExpect(MockMvcResultMatchers.jsonPath("$.success").value("true"));
}
@Test
public void login_test() throws Exception {
// given
UserRequest.LoginDTO loginDTO = new UserRequest.LoginDTO();
loginDTO.setEmail("ssar@nate.com");
loginDTO.setPassword("meta1234!");
User user = User.builder().id(1).roles("ROLE_USER").build();
String requestBody = om.writeValueAsString(loginDTO);
// stub -> ๊ฐ์ ๋ฒ
String jwt = JWTProvider.create(user);
Mockito.when(userService.login(any())).thenReturn(jwt); // token
// when
ResultActions result = mvc.perform(
MockMvcRequestBuilders
.post("/login")
.content(requestBody)
.contentType(MediaType.APPLICATION_JSON)
);
String responseBody = result.andReturn().getResponse().getContentAsString();
String responseHeader = result.andReturn().getResponse().getHeader(JWTProvider.HEADER);
System.out.println("ํ
์คํธ : "+responseBody);
System.out.println("ํ
์คํธ : "+responseHeader);
// then
result.andExpect(MockMvcResultMatchers.jsonPath("$.success").value("true"));
Assertions.assertTrue(jwt.startsWith(JWTProvider.TOKEN_PREFIX));
}
@Test
public void length_test(){
String value = "Bearer eyJ0eX";
System.out.println(value.substring(0,6));
}
}
User์ ๋ํ ๊ธฐ๋ฅ๋ค์ controller ๋จ์ํ ์คํธ๋ฅผ ์ํํ๋ ํด๋์ค์ด๋ค. ํด๋น ํด๋์ค์์๋ @WebMvcTest๋ฅผ ์ฌ์ฉํ์ฌ UserRestController ํด๋์ค์ ํ ์คํธ๋ฅผ ์ํํ๋ค. `UserRestController`์ `GlobalExceptionHandler`๋ฅผ Spring ์ปจํ ์คํธ์ ๋ฑ๋กํ๊ณ , ์ด๋ฅผ ์ด์ฉํ์ฌ ์ปจํธ๋กค๋ฌ๋ฅผ ํ ์คํธํ๋ค.
join_test()
ํ์๊ฐ์
์ ํ์ํ ํ
์คํธ์ด๋ค. UserRequest.JoinDTO ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ , ํด๋น ๊ฐ์ฒด๋ฅผ JSON ํํ๋ก ๋ณํํ์ฌ POST ์์ฒญ์ผ๋ก ์ ์กํ๋ค. ๋ํ, ์๋ต์ผ๋ก ์ค๋ JSON ๊ฒฐ๊ณผ๋ฅผ ๊ฒ์ฆํ๋ค.
login_test()
๋ก๊ทธ์ธ ์์ฒญ์ ๋ํ ํ
์คํธ๋ก, UserRequest.LoginDTO ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ , ํด๋น ๊ฐ์ฒด๋ฅผ JSON ํํ๋ก ๋ณํํ์ฌ POST ์์ฒญ์ผ๋ก ์ ์กํ๋ค. ๋ก๊ทธ์ธ ์์ฒญ์ ๋ํ ์๋ต์ผ๋ก ์์ฑ๋๋ JWT ํ ํฐ์ ๊ฒ์ฆํ๊ณ , ํ ํฐ์ ํ์์ ํ์ธํฉ๋๋ค.
length_test()
๋ฌธ์์ด ๊ธธ์ด์ ๋ํ ํ
์คํธ๋ก, ์ฃผ์ด์ง ๋ฌธ์์ด์์ ์ผ๋ถ๋ฅผ ์๋ผ๋ด์ด ๊ฒ์ฆํ๋ค.
Spring ์ปจํ
์คํธ๋ฅผ ํ์ฉํ์ฌ ์ปจํธ๋กค๋ฌ์ ๋์์ ๊ฒ์ฆํ๊ณ , ๊ฐ ์์ฒญ๊ณผ ์๋ต์ ๋ํ ์ํ ๋ฐ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ๋ค. ํนํ MockBean์ ์ฌ์ฉํ์ฌ UserService์ ErrorLogJPARepository๋ฅผ ๊ฐ์ง ๊ฐ์ฒด๋ก ๋์ฒดํ์ฌ ํ
์คํธ๋ฅผ ์งํํ๋๋ฐ, ์ค์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ํฅ์ ์ฃผ์ง ์๊ณ , ์์๋ ๊ฒฐ๊ณผ๋ฅผ ํ
์คํธํ ์ ์๋ค.
'๐ช kakaotech campus' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
์นดํ ์ผ | [STEP2 clone coding] 6์ฃผ์ฐจ ๊ณผ์ (๋ฐฐํฌ ์๋ฃ !!) (0) | 2023.08.04 |
---|---|
์นดํ ์ผ | [STEP2 clone coding] 5์ฃผ์ฐจ ๊ณผ์ (0) | 2023.07.27 |
์นดํ ์ผ | [STEP2 cloncoding] 4์ฃผ์ฐจ ๊ณผ์ - (1) (0) | 2023.07.19 |
์นดํ ์ผ | [STEP2 clone coding] 3์ฃผ์ฐจ ๊ณผ์ (0) | 2023.07.14 |
์นดํ ์ผ | [STEP2 clone coding] 2์ฃผ์ฐจ ๊ณผ์ - (2) (0) | 2023.07.07 |