I'm using Simple Injector and using pretty advances registrations techniques and may use some of the extension points for even more advances registrations (see motivation below). This has raised the need to write unit tests that verify the container is bootstrapped correctly. For example, assumes types A1
& A2
have dependency on service B
which is implemented by both C1
and C2
, such that A1
should be injected with C1
and A2
should be injected with C2
. I'd like to write a test that verifies that A1
is injected with C1
when resolved and A2
is injected with C2
. While I could expose public properties for all injected services from A1
and A2
to verify their types in a test, I rather not do it just for the sake of testing. Is there a simple API to test how an object graph would be resolved, perhaps something based on the Diagnostics API which seems to do the same for the purpose of debugging views?
Motivation: the motivation behind the advances registrations is implementing design and architectural decisions by substituting/decorating injected services based on the injection context. This has served me really well in keeping the application code simple and testable, putting all the "if-then-else" complexity in the container registrations level, and keeping application code truly SOLID while making changes almost solely to the container registrations. The idea is inspired by .NET Junkie's posts about commands & queries and the usage of decorators, and the capability to apply certain decorators based on compile-time or run-time context, which is really powerful and useful for a SOLID design.
Is there a simple API to test how an object graph would be resolved, perhaps something based on the Diagnostics API which seems to do the same for the purpose of debugging views?
Yes there are several ways to do this. Two options that come to mind are the VisualizeObjectGraph
and GetRelationships
methods on InstanceProducer
. Both allow visualizing object graphs. GetRelationships
gives you a structured graph that you can iterate over, while VisualizeObjectGraph
returns the object graph in a string format, close resembling C#.
Example:
var container = new Container();
// Do registrations
// You need to verify to get the correct output of those methods
container.Verify();
var r = container.GetRegistration(typeof(A1));
Console.WriteLine(r.VisualizeObjectGraph());
This outputs something like
A1(
FileLogger(
Dependency1(),
Dependency2()),
C1(
Dependency1(),
SomeService()));
When using the GetRelationships()
you can recursively iterate through the graph and check if the given type is a (sub) dependency of the registration.
Example:
// Useful extension method
private static IEnumerable<InstanceProducer> GetDependencies(this InstanceProducer p) {
foreach (var r in p.GetRelationships()) {
yield return r.Dependency;
foreach (var d in r.Dependency.GetDependencies()) {
yield return d;
}
}
}
var container = new Container();
// Do registrations
// You need to verify to get the correct output of those methods
container.Verify();
var deps = container.GetRegistration(typeof(A1)).GetDependencies();
Assert.IsTrue(deps.Any(p => p.Registration.ImplementationType == typeof(C1)));
Do note though that I think you should limit these kinds of registration checks as much as possible, because: