NUnit在Finalizer中不会因异常而失败 [英] NUnit does not fail on exception in Finalizer

查看:66
本文介绍了NUnit在Finalizer中不会因异常而失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我们的框架中,有些关键对象具有文件句柄或WCF客户端连接.这些对象是 IDiposable ,并且我们具有验证码(抛出异常)以确保在不再需要它们时可以正确地处理它们.(仅调试,这样我们就不会在发布时崩溃).并不一定要在关机时进行.

In our framework, there is some key objects which have file handles or WCF client connections. Those objects are IDiposable and we have validation code (with exceptions being thrown) to ensure that they are getting properly disposed when not needed anymore. (Debug-only so that we don't want to crash on release). This is not necessarily on shutdown.

最重要的是,我们有运行我们的代码的单元测试,因此,如果我们忘记了此类处置,我们希望它们会失败.

On top of this, we have unit tests which run our code and we thus expect them to fail if we forget such disposals.

问题是:在.NET 4.5.1上,当 Finalizer中出现此类异常时,使用NUnit(2.6.3.13283)运行程序(或使用ReSharper或TeamCity)不会触发测试失败.被抛出.

Problem is: On .NET 4.5.1, with NUnit (2.6.3.13283) runner (or with ReSharper, or TeamCity) does not trigger test failure when such exception in the Finalizer are thrown.

奇怪的事情是:使用 NCrunch (也通过NUnit进行),单元测试 DO 失败!(对我而言,至少在本地,我可以找到这样的遗失物品)

Weird thing is: Using NCrunch (with is over NUnit also), unit tests DO fail! (Which locally for me, at least I can find such missing disposals)

那很糟糕,因为我们的构建机器(TeamCity)看不到此类故障,我们认为一切都很好!但是(调试时)运行我们的软件确实会崩溃,表明我们忘记了处理方法

That's pretty bad, since our build machine (TeamCity) does not see such failures and we think that everything is good! But running our software (in debug) will indeed crash, showing that we forgot a disposal

这是一个显示NUnit不会失败的示例

Here's an example that shows that NUnit does not fail

public class ExceptionInFinalizerObject
{
    ~ExceptionInFinalizerObject()
    {
        //Tried here both "Assert.Fail" and throwing an exception to be sure
        Assert.Fail();
        throw new Exception();
    }
}

[TestFixture]
public class FinalizerTestFixture
{
    [Test]
    public void FinalizerTest()
    {
        CreateFinalizerObject();

        GC.Collect();
        GC.WaitForPendingFinalizers();
    }

    public void CreateFinalizerObject()
    {
        //Create the object in another function to put it out of scope and make it available for garbage collection
        new ExceptionInFinalizerObject();
    }
}

在NUnit运行器中运行它:一切都是绿色.要求ReSharper调试此测试确实会进入Finalizer.

Running this in the NUnit runner: everything is green. Asking ReSharper to debug this test will indeed step into the Finalizer.

推荐答案

因此,在Eric Lippert的帮助下,我发现Ncode不在另一个线程上时,NUnit不会捕获 Exception .因此,终结器线程也会发生同样的情况.

So with the help of Eric Lippert, I found out that Exceptions are not caught by NUnit when they are on another thread. So the same happens to the finalizer thread.

我尝试在NUnit的设置中找到解决方案,但无济于事.

I tried finding a solution in the settings of NUnit, but to no avail.

所以我想出了所有我的 TestFixture 的子类,因此我所有的人都有一个通用的 [SetUp] [TearDown] 测试:

So I came up with subclassing all my TestFixture, so that there is a common [SetUp] and [TearDown] to all my tests:

public class BaseTestFixture
{
    private UnhandledExceptionEventHandler _unhandledExceptionHandler;
    private bool _exceptionWasThrown;

    [SetUp]
    public void UnhandledExceptionRegistering()
    {
        _exceptionWasThrown = false;
        _unhandledExceptionHandler = (s, e) =>
        {
            _exceptionWasThrown = true;
        };

        AppDomain.CurrentDomain.UnhandledException += _unhandledExceptionHandler;
    }

    [TearDown]
    public void VerifyUnhandledExceptionOnFinalizers()
    {
        GC.Collect();
        GC.WaitForPendingFinalizers();

        Assert.IsFalse(_exceptionWasThrown);

        AppDomain.CurrentDomain.UnhandledException -= _unhandledExceptionHandler;
    }
}

很显然,使用此代码,我只能知道引发了异常,但我不知道是哪个异常.但是,对于我来说,这已经足够了.如果以后更改它,我将尝试更新它(或者,如果有人有更好的解决方案,我很乐意将其设置为解决方案!)

Obviously, with this code I can only know that an exception was thrown, but I don't know which one. However, for my usage, it is sufficient. If I change it later, I'll try and update this one (or if someone has a better solution, I'm glad to set as a solution!)

我有两个场景需要介绍,所以在这里包括它们:

I had two scenarios I needed to cover, so I include them here:

[TestFixture]
public class ThreadExceptionTestFixture : BaseTestFixture
{
    [Test, Ignore("Testing-Testing test: Enable this test to validate that exception in threads are properly caught")]
    public void ThreadExceptionTest()
    {
        var crashingThread = new Thread(CrashInAThread);
        crashingThread.Start();
        crashingThread.Join(500);
    }

    private static void CrashInAThread()
    {
        throw new Exception();
    }

    [Test, Ignore("Testing-Testing test: Enable this test to validate that exceptions in Finalizers are properly caught")]
    public void FinalizerTest()
    {
        CreateFinalizerObject();

        GC.Collect();
        GC.WaitForPendingFinalizers();
    }

    public void CreateFinalizerObject()
    {
        //Create the object in another function to put it out of scope and make it available for garbage collection
        new ExceptionInFinalizerObject();
    }
}

public class ExceptionInFinalizerObject
{
    ~ExceptionInFinalizerObject()
    {
        throw new Exception();
    }
}

至于为什么NCrunch可以正确执行,这是一个很好的问题...

As for why NCrunch does it properly, that's a good question...

这篇关于NUnit在Finalizer中不会因异常而失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