vrijdag 4 juni 2010

SharePoint and automated testing


SharePoint is a horrible platform to build applications on. And even more so to automate testing against, with the ui and the data layer so completely interwoven. Even more difficult is writing tests for code spaghetti already written on top of SharePoint by somebody else. Nevertheless, this is what I've been doing the last couple of weeks and actually having some fun with it too. Thought I might share some of the things I learnt.

As refactoring the existing spaghetti code was not an option, I ended up building automated acceptance and integration tests that had to deal explicitly with the SharePoint environment. There were few opportunities for unit tests but if I have time I'll definitely put them in place too.

TIP 1

First off, most existing spaghetti code on top of SharePoint will use the global SPContext.Current somewhere. Nasty, nasty, nasty... . Of course, this dependency should have been nicely injected into the object using it, but this is seldom the case. So to create a "fake" SPContext for testing purposes, use code along the lines of (see also here):


String url = "http://myhost.com/mysitecollection";
SPUserToken token;
using (SPSite site = new SPSite(url))
{
token = site.SystemAccount.UserToken;
}
SPSite site = new SPSite(url, token);
HttpRequest request = new HttpRequest("", url, "");
HttpContext.Current = new HttpContext(request, new HttpResponse(TextWriter.Null));
HttpContext.Current.Items["HttpHandlerSPWeb"] = site.OpenWeb();


Explanation: SPContext looks in the current HttpContext for a reference to the current SharePoint web site. We create a reference by using an existing site url, creating a site (collection) object for the url (impersonating the SystemAccount when we create it so that the tests will have access to lists etc), and finally getting the actual web site object for the url and storing it in HttpContext. Note: The HttpContext.Current we create is a dummy one but we do need an actual existing SharePoint site url.

Now this will get you started. Now you can create tests that call existing spaghetti code and not run into problems if this code calls SPContext.Current.

TIP 2

However, spaghetti SharePoint code often instatiates new SPSite objects left and right (to get access to lists for example) and this causes other problems.

Each time a new site is instantiated in the spaghetti code, it will "run" under the account you are using to run the automated tests. So not the SystemAccount we so nicely impersonated for the SPContext.Current above. Typically, the testing account will not have the necessary rights to do whatever the spaghetti code is trying to do (access lists more often that not). So, to solve this problem, run your test code with elevated privileges using code similar to:

SPSecurity.RunWithElevatedPrivileges(delegate() {
// automated testing code that calls the existing spaghetti code
});


Running with elevated priviliges ensures that the test has full rights to do whatever it wants. Evil but it gets the job done.

TIP 3

A final tip. If you test code is going to get items from lists, update them and then save them back to the list, you're probably going to hit some errors regarding a HTTP GET not being allowed to do an update. This has to do with the fake HttpContext created above and the SharePoint security model. I didn't dive to deep here but the problem can typically be resolved by using code along the lines of:

web.AllowUnsafeUpdates = true;
web.Update();


Here web is the web site you containing the lists you want to update. I just ended up adding this code to my automated tests if I hit the GET problem. But I'm sure there's a better solution out there (and if so, please tell me about it).

NOTES

1) A great thing about writing the automated tests was that I didn't have to attach my VS debugger to the wp3.exe process even once! I just ran (in debug mode if necesary) the tests, which speeded up my development significantly.

2) I initially built all my tests in vs2008 (using mstest) but at the end realized I couldn't run my test in acceptance environment without installing visual studio there completely! Since this is evil and NOT an option, I also made the tests run under NUnit as NUnit has a nice ui tool that can be easily installed (and deinstalled) on an acceptance environment. So I now had a test dll that could run in both testing frameworks and it cost very little extra work :-)

3) Of course, the above testing context is completely unsuited for testing any security functionality as it heavy handedly usurps full control to get the job done.


That's it for now. Happy SharePoint testing!

Geen opmerkingen:

Een reactie posten