如何对IDisposable进行单元测试?

10

我正在编写一个与IDisposable相关的库代码部分。通过using的托管路径易于测试。但是我在想最终器:调用System.GC.Collect()是否足以强制运行终结器?


如果您遵循IDisposable的规定模式,我相信单元测试会非常有用。 - Mitch Wheat
抱歉,我不确定单元测试是否有那么大的用处... - Mitch Wheat
@Mitch:正确实现IDisposable,以便在适当的时刻处理托管和非托管资源并不是一件简单的事情。由于涉及的库代码正是负责这一点的,我认为没有测试的必要... - David Schmitt
https://dev59.com/CXE85IYBdhLWcg3wMQlm#17014062 - constructor
4个回答

8
不,GC.Collect()调用是异步的,你还需要调用以下代码:
System.GC.WaitForPendingFinalizers();

1
我认为GC.Collect()本身是同步的(即它将在返回时释放任何可用的内存),但最终器本身是单独运行的。不过我可能完全错了... - Jon Skeet
我现在正在做这两件事,测试每次都通过。也就是说,从终结器调用了正确的扩展点。 - David Schmitt
注意事项:还要检查一下所讨论的类的初始化代码是否会将对象“根”在某个地方。 - David Schmitt
@EricBurcham:我使用它的一个示例在这里:https://github.com/daszat/zetbox/blob/master/Tests/DisposableMockTemplate.cs - David Schmitt
这对我没用。我调用了 GC.Collect() 然后是 GC.WaitForPendingFinalizers();,但在任何时候 disposing 都不会是 false - Matthew

2

我建议你参考《Dispose,Finalization和资源管理》,这是我所知道的有关此主题的最佳参考。使用他们的模式:

~ComplexCleanupBase()
{
    Dispose(false);
}

public void Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}

protected override void Dispose(bool disposing)
{
   if (!disposed)
   {
        if (disposing)
        {
            // dispose-only, i.e. non-finalizable logic
        }

        // new shared cleanup logic
        disposed = true;
    }

    base.Dispose(disposing);
}

你最终会得到非常简单的Finalizer/Dispose()方法和可测试的Dispose(bool)。不需要使用GC类强制进行终结或其他任何操作。

是的,我正在以这种方式进行。这只是对MSDN推荐的轻微改编。 - David Schmitt

0
你能模拟一个 IDisposable 接口并期望调用 Dispose 吗?这至少可以让你看到对象何时被处理。

设置断点就足以发现这一点。我正在测试Dispose()的实现,而不是它是否被调用。 - David Schmitt

0

我认为我会倾向于使Finalize()调用另一个方法,并测试该方法是否符合您的要求。您不会获得100%的代码覆盖率,但至少您会知道该方法是否正确释放了对象的资源。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接