This might be a bit of a painful post for some people. Episerver CMS has made amazing progress in the last few years towards creating a platform that is very easy to unit test. Episerver Commerce is making baby steps towards this goal as well, but it's very far behind. Before we start going into the how of unit testing commerce.. the big issue is the time. It is definitely possible to unit test a lot of commerce; the big problem is time. Depending on the level of cover you want unit tests to reach, be prepared to have to have to write a lot extra code to make certain features testable. I'll go over the Wrapper pattern that you will get to know VERY well while testing commerce, but to forewarn you now, you'll be creating a lot of extra code around these areas:
- Cart Helper
- LineItem Collection
- Customer Contact
So be pre-warned, you will be creating a few extra 1000's of lines of code to get commerce unit testable. If you have very tight deadlines, you may want to consider the amount of resource you'll need to throw at the problem, as I would estimate it will add on a good 2 weeks. Before we get started, you'll need to understand what a wrapper class is.
A wrapper class is a facade over an existing class, forwarding all of the base classes underling methods and properties into a new interfaced based class. You can then test against your new interface class , where the previous commerce code would just throw an exception. I'll demonstrate a quick example:
The above code is very brief but it will help explain the point. We have a class OldClassWithNoInterface that when you try and call it under test conditions, will throw an Exception. Don't ask why, but in commerce a lot of the base class will throw exceptions when you try and even check if a property is null.
If you are trying to test some code, you either have to wrap your code around a try/catch and ignore the Exception, which isn't ideal for production code, or, you need to break the dependency to commerce and wrap it into a new class that can be mocked, allowing you to test your code. This is where our new WrapperClass comes into play.
The wrapper shouldn't have any logic or do anything except forward and retrieve information from the base class. Your new wrapper class should have an interface defining all the methods and properties it's doing the forwarding/retrieving for. In the class you are trying to test, you inject using StructureMap or whatever DI container you want, to pass in your Wrapper Interface via the constructor, you then get rid of the dependency on the commerce object that will cause your unit test to fail, so you can carry on testing your original bit of code without commerce throwing an exception.
The process is fairly simple, the problem comes when you're working with objects that you need to wrap 40-50 things, then times that by 9 or 10 objects and you a have lot of time wasted just to make commerce testable. Take a real life example, I'm going to use the Payment class.
This wrapper only wraps a very small portion of the payment class, it takes in the payment class and stores it as a private instance variable. We then expose the Parent method that simply forwards on and returns a request to the base Parent property. We then create our own PaymentWrapper interface
Now let's pretend we have a class called ProcessPayment that needs to get a payments Order History; we would inject the wrapper via the constructor so it can be tested.
What we're doing here is passing in the wrapper so we can swap it out under test. In this example 'Parent' would throw an exception if it was called directly. We can then swap the call out to Payment so our unit test runs as expected.
Ok, so by now you should have a basic understanding of how to unit test commerce. You may be thinking, that was a lot of code just to test a singe line of code and I completely agree with that thought. Unfortunately, with the commerce API in it's current state, there is no getting around having to write all this wrapper code if you want to unit test your code. What are your thoughts on this process? Have you tested commerce in a different way or have you got stuck trying to test something yourself? Leave your thoughts in the comments section below.