2010-10-08 61 views
2

我有一种方法,试图调用内存中的图像转换器,如果失败,然后尝试在磁盘上执行图像转换。 (在内存中的图像转换器将尝试分配图像的第二个副本,因此,如果原来是非常大的,我们可能没有足够的内存吧。)JUnit可以模拟OutOfMemoryErrors吗?

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,但随后在后续调用中表现正常。不过,这看起来像是黑客。

回答

6

你应该嘲笑出你的转换器,而不是使用一个真正的。

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

例如,JMock的你可以这样做:

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

注入存根或模拟memory_converterconvert()方法抛出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

它发生,我认为我可以 做出的BufferedImage 抛出一个OutOfMemoryError的 第一次通过调用方法的假子 内存转换器被调用,但 然后在后续的 调用中正常运行。不过,这看起来像是黑客。

你在这里正确的道路上。嘲笑物体正是这些类型的东西有益的。你并不在意OutOfMemory错误是否合法,你只是想确保它被抛出/被捕获并且另一个路径被执行。把它嘲笑出来,你会很开心。

-2

OutOfMemoryError异常的处理和它的测试是非常困难的。你不能用模拟来测试它。根据哪个地方的OutOfMemoryError异常发生的影响可能会非常不同。问题是,该OutOfMemoryError异常无法通过你的调用代码。

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

如果你只想测试你的catch块,那么你可以嘲笑它。

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

+0

我看到检查空闲堆的数量的问题是,发现它太少不能保证分配将失败---尝试分配可能会导致垃圾回收器释放足够的堆以使其成功。 – uckelman 2010-10-09 17:16:51