模拟列表并尝试对其进行迭代 [英] Mocking a List and attempting to iterate over it

查看:130
本文介绍了模拟列表并尝试对其进行迭代的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当前正在使用Mockito从我的一个类中测试一个方法.我的班级包含一个List,并且该方法接受同一班级的对象.问题是当我尝试从对象遍历List时.我得到一个空指针指向列表.在下面,您将看到代码片段.

Currently using Mockito to Test a method from one of my classes. My class contains a List, and the method takes in an object of the same class. The issue is when I attempt to iterate over the List from the object. I'm getting a null pointer to the list. Below you will see the code snippets.

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());
}

在上面您可以看到我的模拟测试,下面是使用该方法的我的课程:

above you can see my mockito test and below is my Class with the method:

公共舱货运{

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(订单订单:excessShipment){ 在mergeShipemts();

When I run the test I am getting a java.lang.NullPointerException for the line: for (Order order : existingShipment){ in mergeShipemts();

问题是;可以模拟一个列表,调用该列表,然后在该模拟的列表上运行一次foreach吗?

The question is; Is it possible to mock a list, call that list and then run a foreach over that mocked list?

推荐答案

存在一些基本问题,为什么您的示例不起作用并抛出NullPointerException.

There are some fundamental issues why your example not does work and throws a NullPointerException.

  1. 对模拟列表上的add()的调用实际上没有任何作用.默认情况下,模拟中的所有void方法均为"no-ops"
  2. 在后台使用for-each语法调用Collection.iterator()遍历列表.这将返回null,因为您尚未将Mockito设置为返回其他任何内容.
  1. The call to add() on the mocked list effectively doesn't do anything. All void methods on mocks are "no-ops" by default
  2. Iterating over a list using for-each syntax calls Collection.iterator() under the hood. This returns null, because you've not setup mockito to return anything else.

相反,我不会模拟列表,而是传递实际列表. Arrays.asList()便于测试.

Instead, I would not mock the list and instead pass an actual list. Arrays.asList() is convenient for testing.

@Before
public void setUp(){
    MockitoAnnotations.initMocks(this);
    shipment = new Shipment(1, Arrays.asList(mockOrder1, mockOrder2));
    shipment2 = new Shipment(2, Arrays.asList(mockOrder3));
}

如果确定要模拟列表,则必须模拟其行为,即使add()实际上存储一些东西,而.iterator()返回一个迭代器.可以非常痛苦地完成此操作,如下所述.我只包括了这一点以说明原理.

If you're determined to mock a list then you'll have to mock its behaviour, i.e. making the add() actually store something and .iterator() return an iterator. This can be done rather painfully as follows. I've only included this to demonstrate the principle.

@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);
    }
}

这篇关于模拟列表并尝试对其进行迭代的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