【问题标题】:SpringBoot Controller Layer Test throws JSONException : Unparsable JSON StringSpringBoot 控制器层测试抛出 JSONException : Unparsable JSON String
【发布时间】:2023-01-11 11:32:55
【问题描述】:

我在使用 spring boot 和 JUnit 5,Mockito 进行控制器层测试时遇到了一些错误。

@WebMvcTest(UsersController.class)
@AutoConfigureMockMvc
public class UsersControllerTest {
    private MockMvc mockMvc;

    @Autowired
    private UsersController usersController;

    @MockBean
    private UsersService usersService;

    @MockBean
    private JwtTokenProvider jwtTokenProvider;

    @MockBean
    private AuthenticationManager authenticationManager;

    @BeforeEach
    void setUp() {
        mockMvc = MockMvcBuilders
                .standaloneSetup(usersController)
                .setControllerAdvice(UsersExceptionHandler.class)
                .build();
    }

    @Test
    @DisplayName("[Controller] Register")
    void Controller_Register_Test() throws Exception {
        //given
        Users users = Users.builder()
                .usersId("test@gmail.com")
                .nickname("testNickname")
                .password("testPassword")
                .build();

        UsersResponseDto responseDto = UsersResponseDto.builder()
                .users(users)
                .build();

        UsersSaveRequestDto requestDto = new UsersSaveRequestDto(
                "test@gmail.com",
                "testNickname",
                "testPassword"
        );

        //mocking
        when(usersService.save(any())).thenReturn(responseDto);


        //when
        mockMvc.perform(post("/api/users/save")
                .contentType(MediaType.APPLICATION_JSON)
                .content(new ObjectMapper().writeValueAsString(requestDto))
                )
        //then
                .andExpect(status().isOk())
                .andExpect(content().json(new ObjectMapper().writeValueAsString(responseDto)))
                .andDo(print());

    }
}

我想测试 ExceptionHandler,所以我使用 @BeforeEach 注释来初始化 mockMvc。

但是,在添加 setup() 方法之后,像这样抛出 JSONException。

Unparsable JSON string: 
org.json.JSONException: Unparsable JSON string: 
    at app//org.skyscreamer.jsonassert.JSONParser.parseJSON(JSONParser.java:56)
    at app//org.skyscreamer.jsonassert.JSONCompare.compareJSON(JSONCompare.java:50)
        ,,,

当我将 ObjectMapper().writeValueAsString 更改为用于测试响应内容的 jsonpath 时,存在相同的异常。

请告诉我为什么抛出此异常,谢谢。

ps) 其他

UsersController

@RequiredArgsConstructor
@RestController
public class UsersController extends BaseController {
    private final UsersService usersService;

    @PostMapping("api/users/save")
    public ResponseEntity<?> save (@RequestBody UsersSaveRequestDto requestDto) {
        return sendResponseHttpByJson(usersService.save(requestDto));
    }

    @PostMapping("api/users/login")
    public ResponseEntity<?> login (@RequestBody UsersLoginRequestDto requestDto) {
        return sendResponseHttpByJson(usersService.login(requestDto));
    }

    @GetMapping("api/users/checkUserExist/{usersId}")
    public ResponseEntity<?> checkUserExist (@PathVariable String usersId) {
        return sendResponseHttpByJson(usersService.findByUsersId(usersId));
    }
}

UsersService

package com.ReRollBag.service;

import com.ReRollBag.auth.JwtTokenProvider;
import com.ReRollBag.domain.dto.UsersLoginRequestDto;
import com.ReRollBag.domain.dto.UsersLoginResponseDto;
import com.ReRollBag.domain.dto.UsersResponseDto;
import com.ReRollBag.domain.dto.UsersSaveRequestDto;
import com.ReRollBag.domain.entity.Users;
import com.ReRollBag.exceptions.usersExceptions.UsersIdAlreadyExistException;
import com.ReRollBag.repository.UsersRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;

@Log4j2
@RequiredArgsConstructor
@Service
public class UsersService {
    private final UsersRepository usersRepository;
    private final PasswordEncoder passwordEncoder;
    private final JwtTokenProvider jwtTokenProvider;

    @Transactional
    public UsersResponseDto save(UsersSaveRequestDto requestDto) {
        Users users = requestDto.toEntity();
        String encryptedPassword = passwordEncoder.encode(users.getPassword());
        users.setPassword(encryptedPassword);
        usersRepository.save(users);
        return new UsersResponseDto(users);
    }

    public UsersResponseDto findByUsersId (String usersId) {
        Users users = usersRepository.findByUsersId(usersId);
        if (users == null) throw new IllegalArgumentException("Users is not Exists");
        return UsersResponseDto.builder()
                .users(users)
                .build();
    }

