But it works on my PC!

The random thoughts of Richard Fennell on technology and software development

Mocking Sharepoint for Testing

In my previous post I talked about using Isolator to mock Sharepoint to aid the speed of the development process. I find this a productive way of working, but it does not really help in the realm of automated testing. You need a way to programmatically explore a webpart, preferably outside of SharePoint to check its correctness.

You could use the methods in my previous post and some form of automated web test, but this does mean you need to spin up a web server of some descriptions (IIS, Cassini etc. and deploy to it) An alternative is look at the Typmock addin Ivonna. This a creates a fake web server to load you page and tools to explore it.

I will describe how to use this technique using the same example as my previous post.

Previously I had placed all the code to fake out SharePoint in the Page_Load event of the test harness page. As I am now trying to write an unit/integration test I think it better to move this into the test itself so I would delete code I placed in the Page_Load event other than any property settings on the actual webpart. I would actually refactor the lines creating the fake URL context and fake SPSite into some helper methods and then call them from my new test. I would then load the page in Ivonna and check it’s values.

I have tried to show this below, using a couple of techniques to show how to get to components in the page.

   1: [TestMethod, Isolated]
   2:      public void LoadWebPage_SpSimpleWebPart_3EntriesInList()
   3:      {
   4:          // Arrange
   5:          TestHelpers.CreateFakeSPSite();
   6:          TestHelpers.CreateFakeURL();
   7:  
   8:          TestSession session = new TestSession(); //Start each test with this
   9:          WebRequest request = new WebRequest("/SpSimpleTest.aspx"); //Create a WebRequest object
  10:          
  11:          // Act
  12:          WebResponse response = session.ProcessRequest(request); //Process the request
  13:  
  14:          // Assert
  15:          //Check the page loaded
  16:          Assert.IsNotNull(response.Page);
  17:          
  18:          // the the Ivonna extension method to find the control
  19:          var wp = response.Page.FindRecursive<DemoWebParts.SpSimpleWebPart>("wp1");
  20:          Assert.IsNotNull(wp);
  21:  
  22:          // so we have to use the following structure and dig knowing the format
  23:          // webpart/table/row/cell/control
  24:          var label = ((TableRow)wp.Controls[0].Controls[0]).Cells[1].Controls[0] as Label;
  25:          Assert.IsNotNull(label);
  26:          Assert.AreEqual("http://mockedsite.com",label.Text);
  27:  
  28:          var list = ((TableRow)wp.Controls[0].Controls[1]).Cells[1].Controls[0] as DropDownList;
  29:          Assert.IsNotNull(list);
  30:          Assert.AreEqual(3, list.Items.Count);
  31:      }

Now I have to say I had high hopes for this technique, but it has not been as useful as I would hope. I suspect that this is due to the rapid changing of the UI design of client’s webparts making these tests too brittle. We have found the ‘mark 1 eyeball’ more appropriate in many cases, as is so often true for UI testing.

However, I do see this as being a great option for smoke testing in long running projects with fairly stable designs.

Mocking Sharepoint for Design with Typemock Isolator

I have found the most productive use of Typemock Isolator with SharePoint is to use it to reduce the time of the F5 cycle (build/deploy/use). If you are using a VPC of some type to do your SharePoint development, as many do, this process can easily take a couple minutes, and these minutes add up.

In my experience webparts usually make fairly simple use of the underlying SharePoint site, by this I mean that they get some data from an SPList(s) or remote data source and render in some way. Or the reverse, they gather data that they drop to an SPLits(s) or remote data source.

So why not remove the requirement for SharePoint during development from the equation? Mock it out with Isolator and an ASP.NET test site.

image

Consider this scenario…

  • You have a part that lists people name and email address in a combo box
  • This data is stored in an SPList
  • The webpart must also list the URL of the site it is hosted on.

All fairly straight forward, but how to implement the wrapper around it?

  • The first we create an ASP.NET Web Application and an ASP.NET web page in the same solution as the WebParts class library.
  • In this web application reference the webpart project
  • Edit the .ASPX to reference the webpart assembly (line 2) and create an instance on the page (line 11-17). It is best to do this declaratively to avoid any question of the ASP.NET personalisation system.

 

   1: <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="SpSimpleTest.aspx.cs" Inherits="TestWebSite.SpSimpleTest" %>
   2: <%@ Register Assembly="DemoWebParts" Namespace="DemoWebParts" TagPrefix="wp" %>
   3: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   4: <html xmlns="http://www.w3.org/1999/xhtml">
   5: <head runat="server">
   6:     <title>Untitled Page</title>
   7: </head>
   8: <body>
   9:     <form id="form1" runat="server">
  10:     <div>
  11:         <asp:WebPartManager ID="WebPartManager1" runat="server">
  12:         </asp:WebPartManager>
  13:         <asp:WebPartZone ID="WebPartZone1" runat="server" >
  14:             <ZoneTemplate>
  15:                 <wp:SpSimpleWebPart ID="wp1" runat="server" />
  16:             </ZoneTemplate>
  17:         </asp:WebPartZone>
  18:     </div>
  19:     </form>
  20: </body>
  21: </html>

  • If you browse to this page you will see a null object exception as it loads the web part but it fails when it calls to SharePoint. This is because we have not mocked that yet. Seeing this error does rely on the fact you have a nice big global Try/Catch in the webparts Render() and CreateChildControls() methods. Note a technique I normally recommend but I think vital for this type of component else errors get swallowed by SharePoint

