【问题标题】:How can I create unit test for void method which just change data and save it如何为仅更改数据并保存它的 void 方法创建单元测试
【发布时间】:2019-06-18 09:50:09
【问题描述】:

我有一些处理程序(在这个例子中我只使用控制器):

@RestController
public class MessageController {

    private final TaskExecutor taskExecutor;
    private final Operation operation;
    private final MessageLogService messageLogService;

    public MessageController(TaskExecutor taskExecutor, Operation operation, MessageLogService messageLogService) {
        this.taskExecutor = taskExecutor;
        this.operation = operation;
        this.messageLogService = messageLogService;
    }

    @PostMapping(value = "/process")
    public String handleMessage(MessageRequest messageRequest){

        MessageLog messageLog = messageLogService.createNewMessageLog();

        taskExecutor.execute(() -> {
            try {
                operation.process(messageLog.getGuid(), messageRequest);
            } catch (MessageLogDoesNotExistException e) {
                throw new RuntimeException(e);
            }
        });
        return "REQUEST_QUOTED";
    }
}
  1. 我收到了一些请求。
  2. 我在 DB 中创建了新的MessageLog,状态为“NEW”和一些默认值(以及来自实际项目中请求的一些数据)值并保存。
  3. 我将messageRequestMessageLog's guid 发送到执行器中的operation 并立即返回同步响应“REQUEST_QUOTED”。

@Service
public class MessageOperation implements Operation {

        private final MessageLogService messageLogService;

        public MessageOperation(MessageLogService messageLogService) {
            this.messageLogService = messageLogService;
        }

        @Transactional
        @Override
        public void process(String guid, MessageRequest messageRequest) throws MessageLogDoesNotExistException {

            MessageLog messageLog = messageLogService.getOne(guid);

            if (messageLog == null)
                throw new MessageLogDoesNotExistException();

            try {
                Message message = createMessage(messageRequest);
                messageLog.setStatus("SUCCESS");
                messageLog.setMessage(message);
            } catch (MessageCreationException e) {
                messageLog.setStatus("FAIL");
                messageLog.setErrorCode(e.getCode());
            }
            messageLogService.save(messageLog);
        }

        private Message createMessage(MessageRequest messageRequest) throws MessageCreationException {
            //logic
            return null;
        }
    }

进入operation 我创建消息并将其与messageLog 绑定。如果我创建并绑定成功 - 如果没有,我设置状态“成功”或“失败”。只需保存 messageLog。

如何为operation's 方法process 创建Unit test?无效。

1) 我收到客户的请求

2) 将请求委托给异步进程的新线程

3) 返回同步响应。

我不明白如何为public void process(String guid, MessageRequest messageRequest) 创建单元测试

【问题讨论】:

  • 这更适合integration test,但如果您真的坚持对该方法进行单元测试,您也可以使用PowerMock 等库。
  • 在单元测试中,您只需要断言您实际调用了您的测试服务使用的外部服务,例如您的方法 process() 调用 messageLogService,您需要断言该调用并模拟服务也是如此,您将在某个时间点调用流程,您将根据预期规则获得模拟响应

标签: java unit-testing spring-boot junit clean-architecture


【解决方案1】:

在这种情况下,对于MessageOperation,我建议使用Mockito https://www.baeldung.com/mockito-annotations 库来模拟类属性

@Mock
private final MessageLogService messageLogService;

然后在您的单元测试中,您使用verify()方法来检查预期的行为是否已经发生。 (例如,正确调用了 save)。

我还会模拟getOne 的响应以满足您的需求

MessageLog messageLog = messageLogService.getOne(guid);

例如

MessageLog messageLog = new MessageLog();
when(messageLogService.getOne(eq("THE GUID YOU GIVE IN THE METHDO CALL"))).thenReturn(messageLog);

这样,既然你有MessageLog的对象引用,你就可以检查测试代码中的状态:

assertEquals("SUCCESS", messageLog.getStatus());

并使用 verify 来检查 save 方法是否被正确调用:

verify(messageLogService).save(same(messageLog));

关于我使用的匹配器https://www.baeldung.com/mockito-argument-matchers

【讨论】:

    猜你喜欢
    • 2019-10-20
    • 2011-08-23
    • 1970-01-01
    • 2019-10-27
    • 2013-11-01
    • 2018-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多