In this blog post of the series I am going reproduce the same test scenarios as shown in my last blog post. Only this time, I will not modify the initial source code to make it testable but instead use the Fakes Framework Shims to test it as it is.
Fakes Framework Sims
Note that Shims get generated the same way as Stubs and that they can also be restricted by applying filters in the SampleCode.fakes xml file.
The internal mechanisms are however quite different and innovative. They even differ from other existing mocking frameworks. So how does it work ? In fact, original method calls are intercepted and redirected at runtime to the methods that are defined in the associated Shims.
In our example, we are able to redefine the calls to the methods that are tightly coupled to external sources without any actual code modifications. As you might remember, the concerned methods are IsValid(…) and Save(…).
The first test could be expressed as follows when using Shims :
Here is an explanation of the unit test code for the example above using Shims :
- We use a ShimsContext in a using block to limit its lifetime and to dispose it correctly. All calls to the IsValid(…) and SaveDeal(…) methods are only redirected if they are declared within the using block.
- We do not use proxy classes anymore, instead we use the code that is implemented in the DealRepository constructor. However, we have to redefine the constructor code because in the original code we return an exception (see previous blog post of the series).
- Methods can be “replaced” by other methods. Those replacement methods have an additional parameter, when compared to the original method. This parameter defines the instance of the object that undergoes the redirection.
- The result is that the initial code has not been modified but we were able to isolate and test the TrySave(…) method nonetheless.
I would like to add that Shims can also be used for static classes, sealed classes, generics, etc.. as easy as I have shown above. You can even generate them for standard .NET framework classes, such as System.DateTime and System.Configuration.ConfigurationManager for example (with the exception of the classes that are in “mscorlib” and “system”). This allows for some really powerful use cases.
Conclusion
The example has shown that using Shims for your unit tests is easier and quicker compared to Stubs. There are no software design requirements so it seems the preferable solution. But it has its drawbacks ! You miss the opportunity to improve your code. One of the main advantages of TDD gets lost: refactoring you code to produce good quality code.
So refactor your code and use Stubs whenever possible. If you cannot modify your code (you have legacy code) or if you need to mock .NET Framework.classes use Shims. The Fakes Framework is the only unit test framework that provides both approaches at the same time. This is a real advantage when compared to RhinoMock or MoQ.
1 comment:
Hi !
Good article.
Some points bother me.
First, I agree that stubs are better. What I dislike is that I don't believe a test framework (or mocking frmwk) should be intrusive and force you to modify your code... Even though it makes your code better !
So I'd say : refactor your code and use stubs if you think it will make your design better.
Second, I feel that the introduction of shims by Microsoft can be dangerous. I feel it could be used to hack other assemblies... but I can't prove it, and I believe Microsoft put barriers against this.
bblmr
Post a Comment