When doing unit testing, one always comes to a point where there this “kind of hard” part to test since the part depends on something you might not have control over or depends on the functionality of the dependency to complete.
In “Working Effectively with Legacy Code” by Michael C. Feathers talks about a dependency breaking technique called “Extract and Override” which is also in Roy Osherove book “Art of Unit Testing“.
The basic technique is quite simple and quite powerful as Roy puts it
“Extract & Override is a very powerful technique because it lets you deal directly with replacing the dependency without going down the rabbit hole at all (changing dependencies deep inside the call stack). That makes it very quick and clean to perform, almost to the point where it corrupts your good sense of object oriented aesthetics, leading you to code that might even have less interfaces but more virtual methods.” (Art of Unit Testing, pg.50)
In this post I am going to show a simple example of how to use the extract and override method, lets say for example you have an Order Class and it has a dependency call User as shown below
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public class Order { private User user; public Order() { _user = new User(); } public bool Add() { if(_user.ValidUser) { //do something return true; } else { //dont add send an exception and log it return false; } } } |
For us to test out the Add method we have a dependency that calls and checks if the user is valid, this basically makes it pretty hard to test, unless you refactor your code to use an interface IUser, pass it in the constructor and mock the user with a Mocking Framework or hand write the stub but lets say you don’t have access to User or some other reason that there will not be a setter for ValidUser on the user object for some reason (security comes to mind). [Although using an interface IUser would be a better design]
This can be one of the reason where some people quit unit testing since it just makes it hard to test but there is a way to test and it is quite simply. The way to do it is actually by extracting the dependency, since to us we don’t really care about the user and we want to test the Add functionality only to see if things are working properly. Let see how we do it
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
public class Order { private User user; public Order() { _user = new User(); } public bool Add() { if(CheckValidUser()) { //do something return true; } else { //dont add send an exception and log it return false; } } protected virtual bool CheckValidUser() { return _user.ValidUser; } } |
We introduced a virtual method called CheckValidUser so that we can override it. Now for our stub we can simply override the method so that it always returns what we want it to
1 2 3 4 5 6 7 8 |
public class StubOrder: Order { public bool myBool = true; protected override bool CheckValidUser() { return myBool; } } |
And finally for our unit testing we can write something like
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
[Test] public void Add_Should_Fail_And_Return_False_When_User_Is_Not_Valid() { Order o = new StubOrder(); o.myBool = false; Assert.That(o.Add, Is.False); } [Test] public void Add_Should_Pass_And_Return_True_When_User_Is_Valid() { Order o = new StubOrder(); o.myBool = true; Assert.That(o.Add, Is.True); } |
There are definitely better ways to design this class by using interface IUser, dependency injection frameworks and mocking frameworks to ease the testing, but those methods would be mentioned later in my blog. Hope you enjoyed the read 🙂
Taswar
[…] lately reguarding testing and unit test practices. One I ran across this morning entitled “Extract and Override refactoring techinque” caught my eye on Taswar Bhatti’s […]
[…] also great methods for developing unit tests against legacy code in object-oriented languages: Â extract-and-override, creating interfaces and using an isolation framework, etc. Â The point of these methods is […]
[…] did not touch on some legacy-code classics such as extract-and-override to isolate a dependency that makes a class hard to test, a technique I rely upon heavily as an […]