When using Ninjects ConstructorArgument you can specify the exact value to inject to specific parameters. Why can't this value be null, or how can I make it work? Maybe it's not something you'd like to do, but I want to use it in my unit tests.. Example:
public class Ninja
{
private readonly IWeapon _weapon;
public Ninja(IWeapon weapon)
{
_weapon = weapon;
}
}
public void SomeFunction()
{
var kernel = new StandardKernel();
var ninja = kernel.Get<Ninja>(new ConstructorArgument("weapon", null));
}
Looking at the source (and the stack trace I got by reproing which you omitted :P)
This is because it's binding to a different overload of the ConstructorArgument
ctor than the normal usage (i.e., where you're passing a Value Type or a non-null Reference Type) does.
The workaround is to cast the null to Object:-
var ninja = kernel.Get<Ninja>( new ConstructorArgument( "weapon", (object)null ) );
Ninject 2 source:
public class ConstructorArgument : Parameter
{
/// <summary>
/// Initializes a new instance of the <see cref="ConstructorArgument"/> class.
/// </summary>
/// <param name="name">The name of the argument to override.</param>
/// <param name="value">The value to inject into the property.</param>
public ConstructorArgument(string name, object value) : base(name, value, false) { }
/// <summary>
/// Initializes a new instance of the <see cref="ConstructorArgument"/> class.
/// </summary>
/// <param name="name">The name of the argument to override.</param>
/// <param name="valueCallback">The callback to invoke to get the value that should be injected.</param>
public ConstructorArgument(string name, Func<IContext, object> valueCallback) : base(name, valueCallback, false) { }
}
Repro:
public class ReproAndResolution
{
public interface IWeapon
{
}
public class Ninja
{
private readonly IWeapon _weapon;
public Ninja( IWeapon weapon )
{
_weapon = weapon;
}
}
[Fact]
public void TestMethod()
{
var kernel = new StandardKernel();
var ninja = kernel.Get<Ninja>( new ConstructorArgument( "weapon", (object)null ) );
}
}
Lesson? You'd be crazy not to download the latest source and look at it. Great comments, nice clean codebase. Thanks again to @Ian Davis for that tip/prodding!
I don't know Ninject, but AFAIK constructor injection is commonly used for mandatory dependencies and thus null makes little sense in this context. If the dependency is not mandatory the type should provide a default constructor and use property injection instead.
This post provides additional info.
I want to use it in my unit tests
There is no need to use an IOC container for unit tests. You should use the container to wire you application together at runtime, and nothing more. And if that begins to hurt, its a smell indicating your class is getting out of hand (SRP violation?)
Your unit test would then be in this example:
var ninja = new Ninja(null);
The above is legit C# code, and passing a null reference for unit testing is a perfectly valid way of unit testing areas which don't need the dependency.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With