์ค๋์ JUnit5 ์ @ParameterizedTest
์ ๋ํด์ ์์๋ณผ ๊ฒ์ด๋ค.
์ด๋ฅผ ์ํด ์ฌ์ฉ๋๋ ํ์ ๊ธฐ์ ์ ๋ค์๊ณผ ๊ฐ๋ค.
- SpringBoot 2.
- JUnit 5
- Validation
- ControllerAdvice
์ด์ ๊ฐ์ DTO ๊ฐ์ฒด๊ฐ ์กด์ฌํ๋ค๊ณ ๊ฐ์ ํด๋ณด์.
@NotBlank
๋ @Size
๋ @Email
์ ๋ชจ๋ validation ์์ ์ฌ์ฉํ๋ ๊ฒ์ธ๋ฐ, ๋ง์ฝ ์ด ์
๋ ฅ ๊ฐ๋ค ์ค์์ ํด๋น constraint๋ฅผ ๋ง์กฑ์ํค์ง ๋ชปํ๋ค๋ฉด MethodArgumentNotValidException
์ ๋ฐ์์ํจ๋ค.
๊ทธ๋ผ ControllerAdvice๋ฅผ ์ด์ฉํด์ ํด๋น ์์ธ๊ฐ ๋ฐ์ํ์์ ๋ ErrorResponse๋ฅผ ์๋ตํ๋ ๊ตฌ์กฐ๋ก ๋ง๋ค์ด๋ณด์.
ControllerErrorAdvice.class
@ResponseBody
@ControllerAdvice
public class ControllerErrorAdvice {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public ErrorResponse handleMethodArgumentNotValidException(MethodArgumentNotValidException exception) {
return new ErrorResponse(exception.getBindingResult().getAllErrors().get(0).getDefaultMessage());
}
}
ํด๋น ControllerAdvice ์์ @ExceptionHandler
๋ก ์ด๋ค ์์ธ๊ฐ ๋ฐ์ํ์๋์ง๋ฅผ ์ก์์ @ResponseStatus
์ ์ฐ๋ฆฌ๊ฐ ๋ด๋ ค์ค ์ํ ์ฝ๋๋ฅผ ๋ช
์ํด์ค๋ค.
DTO
public class ErrorResponse {
private String message;
public ErrorResponse(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
ํด๋น ์์ธ์ ์ง์ ๋ message ํ๋๋ฅผ ๋ฐ์ ํด๋ผ์ด์ธํธ์๊ฒ ์ ๋ฌํด์ค DTO ๊ฐ์ฒด์ด๋ค.
ControllerTest
@SpringBootTest
class ControllerTest {
@Autowired
private MemberService memberService;
@ParameterizedTest // 1
@DisplayName("ํ์ ๊ฐ์
- ๋น์ ์์ ์
๋ ฅ")
@MethodSource("paramsForSignUpInvalidInputs") // 2
void signUp_with_invalid_inputs(String email, String password, String nickname) throws Exception{
// given
Member member = Member.builder()
.email(email)
.password(password)
.nickname(nickname)
.build();
// when & then
MemberRequestSignUpData memberRequestData = modelMapper.map(member, MemberRequestSignUpData.class);
mockMvc.perform(post("/api/members")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(memberRequestData)))
.andDo(print())
.andExpect(status().isBadRequest())
.andExpect(jsonPath("message").exists());
}
private static Stream<Arguments> paramsForSignUpInvalidInputs() { // 3
return Stream.of(
Arguments.of("noEmail", "test1234", "James"), // ์ด๋ฉ์ผ ํ์์ด ์๋
Arguments.of("dhslrl321@gmail.com", "noPw", "James"), // ๋น๋ฐ๋ฒํธ๊ฐ 8๊ธ์ ๋ฏธ๋ง
Arguments.of("dhslrl321@gmail.com", "test1234", "1"), // ๋๋ค์์ด 2๊ธ์ ๋ฏธ๋ง
Arguments.of("", "", "") // ๊ฐ์ด ๋น์ด์๋ ๊ฒฝ์ฐ
);
}
}
์ด์ ๊ฐ์ ํํ๋ก ์ฌ์ฉ๋๋ค.
์์ง ๋ฌด์จ ๋ด์ฉ์ธ์ง ๋ชฐ๋ผ๋ ๊ด์ฐฎ๋ค.
ํ๋ ํ๋ ์์๋ณด์.
์ฃผ์ 1. @ParameterizedTest
ParameterziedTest ๋ JUnit 4์์ ์ฌ์ฉ๋์๋ @RunWith(Parameterized.class)
์ ๋์ผํ ์ญํ ์ ์ํํ๋ค.
ํ ์คํธ ๋ฉ์๋ ํ๋๋ฅผ ์ด์ฉํด์ ๋ค์ํ ๋งค๊ฐ๋ณ์๋ฅผ ์ด์ฉํ ํ ์คํธ ๊ฒฐ๊ณผ๋ฅผ ์ ๊ณตํ๋๋ฐ,
JUnit ๊ณต์ ๋ฌธ์์์ @ParameterizedTest
๋ ๋ค์๊ณผ ๊ฐ์ด ํํ๋๋ค.
@ArgumentsSource
๋ ํด๋น ์ฃผ์์ ๋์ํ๋ ํ๋๋ฅผ ์ด์ฉํด์ ์ ๋ฌํ ๋งค๊ฐ ๋ณ์๋ฅผ ์ง์ ํด์ผ ํ๋๋ฐ, ํด๋น ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ๋ ํ ์คํธ ๋ฉ์๋๋ private ์ด๋ static ์ด์ด์๋ ์๋๋ค.
๋ค์ํ Source๋ฅผ ์ด์ฉํด์ ํ๋ผ๋ฏธํฐ๋ฅผ ๋๊ธธ ์ ์๋ค.
๋ค์ํ Source
@ValueSource
: string, int ํ์์ primtive ํ์ ์ ์ ๋ฌํ ์ ์๋ค.@ValueSource(strings = {"a", "b", "c"})
@NullSource
: Null ๊ฐ์ ํ๋ผ๋ฏธํฐ๋ก ๋ฃ์ด์ค๋ค.@EmptySource
:@EnumSource
: Enum ํ์ ์ value๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ๋ฃ์ด์ค๋ค.@EnumSource(value = UserRole.class, name = {"ADMIN", "USER"}
@MethodSource
- ๊ฐ์ฅ ์ค์ํ Source๋ก ๋ ์์ธํ ์์๋ณด์.
์ฃผ์ 2. @MethodSource
ํด๋น ์ด๋ ธํ ์ด์ ์ด ๊ฐ์ฅ ์ค์ํ๋ค๋ ๋ฐ์๋ ์ด์ ๊ฐ ์๋ค.
์์์ ๋ณด์๋ ๋ฐฉ์์ ์ด๋
ธํ
์ด์
์ ํ๋์ ํ์
๋ง์ ํ๋ผ๋ฏธํฐ๋ก ๋๊ธธ ์ ์๋๋ฐ, @MethodSource
๋ฅผ ์ฌ์ฉํ๋ฉด ์ฌ๋ฌ ํ์
์ ๋๊ธฐ๋ ๊ฒ์ด ๊ฐ๋ฅํด์ง๋ค.
์ด๊ฒ ์ ์ค์ํ๊ฑธ๊น?
์ฐ๋ฆฌ๊ฐ ํ ์คํธํ ๋์์ ํ๋์ ํ์ ๋ง์ผ๋ก ์ด๋ฃจ์ด์ ธ์์ง ์๊ณ ๋ณต์กํ ํ์ ์ผ๋ก ๊ตฌ์ฑ๋์ด์์ ๊ฐ๋ฅ์ฑ์ด ๋งค์ฐ ํฌ๊ธฐ ๋๋ฌธ์ด๋ค.
์์ ๋ณด์๋ ํ ์คํธ ๋ฉ์๋์ ์กฐ๊ธ ๋ณํ์ ์์ผ๋ณด์.
- email: String
- age: int
- UserType: UserType.Enum
- nickname: String
์ด๋ผ๊ณ ํ๋ค๋ฉด ๋ฒ์จ 3๊ฐ์ ํ์ ์ด ์กด์ฌํ๋ค.
์ด๋ฐ ๊ฒฝ์ฐ @MethodSource
๋ฅผ ์ฌ์ฉํ ์ ์๋ ๊ฒ์ด๋ค.
@MethodSource๋ ๋ฉ์๋์์ ๋ฐํ๋๋ ์คํธ๋ฆผ์ ์ด์ฉํด์ ํ ์คํธ์ ํ๋ผ๋ฏธํฐ๋ก ๋๊ธฐ๋๋ฐ, ํ๋ผ๋ฏธํฐ๋ก ์ ๋ฌ๋ ์คํธ๋ฆผ์ ๋ฐํํ๋ ๋ฉ์๋๋ฅผ ์์ฑํด์ฃผ๋ฉด ๋๋ค.
์๋์ ๋ ์์ธํ ์์๋ณด์.
์ฃผ์ 3. paramsForSignUpInvalidInputs()
private static Stream<Arguments> paramsForSignUpInvalidInputs()
์ ํํ๋ฅผ ๋ณด๋ฉด ์๊ฒ ์ง๋ง ํด๋น ๋ฉ์๋์์ ์ฃผ๋ชฉํด์ผํ ์ ์ด 2๊ฐ๊ฐ ์กด์ฌํ๋ค.
- static
- Stream
์์ ๋ง ํ๋ฏ MethodSource๋ ์คํธ๋ฆผ์ ๋ฐํํด์ผ ํ๋ค๊ณ ํ๋ค.
์ฐ๋ฆฌ๋ arguments ์ ๋๋ฆญ์ ์ด์ฉํ ์คํธ๋ฆผ์ ๋ฐํํ ๊ฒ์ด๊ณ ํด๋น ์ด๋ ธํ ์ด์ ์ ๊ผญ static ๋ฉ์๋์ฌ์ผ ํ๋ค.
ํ ์คํธ ์ฝ๋ ๋๋ ค๋ณด๊ธฐ
์์ ๊ฐ์ ๋ฉ์๋๊ฐ ๋๊ธฐ๋ Stream์ผ๋ก ํ ์คํธ ์ฝ๋๋ฅผ ๋๋ ค๋ณด์.
๊ทธ๋ผ ์ ์์ ์ผ๋ก ์ฐ๋ฆฌ์ ๊ธฐ๋ฅ์ด ์ ๋์ํ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
๋๊ธ