Thu Feb 18 2010
I have an xunit test project that is using hand-rolled stubs as concrete implementations of interfaces. StructureMap is the DI container I'm using. I was looking at the names of my stubs, and they followed the convention of TestXYZ as the concrete implementation of IXYZ.
To use StructureMap from xunit tests, I created a base class for any fact class that wanted to use ObjectFactory. In the base class ctor, I call the bootstrapper's ConfigureStructureMap method.
At first I just had a bunch of
x.ForRequestedType<IXYZ>().TheDefaultIsConcreteType<TestXYZ>();
because I had only a handful of stubs and I didn't quite grasp how to scan like the default scanner, only adding "Test" to the beginning of the class name.
Then I found the secret sauce over here, via a method called FindPluginType.
Here is my bootstrapper code for my xunit test project:
public class TestScanner : ITypeScanner{
public void Process(Type type, PluginGraph graph) {
if(type.Name.StartsWith("Test")){
var pluginType = FindPluginType(type);
if(pluginType == null)
return;
graph.AddType(pluginType, type);
}
}
static Type FindPluginType(Type concreteType) {
var interfaceName = "I" + concreteType.Name.Replace("Test", "");
return concreteType.GetInterfaces().Where(t => string.Equals(t.Name, interfaceName, StringComparison.Ordinal)).FirstOrDefault();
}
}
public static class Bootstrapper {
public static void ConfigureStructureMap() {
ObjectFactory.Initialize(x =>
{
x.Scan(s =>
{
s.TheCallingAssembly();
s.WithDefaultConventions();
s.With<TestScanner>();
});
});
}
}
What results is essentially the DefaultConventionScanner, only it's looking for TestXYZ as the concrete implementation of IXYZ.
Killer.