期望测试中出现异常,但无论如何都想验证调用了 dispose

发布于 2024-08-09 00:18:30 字数 1310 浏览 3 评论 0原文

我正在对一个演示应用程序进行单元测试,它是一个 POP3 客户端。 POP3 客户端实现了IDisposable,因此我尝试测试using 循环。

(我使用的是 nunit 2.5.2 和 Moq 4.0)

/// <summary>
/// Unsuccessful construct dispose cycle, no ILogger object given. 
/// Expecting ArgumentNullException. Expecting TcpClient dispose to be called.
/// </summary>
[Test]
[ExpectedException(typeof(ArgumentNullException))]
public void ConstructorDispose_LoggerNull_ArgumentNullException()
{
    mockTcpClient.Setup(x => x.Dispose());
    using (var popClient = new PopClient(null, mockTcpClient.Object))
    {

    }
    mockTcpClient.VerifyAll();
}

正如您所看到的,verifyAll 方法永远不会被调用,但是测试将会成功。那么...

  • 解决这个问题的最佳方法是什么?
  • 还有其他方法尝试捕获吗?

更新我暂时这样修复了它:

        mockTcpClient.Setup(x => x.Dispose());
        var correctExceptionThrown = false;
        try
        {
            using (var popClient = new PopClient(null, mockTcpClient.Object))
            {

            }
        }
        catch (ArgumentNullException)
        {
            correctExceptionThrown = true;
        }
        finally
        {
            mockTcpClient.VerifyAll();
        }
        Assert.That(correctExceptionThrown);

但是没有调用 dispose,似乎是 C# 规范。

I'm unit testing a demo application, which is a POP3 client. The POP3 client implements IDisposable, so I'm trying to test a using cycle.

(I'm using nunit 2.5.2 and Moq 4.0)

/// <summary>
/// Unsuccessful construct dispose cycle, no ILogger object given. 
/// Expecting ArgumentNullException. Expecting TcpClient dispose to be called.
/// </summary>
[Test]
[ExpectedException(typeof(ArgumentNullException))]
public void ConstructorDispose_LoggerNull_ArgumentNullException()
{
    mockTcpClient.Setup(x => x.Dispose());
    using (var popClient = new PopClient(null, mockTcpClient.Object))
    {

    }
    mockTcpClient.VerifyAll();
}

As you can see the verifyAll method will never be invoked and the test will be successful, nonetheless. So ...

  • What is the best way to solve this?
  • Is there another way then try catch?

Update I fixed it like this for the moment:

        mockTcpClient.Setup(x => x.Dispose());
        var correctExceptionThrown = false;
        try
        {
            using (var popClient = new PopClient(null, mockTcpClient.Object))
            {

            }
        }
        catch (ArgumentNullException)
        {
            correctExceptionThrown = true;
        }
        finally
        {
            mockTcpClient.VerifyAll();
        }
        Assert.That(correctExceptionThrown);

But dispose isn't called, seems to be the C# specification.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

心是晴朗的。 2024-08-16 00:18:30
mockTcpClient.Setup(x => x.Dispose());

try 
{
    using (var popClient = new PopClient(null, mockTcpClient.Object))
    {

    }
}
finally 
{
    mockTcpClient.VerifyAll();
}
mockTcpClient.Setup(x => x.Dispose());

try 
{
    using (var popClient = new PopClient(null, mockTcpClient.Object))
    {

    }
}
finally 
{
    mockTcpClient.VerifyAll();
}
梦冥 2024-08-16 00:18:30

这并不能回答您的问题(因为它已经解决了),但它是相关的并且无论如何都值得发布。

[ExpectedException] 是一种非常可靠的测试异常的方法。它可能容易出错,因为错误的行可能会触发预期类型的​​异常,从而导致错误的传递。我强烈建议您改为查看 Assert.Throws() :)

它更好用(您可以查询返回的异常),更具可读性,最重要的是,更安全。

您可以在此处找到示例

This doesn't answer your question (as it's already solved), but it's relevant and worth posting anyway.

[ExpectedException] is a pretty ropey way to test exceptions. It can be error prone, as the wrong line can trigger an exception of the expected type resulting in an erroneous pass. I would strongly advocate that you check out Assert.Throws() instead :)

It's nicer to use (you can query the returned exception), more readable and, above all, safer.

You can find an example here

扎心 2024-08-16 00:18:30

您已经发现,如果构造函数失败,确实应该调用 dispose。但在其他情况下,您可能希望在引发预期异常后验证您的模拟。我只是在测试 TearDown 中这样做:

[SetUp]
public void SetUp()
{
   this.mockFactory = new MockFactory(MockBehavior.Loose);
}

[TearDown]
public void TearDown()
{
   this.mockFactory.VerifyAll();
}


[Test]
[ExpectedException(typeof(NoBananasException))]
public void EatThrowsIfNoBananasAvailable
{
   var bananaProvider = this.mockFactory.Create<IBananaProvider>();
   bananaProvider.SetUp(bp => bp.IsBananaAvailable).Returns(false).Verifiable();

   var monkey = new Monkey(bananaProvider.Object);
   monkey.Eat();
}

You have already discovered that dispose really is not supposed to be called if the constructor fails. But there may still be other cases where you might want to to verify your mocks after an expected exception is thrown. I just do that in the test TearDown like this:

[SetUp]
public void SetUp()
{
   this.mockFactory = new MockFactory(MockBehavior.Loose);
}

[TearDown]
public void TearDown()
{
   this.mockFactory.VerifyAll();
}


[Test]
[ExpectedException(typeof(NoBananasException))]
public void EatThrowsIfNoBananasAvailable
{
   var bananaProvider = this.mockFactory.Create<IBananaProvider>();
   bananaProvider.SetUp(bp => bp.IsBananaAvailable).Returns(false).Verifiable();

   var monkey = new Monkey(bananaProvider.Object);
   monkey.Eat();
}
站稳脚跟 2024-08-16 00:18:30

您似乎正在测试即使构造函数抛出异常,注入的mockTcpClient实例也会被释放,在这种情况下这应该有效:

mockTcpClient.Setup(x => x.Dispose());
try
{
    var popClient= new PopClient(null, mockTcpClient.Object);
}
finally
{
    mockTcpClient.VerifyAll();
}

编辑:实际上,try/finally会比捕获异常更干净。请注意,您不需要处置 popClient,因为没有创建实例。

You seem to be testing that the injected mockTcpClient instance is disposed even if the constructor throws an exception, in which case this should work:

mockTcpClient.Setup(x => x.Dispose());
try
{
    var popClient= new PopClient(null, mockTcpClient.Object);
}
finally
{
    mockTcpClient.VerifyAll();
}

EDIT: Actually, try/finally would be cleaner than catching Exception. Note that you don't need to dispose popClient since no instance is created.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文