NUnit在Finalizer中出现异常时不会失败。

11 浏览
0 Comments

NUnit在Finalizer中出现异常时不会失败。

在我们的框架中,有一些关键对象拥有文件句柄或WCF客户端连接。这些对象实现了IDisposable接口,并且我们有验证代码(使用异常抛出)来确保在不再需要时正确地进行了处理(仅在Debug模式下,以避免在发布时崩溃)。这并不一定发生在程序关闭时。\n除此之外,我们还有单元测试来运行我们的代码,并且我们期望如果我们忘记进行这种处理,测试会失败。\n问题在于:在.NET 4.5.1中,使用NUnit(2.6.3.13283)运行器(或使用ReSharper或TeamCity)时,如果在Finalizer中抛出异常,测试不会失败。\n奇怪的是:使用NCrunch(也是基于NUnit的)运行单元测试会导致测试失败!(至少在本地,我能找到这样的缺失处理)\n这非常糟糕,因为我们的构建机器(TeamCity)无法看到这样的失败,我们以为一切都好!但是在调试模式下运行我们的软件将会崩溃,显示我们忘记了进行处理。\n下面是一个示例,展示了NUnit不会失败的情况:\npublic class ExceptionInFinalizerObject\n{\n ~ExceptionInFinalizerObject()\n {\n //在这里尝试使用\"Assert.Fail\"和抛出异常来确保\n Assert.Fail();\n throw new Exception();\n }\n}\n[TestFixture]\npublic class FinalizerTestFixture\n{\n [Test]\n public void FinalizerTest()\n {\n CreateFinalizerObject();\n GC.Collect();\n GC.WaitForPendingFinalizers();\n }\n public void CreateFinalizerObject()\n {\n //在另一个函数中创建对象,使其超出范围,并使其可以进行垃圾回收\n new ExceptionInFinalizerObject();\n }\n}\n在NUnit运行器中运行此代码,一切都是绿色的。\n要求ReSharper调试此测试将确实进入Finalizer方法。

0
0 Comments

NUnit does not fail on exception in Finalizer这个问题的出现的原因是在NUnit中,当在Finalizer中出现异常时,NUnit并不会将其视为测试失败。这可能导致开发人员在测试过程中没有意识到Finalizer中的异常,从而导致问题难以发现和解决。

解决这个问题的方法是,在Finalizer中捕获异常,并将其记录下来或进行适当的处理。这样可以确保在测试过程中,如果Finalizer中出现异常,NUnit会将其视为测试失败,从而提醒开发人员注意并解决问题。

下面是一个示例代码,展示了如何在Finalizer中捕获异常并将其记录下来:

public class MyClass
{
    ~MyClass()
    {
        try
        {
            // Finalizer code here
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception in Finalizer: " + ex.Message);
            throw;
        }
    }
}
[Test]
public void TestFinalizer()
{
    // Test code here
    MyClass obj = new MyClass();
    obj = null;
    // Force garbage collection
    GC.Collect();
    GC.WaitForPendingFinalizers();
    // Assertion to check if Finalizer ran without exception
    Assert.IsFalse(FinalizerExceptionOccurred);
}

在上面的代码中,通过在Finalizer中使用try-catch块来捕获异常,并在捕获到异常时将其记录下来。然后,在测试方法中,可以添加断言来检查是否出现了Finalizer中的异常。

通过这种方式,可以确保在NUnit中,如果Finalizer中出现异常,NUnit会将其视为测试失败,并提供相应的错误信息,从而帮助开发人员及时发现和解决问题。

总之,NUnit does not fail on exception in Finalizer这个问题的解决方法是在Finalizer中捕获异常,并在测试方法中添加断言来检查是否出现了Finalizer中的异常。这样可以确保在测试过程中,如果Finalizer中出现异常,NUnit会将其视为测试失败,从而提醒开发人员注意并解决问题。

0
0 Comments

NUnit does not fail on exception in Finalizer的问题是由于在早期的.Net版本中,对于Finalizer中的异常会被忽略,而在较新的版本中,CLR会以致命错误退出。所以,我们需要了解这些信息,并且需要知道我正在使用的.Net版本(4.5.1)是否会受到影响。

解决这个问题的方法是在Finalizer中捕获异常并进行处理,以避免引起CLR的致命错误。下面是一个例子,展示了如何在Finalizer中捕获异常:

class MyClass
{
    ~MyClass()
    {
        try
        {
            // 在这里进行资源清理操作
        }
        catch(Exception ex)
        {
            // 处理异常,可以将异常信息记录下来或者进行其他操作
        }
    }
}

通过在Finalizer中捕获异常并进行处理,我们可以避免NUnit在异常发生时失败,并且可以确保程序的正常退出。

,NUnit在Finalizer中的异常不会导致测试失败的原因是因为在早期的.Net版本中,对于Finalizer中的异常会被忽略。解决这个问题的方法是在Finalizer中捕获异常并进行处理,以避免引起CLR的致命错误。

0
0 Comments

NUnit在Finalizer中发生异常时不会发生失败的问题。为了解决这个问题,可以通过为所有的TestFixture创建一个基类来实现。在基类中,通过注册一个UnhandledExceptionEventHandler来捕获所有未处理的异常,并在TearDown方法中验证是否有异常被抛出。下面是一个示例的基类代码:

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;
    }
}

通过使用这段代码,我们可以得知是否有异常抛出,但是无法知道具体是哪个异常。对于我们的需求来说,这已经足够了。如果以后需要修改,可以更新这段代码,或者如果有更好的解决方案,也可以将其作为解决方案。

以上是解决NUnit在Finalizer中异常不会失败的问题的方法。接下来是两个需要覆盖的测试场景的示例:

[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可以正确处理这个问题,这是一个好问题...其实,你可以将异常本身存储起来以便后续报告,而不是使用一个布尔标志(_exceptionWasThrown)。

0