Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I check if any exception has already been thrown?

I'm working on some test automation for a service, and figured out a neat way to roll up some common setup & verification into a 'session' class.

Conceptually, a test case might look like this:

using (var managerSession = new Session(managerRole))
{
    // A manager puts some items in warehouse
}

using (var employeeSession = new Session(employeeRole))
{
    // An employee moves items from warehouse to store
}

using (var customerSession = new Session(customerRole))
{
    // A customer can buy items from the store
}

In the Session object constructor I set up a connection to the service I'm testing with proper authentication per role etc, and in the session Dispose() method I have a common validation block that, for instance, checks that no server-side errors or warnings have been raised during the session lifetime.

Now, of course, this is sort of abusing the IDispose pattern, and if test code inside a using blocks throws an exception AND the validation block also throws an exception the second exception will mask the first.

Conceptually, if we have this scenario:

using (var managerSession = new Session(managerRole))
{
    Assert.IsTrue(managerSession.DoJob(), "Manager did not do his job");
}

...and the assert fails or the call to managerSession.DoJob() throws an exception, then I would like the Session Dispose() method to skip the validation block, i.e.

public void Dispose()
{
    if (NoExceptionThrown())
    {
         Assert.IsFalse(this.serviceConnection.HasErrors(), "Service connection has errors");
    }

    this.serviceConnection.Dispose();
}

...such that the test method never fails with 'Service connection has errors' if it actually fails with 'Manager did not do his job'

My question is: Is it at all possible to implement the 'NoExceptionThrown()' method here? Is there some global property that can be checked, or something hidden in Thread.CurrentThread that could be utilized?

Update:

My question is not how to refactor this :-)

I could of course use this pattern instead:

Session.ForRole(managerRole, (session) => { /* Test code here */ });

With the static method ForRole() defined like

public static void ForRole(Role r, Action<Session> code)
{
    var session = new Session(r);
    try 
    {
        code(session);
        Assert.IsFalse(session.serviceConnection.HasErrors());
    }
    finally 
    {
        session.Dispose();
    }
}

But I am curious whether there exists some way of grabbing the exception state as described above.

like image 216
Christoffer Avatar asked Jul 25 '13 18:07

Christoffer


1 Answers

It would have been helpful if there were an overload of IDisposable.Dispose which took a parameter of type Exception to indicate what exception, if any, was pending in a finally context associated with its cleanup. While a Dispose method generally shouldn't care about the particulars of the exception, conditions may arise during the Dispose method which should be reported to the caller. Any exception thrown from Dispose will replace any exception that had been pending in the caller's finally context, so it would be helpful if a Dispose method could encapsulate a pending exception before replacing it. Unfortunately, no such feature exists and I do not expect any to be added.

While there are some hacks that may be used to achieve something like the desired effect, the only semantically-correct method is for the exception to be a parameter to a Dispose method. The problem with any other approach is that a Dispose may be run from within multiple nested finally blocks, some of which have pending exceptions and some of which don't; code which examines the execution context to determine the status of the most deeply nested finally block may fail if that block isn't the one which guards the lifetime of the object being disposed.

like image 73
supercat Avatar answered Sep 23 '22 08:09

supercat