JJoos
JJoos

Reputation: 587

Expecting an exception in a test but wanting to verify dispose is called anyway

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 ...

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.

Upvotes: 2

Views: 3569

Answers (4)

Wim Coenen
Wim Coenen

Reputation: 66733

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

Upvotes: 2

Mark Simpson
Mark Simpson

Reputation: 23365

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

Upvotes: 2

Lee
Lee

Reputation: 144136

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.

Upvotes: 1

Nat
Nat

Reputation: 9951

mockTcpClient.Setup(x => x.Dispose());

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

    }
}
finally 
{
    mockTcpClient.VerifyAll();
}

Upvotes: 4

Related Questions