模拟CSV阅读器与mockito和多个返回值

时间:2015-01-08 09:39:19

标签: java unit-testing mockito

我不想嘲笑CSVReader。所以我的模拟应该每次返回一个新数组,这应该是通用的。 最后一个值应为null。

nextLine() -> ["a","b","c"]
nextLine() -> ["a","b","c"]
nextLine() -> null

My MockClass:

import au.com.bytecode.opencsv.CSVReader;
import com.sun.javafx.beans.annotations.NonNull;
import org.mockito.Mockito;
import org.mockito.stubbing.OngoingStubbing;

import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class CSVReaderMock {
    CSVReader reader;
    private boolean linesCorrectInitialized;

    public CSVReaderMock()
    {
        reader = mock(CSVReader.class);
    }

    public CSVReaderMock returnLines(@NonNull List<String> lines) {
        // the last value has to be null
        lines.add(null);
        try {
            for (String line : lines) {
                String[] lineArr = null;
                if (line != null) {
                    lineArr = line.split(",");
                }
                when(reader.readNext()).thenReturn(lineArr);
            }
            linesCorrectInitialized = true;
        } catch (IOException e) {
            e.printStackTrace();
        };
        return this;
    }

    public CSVReader create() {
        if (!linesCorrectInitialized) { throw new RuntimeException("lines are not initialized correct"); }
        return reader;
    }

}

这里是一个测试用例(我只想查看我的模拟构建器):

@Test
public void testImportLines() throws Exception {
    CSVReader reader;
    List<String> list = new LinkedList<>();
    list.add("some,lines,for,testing");
    reader = new CSVReaderMock().returnLines(list).create();


    System.out.println(reader.readNext()); // should return [Ljava.lang.String;@xxxx with conent-> ["some","lines","for","testing"]
    System.out.println(reader.readNext()); // should return null
}

实际输出是:

null
null

所以我的问题是,如何在不事先知道列表的外观的情况下传递返回值列表?我知道我可以通过.thenReturn(line1,line2,line3)传递“csv行”,但这会破坏我的做法。

2 个答案:

答案 0 :(得分:1)

您需要使用OngoingStubbing引用将返回值链接到单个when()结果中,例如:

    Iterator<String> ls = org.mockito.Mockito.mock(Iterator.class);
    OngoingStubbing<String> stubbing = when(ls.next());

    for(String s: new String[] { "ABC", "DEF" }) {
        stubbing = stubbing.thenReturn(s);
    }

    System.out.println(ls.next());
    System.out.println(ls.next());

...打印“ABC”,然后打印“DEF”。

答案 1 :(得分:1)

Mockito在这样的场合有一个ReturnsElementsOf答案。

  

返回集合的元素。永远保持返回最后一个元素。当你有一系列要返回的元素时,它们可能会很有用。

所以现在你只需要准备元素然后传入它。因为最后需要添加null调用,所以它会阻止你重复使用CSVReaderMock构建器,但是那个&#39;无论你是否使用答案都是一样的。

List<String[]> returnList = new ArrayList<>();

public CSVReaderMock returnLines(@NonNull List<String> lines) {
  try {
    for (String line : lines) {
      String[] lineArr = null;
      if (line != null) {
        lineArr = line.split(",");
      }
      returnList.add(lineArr);
    }
    linesCorrectInitialized = true;
  } catch (IOException e) { /* ... */ };
  return this;
}

public CSVReader create() {
  if (!linesCorrectInitialized) { /* ... */ }
  // Return null repeatedly after all stubs are exhausted.
  returnList.add(null);
  when(reader.readNext()).thenAnswer(new ReturnsElementsOf(returnList));
  return reader;
}