我有一种尝试调用内存中图像转换器的方法,如果失败,则尝试在磁盘上进行图像转换。 (内存中的图像转换器将尝试分配图像的第二个副本,因此如果原始图像非常大,我们可能没有足够的内存。)
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
,但随后会在后续行为中正常运行调用。不过,这似乎是一种黑客攻击。
答案 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可能会在应用程序中的任何其他线程上产生致命错误,所以应该阻止它。我认为更好的解决方案是计算空闲内存。所需的内存大小,并在发生异常之前调用磁盘转换。