Unit Testing and TypeMock Part 3

The following post is from The SharePoint Baker and reprinted with permission. Read the first and second posts in this series.
This is the third part in my series of posts about unit testing SharePoint with TypeMock. In the previous posts I shared how I had produced a series of demostration to show how TypeMock could be used to test SharePoint code and that worked really well. It’s one thing writing code and tests for a demo and quite another when its real world code. I thought it was time to try unit testing against some real development and so this is what I’ve been doing for the past few days. I’ve been working on some new bespoke SharePoint functionality for a client and have taken the normal approach to development – I’ve not gone and jumped straight into Test Driven Development or anything similar! Sometime soon I will but this wasn’t the project to try it on! I took the approach of whenever I created a new method I tried to produce a unit test script around it that showed that it worked. I’ve also limited the test scripts to the interaction with SharePoint – e.g. accessing data from lists and users etc. 

How did it go?

One thing I found is that it was great being able to test code without using the browser! Part of the new requirement was to enhance some form validation, so without unit testing this would normally have involved manually testing the form itself – going through the different input combinations and valid and invalid inputs and checking the response – which would have taken some time. What I was able to do with TypeMock was to create those different input options and pass them into my new method. For example, the code read something like this:

   1: var validator = new Validator();
   2: Assert.IsTrue(validator1.IsEmail("test@thesharepointbaker.co.uk");
   3: Assert.IsFalse(validator1.IsEmail(null);
   4: Assert.IsFalse(validator1.IsEmail(string.Empty)
   5: Assert.IsFalse(validator1.IsEmail("abcdef");

These test scripts can easily be run without having to load the page in the browser, enter the input, submit, check the error etc.
Another place where unit testing proved useful was that there was also a second part to the development which redirects a user to a new page based on certain properties stored within a List in SharePoint. Again, the manual approach would require setting up a series of users which the various property options set and then running through each scenario in the browser. This is exactly what our testers did and it took time to setup that data and run through it – time as a developer we don’t always have! Here again is where unit testing came in – through TypeMock I could easily produce a series of unit tests which catered for each of these scenarios. This meant I could test this code without having to keep logging in as a different user with different properties set.
One of the ”downsides” to doing unit tests is that they take time to write and maintain. Somes are quick and easy – like the input validation example – but others can get a little more tricky especially when your code makes use of the SharePoint objects. TypeMock goes along way in helping and as I’m getting more familiar with it the test scripts are getting easier to write! For these two pieces of work (which was about 2 days effort) I probably only spent 2-3 hours writing the test scripts so it’s not a lot of extra time.
The good news is that after producing these tests the only issue the system testing (carried out by our tester) found was a configuration issue which none of the test scripts touched upon.

Deciding what to test?

This was one of the questions that I kept asking during the development and testing – how much and what should be tested? Arguably I should have tested every method that I wrote and if time had allowed I probably would have tried to but realistically it’s not always possible. Another question, what degree of testing is required – how many scenerios should be catered for? Take my example of a new form validation method, what combinations of inputs should you include in your unit tests – nulls, empty strings, too short, too long, valid? What if you’re validating a telephone number, or an email address? The possibilities of what could be tested can grow very quickly so sometimes it’s a question of what needs to be tested rather than what could be. I’m sure if you asked a room full of developers about what should be tested then you get almost as many different answers as there are developers! Since I’ve not been able to spend a great of time writing scripts I’ve tried to focus on areas of code which are critcal (e.g. this method breaks and the whole site falls over) and areas like the validation where testing lots of combinations is a pain.

One of the features of testing frameworks like TypeMock is having the ability to mock objects and there methods without necessarily having to mock the method each time. Take this piece of code:

   1: public double CalcTotalCost(double basketCost, int itemWeight)
   2: {
   3: var totalCost = basketCost + GetDelivery(itemWeight);
   4: return totalCost*GetVAT();
   5: }
   6:  
   7: public static double GetVAT()
   8: {
   9: //Call to SharePoint list to get current value
  10: return VATRate;
  11: }
  12:  
  13: public double GetDelivery(int itemWeight)
  14: {
  15: //Call to SharePoint List to get delivery code for weight
  16: return weightCost;
  17: }

Let’s say we have a shopping basket in SharePoint and we use the CalcTotalCost method to do just that. This method in turn calls GetVAT and GetDelivery which both lookup a value in a SharePoint list. When it comes to writing test scripts we don’t necessarily want to have to test the underlying SharePoint lookup in the GetVAT and GetDelivery with every test. What we can do is setup a test script which does run through the actual code within those methods and make sure it does what its supposed to. However when we come to testing CalcTotalCost we should assume that whatever GetVAT and GetDelivery do they actually do properly. This means we can tell our tests to return certain values when it sees a call to either of those methods, for example:

   1: double productCost = 12.00;
   2: double weight = 2;
   3:  
   4: double fakeVat = 1.20;
   5: double fakeDelivery = 5.00;
   6:  
   7: Isolate.NonPublic.WhenCalled("GetVat").WillReturn(fakeVat);
   8:  
   9: var fakeProduct = Isolate.Fake.Instance<MyProductExample>(Members.ReturnRecursiveFakes);
  10: Isolate.Swap.NextInstance<MyProductExample>().With(fakeProduct);
  11: Isolate.WhenCalled(() => fakeProduct.GetDelivery(fakeWeight)).WillReturn(fakeDelivery);
  12: Isolate.WhenCalled(() => fakeProduct.CalcTotalCost(productCost, fakeWeight)).CallOriginal();
  13:           
  14:  
  15: var expectedCost = (productCost + fakeDelivery) * fakeVat; //20.4
  16:  
  17: var product = new MyProductExample();
  18: Assert.AreEqual(expectedCost, product.CalcTotalCost(productCost, weight));

Notice the different code used to mock GetVat and GetDelivery? If you take a look at the actual code you’ll see that GetVat is declared as a static method, where as GetDelivery isn’t. In real code I wouldn’t use a mix of static and non-static methods for what these methods are trying to achieve but in the context of this example it does illustrate different ways TypeMock lets us mock method calls.
For static methods we can use the Isolate.NonPublic.WhenCalled option to specify our returned value.
For non-static methods one option is to create a fake object and then use WhenCalled on the method we want to control the response from. The different here is that we have to also use WhenCalled on the actual method we’re testing, but we can tell TypeMock to actually use the logic within the method using the .CallOriginal().
Now this isn’t necessarily the best approach for this scenario but it illustrates a couple of options of faking a method. These method can easily be copied with different values added and at no point do we need to worry about what GetVat and GetDelivery are actually doing. This is more inline with unit testing thinking of testing individual units of logic – CalcTotalCost doesn’t care what GetVat or GetDelivery do so neither should the test scripts.

So what’s next?

More tests! Now the ball has started rolling it’s more testing and trying to work out the best way to use unit testing to improve the quality of code! Currently the test scripts I’ve written are being triggered manually – I’m going to start looking at how to incorporate them into our build process with TFS (when we’ve got the Build Server license of TypeMock!). I’ll let you know how I get on.

TOP