Last week at the Dallas Techfest I spoke about using TypeMock to Unit Test your SharePoint code. I wanted to follow that up with a few blog posts about mocking, SharePoint, and TypeMock. This first post will just be a quick intro on how to get setup.
Before I discuss how to get started unit testing SharePoint code I will take a step back and ask if it is even worth the effort . The answer is it depends on the size and complexity of the SharePoint project. I would say unit testing SharePoint is for large customization projects of SharePoint where you have numerous web parts, event receivers, workflows and custom business classes. These larger development projects should be treated like any other .NET project and be unit tested in the same way.
Adding SharePoint References
I’m going to assume that you haven’t started a SharePoint project yet. If you have then you should skip to step 3. One of the first things you need to do is add a reference to the SharePoint dll. Depending on what classes in the object model you are referencing will mean you have to add additional dlls. Here you would also configure your build process and how your wsp will get generated. I recommend automated this with a tool like wsp builder. Of course with SP2010 this gets a lot easier. Next you will also want to create a unit test project that will contain your tests for your entire code base.
http://geekswithblogs.net/evgenyblog/archive/2008/01/27/118966.aspx
Installing and Adding TypeMock References
Next we need to download TypeMock isolator for .NET. You don’t need a separate install for SharePoint. http://site.typemock.com/isolator-download?id=1
*Must have TypeMock Isolator for SharePoint
Then add a reference to TypeMock dll from your unti testing project
Examining Our Method Under Test
Once we start to create some unit tests we are going to realize we need some help. The first challenge is we don’t want to test the SharePoint code that our business logic is calling. One reason is because this would become and integration test and make our test slow since they would have to go out to SharePoint and execute the code that we had written. The other reason is I might want an environment where not all my developers are running a SharePoint server. They could then write code, unit test it, and deploy it to some type of integration environment.
Let’s take an example of this method:
public bool UpdateCustomerSPListItem(string firstName, string ID)
{
SPListItem item;
using (SPSite site = new SPSite("http://localhost"))
{
SPWeb spWeb = site.OpenWeb();
var customerSPList = spWeb.Lists["Customers"];
SPQuery query = new SPQuery
{
Query = ("<Where><Eq><FieldRef Name=\"ID\"/><Value Type=\"Text\">" +
ID + "</Value></Eq></Where>"),
ViewAttributes = "Scope='Recursive'"
};
var itemCollection = customerSPList.GetItems(query);
if (itemCollection.Count == 0)
throw new NoSPListItemsFound();
item = itemCollection[0];
//test parameter
if (string.IsNullOrEmpty(firstName))
throw new ArgumentNullException("First Name can't be null or empty");
item["FirstName"] = firstName;
item.Update();
}
return true;
}
The method UpdateCustomerSPListItem is a pretty simple method that takes a first name parameter and updates the custom list item with that id (second parameter). Now this method is pretty simple but imagine that it contained more business rules and logic. The only rule we have right now is first name cannot be null or empty. Notice that this method has several dependencies., SPListItem, SPWeb, SPQuery etc… Those all need to be stubbed out in order to stub or fake this class. We would need to create a FakeSPListItem class that has an update method, a FakeSPWeb class that has a constructor, each of these returning fake values.
Take a few minutes and go through the rest of the dependencies in your head, as you can see this would be a lot of work. The great thing about mocking frameworks is they do this creating of these fake classes for us. Now this is great but most frameworks need an interface to create the fake object. Not only do SharePoint classes not have interfaces but many of the classes are sealed or have private constructors. This is where TypeMock comes in. As far as I know it is the only framework that can mock these types of classes.
We can now write a test method that will test UpdateCustomerSPListItem without having to update an item on a SharePoint server nor do we have to stub out ever class in the SharePoint namespace.
Let’s Write Our First Method
First step would be to create a test method and add a recording using statement. Note I’m using the BDD syntax of naming test methods.
[TestMethod, VerifyMocks]
public void Update_Customer_ListItem_When_Given_ID_AND_Name()
{
using (RecordExpectations rec = RecorderManager.StartRecording())
{
}
}
Next we need to plug in the steps of our UpdateCustomerSPListItem method that we want to test. Just like in the method under test we create a SPSIte, SPWeb, and SPListObjects. We then write a CAML query to get the item we want to update. The difference in our test is we are not interested in what the query is so we can just pass in a SPQuery object without a value.
SPSite mockSite = new SPSite("");
SPWeb web = RecorderManager.CreateMockedObject<SPWeb>();
rec.ExpectAndReturn(mockSite.OpenWeb(), web);
SPList mockList = RecorderManager.CreateMockedObject<SPList>();
rec.ExpectAndReturn(web.Lists[""], mockList);
SPQuery query = new SPQuery();
SPListItemCollection listItemCollection = RecorderManager.CreateMockedObject<SPListItemCollection>();
rec.ExpectAndReturn(mockList.GetItems(query), listItemCollection);
SPItem item = RecorderManager.CreateMockedObject<SPListItem>();
item = listItemCollection[0];
item["FirstName"] = "canbeanything";
item.Update();
Next we need to call our method under test and add an assert statement like so:
var result = classUnderTest.UpdateCustomerSPListItem("Kyle", "1");
Assert.IsTrue(result);
Now this does test that the method returns the correct value but we also want to make sure that the method executes as we expected. For example making sure we call item.Update. In my opinion this is the real value of using a mocking framework. In order to verify expectations we add the VerifyMocks attribute.
The entire test method looks like this:
[TestMethod, VerifyMocks]
public void Update_Customer_ListItem_When_Given_ID_AND_Name()
{
using (RecordExpectations rec = RecorderManager.StartRecording())
{
SPSite mockSite = new SPSite("");
SPWeb web = RecorderManager.CreateMockedObject<SPWeb>();
rec.ExpectAndReturn(mockSite.OpenWeb(), web);
SPList mockList = RecorderManager.CreateMockedObject<SPList>();
rec.ExpectAndReturn(web.Lists[""], mockList);
SPQuery query = new SPQuery();
SPListItemCollection listItemCollection = RecorderManager.CreateMockedObject<SPListItemCollection>();
rec.ExpectAndReturn(mockList.GetItems(query), listItemCollection);
SPItem item = RecorderManager.CreateMockedObject<SPListItem>();
item = listItemCollection[0];
item["FirstName"] = "canbeanything";
item.Update();
}
var result = classUnderTest.UpdateCustomerSPListItem("Kyle", "1");
Assert.IsTrue(result);
}
There you go your first unit test for SharePoint code using TypeMock. My plan is to go into more detail of how to mock out other SharePoint objects like Event Receivers, Web Parts, and Workflows.