@ayende You ought to try Mercurial. in reply to ayende 2 weeks ago
11
May

Reinventing the wheel, badly

A few years ago, I inherited a VB.NET application in which every method (many of which were four hundred lines long, copied and pasted all over the place, and peppered with vague sounding variable names such as blnRunIf and blnRunElse) contained this boilerplate code:

Sub MyMethod()
    Try
        '
        ' ** snip ** '
        '
    Catch ex As Exception
        Throw New Exception ("MyClass.MyMethod::" + ex.Message)
    End Try
End Sub

Those who do not understand Exception.StackTrace are doomed to reinvent it, badly.

04
May

Handling exceptions in assembly-level setup methods in MbUnit

MbUnit allows you to run assembly-level setup and teardown methods as part of your unit tests using the AssemblyCleanUpAttribute:

[assembly: AssemblyCleanUp(typeof(AssemblyCleaner))]
public class AssemblyCleaner
{
    [SetUp]
    public static void SetUp()
    {
        // blah
    }
    [TearDown]
    public static void TearDown()
    {
        // blah
    }
}

This is very useful if you want to do something like restore your database to a known configuration, perhaps incorporating all your change scripts into your unit tests. Unfortunately, there is a little gotcha. If your SetUp() method throws an exception, none of your unit tests will run, but MbUnit will still report success.

For what it’s worth, I think this is a bug, not a feature, but there is a way round it. Capture any exception, and create a unit test that re-throws it:

[assembly: AssemblyCleanUp(typeof(AssemblyCleaner))]

public class AssemblyCleaner
{
    private static Exception setupException = null;

    [SetUp]
    public static void SetUp()
    {
        try {
            // blah
        }
        catch (Exception ex) {
            setupException = ex;
        }
    }

    [TearDown]
    public static void TearDown()
    {
        // blah
    }

    internal static void RethrowSetupException()
    {
        if (setupException != null) {
            // Wrap the original exception to preserve its stack trace
            throw new InvalidOperationException(
                "An error occurred when setting up the tests",
                setupException);
        }
    }
}

// You need to have your unit tests in a separate class.
// MbUnit doesn't like you including test fixtures
// in your assembly cleanup class.

[TestFixture]
public class AssemblyCleanerTest
{
    [Test]
    public void ReportSetupException()
    {
        AssemblyCleaner.RethrowSetupException()
    }
}
23
Apr

The two golden rules of exception handling

The standard instruction that tends to get bandied about on when to throw exceptions is probably the most useless piece of non-advice that I have ever come across.

“You should only throw exceptions in conditions that are exceptional.”

What on earth is that supposed to mean? It’s like saying “You should only eat food that is edible.” And that doesn’t tell you, for instance, that Agaricus bisporus is edible but Amanita phalloides isn’t.

However, there are actually two very simple guidelines that tell you, in terms that are much easier to understand, exactly when to throw an exception and when to catch one. They are:

1. Throw an exception when your method can’t do what its name says it does.

Scott Hanselman blogged about this a while ago and it is probably the best piece of advice I’ve read on the subject:

If your method is called “Save” and it can’t Save, then throw. If it’s called DoSomething and it can’t DoSomething, throw. The idea is that the method name is a verb and a contract. It’s promising to do its best and if it can’t do it, it’s very likely exceptional.

It’s clear, unambiguous, to the point and easy to understand. Each method should do one thing, its name should say what that one thing is, and if it can’t do that one thing, that is when you throw an exception.

2. Don’t catch an exception unless you intend to do something about it.

Now the first rule is about throwing exceptions; it doesn’t say anything about catching them. However, Patrick Cauldwell, whom he links to, has this to say:

Never catch Exception

  • If it’s not a problem you know about, delegate up the call stack, because you don’t know what to do about it anyway

Far too often I see code that catches and silently discards all exceptions. This may give your program a superficial appearance of being more robust, but in actual fact, it is merely masking over a problem that may need to be addressed and dealt with.

Remember that an exception means that something has gone wrong. Unless you know exactly what to do about it to recover from the situation, you should let it propagate up to the top level of your program, where you should log it, and, if appropriate, fire off an e-mail to the developers and/or systems administrator to let them know about it.

There may be times when you need to catch Exception. Transactions may need to be rolled back, resources may need to be disposed, and so on. However, unless you can recover from the situation that caused the exception in the first place, you should re-throw it. And even if you do swallow exceptions for any reason (and you shouldn’t do so unless you have a good reason), you should never do so silently: the very least you should do is record a warning in the application’s event log.