首页 > 解决方案 > 一个模拟类工作正常,另一个返回 null

问题描述

我在我的一个单元测试中模拟 2 个类,用 Mockito 定义行为。何时调用函数。

其中一个模拟类完全按预期工作,另一个返回null。我无法弄清楚两者之间有什么区别。

查询服务测试.java

@Import({ QueryServiceTestConfig.class })
@RunWith(SpringRunner.class)
public class QueryServiceTest {

    @Autowired
    private QueryService queryService;
    @MockBean
    private ElasticConnectionService elasticConnectionService;
    @MockBean
    private HBaseConnectionService hbaseConnectionService;

    @Test
    public void test_getRecordsFromQuery() throws IOException {

        // creation of sample data for inputs and outputs goes here

        // This mock works when called from queryService.getRecordsFromQuery()
        when(elasticConnectionService.getRowIdsFromQuery(filterParams, testIndex)).thenReturn(getRowIdsFromQuery_result);

        List<JSONObject> matches = queryService.getMatchingRowIds(getRowIdsFromQuery_result);

        // matchesArray is directly defined to make sure its exactly the same as in queryService.getRecordsFromQuery()
        JSONObject matchesArray = new JSONObject("{\"testTable\":[\"testUUID\"]}");

        // This mock fails when called from queryService.getRecordsFromQuery()
        when(hbaseConnectionService.getRowsByIDs(matchesArray)).thenReturn(getRowsByIDs_result);

        // This returns getRowsByIDs_result as expected
        JSONArray test = hbaseConnectionService.getRowsByIDs(matchesArray);

        // This returns null
        JSONArray actual = new JSONArray(queryService.getRecordsFromQuery(filterParams, testIndex));
    }
}

查询服务.java

@Service
public class QueryService {

    @Autowired
    private ElasticConnectionService elasticConnectionService;
    @Autowired
    private HBaseConnectionService hbaseConnectionService;
    @Autowired
    private PSQLConnectionService psqlConnectionService;

    public String getRecordsFromQuery(
                    Map<String,String> filterParams,
                    String tablename) throws IOException {
        /**
         * Get records that match simple key/value filters
         */

        // This mocked method returns exactly what was expected
        List<List<JSONObject>> lookupsList = elasticConnectionService.getRowIdsFromQuery(filterParams, tablename);

        List<JSONObject> matches = getMatchingRowIds(lookupsList);

        // matchesArray is exactly the same as in the test class
        JSONObject matchesArray = new JSONObject("{\"testTable\":[\"testUUID\"]}");

        // This returns null
        JSONArray hbResults = hbaseConnectionService.getRowsByIDs(matchesArray);

        return hbResults.toString(4);
    }
}

QueryServiceTestConfig.java

@Configuration
public class QueryServiceTestConfig {

    @Bean
    public QueryService queryService() {
        return new QueryService();
    }

    @Bean
    public ElasticConnectionService elasticConnectionService() {
        return new ElasticConnectionService();
    }

    @Bean
    public HBaseConnectionService hbaseConnectionService() {
        return new HBaseConnectionService();
    }

    @Bean
    public PSQLConnectionService psqlConnectionService() {
        return new PSQLConnectionService();
    }
}

最让我困惑的是,queryService.getRecordsByQuery()模拟elasticConnectionService.getRowIDsFromQuery()返回了预期的结果,但hbaseConnectionService.getRowsByIDs()模拟返回了null

elastic 和 hbase 连接服务类都定义在同一个文件夹中,它们唯一的注解是@Service. 如果两者都失败,我会认为我配置了错误,但调用按预期工作的事实elasticConnectionService告诉我正在发生其他事情。

标签: javaspringunit-testingtestingmockito

解决方案


如果包JSONObjectis org.json,JSONObject的 equals 方法如下所示:

public boolean equals(Object object) {
            return object == null || object == this;
        }

由于 in 的实例与matchesArrayinQueryService的实例不同QueryServiceTest,因此该equals()方法将返回 false。

尝试改变这个:

when(hbaseConnectionService.getRowsByIDs(matchesArray)).thenReturn(getRowsByIDs_result);

对此,看看你的结果是否改变:

when(hbaseConnectionService.getRowsByIDs(Mockito.any())).thenReturn(getRowsByIDs_result);

我认为您也可以这样做:

when(hbaseConnectionService.getRowsByIDs(Mockito.eq(matchesArray))).thenReturn(getRowsByIDs_result);

或者:

when(hbaseConnectionService.getRowsByIDs(Matchers.eq(matchesArray))).thenReturn(getRowsByIDs_result);

因为在引擎盖下,该Matchers.eq()方法可能会调用JSONObject.equals(),Matcher 可能无法工作(我没有检查源代码Matchers.eq())。

通常,在设置模拟方法调用时,您希望将您的方法包装parameter(s)在 Mockito 的 Matcher 方法之一中。不幸的是,这在您的场景中不起作用。

(请注意,Mockito 类扩展了 Matchers)


推荐阅读