【问题标题】:How to create Junit testcases for lambda expression using Mockito Junit 5?如何使用 Mockito Junit 5 为 lambda 表达式创建 Junit 测试用例?
【发布时间】:2021-11-02 11:26:26
【问题描述】:

我想创建方法的 Junit TestCases,我们在其中迭代 List<Map<String,Object>> 使用带有 lambda 表达式的 forEach 循环。现在我想模拟声明objectMapper.writeValueAsString(recordObj.get("value"));,但我不明白如何使用recordObj

public String apply(MyRequestWrapper requestWrapper) {
        String resultStr=null;
        final Map<String, List<PubSubEvent>> packagesEventList = AppUtilities.getPackagesEventsMappedList();

        try {
            logger.debug("Received Record:: " + requestWrapper.getBody().toString());
            List<RecordProcessedResult> results = new ArrayList<>();
            List<Map<String,Object>> recordMaps= string2List(objectMapper,requestWrapper.getBody().toString());
            logger.debug("Parsed received payload ::: "+ LocalDateTime.now() + " batch size is ::: "+ recordMaps.size());
            
            
            if(! ObjectUtils.isEmpty(recordMaps) && !recordMaps.isEmpty() ) {
                recordMaps.forEach(recordObj ->{
                    ConsumerRecord record=objectMapper.convertValue(recordObj, ConsumerRecord.class);
                    String topicName = recordObj.get("topic").toString();
                    String key = null;
                    String value = null;
                    String offset = null;
                    String xTraceabilityId = ((Map<String, String>) recordObj.get("headers")).get(IdTypeConstants.XTRACEABILITYID);
                    String xCorrelationId = ((Map<String, String>) recordObj.get("headers")).get(IdTypeConstants.XCORRELATIONID);
                    
                    MDC.put(IdTypeConstants.XTRACEABILITYID, xTraceabilityId);
                    MDC.put(IdTypeConstants.XCORRELATIONID, xCorrelationId);
                    
                    try {
                        key = objectMapper.writeValueAsString(recordObj.get("key"));
                        value = objectMapper.writeValueAsString(recordObj.get("value"));
                        offset = objectMapper.writeValueAsString(recordObj.get("offset"));
                    
                        MyEvent myEvent= objectMapper.readValue(value, MyEvent.class);

                        subscribedPackageProcessor.setInput(input);
                        subscribedPackageProcessor.setOutput(output);
                        subscribedPackageProcessor.setPackagesEventList(packagesEventList);
                        subscribedPackageProcessor.setRequesterType(requesterType);                subscribedPackageProcessor.processSubscribedPackage(myEvent.getPackageId());
                        RecordProcessedResult rpr = new RecordProcessedResult(record, true, null, xTraceabilityId, xCorrelationId, key, System.currentTimeMillis());
                        results.add(rpr);
                    }
                    catch(Exception e) {
                        RecordProcessedResult rpr = new RecordProcessedResult(record, false, ExceptionUtils.getStackTrace(e), xTraceabilityId, xCorrelationId, key, System.currentTimeMillis());
                        results.add(rpr);
                        logger.info("Exception occured while processing fund data :::out  ", e);
                    }
                    MDC.clear();

                });
            }
            resultStr = objectMapper.writeValueAsString(results);
        }catch (Exception e) {
            logger.debug(e.getMessage());
        }
        return resultStr;
    }

我已经尝试过以下测试用例。

@Test void applyTest() throws Exception { 
        MyEvent myEvent = new MyEvent(); 
        myEvent.setPackageId("test"); 
        MyRequestWrapper flowRequestWrapper= getMyRequestWrapper();
        List<Map<String, Object>> maps = string2List(objectMapper1, flowRequestWrapper.getBody().toString());
        Map<String,Object> map = new HashMap<String, Object>();
        Mockito.when(objectMapper.readValue(Mockito.anyString(), Mockito.any(TypeReference.class))).thenReturn(maps);
        Mockito.when(objectMapper.writeValueAsString(Mockito.anyString())).thenReturn("test");
        Mockito.when(objectMapper.readValue(Mockito.anyString(), Mockito.eq(MyEvent.class))).thenReturn(myEvent);
        //doNothing().when(subscribedPackageProcessor).processSubscribedPackage("");
        String response = processESignCompletedEventSvcFlow.apply(flowRequestWrapper);
        Assertions.assertNotNull(response); 
    }

请帮忙,谢谢

【问题讨论】:

    标签: java lambda mockito junit5


    【解决方案1】:

    您的方法过于复杂,无法进行单元测试。例如,它通过调用同一类中的方法来声明依赖关系。你不能模拟这些,这会使测试变得复杂很多倍。

    List<Map<String,Object>> recordMaps =
        string2List(objectMapper,requestWrapper.getBody().toString());
    

    您需要将string2List 方法提取到一个独立类(带有它自己的单元测试)中,该类作为依赖项注入到您的类中。

    然后,您可以模拟 string2List 类,当您这样做时,您可以通过此方法的单元测试控制 recordObj 实例的创建。

    您的第二个“罪过”是滥用 lambda,创建一个长度超过两行的 lambda。 Lambdas 应该很短。 如果它跨越几行,则必须将其提取到可以单独进行单元测试的独立类中。同样,当您将此 lambda 提取到一个独立的类中并对其进行单元测试时,您不能只在您的方法中使用“new RecordObjConsumer(results)”,因为这会创建一个您再次无法模拟的硬编码依赖项。您需要设计消费者,以便它可以作为外部依赖注入到您的类中。

    【讨论】:

    • 感谢托本的建议
    • 感谢 Torben 的建议,但如果我们将功能的复杂性放在一边,并将进一步优化,您能否建议,如何使用 "recordMaps.forEach(recordObj ->{" 作为模拟,以便我可以在“Mockito.when”中使用它?
    猜你喜欢
    • 1970-01-01
    • 2017-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-21
    • 2020-02-27
    • 2017-01-19
    • 1970-01-01
    相关资源
    最近更新 更多