Proper unit testing involves identifying the smallest pieces of testable code and ensuring that they function properly. Testing these units effectively generally requires somehow isolating them from the rest of the code base. There are a number of frameworks that help with this isolation but the Fakes isolation framework goes beyond interfaces and virtual methods by allowing us to detour any framework method. In this session we’ll explore how stubs and shims can help us isolate testable units regardless of whether we control the dependencies.
4. Inheritance based
Used when testing a defined contract
5. Let me start by saying Shims are evil. But they are
evil by design. They let you do things you otherwise
couldn’t do, which is very powerful. They let you do
things you might not want to do, and might know
you shouldn’t do, but because of the real world of
software, you have to do.
Peter Provost
Program Manager Lead
Visual Studio ALM Tools
6. Use a profiler to rewrite existing method
bodies
Detour virtually any .NET method
Performance issues due to the profiler
7. No additional installation required
Isolation type generation driven by .fakes file
Microsoft.QualityTools.Testing.Fakes
assembly/namespace
8. Delegates are used to provide the faked
functionality
Custom delegate types including support for
out and ref parameters
Static class:
Microsoft.QualityTools.Testing.Fakes.FakesDelegates
10. Isolation types are placed in a .Fakes namespace
Stub types are prefixed with “Stub”
Shim types are prefixed with “Shim”
Method parameter types are appended to the
method name
“Get” or “Set” is appended to property names
Setters also include parameter type names (like
methods)
Generic type arguments are appended to the
method name for generic methods
Constructors have parameter type names
appended to “Constructor”
11. Assign a delegate to the field that
corresponds to the member being isolated
12. Same process as methods
Get and Set can be assigned individually
AttachBackingFieldTo[PropertyName]
convenience method
13. The framework generates a public method to
invoke events
[EventName]Event
14. Allow calling the base implementation when
a delegate is not set for a member
15. Control what happens when a delegate has
not been provided for a member
Set through the InstanceBehavior property
16.
17. Shim properties for static members are static
on the shim type
Static AllInstances property for applying
delegates to all instances of the shim type
Instance properties for applying delegates to
a single instance
18. ShimsContext
Sets up the shim under the IntelliTrace profiler
ShimsContext.Create()
19. Events don’t have a method to invoke
Properties representing the Add and Remove
operations are provided instead
Base type members aren’t directly accessible
Static constructors are “shimmable”
Bind method for each interface implemented
by the shimmed type
Behaviors are controlled by ShimBehaviors
20.
21. Controlling Type Generation
Strong Name Signing
22. Generating the isolation types is expensive
and will extend build time
Configure through the .fakes file
Filtering
23. Attribute Type Stubs? Shims?
AbstractClasses Boolean
FullName String
Interfaces Boolean
Namespace String
Obsolete* Boolean
TypeName String
* Applies only to Remove elements
24. ! forces an exact, case sensitive match
* matches the beginning of the string
25. Fakes assemblies will be signed with the
same key as the underlying assembly unless
otherwise specified
Compilation element’s KeyFile attribute in
.fakes file
26. Beware the Docs!
Notable Changes from Moles
27. Configured through .fakes file rather than .moles
Namespace and assembly are .Fakes rather than
.moles
Mole types are now shim types
Stub prefix is “Stub” rather than “S”
Shim prefix is “Shim” rather than “M”
ShimsContext replaces HostTypeAttribute
Automatic properties can be isolated!
Moles allowed for erasing static constructors and
finalizers. Fakes allows shimming static constructors
but has no support for finalizers
Moles could control the bitness of the profiler
“classes” filter attribute was removed
28. Isolating Unit Test Methods with Microsoft
Fakes
http://bit.ly/KYMkyX
Moles Isolation Framework for .NET
http://bit.ly/LebqZ2
Going Underground: Microsoft Moles
http://bit.ly/y66D5C
Editor's Notes
OriginsPex & Moles from Microsoft ResearchPex dates back to at least 2007Moles dates back to at least 2009I didn’t learn about them until late 2011Tell GiveCamp storyProductization of Moles in VS2012 (Premium & Ultimate or just Ultimate?)Docs say Premium & UltimateA Connect post says Ultimate onlyIsolation FrameworkStubs and ShimsGenerated according to a .Fakes fileNo validation off its ownMoq has .Verify methodsUse whichever test framework you wantVS2012 allows running tests with any framework that has the appropriate adapterGet from extension managerMore in common with Telerik’sJustMock than anything else
InterfacesVirtual members of non-sealed classesNative implicit substitutionStubbed concrete classes derive directly from the stubbed typeStubbed interfaces derive from StubBase<T> and implement the stubbed interface
No support for interfaces or abstract members (no bodies to rewrite)Favor stubs whenever possibleRequired for:Private membersStatic membersSealed types3rd Party libraries w/o a testable APIProvide an implicit conversion operator to the underlying typeAlso have a .Instance property
.fakes fileXML File (with an installed schema!)Intellisense!Add by right-clicking a reference in the project where your tests live and selecting “Add Fakes Assembly” to automatically:Create the .fakes file with the minimum XML required to identify the types that will be isolatedSet the build action for the .fakes file to Fakes (a custom MSBuild task)Generate the assembly containing the isolation typesAdd the necessary references including the newly generated assembly
Stubs expose members as fieldsShims expose members as write-only properties
Generic methods are a bit different – they’re overloaded methods rather than fields
AttachBackingFieldTo… auto-wires backing field behavior only when neither the get and set delegates have been assigned
NOTE: Be sure to make your event virtual to get this functionality
Enabled by setting the CallBase propertyOnly works with concrete types – nothing to call on interfacesCallBase isn’t even generated for interface stubs
Default behavior is DefaultValue (Docs say NotImplemented)Change the default behavior by setting the Current property on StubBehaviors
ShimsContext is requiredAlways instantiate within a using block to ensure disposal Shims are not thread-safe and if not disposed, will live as long as the AppDomain
Shims are used in roughly the same was as StubsConstructor overload to access base type members Create a shim for the child and pass it to a shim for the parentMust assign the static constructor delegate before accessing any shim memberDefault is NotImplemented
StubGeneration and ShimGeneration elementsPrevent a type’s generation entirely by setting the disabled attribute on either elementFiltering follows the familiar Clear, Add, Remove pattern
Preliminary & subject to changeAlready found some inaccuraciesDefault behavior for stubsFiltering example uses incorrect schema
HostTypeAttribute “just works” with MSTestRunnable with the Nunit console runner – good luck with the GUI