There are a lot of different ways to do mocking in .NET unit tests, from writing your own mock interface implementations to fully built out commercial frameworks like TypeMock. The Moles Isolation framework from Microsoft Research offered some intriguing possibilities but as a research project has never had the same level of support as a full product. Now the Moles concepts and much of the usage syntax have shown up in the Visual Studio 11 beta renamed as Fakes.
The first step in using Fakes is to add a reference to the new Microsoft.QualityTools.Testing.Fakes assembly in your unit test project. This reference can also be added for you automatically when you create a Fakes assembly for the first time. A Fakes assembly is a generated helper assembly that contains all of the shim and stub types for a referenced assembly which can then be used in tests. Right-clicking any assembly in your test projects References should show the new “Add Fakes Assembly” option, which will create the assembly and a .fakes configuration file which can be used for customization of the generation and behavior of the assembly’s Fakes.
Once Fakes have been created for an assembly, two new types of objects are available to use in your tests: Stubs for interfaces, and Shims for classes.
A Stub provides an empty implementation of an interface into which you can inject delegates for individual properties and methods as needed. Stub types are named the same as the original interface with Stub prepended and exist in the original namespace with an extra .Fakes added at the end. Delegates can be provided for any methods of properties that need to be used in the test. Options also exist to automatically wire up property backing fields and to return default values or throw NotImplementedExceptions from any members which have not been otherwise hooke up. This example passes a shim object to a View Model that requires a non-null Name and wraps the Description of the IParameterObject passed to it. Other interface members will return default values.
[TestMethod] public void CreateVmFromInterface() { const string text = "Hello"; var contextObject = new StubIParameterObject { DescriptionGet = () => text, NameGet = () => String.Empty }; contextObject.BehaveAsDefaultValue(); ContainerViewModel target = new ContainerViewModel(contextObject); Assert.AreEqual(text, target.Description); }
For mocking of objects that don’t use interfaces, Fakes use Shim objects to replace usages in the same basic way as Stubs. When using a Shim an additional step of setting up a ShimsContext to allow the Fakes framework to work properly. ShimContext.Create() returns an IDisposable so the easiest way to use it is to wrap your test code in a using block. This example uses a Shim in the same way as the previous example. The BehaveAsDefaultValue option is available here as well but is not used as all necessary properties have Get delegates set explicitly.
[TestMethod] public void CreateVmFromObject() { const string text = "Hello"; using (ShimsContext.Create()) { var contextObject = new ShimParameterObject(); contextObject.NameGet = () => String.Empty; contextObject.DescriptionGet = () => text; contextObject.IdGet = () => 5; ContainerViewModel target = new ContainerViewModel(contextObject, true); Assert.AreEqual(text, target.Description); } }
Most of what Stubs and Shims can do with instances can be done by most mocking frameworks (in some cases requiring virtual members) but where Fakes really stands out is what it can do with multiple instances and static members. To provide a delegate for a member on all instances of a Shim type, the AllInstances static property on any Shim Type can be used.
[TestMethod] public void GetTotalAgesVariable() { const int otherChildCount = 6; const int individualAge = 22; var target = new SomeDataObject(); using (ShimsContext.Create()) { target.MainChild = new ShimChildDataObject(); foreach (ShimChildDataObject item in Enumerable.Range(0, otherChildCount).Select(i => new ShimChildDataObject())) { target.OtherChildren.Add(item); } // All items added above will now get the same birth date ShimChildDataObject.AllInstances.BirthDateGet = _ => DateTime.Today.AddYears(-individualAge); Assert.AreEqual(individualAge * (otherChildCount + 1), target.TotalAges); } }
Replacing static members works similarly to instance members but delegates are statically applied to the Type. A canonical example is replacing DateTime.Now to run a test as though on a fixed date. In this case I chose Add Fakes Assembly for the System reference, which fakes both System and mscorlib.
[TestMethod] public void CheckFixedDate() { using (ShimsContext.Create()) { ShimDateTime.NowGet = () => new DateTime(1776, 7, 4); Assert.AreEqual(1776, DateTime.Now.Year); } }
In case you need to execute part of a test without using the Shim delegates you have set up, ShimsContext also includes an ExecuteWithoutShims method which takes a Func or Action to be run as normal.
Product comparison shows that Fakes are only available in Ultimate edition of VS2012. [http://www.microsoft.com/visualstudio/11/en-us/products/compare](http://www.microsoft.com/visualstudio/11/en-us/products/compare) Just expand the “Testing Tools” section.
Pingback: How do I add a fakes assembly in VS 2012 Professional RC? | Ask Programming & Technology