    public Boolean checkUserExist (String usersId) throws UsersIdAlreadyExistException {
        if (usersRepository.existsByUsersId(usersId)) throw new UsersIdAlreadyExistException();
        return true;
    }
    public UsersLoginResponseDto login (UsersLoginRequestDto requestDto) {
        String targetUsersId = requestDto.getUsersId();
        Users targetUsers = usersRepository.findByUsersId(targetUsersId);

        if (targetUsers == null) throw new IllegalArgumentException("Users Id is wrong");

        if (!passwordEncoder.matches(requestDto.getPassword(), targetUsers.getPassword())) {
            throw new IllegalArgumentException("Password is wrong");
        }

        if (jwtTokenProvider == null) log.error("jwtTokenProvider is NULL!");
        String accessToken = jwtTokenProvider.createAccessToken(requestDto.getUsersId());
        String refreshToken = jwtTokenProvider.createRefreshToken(requestDto.getUsersId());

        return UsersLoginResponseDto.builder()
                .accessToken(accessToken)
                .refreshToken(refreshToken)
                .build();
    }
}

由于 JsonException,无法测试 http 响应内容的 json 解析测试。 我认为初始化 mockMvc 有问题。 请让我知道为什么会引发此异常。

【问题讨论】:

    标签: java spring-boot unit-testing mockito junit5


    【解决方案1】:

    我的代码有问题。我可以通过集成测试捕获此错误。

    UsersController.checkUserExist 方法调用 UsersService.findByUsersId,而不是 UsersService.checkUserExist

    另外,我不需要使用 initialize mockMvc 来测试 ExceptionHandler。

    这是我的最终代码。请理解有一些韩文字符。

    @WebMvcTest(UsersController.class)
    @AutoConfigureMockMvc
    public class UsersControllerTest {
        @Autowired
        private MockMvc mockMvc;
    
        @Autowired
        private UsersController usersController;
    
        @MockBean
        private UsersService usersService;
    
        @MockBean
        private JwtTokenProvider jwtTokenProvider;
    
        @MockBean
        private AuthenticationManager authenticationManager;
        
        @Test
        @DisplayName("[Controller] 회원 가입")
        void Controller_회원가입_테스트() throws Exception {
            //given
            Users users = Users.builder()
                    .usersId("test@gmail.com")
                    .nickname("testNickname")
                    .password("testPassword")
                    .build();
    
            UsersResponseDto responseDto = UsersResponseDto.builder()
                    .users(users)
                    .build();
    
            UsersSaveRequestDto requestDto = new UsersSaveRequestDto(
                    "test@gmail.com",
                    "testNickname",
                    "testPassword"
            );
    
            //mocking
            when(usersService.save(any())).thenReturn(responseDto);
    
    
            //when
            mockMvc.perform(post("/api/users/save")
                    .contentType(MediaType.APPLICATION_JSON)
                    .content(new ObjectMapper().writeValueAsString(requestDto))
                    )
            //then
                    .andExpect(status().isOk())
                    .andExpect(content().json(new ObjectMapper().writeValueAsString(responseDto)))
                    .andDo(print());
    
        }
    
        @Test
        @DisplayName("[Controller] 로그인 및 토큰 발급")
        void Controller_로그인_토큰발급_테스트() throws Exception {
            //given
            UsersLoginRequestDto requestDto = new UsersLoginRequestDto("test@gmail.com", "testPassword");
            UsersLoginResponseDto responseDto = UsersLoginResponseDto.builder()
                    .accessToken("testAccessToken")
                    .refreshToken("testRefreshToken")
                    .build();
            //mocking
            when(usersService.login(any())).thenReturn(responseDto);
            //when
            mockMvc.perform(post("/api/users/login")
                    .contentType(MediaType.APPLICATION_JSON)
                    .content(new ObjectMapper().writeValueAsString(requestDto))
                    )
            //then
                    .andExpect(status().isOk())
                    .andExpect(content().json(new ObjectMapper().writeValueAsString(responseDto)))
                    .andDo(print());
        }
    
        @Test
        @DisplayName("[Controller] 아이디 중복 검사 성공 case")
        void Controller_아이디_중복검사_성공() throws UsersIdAlreadyExistException {
            //given
            String usersId = "test@gmail.com";
            //mocking
            when(usersService.checkUserExist(usersId)).thenReturn(true);
            //when
            try {
                mockMvc.perform(get("/api/users/checkUserExist/"+usersId))
            //then
                        .andExpect(status().isOk())
                        .andReturn();
            } catch (UsersIdAlreadyExistException e) {
                throw new UsersIdAlreadyExistException();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        @Test
        @DisplayName("[Controller] 아이디 중복 검사 실패 case")
        void Controller_아이디_중복검사_실패() throws UsersIdAlreadyExistException {
            //given
            String usersId = "test@gmail.com";
            //mocking
            when(usersService.checkUserExist(usersId)).thenThrow(UsersIdAlreadyExistException.class);
            //when
            try {
                mockMvc.perform(get("/api/users/checkUserExist/" + usersId))
                        .andExpect(status().isAccepted())
                        .andReturn();
            } catch (UsersIdAlreadyExistException e) {
                throw new UsersIdAlreadyExistException();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-20
      • 2022-01-12
      • 1970-01-01
      • 2017-10-03
      • 2021-10-30
      相关资源
      最近更新 更多