目前正在使用Mockito从我的一个类中测试一个方法。我的类包含一个List,该方法接受同一个类的对象。问题是当我尝试从对象迭代List时。我得到了一个指向列表的空指针。您将在下面看到代码段。
private Shipment shipment;
private Shipment shipment2;
@Mock
private Order mockOrder1;
@Mock
private Order mockOrder2;
@Mock
private Order mockOrder3;
@Mock
private ArrayList<Order> mockShipmentOrders;
@Mock
private ArrayList<Order> mockShipmentOrders2;
@Before
public void setUp(){
MockitoAnnotations.initMocks(this);
mockShipmentOrders.add(mockOrder1);
mockShipmentOrders.add(mockOrder2);
mockShipmentOrders2.add(mockOrder3);
shipment = new Shipment(1, mockShipmentOrders);
shipment2 = new Shipment(2, mockShipmentOrders2);
}
@Test
public void test_mergeShipments_increasesByOneWhenAShipmentOfOneAddedToAShipmentORderSizeOfTwo(){
shipment.mergeShipments(shipment2);
assertEquals(3, shipment.getShipmentOrders().size());
}
上面你可以看到我的模拟测试,下面是我的类,方法是:
公共舱发货{
private long shipmentID;
private List<Order> shipmentOrders;
public Shipment(long shipmentID, List<Order> shipmentOrders){
this.shipmentID = shipmentID;
this.shipmentOrders = shipmentOrders;
}
public List<Order> getShipmentOrders(){
return shipmentOrders;
}
public void mergeShipments(Shipment shipment2){
List<Order> existingShipment = shipment2.getShipmentOrders();
for (Order order : existingShipment){
shipmentOrders.add(order);
}
}
当我运行测试时,我得到一行的java.lang.NullPointerException:for(Order order:existingShipment){ 在mergeShipemts();
问题是;是否可以模拟列表,调用该列表,然后在该模拟列表上运行foreach?
答案 0 :(得分:2)
有一些基本问题导致您的示例无法正常工作并抛出NullPointerException
。
add()
的调用实际上没有做任何事情。模拟中的所有无效方法都是&#34; no-ops&#34;默认情况下Collection.iterator()
。这将返回null,因为您没有设置mockito来返回任何其他内容。相反,我不会模拟列表而是传递实际列表。 Arrays.asList()
便于测试。
@Before
public void setUp(){
MockitoAnnotations.initMocks(this);
shipment = new Shipment(1, Arrays.asList(mockOrder1, mockOrder2));
shipment2 = new Shipment(2, Arrays.asList(mockOrder3));
}
如果您决定模拟列表,那么您必须模拟其行为,即使add()实际存储某些内容,而.iterator()返回迭代器。这可以通过以下方式相当痛苦地完成。我只是将其包括在内以证明这一原则。
@Mock
private List<String> mockedList;
@Before
public void init() {
MockitoAnnotations.initMocks(this);
List<String> realList = new ArrayList<>();
doAnswer(new Answer<String>() {
@Override
public String answer(InvocationOnMock invocation) throws Throwable {
realList.add(invocation.getArgumentAt(0, String.class));
return null;
}
}).when(mockedList).add(any());
when(mockedList.iterator()).thenAnswer(new Answer<Iterator<String>>() {
@Override
public Iterator<String> answer(InvocationOnMock invocation) throws Throwable {
return realList.iterator();
}
});
mockedList.add("bar");
mockedList.add("baz");
}
@Test
public void iterateOverMockedList() {
for (String each : mockedList) {
System.out.println(each);
}
}
答案 1 :(得分:0)
您无法为Mocked元素添加值。你可以从数据列表中删除@Mock并使用new关键字来启动它。
private Shipment shipment;
private Shipment shipment2;
@Mock
private Order mockOrder1;
@Mock
private Order mockOrder2;
@Mock
private Order mockOrder3;
private ArrayList<Order> mockShipmentOrders;
private ArrayList<Order> mockShipmentOrders2;
@Before
public void setUp(){
MockitoAnnotations.initMocks(this);
mockShipmentOrders = new ArrayList<>();
mockShipmentOrders2 = new ArrayList<>();
mockShipmentOrders.add(mockOrder1);
mockShipmentOrders.add(mockOrder2);
mockShipmentOrders2.add(mockOrder3);
shipment = new Shipment(1, mockShipmentOrders);
shipment2 = new Shipment(2, mockShipmentOrders2);
}
@Test
public void test_mergeShipments_increasesByOneWhenAShipmentOfOneAddedToAShipmentORderSizeOfTwo(){
System.out.println(shipment);
System.out.println(shipment2);
shipment.mergeShipments(shipment2);
assertEquals(3, shipment.getShipmentOrders().size());
}
答案 2 :(得分:0)
@Adam所说:“在后台使用for-each
语法调用Collection.iterator()
遍历一个列表。由于您没有设置mockito
来返回任何其他内容,因此返回null。”
因此,您必须以这种方式设置模仿;
@Test
public void test_mergeShipments_increasesByOneWhenAShipmentOfOneAddedToAShipmentORderSizeOfTwo(){
//GIVEN
//Mock the iterator
Iterator<Order> stockIteratorMock = mock(Iterator.class);
//WHEN
//In setUp method you put two objs
when(mockShipmentOrder.size()).thenReturn(2);
//Set a mock for iterator
when(mockShipmentOrder.iterator()).thenReturn(iteratorMock);
// Instruct the iteratorMock when stop to return item
when(iteratorMock.hasNext())
.thenReturn(true)
.thenReturn(true)
.thenReturn(false);
// Instruct the iteratorMock what obj return on each call
// You can skip this: mockShipmentOrders.add(mockOrder1);
when(stockIteratorMock.next())
.thenReturn(mockOrder1)
.thenReturn(mockOrder2);
shipment.mergeShipments(shipment);
//THEN
assertEquals(2, shipment.getShipmentOrders().size());
}
这种方式很冗长,但是您可以随意修改数组列表的行为,也可以了解其在后台的工作方式。