TypeMock Isolator, SPTypeMock and SharePoint testing

I had to work unexpectedly from home yesterday, this has given me a chance to look at TypeMock Isolator and SPTypeMock to aid in the testing of SharePoint without the normal disturbances of being in the office.

First thing I have to say is TypeMock is an amazing tool, OK it costs some money, unlike RhinoMocks, but it’s ability to mock out sealed classes that have no public constructors is essential when testing SharePoint (which seems to contain nothing but sealed classes with no public constructors).

I decided to try to retro-fit some tests to an old existing WebPart.This was a simple contact form that populated some combo-boxes from SPList collections then saved it’s results to another SPList. This had all been coded making direct calls to the SPList objects as required from within the WebPart. All very old school VB6 style, no MVC pattern, so a block of legacy code that is hard to test. However, the beauty of using this mocking framework is that all you production code remains unaltered (though as we will see there is a good argument for designing/refactoring to aid testing).

I first started with the SPTypeMock library. This CodePlex project has been produced by a pair of MOSS MVPs Carlos Segura (http://www.ideseg.com) and Gustavo Velez (http://www.gavd.net ). It provides a set of wrapper classes in the form MockSPList etc. classes that you can use to construct the the SharePoint mocks, basically they hide some of the TypeMock constructions. This means that test logic ends as follows (using the sample from CodePlex)

Mocking a List Collection
– Method to be tested:

        public static string TestMock_02()
        {
            string strReturn = String.Empty;
            try
            {
                using (SPSite mySite = new SPSite("http://MiServidor"))
                {
                    using (SPWeb myWeb = mySite.OpenWeb())
                    {
                        int intTeller = 0;
                        foreach (SPList oneList in myWeb.Lists)
                        {
                            Debug.WriteLine(oneList.Title);
                            intTeller++;
                        }
                        strReturn = intTeller.ToString();
                    }
                }
            }
            catch (Exception ex)
            {
                strReturn = ex.ToString();
            }
            return strReturn;
        }



– Mocking method:

        [TestMethod]
        public void TestMethod2()
        {
            MockSPSite mockSite = new MockSPSite("TestSite");          
            MockSPWeb mockWeb = new MockSPWeb("TestWeb");  
 
            MockSPList mockList0 = new MockSPList("MyList0");         
            MockSPList mockList1 = new MockSPList("MyList1");      
            MockSPList mockList2 = new MockSPList("MyList2");
            mockWeb.Lists = new MockSPListCollection(new[]             
               {
                   mockList0,
                   mockList1,
                   mockList2
               });
 
            mockSite.Mock.ExpectGetAlways("RootWeb", mockWeb.GetInstance()); 
 
            SPWeb WebMocked = mockWeb.GetInstance();    
 
            using (RecordExpectations recorder = RecorderManager.StartRecording())    
            {
                SPSite SiteMocked = new SPSite("");    
                recorder.ExpectAndReturn(SiteMocked.OpenWeb(), WebMocked);    
            }
 
            string expected = "3";   
            string actual;
            actual = Program.TestMock_02();
            Assert.AreEqual(expected, actual);
        }


This works well, they have done a good job. You get a more readable way to express standard TypeMock structure. Yes, the SPTypeMock library is missing some bits, but is a first release and they make point out there is work to do themselves. You can always just write the mocks yourself as in basic TypeMock tests.



However, I did not stop looking here, after doing a bit more reading I started to look at  Isolators' new AAA library (Arrange, Act, Assert) which I think first shipped with  5.1.0. This aims to hide much of the mocking process inside Isolator, by default an ‘empty fake’ is created for everything in the object tree being mocked and you just set values for the bits you care about. This makes it very easy to create a fake of a large system such as Sharepoint by using the magic Members.ReturnRecursiveFakes option



This allowed me to greatly reduce the code required to setup by tests. I create a fake SPSite (and all the object under it) and then set the values for just the items I care about for the test.



 



SPSite fakeSite = Isolate.Fake.Instance<SPSite>(Members.ReturnRecursiveFakes);
           Isolate.Swap.NextInstance<SPSite>().With(fakeSite);



           Isolate.WhenCalled(() => fakeSite.RootWeb.Lists["Centre Locations"].Items).WillReturnCollectionValuesOf(
               new List<SPItem> {
                   Isolate.Fake.Instance<SPItem>(),
                   Isolate.Fake.Instance<SPItem>(),
                   Isolate.Fake.Instance<SPItem>() });



           Isolate.WhenCalled(() => fakeSite.RootWeb.Lists["Centre Locations"].Items[0]["Title"]).WillReturn("Title1");
           Isolate.WhenCalled(() => fakeSite.RootWeb.Lists["Centre Locations"].Items[0]["Email Address"]).WillReturn("email1@email.com");



           Isolate.WhenCalled(() => fakeSite.RootWeb.Lists["Centre Locations"].Items[1]["Title"]).WillReturn("Title2");
           Isolate.WhenCalled(() => fakeSite.RootWeb.Lists["Centre Locations"].Items[1]["Email Address"]).WillReturn("email2@email.com");



           Isolate.WhenCalled(() => fakeSite.RootWeb.Lists["Centre Locations"].Items[2]["Title"]).WillReturn("Title3");
           Isolate.WhenCalled(() => fakeSite.RootWeb.Lists["Centre Locations"].Items[2]["Email Address"]).WillReturn("email3@email.com");



This I think makes the unit testing of business logic within SharePoint viable without having to jump through too many hoops.



Given the choice between the SPTypeMock and the AAA syntax I think I would stick with the latter, but you never know in the future. I suppose it will all come down to which syntax gives the quickest (and maybe more importantly easiest to read) tests in the future.



I did say said I would come back to the application under test’s architecture. This simple WebPart, which contain a good selection of calls to SPLists and had client side validation has proved to be very hard to test, as you would expect. OK you have used TypeMock to get data into it, but how do you test it is in the right field? You can try to render the control but here are issues of WebPartManagers and script registration that frankly are not worth trying to fix. The better solution is some design for test, which I think for WebParts means MVC. In some ways this pattern would negate the need for TypeMock as you would create an IDataModel interface and have any test version you require, though of course you could mock this with TypeMock.



All this said I am hugely impressed by TypeMock Isolator, a really powerful tool for the testing of complex platforms like SharePoint