Testing for Expected Exceptions Without Compromising BDD Conventions

Home/.Net, Unit Testing/Testing for Expected Exceptions Without Compromising BDD Conventions

Today I decided to relearn some of the BDD concepts I picked up at the end of last year and ran into a scenario where I needed to test that a specific type of exception was being thrown by a method. The simple way to do this is to decorate your test method with an ExpectedException attribute, but that forces you to combine the Act/Assert parts of your test.

Not happy with that solution I decided that I would rather catch the exception in one part of my test and validate it’s type later. In the end, I created a helper class to do some of the work:

public class ExceptionTestHelper
{
    public static Exception CatchException(Action action)
    {
        try
        {
            action.Invoke();
        }
        catch (Exception ex)
        {
            return ex;
        }

        return null;
    }
}

Pretty simple. And now our tests seem a little more natural.

[TestFixture]
public class When_asked_to_get_a_users_goals_using_an_invalid_user_id 
    : GoalsServiceTestBase
{
    private Exception caughtException;

    protected override void because()
    {
        base.because();
        caughtException = 
            ExceptionTestHelper.CatchException(
                () => goalsService.GetGoalsForUser(-1));
    }

    [Test]
    public void should_throw_an_argument_exception()
    {
        Assert.That(caughtException, 
            Is.InstanceOfType(typeof(ArgumentException)));
    }
 }

 

public abstract class GoalsServiceTestBase : TestBase

{
    protected IGoalsRepository stubGoalsRepository;
    protected IGoalsService goalsService;
    protected Goal stubGoal;

    protected override void  establish_context()
    {
        base.establish_context();
        stubGoalsRepository = 
            MockRepository.GenerateStub<IGoalsRepository>();
        goalsService = new GoalsService(stubGoalsRepository);
        stubGoal = new Goal();
    }
}
[TestFixture]
public abstract class TestBase
{
    [SetUp]
    public void setup()
    {
        establish_context();
        because();
    }

    protected virtual void establish_context()
    { }

    protected virtual void because()
    { }
}

At first glance I like it. Although I’m sure that someone out there that may have a better solution that still sticks with our BDD approach.

DotNetKicks Image
Tags: , , , |

Share This Story, Choose Your Platform!

About the Author:

Freelance software developer in the Cleveland area.

Leave A Comment

Toggle Sliding Bar Area