Unit testing MOSS part 1 (of 2)
Some of our team members, including me and Frank Jusnes, were recently responsible for providing recommendations on how to unit test in SharePoint projects, and this is an overview of our findings and experiences. This is the first of two posts on the subject giving an overview. In the second post we are aiming for more examples and explanations.
Unit testing SharePoint has never been an easy task to accomplish due to the many dependencies on the SharePoint platform.
The only real alternative to unit testing SharePoint is by using isolating the unit tests from the outside world (also called Integration tests) with the use of Mock objects.
With the evolvement of .Net, there are now great easy-to-use tools (like the commercial Typemock) on the market one can use to create unit tests with techniques like lambda expressions and others.
In addition, the Microsoft Patterns and practices team has now released a guidance on SharePoint development which includes guidance on how to unit test in a SharePoint development projects.
The guidance recommends unit testing SharePoint using Mocks. The concept is that you have to isolate all the dependencies on SharePoint (and other external dependencies) with fake objects, and act on these fake objects instead.
With the Typmock Isolator tools we are able to isolate SharePoint out of the equation in our tests since it is possible to call into private methods, sealed classes and event handlers among others.
What tests to write?
The ambition level of test coverage is a difficult discussion to have, as there are many meanings on the subject, but here is what we initially suggest:
- Positive tests verifying the flow of the code in successful calls
- Input validation, all combinations
- The logic of the code
- And last but not least the Exception handling-flow
Here are some of the more important terms used in relations to unit testing with the Typemock Isolator
- Mock = Pretender object, intercepts the real object
- Fake = Mostly the same as a Mock, but a simpler variant
- Stub = Fake method call
- Expectations = Prepare expected results for later Asserts
Way it works
Authoring unit tests with Typemock Isolator involves following a certain pattern when writing the test. This pattern is called:
Arrange-Act-Assert test authoring pattern
As the title implies, there are three sections you have to create in your tests.
- Arrange: This is the section where you set up fake objects and expectations
- Act: Here you perform the calls on your class in test (often faked objects calls)
- Assert: In the end there has to be some verification and asserts
The Typemock framework has 3 API's you can use to create tests
1. generation API, do not provide strongly typed mock objects
2. generation API, uses a "recorder" to to set up expectations. Strongly typed mock objects
AAA Typemock Isolator
3. generation API. Strongly typed fake objects, more readable test code and can even fake live objects.
This is the API recommended to use for SharePoint unit tests, due to the fact that we are able to implicitly create hierarchies of fake objects. Especially valuable when it comes to faking e.g. SPSite objects.
That said, since the AAA Typemock API does not support all test scenarios one will probably have to combine at least AAA Typemock Isolator and Natural Mocks to get the full range of advanced test cases covered.
The following is a comparison between AAA, Natural Mocks™ and Reflective Mocks (from the Typemock site):
|Compile time checks||Yes||No (methods are passed as strings)||Yes|
|Refactoring support||Yes||Partial (methods are passed as strings)||Yes|
|Fake recursive objects||Yes||No||No|
|Static method behavior setting and verification||Yes||Yes||Yes|
|Non-public methods mocking||Yes||Yes||No|
|Argument checking||Yes||Fake chains||Yes|
|Setting calls to behave as implemented||Yes||Yes||Yes|
|Custom argument checking||Partial (For non-public members only)||Yes||Yes|
|Conditional execution of custom code||No||Yes||Yes|
|Faking all instances||No||Yes||Yes|
Some useful techniques in your test code
Creating Fakes that returns a provides full hierarchy recursively:
var fakeSite = Isolate.Fake.Instance<SPSite>(Members.ReturnRecursiveFakes);
Swap an instance of the live object with the Fake
Setting behaviour using .Whencalled and .WillReturn
Isolate.WhenCalled(() => fakeObject.Name).WillReturn("Name to return when called");
Setting behavior using .Ignore which will ignore the call (only on void methods)
Isolate.WhenCalled(() => fakeObject.VoidCall()).IgnoreCall();
Setting behavior using .WillReturn to tell what a call should return (only on methods returning values)
Isolate.WhenCalled(() => fakeObject.IntCall()).WillReturn(1);
Verify behavior using .Verify. For instance if a method was called or not
Isolate.Verify.WasNotCalled(() => fakeObject.Update("This should not be called"));
How to attack?
First of all, if unit testing is a new technique to you, try get the overview by reading the excellent developer guide on the Typemock site. They also have videos providing intro to the framework. Get your head around the examples and try them out.
Use TDD principles to write good thought-through code, but if you have to create tests on some legacy code here are some tips:
First identify needed Fakes you will have to create
For instance if there is a SharePoint object creation in the code you test (e.g. SPSite):
- Create a Fake SPSite
- Replace the SharePoint object with the Fake (future swapped)
A SharePoint object method call following the previous instance (e.g. SPSite.OpenWeb):
- Replace it with a method call on the Fake SharePoint object
A SharePoint property get:
Replace it with a .WhenCalled/.WillReturn behavior setup on the Fake
Verify and Assert