【问题标题】:How to mock a exception in rest controller where the exception is thrown from a service如何在从服务引发异常的休息控制器中模拟异常
【发布时间】:2020-07-20 12:23:42
【问题描述】:

我正在为 Spring Boot 中的 Rest Controller 编写测试用例。

为了提供有关该问题的一些背景信息,我无法模拟从控制器层的服务中抛出的异常。

我正在使用 PowerMokito 编写测试用例。

@RunWith(PowerMockRunner.class)
@PrepareForTest(UserApiController.class)
public class UserApiControllerTest {


   /* private MockMvc mockMvc;*/
    @Mock
    GenericService genericService;

    @Mock
    UserService userService;

    @Mock
    UserRoleService userRoleService;

    @Mock
    MessageService messageService;

    @Mock
    CurrentUserService currentUserService;

    @Mock
    UserRepository userRepository;

    @Mock
    UserRoleRepository userRoleRepository;

    @InjectMocks
    UserApiController userApiController;


    @Before
    public void setup() {
        // this must be called for the @Mock annotations above to be processed
        MockitoAnnotations.initMocks(this);
        //Set up mocking for repository methods
    }

    @Test(expected = DuplicateUserEmailException.class)
    public void saveUserByEmailFailure() throws Exception {
        HashMap mockUser = new HashMap<String,Object>();
        mockUser.put("email","test_dy1@gmail.com");
        String user = new ObjectMapper().writeValueAsString(mockUser);
        doThrow(new DuplicateUserEmailException()).
                when(userService).saveUserByEmailId(any());

        userApiController.saveUserByEmailId(user);
    }

请在下面找到控制器的详细信息。

    @RequestMapping(value = "/save_user_by_email", method = RequestMethod.POST)
    public String saveUserByEmailId(@RequestParam("user") String user) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        HashMap<String, Object> userJson = new HashMap<String, Object>();
        userJson = mapper.readValue(user, new TypeReference<Map<String, Object>>(){});
        JsonObjectBuilder responseBuilder = Json.createObjectBuilder();
        try {
            userService.saveUserByEmailId(userJson);
            responseBuilder.add("success", true).add("code", genericService.getSuccessCode()).add("message",
                    userJson.containsKey("id") ? messageService.getMessage("message.success.update")
                            : messageService.getMessage("message.success.create"));
        } catch (Exception exception) {
            LOGGER.error(exception.getMessage(), exception);
            if(exception instanceof DuplicateUserEmailException)
                throw new DuplicateUserEmailException();
        }

        return responseBuilder.build().toString();
    }

【问题讨论】:

  • @N.K.SunilSunilnk 你能分享一下 UserApiController 的代码吗?
  • @Lemmy 请在上面找到控制器详细信息
  • 我刚刚复制/粘贴了您的代码,一切正常。你能分享你的堆栈跟踪和整个测试类(连同导入部分
  • @InjectMocks ApiExceptionHandlerAdvice apiExceptionHandlerAdvice;
  • 这部分很重要。

标签: java spring-boot spring-mvc spring-restcontroller


【解决方案1】:

最后,我解决了。如果您有疑问,请找到下面的代码并发表评论。

@RunWith(PowerMockRunner.class)
@PrepareForTest(UserApiController.class)
public class UserApiControllerTest {


    private MockMvc mockMvc;
    @Mock
    GenericService genericService;

    @Mock
    UserService userService;

    @Mock
    UserRoleService userRoleService;

    @Mock
    MessageService messageService;

    @Mock
    CurrentUserService currentUserService;

    @InjectMocks
    ApiExceptionHandlerAdvice apiExceptionHandlerAdvice;

    @Mock
    UserRepository userRepository;

    @Mock
    UserRoleRepository userRoleRepository;

    @InjectMocks
    UserApiController userApiController;


    @Before
    public void setup(){

      //  MockitoAnnotations.initMocks(this);
        this.mockMvc = MockMvcBuilders.standaloneSetup(userApiController).setControllerAdvice(apiExceptionHandlerAdvice).build();
    }

    @Test
    public void testAddDuplicateCustomer() throws Exception {

        HashMap mockUser = new HashMap<String,Object>();
        mockUser.put("email","test_dy1@gmail.com");
        String user = new ObjectMapper().writeValueAsString(mockUser);
        when(userService.saveUserByEmailId(any())).thenThrow(DuplicateUserEmailException.class);
        when(messageService.getMessage(any())).thenReturn("200");
        RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/user/api/save_user_by_email").param("user",user);
        MvcResult result = mockMvc.perform(requestBuilder).andReturn();
        MockHttpServletResponse response = result.getResponse();
        assertEquals(HttpStatus.BAD_REQUEST.value(), response.getStatus());
        // assertEquals(HttpStatus.BAD_REQUEST.value(), response.getStatus());
    }

【讨论】:

    【解决方案2】:

    试试这样:

    PowerMockito.doThrow(new DuplicateUserEmailException()).
                    when(userService).saveUserByEmailId(any(String.class));
    

    确保 saveUserByEmailId 方法是 void 返回类型

    【讨论】:

    • 您的 UserService 是否在测试类中使用 @MockBean 注释?
    【解决方案3】:

    您可能没有将该模拟实例传递给 userApiController 真实实例。这是模拟服务的一个非常常见的错误。您是为此使用 @InjectMocks ,还是手动构建 userApiController 实例?您能否告诉我们您在上面的测试类中使用的注释?

    说实话,我建议只使用 Mockito,因为使用 PowerMock 你可以模拟很多疯狂的东西,而且它可以进行字节码操作

    使用 Mockito 将如下所示:

    doThrow(newRuntimeException()).when(paymentService).completePayment(any(), any(), any());
    

    如果你想模拟网络调用,请使用 WireMock,我们已经使用了很长时间,它为我们的测试包增加了很多价值。

    【讨论】:

    • 是的,我正在使用@injectMocks。
    • 好的,您是否使用:@RunWith(PowerMockRunner.class) 运行测试?
    • 我只面临编写异常情况的问题。不适用于其他阳性病例。不工作
    • 我觉得不错。它是否因其他错误而失败? ,或者在这种情况下控制器没有抛出任何错误?
    • 是的,可能在这种情况下,我会调试一下,看看 userService 是否是一个模拟实例。但是,如果其他测试有效,那么应该是一个模拟实例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-09
    • 1970-01-01
    • 1970-01-01
    • 2021-06-22
    • 2023-03-07
    相关资源
    最近更新 更多