codeflood logo

Unit Testing in Sitecore is Not Scary

I was chatting to another Sitecore developer the other day about unit testing in Sitecore. The impression I got from the developer was that although they knew unit testing could be done, they felt it was quite cumbersome and difficult. Possibly the length of my previous series on unit testing in Sitecore didn’t help the cause either. So I’d like to show you just how easy unit testing in Sitecore is. One reason my previous series was so long was because it covered a lot of topics and areas related to unit testing and how to test various UI components in Sitecore as well as different strategies for setting up and pulling down your test data. Unit testing of UI is not as important as unit testing of business logic and utility methods. These are the easiest pieces of any system to test and it’s where you should spend you initial time, especially if you’re trying to introduce unit testing on your projects for the first time. Your UI components would need testing though if they themselves contained a level of business logic. And I’m not talking about heavy business logic, more the things like altering or filtering the output based on parameters passed to your component (especially relevant for XSLTs). So I’ve recorded a video showing exactly how to setup unit testing on your Sitecore project using my custom NUnit test runner. I’ve found it much easier and safer to use this custom test runner rather than trying to fake the HttpContext or mocking. I’m a strong believer that you shouldn’t try and mock something unless you have intimate knowledge of the component being mocked and can have it changed if it doesn’t meet the assumptions your tests and mocks were built around. Mocking an entire system such as Sitecore or SharePoint is fraught with danger and it’s likely that you think you have a good idea about how the system works, but you don’t have the ability to change it if an assumption you’ve baked into your mock is wrong. Part of the unit tests running inside the system is to validate your understanding of the system. The process I show in the video is:

  1. Download the custom test runner
  2. Include the test runner it in your test project
  3. Configure the build using MSBuild
  4. View the test runner

This is probably the simplest form of unit testing for your Sitecore projects.

https://www.youtube.com/watch?v=mZKSl3pemEs

You can download the custom test runner I use in the project from the codeflood website. In the next video I’ll show how to start writing your unit tests.

Comments

I'm not sure that I'd call that easy. You need to know a (some-what) obscure MSBuild syntax and it is also not able to be included as part of a CI process since it runs in-browser (or so is implied by your video).
Limiting your unit tests to only being run on each developers machine, and not part of a CI process is not really a good idea, as you're CI will be able to produce failing builds without you being aware.
For unit testing applications which rely on the HttpContext (as you're referring to) I find it's much simpler to use MSTest and have it kick off cassini. You can then test those APIs as the HttpContext is available (it's what we did with the Umbraco 4.5 release).
But in reality I'm much more of an advocate of using an abstraction layer. Say for example you have a static object which comes from your underlying framework (aka Sitecore) I would create an interface or abstract class (depending what's best in the scenario) and then pass that into the user control (well really I'd use WebForms MVP and have a DI framework wiring up the dependencies but covering that in a comment isn't a good idea :P).
This way you can write a unit test that runs through a test running (like NUnit) without needing the HttpContext at all.
Just my $0.02AUD

Alistair Deneys

OK, granted, perhaps I made it look harder than it needs to be because of my use of MSBuild. I use MSBuild to maintain a strict separation between my code and the system I'm developing into. After all, I'm only using it to copy some files around after the build, and you could actually do that with some simple bat commands (not quite as elegant) or just dev directly in the same folder as Sitecore (again, not quite as elegant IMHO).
The CI considerations are a good point. I've been thinking about updating the test runner to have some kind of XML interface to allow calling from a program (other unit tests perhaps?). I'll have to explore your Cassini approach to see if I can make it work. And although CI is important later on, the initial hurdle is to get devs writing tests. Baby steps.
In terms of the abstraction layer, it feels a little heavy for a simple content system. If you're developing a large web application then it sounds like a very good idea, but abstracting away the system for a basic content website feels like a lot of work (especially in a very competitive market).
Thanks for your feedback Az, I'm looking forward to seeing your blog posts on everything you mentioned above (particularly MsTest with Cassini and hooking that into CI) :)

Still struggling to get CI and testing going? Bloody hell I was trying to get that started when I use to work with you. Get your act together boy :P
I disagree that creating an abstraction layer between your data store and your business logic is overkill, and that's what you're testing right, interaction between a data store (in this scenario Sitecore) and business logic, not interaction between the data store and the UI (accessing a field and putting it into a label)? Right?
Creating a separation of concerns layer means that you actually have to think more about why you're interacting with the data store (or any sub-system) more than going "lets just grab some data". It can help you identify commonality between API calls (if I need to access data X and you need to access data X let's have a single method we can both use), where as if you're writing Sitecore.Some.Api.Method.Access.Data["blah"] it's not as easy to pick up.
At TheFARM we never exposed Umbraco to our Web project, we always had a middle tier (with the exception of when you just wanted to use then you use the Umbraco API, but that's not something you'd unit test anyway ;)) and although it seems excessive the first time the second time you do it it makes sense and the third time you get shitty when it's not already setup for you.
If you ever were on IM programs it'd be easier for me to berate you than in your blog comments :P

Alistair Deneys

Is it lonely all the way up there on your pedestal Az? :)
Ah, I get you now. Yes, I agree. In fact, I normally try to do what you've described in that the UI project shouldn't access Sitecore directly but should always go through a business layer project to get the data it needs. If you also abstract your data engine (Sitecore, Umbraco, SharePoint, whatever) away from your business logic code then you can use whatever unit testing framework you like cause your business code shouldn't rely on HttpContext.
The method I show in the video and will continue in the next video is testing that data layer, where you can't run without HttpContext. At the start of the video I showed a data method I'm going to test that should get a list of filtered data items. This is the case you need the custom test runner cause you can't avoid or abstract the CMS API away.
And why do you think I stay off the IMs :)

My pedestal gives me a good view of the landscape :P.
The issue I have with what you're talking about is that you're testing something you don't have control over, you're testing that the Sitecore.Context.(and so on) returns data in the format you expect (and/ or require). But what if it *doesn't* work as expected? How do you resolve that? You can't change the Sitecore API...
What you're showing here is not unit testing, but instead its integration testing, so that "with data api A I get data B and it should do X", where as the unit test should only do "for data B (from any source) it should do X".
You should never have expectations on a system you can't control in a unit test ;)

Alistair Deneys

It would seem we've come to a consensus. I agree. By definition what I have shown in the video is not unit testing, it is integration testing as this style is all about calling the API of that external system which you have no control over. I used the term "unit testing" as a general term as developers understand what they are. As you'll see in the next video I'm not testing the Sitecore API itself, but my business logic which uses the API.

Just like an old married couple! :)

Alistair Deneys

Yes, but I'm the man in the relationship :)

[...] finally found enough free time to record the continuation of my first unit testing in Sitecore video which showed how to add a test project to your solution which used the codeflood custom NUnit test [...]

[...] Deneys blog on unit testing with Sitecore using a custom test runnner can be found here.How to change config files to work with Sitecore without a “context” here. By Mike [...]

Jason

I agree with Powell about putting sitecore in a data-access layer and then using a test-double for it. Been there; done that. But I will say you're right about the heaviness as well. For those just learning sitecore (and maybe tdd) it can be enough to kill the testing all together ...

Hello, Late to the party! Just trying to find a good approach for unit testing Sitecore (in a large and largely un-unit-tested project) and came across this post and conversation. Just wondered if/how you can enable Page Editor if you’re abstracting away the Sitecore gubbins from the UI? Thanks, Owen

Thinking about it/Googling – I’d probably use Glass.Mapper.

[…] and read Alistair Deneys’ blog post Unit Testing in Sitecore is not Scary […]

Leave a comment

All fields are required.