Unit Testing against the SharePoint Object Model
Automated unit testing is cool. It's the latest thing. But it has always been a little more difficult in SharePoint development than with some other technologies because there is a big black box SharePoint object model involved. The usual suggestions have been to:
- Use an elaborate Model-View-Controller type of pattern involving lots of classes and interfaces, most of which doing nothing, in order to wrap the calls to SharePoint so that it can be replaced with test stubs. The problem is that the important stuff gets stubbed out in the tests.
- Use a mocking framework to replace the calls to the SharePoint object model. The problem is that this assumes that you can figure out the behaviour of SharePoint in order to mock it. The problem is that this is one of the key parts of the application you need to test.
- Create a set of domain objects that make the calls to the SharePoint object model, in a manner analogous to an ORM for database queries. Replace those with stubs or fakes for testing. The problem is that the domain objects contain the code that is often in most need of unit testing.
- Build a complete fake of the SharePoint object model and test against it. The problem is that the SharePoint OM is very big and is frequently updated.
- Use a local installation of SharePoint, populate it with test data, and unit test against it. The problem is that this is not strictly a unit test because it involves the whole system and not just the unit under test.
I tried to work with option 4 with some success using FakePoint. Building a fake SharePoint OM turns out to be easier than I expected, but still unrealistically time consuming. I was hoping that by putting it on CodePlex it might attract interest from other developers and that it might be possible to solve this problem as a community effort. World peace and an end to poverty would have been nice as well.
Option 2 requires a mocking framework, and the free ones won't work with the SharePoint object model classes. So you need to invest in a third-party commercial mocking framework, which means you have to accept another dependency. Options 1 and 3 require you to change your architecture in order to facilitate unit testing. To me, that seems like the wrong way of going about things.
So we are left with option 5. With SharePoint 2010 we have the ability to set up a development environment on the Windows 7 desktop operating system. That avoids the need to have a separate machine (or VM) running a server operating system to be able to do SharePoint development. So the development environment consists of Visual Studio 2010 and a SharePoint stand-alone style environment. (I say stand-alone style meaning SharePoint and SQL Server are on the same box - I don't recommend choosing the "stand-alone" option when installing SharePoint). If we can assume that the SharePoint runtime will be present, I think that a test that is run against that environment can be legitimately called a "unit test".
So far so good. Now Visual Studio has a built-in unit testing framework - MSTest. That used to be incompatible with SharePoint because it was dependent on the .NET Framework 4.0. You could still do unit testing using another framework such as NUnit, but debugging was a pain - you had to attach the debugger to the NUnit test runner process every time. It would be much better if we could use MSTest because you can run a test in debug mode directly from the IDE and do your test/debug cycle right there. The good news is that with Visual Studio Service Pack 1, MSTest is able to work with .NET Framework 3.5. So now we can build tests using the integrated MSTest framework and also use test-driven development techniques such as setting up a failing test and then debugging by breakpointing the executing test.
There are one or two tricks you need to know to get this working. So the steps to set up your environment are:
- Install SharePoint (presumably on a non-server OS - see instructions).
- Install Visual Studio 2010 Service Pack 1.
- Create a test project.
- Change the target framework in Project Properties->Application to 3.5
- Go to menu Test->Edit Test Settings->Hosts and change to "Run in 64-bit process on 64-bit machine"
You can now build a web part, say, as described in another article. Now as you want to add functionality you can first create a test and then do the whole TDD thing. I am not saying you should necessarily always do test-driven development. But if it is easy to set up, and doesn't mean ending up with a distorted architecture, why not.