我最近在接受采访时被问到如何编写一个junit单元测试用例来测试“OutOfMemoryError”,并且我编写了以下代码: -
public class OutOfMemoryError {
public static void main(String[] args) {
new OutOfMemoryError().throwError();
}
public void throwError() {
List<String> list = new ArrayList<>();
for (int i = 0;; i++)
list.add("1");
}
}
Junit测试案例:
public class ExceptionTest {
private OutOfMemoryError outOfMemoryError;
@Before
public void init() {
outOfMemoryError = new OutOfMemoryError();
}
@After
public void tearDown() {
outOfMemoryError = null;
}
@Test(expected = Error.class)
public void testError() {
outOfMemoryError.throwError();
}
}
面试官告诉我,Junit测试用例不正确。任何人都可以告诉我正确的写作方式吗?
答案 0 :(得分:0)
JUnit可能无法正确处理由OutOfMemoryErrror引起的测试失败,因为JUnit本身需要(很少但不是没有)堆内存来处理失败。
不幸的是,在Throwable处理程序启动之前,JUnit不会释放对被测对象的引用(仍然在Statement
对象中引用),所以即使垃圾收集也无法帮助。查看发生这种情况的ParentRunner.runLeaf来源:
} catch (Throwable e) {
eachNotifier.addFailure(e);
然后
notifier.fireTestFailure(new Failure(description, targetException));
如果没有剩余堆内存,Failure::new
将抛出另一个错误,阻止正确的测试失败处理。
回到访谈:面试官可能希望听到由于JUnit框架没有被设计为使用直接方法而不能(可靠地)使用JUnit测试OutOfMemoryErrors如上所述,这样做。面试可能也希望看到像
这样的解决方法@Test(expected = Error.class)
public void testError() {
byte[] memoryRequiredByJUnitHandler = new byte[100_000];
try {
outOfMemoryError.throwError();
} catch (Throwable t) {
// free enough heap memory so JUnit can handle exception
memoryRequiredByJUnitHandler = null;
throw t;
}
}
有关更多背景信息,您可能还需要查看this answer to "When to catch java.lang.Error?"。