如何模拟FileInputStream和其他* Streams

我有一个类,它获取GenericFile作为输入参数读取数据并进行一些额外的处理。 我需要测试它:

public class RealCardParser { public static final Logger l = LoggerFactory.getLogger(RealCardParser.class); @Handler public ArrayList handle(GenericFile genericFile) throws IOException { ArrayList strings = new ArrayList(); FileInputStream fstream = new FileInputStream((File) genericFile.getFile()); DataInputStream in = new DataInputStream(fstream); BufferedReader br = new BufferedReader(new InputStreamReader(in)); String strLine = br.readLine();//skip header while ((strLine = br.readLine()) != null) { l.info("handling in parser: {}", strLine); strings.add(strLine); } br.close(); return strings; } } 

问题在于新的FileInputStream。 我可以模拟GenericFile但它没用,因为FileInputStream检查文件是否存在。 我改变了我的课程:

 public class RealCardParser { public static final Logger l = LoggerFactory.getLogger(RealCardParser.class); protected BufferedReader getBufferedReader(GenericFile genericFile) throws FileNotFoundException { FileInputStream fstream = new FileInputStream((File) genericFile.getFile()); DataInputStream in = new DataInputStream(fstream); return new BufferedReader(new InputStreamReader(in)); } @Handler public ArrayList handle(GenericFile genericFile) throws IOException { ArrayList strings = new ArrayList(); BufferedReader br = getBufferedReader(genericFile); String strLine = br.readLine();//skip header while ((strLine = br.readLine()) != null) { l.info("handling in parser: {}", strLine); strings.add(strLine); } br.close(); return strings; } } 

所以现在我可以覆盖方法getBufferedReader和测试方法处理程序:

 @RunWith(MockitoJUnitRunner.class) public class RealCardParserTest { RealCardParser parser; @Mock GenericFile genericFile; @Mock BufferedReader bufferedReader; @Mock File file; @Before public void setUp() throws Exception { parser = new RealCardParser() { @Override public BufferedReader getBufferedReader(GenericFile genericFile) throws FileNotFoundException { return bufferedReader; } }; when(genericFile.getFile()).thenReturn(file); when(bufferedReader.readLine()).thenReturn("header").thenReturn("1,2,3").thenReturn(null); } @Test public void testParser() throws Exception { parser.handle(genericFile); //do some asserts } } 

Handler方法现在已经被测试覆盖了,但我仍然发现了导致cobertura问题的方法getBufferedReader。 如何测试方法getBufferedReader或者可能有另一个问题的解决方案?

也许这是一个坏主意,但我的第一种方法是创建一个实际的测试文件而不是模拟流对象。

有人可能会说这将测试GenericFile类而不是getBufferedReader方法。

也许可接受的方法是通过模拟的getBufferedReader返回一个实际存在的测试文件来测试getBufferedReader

我首先将Stream的创建提取为依赖项。 因此,您的RealCardParser将StreamSource作为依赖项。

现在你可以解决你的问题:

  1. 对于您当前的测试,提供一个模拟(或者在这种情况下,我更喜欢一个假的)实现,返回一个由String构造的Stream。

  2. 使用真实文件测试实际的StreamSource,确保它返回正确的内容和不返回的内容。

您可以使用PowerMockRunner和PowerMockito模拟FileInputStream。 请参阅以下代码进行模拟 –

 @RunWith(PowerMockRunner.class) @PrepareForTest({ FileInputStream.class }) public class A{ @Test public void testFileInputStream () throws Exception { final FileInputStream fileInputStreamMock = PowerMockito.mock(FileInputStream.class); PowerMockito.whenNew(FileInputStream.class).withArguments(Matchers.anyString()) .thenReturn(fileInputStreamMock); //Call the actual method containing the new constructor of FileInputStream } } 

我知道这不是你想要的答案。

unit testing的想法是确保您的逻辑正确。 unit testing可以捕获已写入错误逻辑的错误。 如果方法不包含逻辑(即没有分支,循环或exception处理),那么对它进行unit testing是不经济的。 通过这种方式,我的意思是unit testing花费金钱 – 写它的时间,以及维护它的时间。 大多数unit testing都会通过查找错误或者向我们重新确认在测试的域中没有错误来支付我们的投资回报。

但是,针对您的getBufferedReader方法的unit testing不会为您的投资回报。 它的成本有限,但效益为零,因为没有可能出错的实际逻辑。 因此,您不应该编写这样的unit testing。 如果您的Cobertura设置或您的组织标准要求存在此类unit testing,那么这些设置或标准是错误的并且应该更改。 否则,您的雇主的钱花在具有无限成本:收益比的事物上。

我强烈建议您更改标准,以便只为包含分支,循环或exception处理的方法编写unit testing。