JUnit可以模拟OutOfMemoryErrors吗?

时间:2010-10-08 21:11:11

标签: java unit-testing testing junit out-of-memory

我有一种尝试调用内存中图像转换器的方法,如果失败,则尝试在磁盘上进行图像转换。 (内存中的图像转换器将尝试分配图像的第二个副本,因此如果原始图像非常大,我们可能没有足够的内存。)

public BufferedImage convert(BufferedImage img, int type) {
  try {
    return memory_converter.convert(type);
  }
  catch (OutOfMemoryError e) {
    // This is ok, we just don't have enough free heap for the conversion.
  }

  // Try converting on disk instead.
  return file_converter.convert(img, type);
}

我想为JUnit编写单元测试来运行每个代码路径,但是运行JUnit并使用足够少的堆来强制OutOfMemoryError是不方便的。有没有办法在JUnit中模拟OutOfMemoryError

我发现我可以创建一个BufferedImage的伪子类,它在第一次调用内存转换器调用的方法时抛出OutOfMemoryError,但随后会在后续行为中正常运行调用。不过,这似乎是一种黑客攻击。

4 个答案:

答案 0 :(得分:6)

你应该嘲笑你的转换器,而不是使用真实的转换器。

一旦你这样做,你只需让你的模拟库在调用convert()方法时抛出一个新的OOME。

例如,使用JMock,您可以这样做:

allowing(mockConverter).convert(with(any(int.class)));
will(throwException(new OutOfMemoryError()));

答案 1 :(得分:3)

注入memory_converter方法抛出convert()的存根或模拟OutOfMemryError

  

我发现我可以创建BufferedImage的伪子类,它在第一次调用内存转换器调用的方法时抛出OutOfMemoryError,但随后在后续调用中表现正常。不过,这似乎是一种黑客攻击。

模拟框架通常非常强大,应该让您指定此行为。例如,JMock:

http://www.jmock.org/returning.html

  

在连续通话中返回不同的值

     

有两种方法可以在不同的调用上返回不同的值。第一个是定义多个期望并从每个期望中返回不同的值:

oneOf (anObject).doSomething(); will(returnValue(10));
oneOf (anObject).doSomething(); will(returnValue(20));
oneOf (anObject).doSomething(); will(returnValue(30));
     

doSomething的第一次调用将返回10,第二次调用20和第三次30。

答案 2 :(得分:2)

  

我发现我可以   make BufferedImage的伪子类   抛出一个OutOfMemoryError   第一次调用的方法   内存转换器被调用,但是   然后在后续行动中表现正常   调用。不过,这似乎是一种黑客攻击。

你正走在正确的道路上。模拟对象正是这些类型的事物有益的。你真的不关心OutOfMemory错误是否合法,你只是想确保抛出/捕获它并执行另一个路径。嘲笑它,你会很高兴。

答案 3 :(得分:-2)

处理OutOfMemoryError并对其进行测试非常困难。你无法用模拟测试它。根据OutOfMemoryError异常发生的位置,效果可能会有很大差异。问题是OutOfMemoryError无法传递给您的调用代码。

如果你想要一个真正的测试,那么你需要在第二个线程内存中分配并产生一个OutOfMemoryError。这应该重复多次以查看不同的效果。

如果您只想测试一下catch块,那么您可以模拟它。

因为OutOfMemoryError可能会在应用程序中的任何其他线程上产生致命错误,所以应该阻止它。我认为更好的解决方案是计算空闲内存。所需的内存大小,并在发生异常之前调用磁盘转换。