image

  • Add a reference to the SharePoint assemblies and Typemock Isolator (which of course you need a licensed copy of, or the 30 day demo) in the Test web application
  • In the Page_Load event you now need to add the code to do the faking, I think the comments below explain what is going on. (There is a good argument to refactor much of this into a TestHelper class so it is easy to reuse).
   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Web;
   5: using System.Web.UI;
   6: using System.Web.UI.WebControls;
   7: using TypeMock.ArrangeActAssert;
   8: using Microsoft.SharePoint;
   9:  
  10: namespace TestWebSite
  11: {
  12:     public partial class SpSimpleTestWithMockedSP : System.Web.UI.Page
  13:     {
  14:         protected void Page_Load(object sender, EventArgs e)
  15:         {
  16:  
  17:             // set the name of the list to read data from
  18:             wp1.DataList = "ListName";
  19:  
  20:             // set the fake return value for the currently running context
  21:             // we can us null as the current parameter as this is what this web page will return
  22:             Isolate.WhenCalled(() => Microsoft.SharePoint.WebControls.SPControl.GetContextSite(null).Url).WillReturn("http://mockedsite.com");
  23:  
  24:  
  25:             // create the mock SP Site we are using
  26:             SPSite fakeSite = Isolate.Fake.Instance<SPSite>();
  27:             Isolate.Swap.NextInstance<SPSite>().With(fakeSite);
  28:  
  29:             // create a fke collection to hold our test data
  30:             var itemCollection = new List<SPListItem>();
  31:             for (int i = 0; i < 3; i++)
  32:             {
  33:                 var fakeItem = Isolate.Fake.Instance<SPListItem>();
  34:                 itemCollection.Add(fakeItem);
  35:  
  36:                 Isolate.WhenCalled(() => fakeItem["Title"]).WillReturn(string.Format("Title {0}", i));
  37:                 Isolate.WhenCalled(() => fakeItem["Email Address"]).WillReturn(string.Format("email{0}@email.com", i));
  38:  
  39:  
  40:             }
  41:  
  42:             // set what is returned when a call is made for the list
  43:             Isolate.WhenCalled(() => fakeSite.RootWeb.Lists["ListName"].Items).WillReturnCollectionValuesOf(itemCollection);
  44:         }
  45:     }
  46: }
  • Once this code is entered you can browse to the page again and you should see a working webpart that thinks it is talking to a real SharePoint site.

image

So now you have a way to run you SharePoint dependant webpart outside of SharePoint.This means the F5 cycle is reduced to seconds as opposed to minutes, and debugging is loads easier.

What I find this particularly useful for is sorting CSS and JavaScript issues, where is loads of tiny edits to text files.

THIS DOES NOT MEAN YOU DON’T NEED TO TEST IN SHAREPOINT, but it does means you can avoid much of it. The SharePoint phase become far more a test/QA/UAT process as opposed a development one. This model as a developer productivity enabling one.

In my next post I will talk about Mocking Sharepoint for Test with Typemock Isolator

Post SharePoint Evolution thoughts

I am on the way home from my whistle stop visit to the SharePoint Evolution conference. I must say congratulations to the organisers for putting on such a successful event given all the problems they have had related to speakers and air travel, well done.

My slides, on Testing Webparts with Typemock, will appear on the conference site soon, but I thought it a good idea to link here to previous posts I have done on the subject. Imaging how surprised I was to realise to find I never wrote them! If you search my blog you will find links to older versions of today's slide stack, but no coding samples.

So I will do a couple of posts as quick as I can that go through the demos I did today, so expect one on ‘Mocking Sharepoint for Design’ and another for ‘Mocking Sharepoint for Tests’

Updated 22 Mar 2010 – added links to the posts as I wrote them

Speaking at Developer Day South West

I have just heard I will be speaking at Developer Day South West on June the 5th. My subject is Using the new Developer and Test features of VS 2010 to track down and fix bugs, this is basically the same session as I have at our TechDays fringe event yesterday.

Hope to see you there

DDDSouthWest2BadgeSmall[1]

Useful tool to move Reporting Services reports between servers

When you are moving TFS contents around between servers, as many people will be doing as they implement new 2010 servers and want to make use of Team Project Collections; you often have to move Reporting Services reports. In many cases you find people have lost their customised .RDL files they uploaded in the first place, and don’t want to restore the whole Reporting Services DB.

So how to extract an RDL file from a Reporting Services instance and moving it to a new Reporting Services instance?

Well have a look at Reporting Services Scripter, make makes the process fairly straight forward.