I've found really useful to test our IoC container to make sure that all the components that are registered can be resolved.
This is the way I usually test my Ninject container
The model
so let's say that we have the following model:
public interface ICommand { }
public interface ICommandHandler<in T> where T : ICommand
{
void Handle(T command);
}
public class DeploySqlScriptsUsingAGlobalTransactionCommand : ICommand
{
public DeploySqlScriptsUsingAGlobalTransactionCommand(IEnumerable<string> scripts)
{
Scripts = scripts;
}
public IEnumerable<string> Scripts { get; private set; }
}
public class DeploySqlScriptsUsingAGlobalTransactionCommandHandler :
ICommandHandler<DeploySqlScriptsUsingAGlobalTransactionCommand>
{
private readonly IScriptDeployerService _scriptDeployerService;
public DeploySqlScriptsUsingAGlobalTransactionCommandHandler(IScriptDeployerService scriptDeployerService)
{
_scriptDeployerService = scriptDeployerService;
}
public void Handle(DeploySqlScriptsUsingAGlobalTransactionCommand command)
{
//shalalalalal
command.Scripts.ToList().ForEach(_scriptDeployerService.Deploy);
Console.WriteLine("Scripts deployed");
}
}
public interface IScriptDeployerService
{
void Deploy(string script);
}
Note that we don't have a concrete implementation of IScriptDeployerService
The test
So we create this test to make sure that the container is valid:
[TestMethod]
public void it_should_resolve_all_registered_components_in_the_container()
{
#region Binding container
var kernel = new StandardKernel();
kernel.Bind(config =>
{
config.FromThisAssembly()
.SelectAllClasses()
.BindAllInterfaces();
});
ServiceLocator.SetLocatorProvider(() => new NinjectServiceLocator(kernel));
kernel.Bind<IServiceLocator>().ToConstant(ServiceLocator.Current);
#endregion
#region Testing container
var field = typeof (KernelBase).GetField("bindings",
BindingFlags.Instance | BindingFlags.NonPublic);
field.Should().NotBeNull();
var bindingsMap = field.GetValue(kernel) as Multimap<Type, IBinding>;
bindingsMap.Should().NotBeNull();
bindingsMap.Should().NotBeEmpty();
var locator = ServiceLocator.Current.GetInstance<IServiceLocator>();
locator.Should().NotBeNull();
bindingsMap.SelectMany(x => x.Value).ToList()
.ForEach(binding => ServiceLocator.Current.Invoking(instance =>
{
var services = instance.GetAllInstances(binding.Service);
services.Count().Should().BeGreaterOrEqualTo(1);
if (services.Count() == 1)
{
instance.GetInstance(binding.Service);
}
}).ShouldNotThrow());
#endregion
}
The error
When we run the test we receive the following error from Ninject:
Result Message: Did not expect any exception, but found Ninject.ActivationException with message "Error activating IScriptDeployerService No matching bindings are available, and the type is not self-bindable. Activation path: 2) Injection of dependency IScriptDeployerService into parameter scriptDeployerService of constructor of type DeploySqlScriptsUsingAGlobalTransactionCommandHandler 1) Request for ICommandHandler{DeploySqlScriptsUsingAGlobalTransactionCommand}
Very explicit
The fix
So now let's fix it:
Let's add the missing concrete implementation:
public class ScriptDeployerService : IScriptDeployerService
{
public void Deploy(string script)
{
Console.WriteLine("Script deployed: {0}", script);
}
}
The result
And now our test pass =) Awesome
No comments:
Post a Comment
If you found this post useful please leave your comments, I will be happy to hear from you.