Before I can proceed on in the Life Through A Lens series of blog posts, I thought I would cover something that has been somewhat of a bug bear of mine since I started working on the Sitecore platform, this is Unit Testing. I wanted in particular to address some of the misconceptions with unit testing and on using Glass Mapper in unit test scenarios. I have been using TDD (and as we all do Test After Development) since around 2007 and have learned a lot in this time. Due to this – I have decided to write this post before continuing with the Life Through A Lens Series to give a backdrop of what I feel is a key idea behind unit testing. I feel it is really important to cover off some of the classic TDD mistakes before I get involved with actually demonstrating how I use Glass Mapper to solve some of these problems.
I will before I go any further give a massive nod of the cap to Simon in his improvement of my knowledge in this area. I did know some things on this subject, but his patience and teaching allowed my knowledge to progress significantly beyond where it was at a rate quicker than it would have done otherwise.
Ok, so with the above in mind, I will move on to some of the most common phrases I hear from developers / managers ( / whomever ), these are usually in response to my first day questioning of ‘What unit test / mocking frameworks do you guys use?’. The answer of ‘none’ ( I don’t know why ) still offends me.
You can’t unit test Sitecore
AGREED – absolutely – that is Sitecore’s responsibility ( another bugbear for another day ;) ), we are there to ensure that OUR code does what we intend it to, that our code can deal with (sorry if any of you guys are Sitecore employees) Sitecore’s inherent flaws / bugs / ‘features’ / whatever. Simply put, if your code is reliant on Sitecore’s api, in many cases you are in the realm’s of integration NOT unit testing.
Integration testing and Unit Testing
So here is another point I have come across in my years as a developer and it is something I have had to explain over and over. I hear the phrase ‘I have to test that I get this value out of the database / Sitecore / web service / payment gateway’. As a young(er) developer, I made this classic developer mistake. I used to have ‘test’ databases set up that would allow me to insert / update / delete / get data in a manner that allowed my unit tests to run. In my defence, in 2007 RhinoMocks was about the only semi mature mocking framework I had encountered and you had to ‘record’ and ‘playback’ items through your tests. I was also still stuck in the realms of happily using static methods, little in the way of interfaces and had never really considered automated unit testing in any kind of serious manner. So, this in mind I failed to understand that by testing that I could get / set a value in the database I was in fact INTEGRATION not unit testing.
It is important to understand at this juncture that integration testing is / should also be considered as a valid and valuable way of testing your codes behaviour, and sometimes provides great insight into how third party api’s do behave. This can also be particularly of use when performing upgrade between versions of these api’s. Lucinq for example consists of more integration than unit tests as it is an api designed with more or less the sole purpose of driving lucene.net in a less verbose manner. Many of the tests therefore are ‘create a term query using the raw lucene api, do the same thing lucent, compare them’. Without this testing, I would have broken the API countless times, and in upgrading (as Sitecore did) from 2.9.4.1 to 3.0, I would have broken it further.
So – simply put, if you are calling something / getting something from Sitecore, reading values from its context / settings / factory. You are almost certainly in the realms of integration testing NOT unit testing. With this in mind :-
You can’t unit test with Sitecore
YES YOU CAN! It does however require a little in the way of abstraction & thinking out of the box.
Take the context example above – you want to get the current language? Create yourself an interface (and therefore concrete), use the Dependency Inversion Principle to inject this as a constructor parameter into your code.
public interface IContextRepository { string Language { get; set; } }
Using any reasonable mocking framework you can then inject a mocked version of this object into you code and take control of the Language property, allowing you to return a valid string, an empty string, null. In doing so you allow yourself to test the codes behaviour in these scenario’s. For example – you may want to explicitly throw an exception, you may want it to log the error but carry on, you may just want it to drop out gracefully returning a null, you may even want it to (dare I say it) assume that we are all English speakers. The point is….. YOU CAN TEST IT.
It takes too long to unit test with Sitecore
It takes a little longer sure (my estimate is 10 – 15% for an experienced TDD aware developer), but the dividends for example on the project I am working on right now are already paying off. Code that was written 8 – 10 months ago has stood up to all of the real world scenario’s we have thrown at it and in many cases IMPROVED SIGNIFICANTLY due to additional test scenario’s being written and therefore better tested. We have (as is the case with many developments) refactored sections several times throughout the course of the process, we have made the build go ‘red’ several times by doing something stupid. This for my mind at least signifies the number of times that experienced Sitecore developers (the least experienced in the current team has being using Sitecore for 4 years) would have potentially sent code to production that would have broken existing functionality.
The largest number of bugs / issues that have been raised in the current development by the content editors have generally been either a) configuration related (which I admit is harder to test – things like indexing settings does have to be manual) or b) code without unit tests. Point a) is a necessary evil and a part of what we get paid to do, we reduce it as much as possible, but Sitecore is a big old beast. Point b) SHOULD VIRTUALLY NEVER HAPPEN!!!
The better than before paradigm – ‘it has never been tested’
Man – this one really winds me up…. I get the response of ‘that is how it has always been’. Then why the hell aren’t you using classic asp!!
Yes, I get it wasn’t tested before and of course – yes, I get that it is a pain in the ass to test it now, so consider this:
- You have an existing codebase with 0 tests
- You add 1 test
- You now have a an existing codebase with 1 test
This as a minimum gives you:
- An existing codebase with more tests than it used to have
- A better understanding of what this existing codebase is doing
- A better chance of refactoring that code in the future
These tests in many cases MIGHT WELL be integration tests as unit tests would prove too costly or dangerous, but it still maps the behaviour.
Something that I either a) figured out or b) heard from a presenter at a UK Sitecore Technical Users Group (Lee Cook from Aqueduct I believe) was the idea that you could implement the following code coverage metric, it is surmised by the following statement.
‘Our code coverage policy is not a finite value, merely a value that is equal or greater than the last release.’
This means looking at the above, my code coverage percentage may be only 0.1%, but it is still in fact .1% better tested and understood than the time we released it before. Sometimes this may be using something like the [ExcludeFromCodeCoverage] attribute or whatever to give a positive indication that this code would be uneconomical to test. This in itself a) improves your code coverage metric and b) gives you touch points and identifies code smells that you could hopefully devise a way to refactor out in time.
Eventually of course you may reach a logical plateau, but the fact is that if that plateau is even at 30%, that’s still A LOT better than when you started.
Of course on new developments you should give more of a finite value.
It hurts at first
I would grant any developers beginning their journey of discovery into TDD that it seems painful. It’s painful to realise that so many of your regularly coding practices make for rigidity in your code and that in some cases your knowledge was not as great as you thought. It’s often therefore painful to change your (ego,) mindset and practices to use dependency injection, mocking, the test frameworks, code coverage tools etc. As with any change, it’s oh so easy to label it as too complex or not worthwhile or too costly.
Conclusion
I guess in most cases when you are looking at TDD, 9 / 10 times you look at tests as too tough, it’s because your code isn’t up to the task. It’s a bitter pill and one that when you swallow will often allow to move on to better more tested code.
In the next post – I will take a look at strategies for testing your codebase.
Related Posts
Don’t Fight The Framework Series
