One step past Assert.Throws<>


If you’re not using xUnit (and you should be), at least consider adopting the practices they have for dealing with exceptions in unit tests. From the very first release, they moved us from this:

[ExpectedException(typeof(InvalidOperationException))]
public void WithdrawingMoreThanBalanceThrows()
{
    Account account = new Account();
    account.Deposit(100);

    account.Widthraw(200);
}

to the far-better:


public void WithdrawingMoreThanBalanceThrows()
{
    Account account = new Account();
    account.Deposit(100);

    Assert.Throws<InvalidOperationException>(delegate
                                             {
                                                 account.Widthraw(200); 
                                             });

}


But we’re still not following the 3 As pattern. Recently (not sure exactly when) they took us one step further to this (in 3.5 syntax):


public void WithdrawingMoreThanBalanceThrows()
{
    Account account = new Account();
    account.Deposit(100);

    Exception ex = Record.Exception(() => account.Widthraw(200));

    ex.ShouldBeType<InvalidOperationException>();

}


and now we are exactly where we should be 🙂


(I was just told that () => is called the ‘crotch operator’ today. Can’t wait to use that in a code review.)

Comments (2)
  1. Keith Farmer says:

    I prefer the first.  It captures, visually, the scope of the exceptional case.  Further, if the case is progressive — I verify that I receive an exception and move on to other things — then the first approach makes this clearer.

    Especially if a test fails, in which case you’ll enter the debugger at the failing case, rather than at the assertion for that case.  When a test fails, I want to be pointed as close as possible to the part that failed, in which case keeping all the actions ahead of all the assertions is precisely what you don’t want.

    Now, what the second could give you is some flexibility in being able to define assertion extensions on type: Assert.SomeTest(this Type, args), but I’d probably want, instead:

    Assert.Exception(action)

    .IsType<T>()

    .HasMessage(Errors.FooError(args)); // important!  How do you know you got the right one, and how do you know it’s been localized?

    .. But I can get that with

    Assert.ExpectedException(Exception, Action, Comparer<Exception>)

  2. Stephen says:

    Crotch operator… AHHHH I See it now 🙂

Comments are closed.

Skip to main content