2

我的班级中有全局静态注册表,在某些情况下会注册实例。实际上它并不依赖于垃圾收集,但一些功能显然是放在finalize().

在 jUnit 测试期间,我希望测试此功能是如何工作的,但我无法强制调用 GC。我打电话给gc()tearDown()

@After
public void tearDown() throws Exception {

    log.debug("tearDown()");

    a = null;
    b = null;
    c = null;
    d = null;
    e = null;
    f = null;
    g = null;

    System.gc();

    log.debug("asserting hash size");
    assertEquals(0, Myclass.getRegisterSize());
}

但这无济于事。我在日志中看到断言消息出现在最终确定之前。

是否可以等到所有最终确定发生?

是否有任何其他方法,例如重新启动类加载器或刷新堆或 jUnit 中的某些东西?我的意思是从头开始做所有事情?

4

5 回答 5

2

如果您要覆盖 finalize 为什么不直接调用它。目前finalize受到保护,但您的子类可以将其公开。然后你可以直接调用它并检查那里调用了什么。测试应该是确定性的,因此您希望它每次都运行。依赖垃圾收集器可能会给你的测试带来不一致,因为你不能保证什么/什么时候被调用

于 2012-10-30T20:32:06.710 回答
1

不,不可能等待所有最终确定发生。它们可能根本不会发生。当对象被垃圾回收时,Finalize 会运行。有些对象永远不会被收集,例如 Main 类。这不会收集垃圾,因为 JVM 在运行 gc() 之前就退出了。

最好的想法(真的)是添加一个进行清理的方法,然后从您的 JUnit 测试中调用它。而且,如果你真的,真的需要,也可以从 finalize() 开始。但是你永远不能依赖 finalize() 被调用。

于 2012-10-30T20:28:36.973 回答
0

编写测试的第一条规则是编写可测试的代码。定稿很难测试,除非您可以测试设计一个监控定稿效果的测试。

通常,您可以相信finalize()最终会被调用,因此您可能不需要特别测试此功能,而是测试该方法调用的任何finalize()方法。要么这样,要么扩展您的类以允许测试代码注入一些将由该finalize()方法修改的对象。

要么就是这样,要么finalize()直接从您的测试代码中调用 - 方法。

于 2012-10-30T20:35:01.483 回答
0

看起来您正在尝试测试 JVM 的“最终确定”功能 - 您不应该这样做。可以在这里工作 - 将您要测试的代码移动到一个单独的方法并像往常一样编写一个简单的单元测试。

于 2012-10-30T20:39:48.840 回答
0

从发布的代码中,您将 null 设置为对 junit 测试中对象的引用,而不是在运行断言的类上。所以 MyClass 仍然会引用对象。

于 2012-10-30T20:39:54.223 回答