Is your test method self-validating ?

Posted by mehfuzh on ASP.net Weblogs See other posts from ASP.net Weblogs or by mehfuzh
Published on Sun, 23 May 2010 10:17:14 GMT Indexed on 2010/05/23 10:21 UTC
Read the original article Hit count: 533

Filed under:
|
|
|

Writing state of art unit tests that can validate your every part of the framework is challenging and interesting at the same time, its like becoming a samurai. One of the key concept in this is to keep our test synced all the time as underlying code changes and thus breaking them to the furthest unit as possible.  This also means, we should avoid  multiple conditions embedded in a single test.

Let’s consider the following example of transfer funds.

  1. [Fact]
  2. public void ShouldAssertTranserFunds()
  3. {
  4.     var currencyService = Mock.Create<ICurrencyService>();
  5.     //// current rate
  6.     Mock.Arrange(() => currencyService.GetConversionRate("AUS", "CAD")).Returns(0.88f);
  7.  
  8.     Account to = new Account { Currency = "AUS", Balance = 120 };
  9.     Account from = new Account { Currency = "CAD" };
  10.  
  11.     AccountService accService = new AccountService(currencyService);
  12.  
  13.     Assert.Throws<InvalidOperationException>(() => accService.TranferFunds(to, from, 200f));
  14.  
  15.     accService.TranferFunds(to, from, 100f);
  16.  
  17.     Assert.Equal(from.Balance, 88);
  18.     Assert.Equal(20, to.Balance);
  19. }

At first look,  it seems ok but as you look more closely , it is actually doing two tasks in one test. At line# 10 it is trying to validate the exception for invalid fund transfer and finally it is asserting if the currency conversion is successfully made.

Here, the name of the test itself is pretty vague. The first rule for writing unit test should always reflect to inner working of the target code, where just by looking at their names it is self explanatory. Having a obscure name for a test method not only increase the chances of cluttering the test code, but it also gives the opportunity to add multiple paths into it and eventually makes things messy as possible.

I would rater have two test methods that explicitly describes its intent and are more self-validating.

ShouldThrowExceptionForInvalidTransferOperation
ShouldAssertTransferForExpectedConversionRate

Having, this type of breakdown also helps us pin-point reported bugs easily rather wasting any time on debugging for something more general and can minimize confusion among team members. Finally, we should always make our test F.I.R.S.T ( Fast.Independent.Repeatable.Self-validating.Timely) [ Bob martin – Clean Code]. Only this will be enough to ensure, our test is as simple and clean as possible.

 

Hope that helps

© ASP.net Weblogs or respective owner

Related posts about c#

Related posts about Unit Test