Lately I have been doing quite a bit of development inside of SharePoint. I am a big fan of Test Driven Development so naturally I wanted to carry over one of my favorite development techniques to SharePoint.
I wanted to share some of the obstacles I ran into along the way and techniques I used to overcome them.
Before I go on I want to point out that I am using Visual Studio 2008 for my development environment.
Missing Method Exception
One of the first problems I encountered was a Missing Method Exception when I would run the unit tests. I never did really find out what was happening. I did find a nice technique for working around it.
I modified the PostBuild routine of my Unit Tests to install my target DLL in the GAC. I also executed my tests in Debug mode. Doing both things overcame the issues. You can read the details here.
Testing Routines that require HTTPRuntime context
The next big challenge for me was to find a way to test routines that needed the HTTPRuntime, HTTPContext or SPContext objects.
I'm not a big fan of using mock objects when unit testing. And the thought of mocking any of those classes (or any of the SharePoint classes) turns my stomach.
For the most part my routines are built so they do not require runtime context. If I had to guess I would say < 5% of my tests are setup this way. Even though it is such a small part of my test footprint it is still a very important part.
Since I am using Visual Studio 2008 (this was available in VS.Net 2005 too) I am able to decorate those tests that require context with the HostType and UrlToTest attributes. Using these attributes will tell MSUnit to run my tests within the context of the IIS runtime.
[TestMethod()]
[HostType("ASP.Net")]
[UrlToTest("Url to SharePoint Page"]
public void FooBarTest
{
string expected = "raBooF";
string actual = MySharePointRoutine.RoutineThatUsesSPContext();
Assert.AreEqual(expected, actual);
}
This works great, but there are some drawbacks.
1. Requires SharePoint site to be configured with Full trust
For MSUnit to hook into the IIS runtime context it has to do some tricky stuff. Unfortunately it doesn't work unless you configure the SharePoint site Full Trust.
One could argue that this invalidates my Unit Tests since it is quite possible that I will have some code that executes one way under Full Trust and another under WSS_Minimal Trust. While this is true I believe the chance of this happening is small.
2. Does not work with Publishing Pages
If you try to use a publishing page in the UrlToTest attribute the test will fail. Below is the error message.
The Web request 'SharePoint URL' completed successfully without running the test. This can occur when configuring the Web application for testing fails (an ASP.NET server error occurs when processing the request), or when no ASP.NET page is executed (the URL may point to an HTML page, a Web service, or a directory listing). Running tests in ASP.NET requires the URL to resolve to an ASP.NET page and for the page to execute properly up to the Load event. The response from the request is stored in the file 'WebRequestResponse_RelatedLinkPathTest_.html' with the test results; typically this file can be opened with a Web browser to view its contents.
I do not know exactly what this means, but I believe the problem may be caused by the fact that Publishing pages are virtual pages that map directly to a list item (i.e. they are not actually an ASPX page).
This kind of stinks because some of the tests may expect the SPContext.Current.ListItem property to be loaded with a valid list item. As a work around I discovered that I could could use the URL that will display list properties for a publishing page (Pages/Forms/DispForm.aspx?ID={List ID}).
To find create the DispForm Url I will first open a browser and point to /pages/forms/allitems.aspx (where pages represents the Publishing pages list). This will provide a list of all of the pages. I then choose the item I want and select View Properties.
Then I copy the URL from the web browser and I have what I need.
3. Difficult for Team Environments
Another problem is the fact that it is not possible (or I could never find a way) to parameterize the UrlToTest attribute. This means that the URL must be generalized so it works on all of the developer and build machines.
Microsoft has a great article that discusses issues teams will encounter when testing web pages (here). The article discuss's using the AspNetDeveloperServerHost attribute in the MSUnit. This attribute supports context parameters so tests can be made to work across teams. Unfortunately I was not able to AspNetDevelpoerServerHost to work with SharePoint Url's. When you think about all of the infrastructure needed to make WSS work it is not surprising that this does not work.
Conclusions
Test Driven Development with SharePoint is doable. The difficulties of setting up Unit Tests will vary depending on what your tests need to do.

6 comments:
Hi thanks for this blog. I'm trying to do what you did but my SPContext is null.
Do you know what I'm doing wrong:
[HostType("ASP.Net")]
[UrlToTest("http://MyServer/sites/Testing/Lists/Test%20List/AllItems.aspx")]
[TestMethod]
public void TestMethod1()
{
SPWeb web = SPContext.Current.Web; // this puppy is 'null' and I'm not sure why.
}
The tests are run inside a special proxy that gets instantiated before the SharePoint handler. So things like SPContext are not available directly inside the test method..
However if you have your test method references a DLL that is deployed to the SharePoint site then that method will have access to SPContext at runtime.
So if you had put the following code in a DLL, deployed it to the SharePoint site and then referenced it from inside your test method it would have worked.
public SPContext RoutineToGetCurrentContext()
{
return SPContext.Current;
}
Thanks for your response.
I tried that and it didn't work. I created a new project, signed it and dropped it into the GAC. The new project had a class that returned the SPContext.Current (as per the posting above) but the method also returned a null SPContext.
I then put the dll into the web app's bin and that didn't work either.
Here's the code for the new project:
namespace TestUtils
{
public class Class1
{
public static SPContext GetSPContext()
{
return SPContext.Current; //returns null
}
}
}
PS.
Here's the code the references it:
[TestMethod]
[HostType("ASP.Net")]
[UrlToTest("http://MyServer/sites/Testing/Lists/Test%20List/AllItems.aspx")]
public void TestMethod1()
{
SPContext context = TestUtils.Class1.GetSPContext();
}
I tested this again today. Works fine on my development enviornment.
One of our developers had a problem, but it was caused by not having [HostType("ASP.Net")] and having an invalid url in UrlToTest.
Also we use localhost as the hostname in the url.
Hi, good post. Only one comment with Team System we can automate testing in web applications.
Introduction to Testing Web Applications with Team System:
http://www.asp.net/learn/vsts-videos/video-127.aspx
Post a Comment