Extract and Conquer!
..Or ‘Extract and Override’ as it’s otherwise known
Not that it’s specific to CRM, or any particular type of development – indeed, Roy states that he always tries to use this technique first and only defers to other methods of testing if it isn’t possible. I had certain reservations when I first read about it, but having given it a try over the last few weeks I am now a convert.
The purpose of this technique is to insert a ‘seam’ into your code – a place where you can replace dependencies on other classes & services with fake versions, so you can test one class at a time. Previously, I’d always done this using constructor injection, whereby you pass the dependencies into the class constructor:
This way, when we want to test the robot mood logic in KillHumans(), we can create fake versions of IWeaponSystem, ICommunication and IMoodManager, and just test the Robot logic. In the actual system, the real versions of these things would be supplied by a Service Locator/IOC container or similar.
This is all very well, but doesn’t work with CRM because you don’t control creation of classes. Basically you get passed a service and have to use that for all of your communication with CRM. To stay with the robot example, it would look something like this:
Because all communication is going through RobotService.Execute(), it’s very difficult to fake this, especially when it’s called multiple times and you need different return values.
To get over this, we can use Extract and Override. This works by putting the calls to the external services in their own methods, and then overriding them while we’re testing. This way, we don’t have to create fake services at all! Just a single fake version of the class we’re testing. The code in Robot would now look something like this:
Notice that the extra methods are ‘virtual’ so we can override them. they are also ‘protected’ so they’re accessible from classes which inherit from them. So now instead of creating fake services, we’d create a testable version of the robot class, like this:
We now have full control over what gets returned from those methods, and we can record when got sent into them. As such, we can happily test the mood logic in KillHumans() without worrying about those dependencies.
Now, this isn’t limited to the CRM situation described – you can use this technique any time you have a dependency on another service, as an alternative to Dependency Injection. You can read a bit more about it in one of Roy’s blog posts, which probably explains it a bit better! Although sadly without the use of robots.