英文:
How to mock a exception in rest controller where the exception is thrown from a service
问题
我正在编写 Spring Boot 中的 REST Controller 的测试用例。
为了提供一些关于问题的背景,我无法在控制器层从服务中抛出的异常进行模拟。
我在编写测试用例时使用了 PowerMockito。
```java
@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();
}
<details>
<summary>英文:</summary>
I am working on writing a test cases for rest Controller in Spring boot.
To give some context about the problem, I am not able to mock the exception that has been thrown from service at the controller layer.
I am using PowerMokito for writing test cases.
```java
@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);
}
Please find the details of the controller below.
@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();
}
答案1
得分: 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(){
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());
}
}
英文:
Finally, I solved it. Please find the code below and comment if you have doubts.
@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
得分: 0
尝试如下方式:
PowerMockito.doThrow(new DuplicateUserEmailException()).
when(userService).saveUserByEmailId(any(String.class));
确保 saveUserByEmailId
方法的返回类型是 void。
英文:
Try it like this:
PowerMockito.doThrow(new DuplicateUserEmailException()).
when(userService).saveUserByEmailId(any(String.class));
Make sure saveUserByEmailId
method is void return type
答案3
得分: 0
可能你没有将那个模拟实例传递给userApiController的真实实例。这是使用模拟服务经常出现的错误。你是在使用 @InjectMocks 吗?还是在手动构造userApiController实例?你能告诉我们你在测试类上面使用的注解是什么吗?
老实说,我建议只使用Mockito,因为使用PowerMock可以模拟许多疯狂的事情,它涉及到字节码操作。
使用Mockito,代码如下:
doThrow(newRuntimeException()).when(paymentService).completePayment(any(), any(), any());
如果你想要模拟网络调用,请使用WireMock。我们已经使用了很长时间的WireMock,它为我们的测试套件增添了很多价值。
英文:
Possible you're not passing that mock instance towards userApiController real instance. That is a really common mistake with mock services. Are you using @InjectMocks for that, or are you constructing userApiController instance manually ? Could you please tell us the annotations that are you using above test class ?
To be honest I'd suggest to use only Mockito since with PowerMock you can mock a lot of crazy things, and it's making byte code manipulation
With Mockito this will look like this:
doThrow(newRuntimeException()).when(paymentService).completePayment(any(), any(), any());
And if you want to mock networking calls, please use WireMock, we've used it for a long time now and it adds a lot of value to our tests pack.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论