如何用MS Fakes模拟无公共构造函数的抽象类(如ToolStripItem)?
Great question! This is a common pain point when working with MS Fakes and abstract classes like System.Windows.Forms.ToolStripItem that lack public constructors—especially when your test assembly doesn't have any existing subclasses to reuse. Here are a few clean, generic workarounds that avoid writing one-off test subclasses:
1. Use FormatterServices.GetUninitializedObject to Create an Uninitialized Instance
The System.Runtime.Serialization namespace has a handy method that lets you create an object instance without calling any constructor—perfect for abstract classes that you can't instantiate normally. Here's how to use it:
First, add a reference to the System.Runtime.Serialization assembly in your test project, then use this code:
using System.Runtime.Serialization; // Create an uninitialized ToolStripItem instance (no constructor runs) var toolStripItemInstance = (ToolStripItem)FormatterServices.GetUninitializedObject(typeof(ToolStripItem)); // Pass it to the Shim constructor var shimItem = new ShimToolStripItem(toolStripItemInstance);
Note: This method leaves all fields at their default values (null for reference types, default value for value types), but since Shim intercepts all method and property calls, the original instance's state doesn't matter at all. It's just a placeholder to satisfy the Shim's constructor requirement.
2. Combine Stub and Shim for Easier Mocking
MS Fakes generates both ShimX and StubX classes for abstract types. StubX is designed specifically to mock abstract classes/interfaces—it automatically implements all abstract members with default behavior, and you don't need an existing instance to create it. You can pass a Stub instance directly to the Shim constructor to get the best of both worlds:
// Create a StubToolStripItem (automatically implements all abstract members) var stubItem = new StubToolStripItem(); // Wrap it in a Shim to override specific methods/properties as needed var shimItem = new ShimToolStripItem(stubItem);
This is my go-to approach for most cases because it's built into MS Fakes, no extra dependencies, and you only need to override the members you care about in the Shim.
3. Use a Dynamic Proxy Library to Generate a Temporary Subclass
If you want even more flexibility (or don't want to rely on MS Fakes' Stub system), you can use a dynamic proxy library like Castle DynamicProxy to generate a subclass of the abstract class on the fly. Here's how:
- Install the
Castle.CoreNuGet package in your test project. - Use this code to create a dynamic instance:
using Castle.DynamicProxy; var proxyGenerator = new ProxyGenerator(); // Dynamically generate a subclass of ToolStripItem and create an instance var dynamicInstance = proxyGenerator.CreateClassProxy<ToolStripItem>(); // Pass the dynamic instance to the Shim constructor var shimItem = new ShimToolStripItem(dynamicInstance);
This works for any abstract class, regardless of constructor access modifiers, and you can add custom interceptors if you need to handle specific member calls before the Shim does.
Quick Notes
GetUninitializedObjectis great for a no-dependency solution, but avoid using it for types that rely on constructor logic to function properly (though this isn't an issue for Shim scenarios since all calls are intercepted).- If you only need to mock the abstract class's contract (and not intercept existing instance calls), using the Stub class alone might be sufficient—you don't even need the Shim in that case.
内容的提问来源于stack exchange,提问作者Konstantinos Papakonstantinou

