Randomise your unit tests – numeric calculations

When unit testing it’s helpful to ensure that the expected value for a unit test should not be hard coded. For numeric calculations, this usually entails creating a random set of inputs, calculating the expected value in a way that is different to how it’ll be implemented, then calling the method under test to get the actual value for comparison. This process has the added advantage of changing the inputs every time it runs, so the chances of false positive/negative are minimal.

When you want some inputs to be exclusive and want to avoid the small chance of random repeating, the following extension method can be used.
 public static IList ExclusiveInts(this Random random, int count)
 {    
        var list = new List();
        Enumerable.Range(1, count).ForEach(x =>
                   {
                        var item = random.Next();
                        while(list.Contains(item))
                        {   item = random.Next();  }
                        list.Add(item);
                  });    
        return list;
 } 
C# Random provides a NextDouble method for a random double. To get random decimal and long values, the following extension methods can be used.
        
 public static decimal NextDecimal(this Random random)
 {
     var scale = (byte)random.Next(29);
     var sign = random.Next(2) == 1;
     return new decimal(random.Next(), random.Next(),
                        random.Next(), sign, scale);
 }
 public static long NextLong(this Random random)
 {
     var buffer = new byte[sizeof(Int64)];
     random.NextBytes(buffer);
     return BitConverter.ToInt64(buffer, 0);
 }

Besides ensuring that the unit test is as strict as possible, this takes care of varying the input values for different tests in the same class, something advisable for easy debugging when tests break. It also takes out the chance that a unit test is passing because of the choice of inputs and expected value.

The developer should also strive work out an alternate way of calculating the expected value as part of the unit test. Besides verifying the test independently, this can be helpful when debugging, changing the unit tests when extending the class under test or when someone is trying to understand what the code/unit test does.

To cater for the inconvenience of not having hard coded values to look up if test breaks, the messages written out in case of failure should be descriptive and include all the relevant inputs.

Another benefit of this process is an automatic warning when a method under test is doing too much – when it becomes cumbersome to calculate the expected value.

Next: Randomise your lists for unit tests.
The completed code for these and other extensions can be found at GitHub.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s