The following post is from The SharePoint Baker and is reprinted with permission.We previously wrote about his first impressions unit testing with SharePoint.
As you may have read in Part 1, I recently started playing with TypeMock Isolator for SharePoint and trying to introduce some unit testing. I’ve discovered a lot over the last week and so I wanted to put together another post picking up from where I left off last time.
In the last post I began showing how TypeMock could be used to create various “fake” SharePoint objects that could use to test against. I was giving the example of a very simple class that would retrieve a list of documents from a document library, along with some of its properties. The test that had setup expected a single document to be returned and that is what it did. The next step I’ve taken is to use the same classes and tests but to extend so that the test script can cater for several documents being returned- which is probably what the MyDocuments class will be dealing with in the real world.
Returning multiple results
For this example, I started by taking a copy of the existing test script but extended it by adding an additional item, as below:
1 |
<span class="lnum"> 1: </span>var fakeItem2 = fakeList.AddItem(); |
1 |
<span class="lnum"> 2: </span>fakeItem2[<span class="str">"Title"</span>] = <span class="str">"document 2"</span>; |
1 |
<span class="lnum"> 3: </span>fakeItem2[<span class="str">"Created"</span>] = DateTime.Now; |
1 |
<span class="lnum"> 4: </span>fakeItem2[<span class="str">"Modified"</span>] = DateTime.Now; |
1 |
<span class="lnum"> 5: </span>fakeItem2[<span class="str">"Created By"</span>] = <span class="str">"User 2"</span>; |
1 |
<span class="lnum"> 6: </span>fakeItem2[<span class="str">"Modified By"</span>] = <span class="str">"User 2"</span>; |
I also modified the WillReturnCollectionValuesOf property to this:
1 |
<span class="lnum"> 1: </span>Isolate.WhenCalled(() => fakeList.GetItems(fakeQuery)).WillReturnCollectionValuesOf(<span class="kwrd">new</span>[] { fakeItem1, fakeItem2 }); |
Using this approach it turns out has some interesting results. Firstly you get the correct number of items returned – my Assert statement expected 2 results and that’s what it got. However, when I drilled down into those results I found that both results were fakeItem2 – the same list item was being return multiple times! I think what’s happened is that this code fakes the call to GetItems but then fakeItem1/fakeItem2 aren’t properly faked and are being passed into the foreach loop – if anyone knows exactly what’s wrong I’d be interested to hear. Good news is that I did a bit of research and found a different approach to returning data – one that appears to work for what I want!
This new approach doesn’t add items to the list (using the AddItem method) but instead uses the WhenCalled method of TypeMock to return the different items that we want – probably easier to take a look:
1 |
<span class="lnum"> 1: </span>Isolate.WhenCalled(() => fakeResults[0][<span class="str">"Title"</span>]).WillReturn(<span class="str">"document 1"</span>); |
1 |
<span class="lnum"> 2: </span>Isolate.WhenCalled(() => fakeResults[0][<span class="str">"Created"</span>]).WillReturn(DateTime.Now.AddDays(-2)); |
1 |
<span class="lnum"> 3: </span>Isolate.WhenCalled(() => fakeResults[0][<span class="str">"Created By"</span>]).WillReturn(<span class="str">"User 1"</span>); |
What happens here it that when the GetAll method from the MyDocuments library iterates through the results collection (e.g. item[0], item[1] etc) TypeMock replaces it with values provided. Using this approach we can add as many items we like to our results and with what ever values we choose.
Using unit tests with development
Unit tests, if used right, can not only help testing but can also help drive development. I’m not going to attempt to describe test driven development (TDD) here because there’s no way I could do it justice. If it’s something you’re interested in then I would definitely recommend looking into it in more detail. What struck me was the advantage of being able to develop code and unit tests alongside each other – allowing both of them to influence the other. Once a piece of development is complete if there’s a series of unit tests already prepared they’re ready to go. I was looking at the code in MyDocuments where it actually creates the individual MyDocument objects, here’s what it does:
1 |
<span class="lnum"> 1: </span>DocumentTitle = item[<span class="str">"Title"</span>].ToString(), |
1 |
<span class="lnum"> 2: </span>CreatedBy =item[<span class="str">"Created By"</span>].ToString(), |
1 |
<span class="lnum"> 3: </span>ModifiedBy = item[<span class="str">"Modified By"</span>].ToString(), |
1 |
<span class="lnum"> 4: </span>Created = Convert.ToDateTime(item[<span class="str">"Created"</span>]), |
1 |
<span class="lnum"> 5: </span>Modified = Convert.ToDateTime(item[<span class="str">"Modified"</span>]) |
What would happen if a document didn’t have a Modified or Modified By value set? We could try and replicate the data in SharePoint but it would be a lot easier to do with a unit test. I took the test script that was previously written and removed where it sets the Modified and Modified By values (thus making them null). Re-run the test and guess what – it failed! As those fields were null the above code threw an exception. This was a very simple example – it was fairly easy to spot that the code could do with being refactored with some null checks. In real world code these types of potential problems might not be so easy to spot and so having unit tests that can easily be run to flag problems is a great tool.
I’m still learning my way through TypeMock and there may be one or two more posts coming up!
Do you have tips for unit testing in SharePoint? Let us and the SharePoint Baker know.