With Orcas and TypeMock 4.1 you can now mock Extension methods, easily.
Suppose we added a new method to int that return the Roman Number equivalent of that number:
public static class Extend { public static string RomanNumber(this int number) { // do complex logic return romanString; } }
Now we use this method in our code
string romanNumber = 2010.RomanNumber();
Here is how we mock this.
Reflective Mocks (Community Edition)
We mock that actual static extension method
Mock extentionMethodMock = MockManager.Mock(typeof(Extend)); extentionMethodMock.ExpectAndReturn("RomanNumber","MCMLIX");
Natural Mocks (Professional Edition)
We just call the extension method
using (RecordExpectations rec = new RecordExpectations()) { rec.ExpectAndReturn( 2010.RomanNumber(), "MCMLIX"); }
Checking Arguments
Care should be taken when Checking Arguments as the first argument is the instance of the type we are extending, suppose the extension method takes another argument
public static class Extend { public static string RomanNumber(this int number, bool upperCase) { // do complex logic return romanString; } }
Here is how we validate the arguments.
Reflective Mocks (Community Edition)
We have to implicitly ignore the first argument
// first arg is instance, second must be false Mock extentionMethodMock = MockManager.Mock(typeof(Extend)); extentionMethodMock.ExpectAndReturn("RomanNumber","MCMLIX"). Args(Check.IsAny(),false);
Natural Mocks (Professional Edition)
TypeMock automatically handles the first argument
using (RecordExpectations rec = new RecordExpectations()) { // TypeMock knows that this is an extension method and ignores first
// argument automatically rec.ExpectAndReturn( 2010.RomanNumber(false), "MCMLIX") .CheckArguments(false); }
It’s clever that you can do this, but I think anyone who feels they need it should reconsider their design.
Test an extension method directly, sure, but if the functionality is so significant as to warrant mocking then it should be a dependency and not an extension.
I don’t follow your logic Peter,
There is a huge difference between good design and functionality that you need to isolate.
example – suppose we have an extension method on DateTime that returns IsLeapYear.
This is good design as the code is readable sleek and maintainable, we can now use:
time.IsLeapYear()
instead of Utils.IsLeapYear(time)
Now, there is a HUGE CASE for isolating this code – when we want to simulate a LeapYear.
Also see http://www.elilopian.com/2008/04/29/understanding-mock-objects-better-design/