Junit - 断言两个相同的数组列表会使测试失败

Junit - Asserting two identical arraylists makes test fail

我正在对一个端点进行测试。这个端点 returns 一个对象列表,所以我的测试包括与数组列表进行比较。测试已经在第一个元素中失败,即使日志显示对象的字段相同:

org.opentest4j.AssertionFailedError:可迭代内容在索引 [0] 处不同,预期: 但是是:<{dispatchNumber=1, creationDate=null, pickUpDate=null, completionDate=null, estimatedDate=null, deliverymanName=edgar, receiverName= null, receiverTlfNumber=null, status=null}>

测试代码如下:

@Test
void whenFindByUser(){
    Dispatch disp1 = new Dispatch();
    disp1.setDispatchNumber(1);
    disp1.setDeliverymanName("edgar");

    Dispatch disp2 = new Dispatch();
    disp2.setDispatchNumber(2);
    disp2.setDeliverymanName("paola");

    Dispatch disp3 = new Dispatch();
    disp3.setDispatchNumber(3);
    disp3.setDeliverymanName("marco");

    List<Dispatch> dummyDispatches = new ArrayList<Dispatch>(Arrays.asList(disp1, disp2, disp3));

    when(service.findByUser("123")).thenReturn(dummyDispatches);

    List<Dispatch> realDispatches = restClient.getForObject(localhost + port + "/find/user/123", dummyDispatches.getClass());

    //assertArrayEquals(dummyDispatches.toArray(), realDispatches.toArray());
    //assertEquals(dummyDispatches.get(1), realDispatches.get(1));
    assertIterableEquals(dummyDispatches, realDispatches);
}

测试结束时注释的功能是我采用的其他方法使其工作,但没有用。

再看看错误信息。比较两个值:

<Dispatch(dispatchNumber=1, creationDate=null, pickUpDate=null, completionDate=null, estimatedDate=null, deliverymanName=edgar, receiverName=null, receiverTlfNumber=null, status=null)>

<{dispatchNumber=1, creationDate=null, pickUpDate=null, completionDate=null, estimatedDate=null, deliverymanName=edgar, receiverName=null, receiverTlfNumber=null, status=null}>

如果它们相等,那么这 2 个值看起来应该完全相同,但实际上并非如此。
第一个有 Dispatch(...),第二个有 {...}.

这是为什么?好吧,首先是在 Dispatch class 上调用 toString() 的结果。第二个不是,不可能,那是什么?

如果我们回头看看第二个来自哪里,我们会发现:

List<Dispatch> realDispatches = restClient.getForObject(..., dummyDispatches.getClass());

问题在于,由于 type erasuredummyDispatches.getClass()List.class 相同,即该方法仅被告知解析为List,但不是列表中应包含何种对象。

在不知道对象种类的情况下,它解析为 Map<String, Object>,它适合第二个值的输出,即 {name=value, ...}.

但是,你接着说,return 值被声明为 List<Dispatch>,而不是 List<Map<String, Object>>,那么我们为什么不报错呢?

因为 List.classraw 类型,使得 return 值声明为 raw List<Map>,并且是 raw,出于向后兼容的原因,它默默地被认为与 List<Map<ANYTHING>> 赋值兼容。

在 IDE 中,您可以启用编译器警告来提醒您注意此类问题。

解决方案:改为使用数组,因为数组组件类型在运行时保留:

Dispatch[] realDispatches = restClient.getForObject(..., Dispatch[].class);

这当然会影响您的 assert 调用,但您可以使用 Arrays.asList(...).

转换为列表