views:

82

answers:

1

I'm working on a project at the moment where I need to inter-operate with code that swallows exceptions. In particular, I'm writing NUnit unit tests. There are some places where I want to embed assertions within code that gets passed as a delegate, as part of mocking a particular behavior. The problem I'm having is that the AssertionException gets swallowed by the code calling the delegate, which means the test passes, even though the test Assert failed.

Is there any way to inform NUnit that a test should fail that can't be circumvented by catching AssertionException? I can't modify the code that swallows the exceptions, as I don't have full ownership and it's already in semi-production use. I'm hoping there's a clean way to accomplish this.

The best I've come up with is something like this:

    private static string _assertionFailure;
    public static void AssertWrapper(Action action)
    {
        try
        {
            action();
        }
        catch (AssertionException ex)
        {
            _assertionFailure = ex.Message;
            throw;
        }
    }

    [Test]
    [ExpectedException(typeof(AssertionException))]
    public void TestDefeatSwallowing()
    {
        Action failure = () => AssertWrapper(() => Assert.Fail("This is a failure"));

        EvilSwallowingMethod(failure);

        if (_assertionFailure != null)
            Assert.Fail(_assertionFailure);
    }

    private void EvilSwallowingMethod(Action action)
    {
        try
        {
            action();
        }
        catch
        {
        }
    }

It works, but it's pretty ugly. I have to wrap every Assert call and I have to check at the end of every test if an assertion was swallowed.

+2  A: 

So you're doing something like this? (this is using Moq syntax)

var dependency1 = new Mock<IDependency1>();
dependency1.Setup(d => d.CalledMethod([Args])
    .Callback(TestOutArgsAndPossiblyThrow);

var objectUnderTest = new TestedObject(dependency1.Object);
objectUnderTest.MethodThatCallsIDependency1dotCalledMethod();

And you've got TestOutArgsAndPossiblyThrow encapsulated in your AssertWrapper class?

Unless that's way off, I'd say you're doing it just about right. You have execution re-entering your test at a point where you can record the state of the call to the dependency. Whether that's done via catching exceptions and analyzing them or just directly inspecting the values of the method parameters, you've just gotta do the work. And if you're swallowing exceptions inside the black box, you're going to have to monitor them before they get back into the black box.

I still say you'd be much better off with appropriate logging and notification (you don't have to notify the end users, necessarily). To @TrueWill's point - what do you do when there's an IOException or the database isn't available?

DISCUSSION EDIT

Is your scenario structured like this?

TEST -> TESTED CODE -> SWALLOWING CODE -> THROWING MOCK
arootbeer
The above is basically what I'm doing, yes. The production code does have logging for (most) of the catch locations, but it is still preventing exceptions from propagating. The swallowing is occurring in code that I depend on, but which is central to implementing the logic of the code I've written and am testing, so it shouldn't be mocked. I suppose I could create a copy of the class that doesn't swallow exceptions and use that copy only for my code, but that creates other political and maintenance problems.
Dan Bryant