【问题标题】:Can JUnit simulate OutOfMemoryErrors?JUnit 可以模拟 OutOfMemoryErrors 吗?
【发布时间】:2010-10-08 21:11:11
【问题描述】:

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

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,但随后在后续调用中表现正常。不过,这似乎是一种 hack。

【问题讨论】:

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


    【解决方案1】:

    您应该模拟您的转换器,而不是使用真正的转换器。

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

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

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

    【讨论】:

      【解决方案2】:

      注入一个存根或模拟memory_converter,其convert() 方法抛出OutOfMemryError

      我突然想到,我可以制作 BufferedImage 的假子类,它在第一次调用内存转换器调用的方法时抛出 OutOfMemoryError,但随后在后续调用中表现正常。不过,这似乎是一种 hack。

      模拟框架通常非常强大,应该让您指定这种行为。例如,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。

      【讨论】:

        【解决方案3】:

        我突然想到我可以 制作 BufferedImage 的假子类 抛出 OutOfMemoryError 的 第一次调用的方法 内存转换器被调用,但是 然后在随后的表现正常 来电。不过,这似乎是一种 hack。

        你在这里走的是正确的道路。模拟对象正是这些类型的东西的有益之处。您并不真正关心 OutOfMemory 错误是否合法,您只想确保它被抛出/捕获并执行其他路径。模拟出来,你会很高兴的。

        【讨论】:

          【解决方案4】:

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

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

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

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

          【讨论】:

          • 检查空闲堆的数量我看到的问题是发现它太少并不能保证分配会失败——尝试分配可能会导致垃圾收集器释放足够的堆让它成功。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-12-12
          • 2015-12-24
          • 2011-07-06
          • 1970-01-01
          • 2011-07-10
          相关资源
          最近更新 更多