๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐ŸŒพBackEnd/๐ŸŒฑ Spring

[ Jackson ] Jackson mock ํ…Œ์ŠคํŠธ ์—ญ์ง๋ ฌํ™” ์˜ค๋ฅ˜

by MuGeon Kim 2023. 3. 11.
๋ฐ˜์‘ํ˜•

๊ธฐ๋ณธ์ ์ธ ์ฝ”๋“œ๋ฅผ ํ…Œ์ŠคํŠธ ํ•˜๋ฉด์„œ JSON์„ ํŒŒ์‹ฑํ•˜๋Š” JackSon ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋„ˆ๋ฌด ๋ชจ๋ฅด๊ณ  ์‚ฌ์šฉ์„ ํ•˜์˜€๋‹ค.

๊ทธ๋ž˜์„œ ๊ฐ„๋‹จํ•œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑ์„ ํ•ด๋„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค. ์ผ๋‹จ ๋ฐœ์ƒํ•œ ์˜ค๋ฅ˜๋ฅผ ์„ค๋ช…ํ•˜๊ณ  Jackson์ด ์–ด๋–ป๊ฒŒ ํŒŒ์‹ฑ์„ ํ•˜๊ณ  ๊ทธ ์ดํ›„์— ์–ด๋–ค ํ–‰๋™์„ ํ•˜๋Š”์ง€ ์•Œ์•„๋ณด๊ฒ ๋‹ค.

 

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public UserData create(@RequestBody UserData userData){
    User user = userService.registerUser(userData);

    return UserData.builder()
            .email(user.getEmail())
            .build();
}
@Getter
@Builder
@AllArgsConstructor
public class UserData {
    private Long id;
    private String email;
    private String name;
}
@Test
@DisplayName("register")
public void registerUserWithValidAttributes() throws Exception{
    //given
    given(userService.registerUser(any(UserData.class))).will(invocation -> {
        UserData userData = invocation.getArgument(0);
        User user = User.builder()
                .email(userData.getEmail())
                .build();
        return user;
    });

    //when
    //{"email":"test@exampel.com", "password":"1234",...}
    mockMvc.perform(post("/users")
            .contentType(APPLICATION_JSON)
            .content("{\"email\": \"test@example.com\", \"name\":\"tester\"," +
                    "\"password\": \"test\"}"))
            .andExpect(status().isCreated())
            .andExpect(content().string(
                    containsString("\"email\":\"test@example.com\"")
            ));

    //Then
    verify(userService).registerUser(any(UserData.class));
}

์œ„์— ์ฝ”๋“œ๋Š” ๊ฐ„๋‹จํ•˜๊ฒŒ ์ƒ์„ฑ ํ…Œ์ŠคํŠธ๋ฅผ ํ™•์ธํ•˜๋Š” ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์ด๋‹ค.

UserData๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์•„ UserData ํƒ€์ž…์œผ๋กœ ๋ฐ˜ํ™˜์„ ํ•ด์ฃผ๋Š” ์ฝ”๋“œ์ด๋‹ค.

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์— ๋Œ€ํ•ด์„œ ์„ค๋ช…ํ•˜๋ฉด content๋กœ JSON์„ ๋„˜๊ฒจ์„œ Jackson์„ ํ†ตํ•˜์—ฌ ์ง๋ ฌํ™”๋ฅผ ํ•˜๊ณ  ์ดํ›„ andExcept์˜ content๋ฅผ ํ†ตํ•˜์—ฌ ์—ญ์ง๋ ฌํ™”๋ฅผ ํ•˜์—ฌ ๊ฒ€์ฆํ•˜๋Š” ์ฝ”๋“œ์ด๋‹ค.

๋‚ด ์ƒ๊ฐ์œผ๋กœ๋Š” ๋ฌธ์ œ๊ฐ€ ์—†๋‹ค๊ณ  ์ƒ๊ฐ์„ ํ•˜์˜€์œผ๋‚˜ ์˜ค๋ฅ˜๊ฐ€ ํ•˜๋‚˜ ๋ฐœ์ƒํ•˜๋Š”๋ฐ

org.springframework.web.util.NestedServletException: Request processing failed; 
nested exception is org.springframework.http.converter.HttpMessageConversionException: 
Type definition error: [simple type, class com.codesoom.assignment.dto.UserData];
nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException:
Cannot construct instance of `com.codesoom.assignment.dto.UserData` 
(no Creators, like default constructor, exist): cannot deserialize from Object value
(no delegate- or property-based Creator)
 at [Source: (PushbackInputStream); line: 1, column: 2]

์ด๋Ÿฌํ•œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒ์„ ํ•˜์˜€๋‹ค. ์˜ค๋ฅ˜์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด๋ฉด UserData๋ฅผ ์—ญ์ง๋ ฌํ™” ํ•˜๋Š” ๊ณผ์ •์—์„œ ์ƒ๊ธด ๋ฌธ์ œ์ด๋‹ค.

 Cannot construct instance of `com.codesoom.assignment.dto.UserData` (no Creators, like default constructor, exist)

๊ทธ ์ด์œ ๋ฅผ ์ฐพ์•„๋ณด๋ฉด Jackson ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ UserData ํด๋ž˜์Šค์˜ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋ ค๊ณ  ํ•˜์ง€๋งŒ ์ง€๊ธˆ ํด๋ž˜์Šค์—๋Š” ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์—ญ์ง๋ ฌํ™”๊ฐ€ ์‹คํŒจํ•œ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค. 

 

๊ทธ๋ž˜์„œ UserData์— ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋œ๋‹ค.

 

์ด์ œ Jackson์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž

Jackson๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” JSON ๋ฐ์ดํ„ฐ๋ฅผ ์ž๋ฐ” ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์—ญ์ง๋ ฌํ™” ๊ณผ์ •์— ๋Œ€ํ•ด์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‹คํ–‰๋œ๋‹ค.

1 .JSON ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

2. JSON ๋ฐ์ดํ„ฐ๋ฅผ ์ž๋ฐ” ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ ์œ„ํ•ด Jackson ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ObjectMapper๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

3. ObjectMapper๋Š” JSON ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด๋“ค์—ฌ ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•˜๋Š”๋ฐ, ์ด๋•Œ ํด๋ž˜์Šค์˜ ์ •๋ณด๋ฅผ ์ฐธ์กฐํ•˜์—ฌ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

4. ํด๋ž˜์Šค์— ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์—†๋Š” ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ, Jackson์€ ์ด ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

5. ์ƒ์„ฑ์ž๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ, Jackson์€ ๋‹ค๋ฅธ ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ ์ƒ์„ฑ์ž์˜ ๋งค๊ฐœ๋ณ€์ˆ˜์™€ JSON ๋ฐ์ดํ„ฐ์˜ ํ‚ค๊ฐ€ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ์ผ์น˜ํ•˜๋Š” ๊ฒฝ์šฐ ํ•ด๋‹น ๊ฐ’์„ ๋งค๊ฐœ๋ณ€์ˆ˜์— ์ „๋‹ฌํ•˜์—ฌ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

6. ํด๋ž˜์Šค์— ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์—†๋Š” ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋„ ์—†๊ณ , ๋‹ค๋ฅธ ์ƒ์„ฑ์ž๋„ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ, Jackson์€ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์—†๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

 

๋ฐ˜์‘ํ˜•