Mockito测试失败 - 参数(Mongo DBObjects)是不同的(不是!)

时间:2014-01-08 13:23:44

标签: java mongodb mockito

编辑:问题在下面提到了一个更具体的问题。

测试未通过,发生此故障:

Argument(s) are different! Wanted:
declColl.find(
    { "declensions" : { "$in" : [ "testtest"]}}
);
-> at cz.xxx.CzechMongoWordDeclensionsRetrieverTest.getLemmaTest(CzechMongoWordDeclensionsRetrieverTest.java:63)
Actual invocation has different arguments:
declColl.find(
    { "declensions" : { "$in" : [ "testtest"]}}
);

您可以从失败的输出中立即看到我的问题。没有区别。 toString方法可能是欺骗性的,equals方法可能false方法返回DBObject ... {我在下面说明,我不知道如何检查这个,但是检查两个“queryBuilt”相同的DBObject返回true

测试很短,看起来像这样:

@InjectMocks
private CzechMongoWordDeclensionsRetriever declRetriever;
@Mock
private DBCollection declColl;

@Before
public void setUp() {
    MockitoAnnotations.initMocks(this);
    Object[] criteria = new String[1];
    criteria[0] = "testtest";

    //mocks init
    DBCursor cur = mock(DBCursor.class);
    DBObject queryObj = QueryBuilder.start("declensions").in(criteria).get();
    when(declColl.find(queryObj)).thenReturn(cur);
    when(cur.size()).thenReturn(1);
    when(cur.next()).thenReturn(new BasicDBObject("lemma", "testtest"));
}

@Test
public void getLemmaTest() {
    Object[] criteria = new String[1];
    criteria[0] = "testtest";
    DBObject queryObj = QueryBuilder.start("declensions").in(criteria).get();

    String toTest = "testtest";
    String testResult = declRetriever.getLemma(toTest);

    verify(declColl).find(queryObj);
}

使用这样的getLemma方法:

public String getLemma(String word) {
        criteria[0] = word;
        DBObject lemmaObj = QueryBuilder.start("declensions").in(criteria).get();
        DBCursor cursor = declColl.find(lemmaObj);

        if(cursor == null)     return null;
        if(cursor.size() > 1)  return null; 
        if(cursor.size() == 0) return null; 

        return (String) cursor.next().get("lemma");
    }

代码甚至不会低于if(cursor == null)部分,因为存根不起作用。我通过运行DBObject两次创建了两个不同的QueryBuilder,然后检查它们是否相等(我不知道equals Mongo DBObject的实现是什么样的 - 编辑:比较地图条目)。

我不知道为什么会发生失败。

编辑:(这应该是一个新问题?)

我尝试过Biju Kunjummen的答案,起初没有帮助,但我试过了:

    Object[] criteria = new String[1];
    criteria[0] = "testtest";
    DBObject queryObj = QueryBuilder.start("declensions").in(criteria).get();
    Object[] criteria2 = new String[1];
    criteria2[0] = "testtest";
    DBObject queryObj2 = QueryBuilder.start("declensions").in(criteria).get();
    assertTrue(queryObj.equals(queryObj2));

并且断言失败。所以我可以看到问题不在于Mockito,但DBObjects不匹配,即使它们应该。对我来说,语义上的查询是相同的。 (如下所述):似乎,如果Map.entry的{​​{1}}值与已比较的Object[] Object[] equals的内容相同,如果false与被比较的参考不同。

2 个答案:

答案 0 :(得分:1)

可能是因为您的DBObject.equals(和哈希码)没有正确实现,检查它的快速方法是试试这个:

DBObject queryObj1 = QueryBuilder.start("declensions").in(criteria).get();
DBObject queryObj2 = QueryBuilder.start("declensions").in(criteria).get();

assertTrue(queryObj1.equals(queryObj2))

这可能会失败,这就是Mock断言错误的原因。

答案 1 :(得分:1)

所以:verify方法正在检查,如果我使用相同的queryObj作为属性。由于它使用了equals,并且DBObject通过Map equals方法通过映射值进行了比较,因此检查了Map entry s的相等性。我相信,它没有比较两个Object[]数组的内容,但检查了引用并发现它们不匹配。因此,平等为falseverify表示它期待不同的参数。

我将Object[]的使用替换为List<>,现在verify方法很高兴 - 它通过了。

测试仍然不起作用,但出于完全不同的原因,我可能会在另一个问题中描述://如果我找到一个足够重要的答案,就会发布在这里。

无论如何,测试现在可以正常运行:

@Test
public void getLemmaTest() {

    //... now I use List<String> instead of Object[]. declColl is already stubbed 
    // to return something, when a find(queryObj) is called.
    List<String> criteriaColl = new ArrayList<>();
    criteriaColl.add("testtest");
    DBObject queryObj = QueryBuilder.start("declensions").in(criteriaColl).get();

    String expResult = "testtest";
    String toTest = "testtest";
    String testResult = declRetriever.getLemma(toTest);

    verify(declColl).find(queryObj);
    assertEquals(expResult, testResult);  
}

和getLemma的实现。

public String getLemma(String word) {
    criteria.set(0, word);
    DBObject lemmaObj = QueryBuilder.start("declensions").in(criteria).get();
    DBCursor cursor = declColl.find(lemmaObj);
    if(cursor == null)      return null;
    if(cursor.size() > 1)   return null;
    if(cursor.size() == 0)  return null;
    return (String) cursor.next().get("lemma");
}

我无法使用

criteria.add(word);
//....
criteria.remove(0);

原因不明,我可能会在下一个问题中提出这个问题。 (如果我创建问题,我会在这里发布链接)