【问题标题】:ServiceResponse mocked which gives a null value and not expected this null模拟的 ServiceResponse 给出了一个空值,而不是预期这个空值
【发布时间】:2019-04-24 19:37:39
【问题描述】:

我正在为我的服务编写 j-unit 测试用例,其中我无法正确模拟服务响应,这给了我一个空值。有人可以帮我解决这个问题吗?

public ResponseEntity<Void> lockGet(
        @ApiParam(value = "Unique identifier for this request.", required = true) @RequestHeader(value = "service-id", required = true) String serviceId,
        @ApiParam(value = "Logged in userid.", required = true) @RequestHeader(value = "user-id", required = true) String userId,
        @ApiParam(value = "Unique messageid.", required = true) @RequestHeader(value = "message-id", required = true) String messageId,
        @RequestHeader(value = "access-token", required = true) String accessToken,
        @ApiParam(value = "Unique id of the doamin of the entity", required = true) @RequestParam(value = "lockDomainId", required = true) Long lockDomainId,
        @ApiParam(value = "Unique id of the entity to be fetched", required = true) @RequestParam(value = "lockEntityId", required = true) Long lockEntityId,
        HttpServletRequest request, HttpServletResponse response) {

    ResponseEntity<Void> result = null;
    if (request.getAttribute("user-id") != null)
        userId = (String) request.getAttribute("user-id");
    String logContext = "||" + lockDomainId + "|" + lockEntityId + "||";
    ThreadContext.put("context", logContext);
    long t1 = System.currentTimeMillis();
    LOG.info("Method Entry: lockGet" + logContext);
    ServiceRequest serviceRequest = AppUtils.mapGetRequestHeaderToServiceRequest(serviceId, userId, lockDomainId,
        lockEntityId);
    try {
        ServiceResponse serviceResponse = lockService.getLock(serviceRequest);
        // set all the response headers got from serviceResponse
        HeaderUtils.setResponseHeaders(serviceResponse.getResponseHeaders(), response);
        result = new ResponseEntity<Void>(HeaderUtils.getHttpStatus(serviceResponse));
    } catch (Exception ex) {
        LOG.error("Error in lockGet", ex);
        result = new ResponseEntity<Void>(HttpStatus.INTERNAL_SERVER_ERROR);
    }
    ThreadContext.put("responseTime", String.valueOf(System.currentTimeMillis() - t1));
    LOG.info("Method Exit: lockGet");
    return result;
    }
@Test
    public void testLockGetForError() {
        request.setAttribute("user-id","TestUser");
        ServiceRequest serviceRequest = new ServiceRequest();
        serviceRequest.setUserId("TestUser");
        ServiceResponse serviceResponse = new ServiceResponse();
        LockService service = Mockito.mock(LockService.class);
        when(service.getLock(serviceRequest)).thenReturn(serviceResponse);
//      ServiceResponse serviceResponse = lockService.getLock(serviceRequest);
        ResponseEntity<Void> result = new ResponseEntity<Void>(HeaderUtils.getHttpStatus(serviceResponse));
        ResponseEntity<Void> lockGet = lockApiController.lockGet("1234", "TestUser", "TestMessage", "TestTkn", 12345L, 12345L, request, response);
        assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, lockGet.getStatusCode());
    }

我尝试了不同的场景,但无法解决这个问题。有人可以帮我吗。提前致谢。

【问题讨论】:

  • 这一行 when(service.getLock(serviceRequest)) 尝试使用 ArgumentMatchers 表示 when(service.getLock(ArgumentMatchers.any()))
  • mock:LockService service = Mockito.mock(LockService.class);如何进入测试类lockApiController? Java 中的 Mocking 与 Javascript 不同。您必须通过构造函数、设置器等将模拟实例添加到被测类。

标签: spring-boot java-8 mockito junit4


【解决方案1】:

从您输入的代码中,我看到的问题是您实际上是在模拟 LockService 对象,但是在调用 lockApiController.lockGet 方法时,代码实际上并没有使用模拟对象 LockService 因为 lockApiController 有自己的 LockService 对象。

  • 解决此问题的一种方法是注入模拟的LockService 使用@Spy 将对象放入lockApiController 对象。这边走 当getLock() 被调用时,它实际上会在 模拟对象并将返回提供的模拟响应。

所以在你的测试中:

@Test
    public void testLockGetForError() {
        LockService service = Mockito.mock(LockService.class);
        LockApiController lockApiController = Mockito.spy(new LockApiController(service));
        request.setAttribute("user-id","TestUser");
        ServiceRequest serviceRequest = new ServiceRequest();
        serviceRequest.setUserId("TestUser");
        ServiceResponse serviceResponse = new ServiceResponse();
        when(service.getLock(serviceRequest)).thenReturn(serviceResponse);
//      ServiceResponse serviceResponse = lockService.getLock(serviceRequest);
        ResponseEntity<Void> result = new ResponseEntity<Void>(HeaderUtils.getHttpStatus(serviceResponse));
        ResponseEntity<Void> lockGet = lockApiController.lockGet("1234", "TestUser", "TestMessage", "TestTkn", 12345L, 12345L, request, response);
        assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, lockGet.getStatusCode());
    }

因此,您可以尝试将模拟的 LockService 对象传递给 spy 对象。

  • 另一种方法是尝试使用@InjectMocks 注入mocked 对象放入LockApiController

@InjectMocks 标记应执行注入的字段。 Mockito 将尝试仅通过构造函数注入、setter 注入或属性注入来注入模拟——按此顺序。如果任何给定的注入策略失败,则 Mockito 不会报告失败。

例如:

@Mock
Map<String, String> wordMap;

@InjectMocks
MyDictionary dic = new MyDictionary();

@Test
public void whenUseInjectMocksAnnotation_thenCorrect() {
    Mockito.when(wordMap.get("aWord")).thenReturn("aMeaning");

    assertEquals("aMeaning", dic.getMeaning("aWord"));
}

对于班级:

public class MyDictionary {
    Map<String, String> wordMap;

    public MyDictionary() {
        wordMap = new HashMap<String, String>();
    }
    public void add(final String word, final String meaning) {
        wordMap.put(word, meaning);
    }
    public String getMeaning(final String word) {
        return wordMap.get(word);
    }
}

要使这两个工作,您必须有一个构造函数或适当的设置器来将模拟对象设置为LockApiController 类。

参考:https://howtodoinjava.com/mockito/mockito-annotations/

【讨论】:

    猜你喜欢
    • 2021-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多