Java 一个模拟类工作正常,另一个返回null

Java 一个模拟类工作正常,另一个返回null,java,spring,unit-testing,testing,mockito,Java,Spring,Unit Testing,Testing,Mockito,我在一个单元测试中模拟了两个类,用Mockito定义了行为。然后调用函数 其中一个模拟类完全按照预期工作,另一个返回null。我想不出两者之间有什么区别 QueryServiceTest.java @Import({ QueryServiceTestConfig.class }) @RunWith(SpringRunner.class) public class QueryServiceTest { @Autowired private QueryService querySe

我在一个单元测试中模拟了两个类,用Mockito定义了行为。然后调用函数

其中一个模拟类完全按照预期工作,另一个返回
null
。我想不出两者之间有什么区别

QueryServiceTest.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));
    }
}
@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);
    }
}
@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()
mock返回预期的结果,而
hbasConnectionService.getRowsByIDs()
mock返回
null


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

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

public boolean equals(Object object) {
            return object == null || object == this;
        }
由于
QueryService
中的
matchesArray
实例与
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);
或:

因为在引擎盖下,
Matchers.eq()
方法可能调用
JSONObject.equals()
,所以匹配器可能无法工作(我没有检查
Matchers.eq()
的源代码)

通常,在设置模拟方法调用时,您希望将
参数
封装在一个Mockito的Matcher方法中。不幸的是,这在您的场景中不起作用


(注意Mockito类扩展了Matchers)

JSONObject的包是什么?@stvnbrkdell我正在使用org.jsontanks!我可以使用
any()。在这种情况下,我可以不用使用
any()
,但如果可能的话,我更愿意在测试中更加具体,有没有办法让
JSONObject
在Mockito中按预期的方式运行?因为JSONObject的equals()方法是以这种方式实现的,不,你不能让它按你希望的方式运行(即,你不能使用匹配器)为了使代码更易于测试和更灵活,请考虑将MatChESART数组作为参数获取GETReCordSoFQuices()。这将允许您在单元测试中使用匹配器,也使您的方法更加灵活。好吧,在我开始挖掘新的JSON库之前,您是否推荐一个可以很好地与Mockito配合使用的库?请看Jackson
when(hbaseConnectionService.getRowsByIDs(Matchers.eq(matchesArray))).thenReturn(getRowsByIDs_result);