Avoiding Constructor Argument issues when using Moq, RhinoMocks and NSubstitute

Suppose you have a class without a parameterless constructor.

public class X  
{
    public X(string y){     }
}

If you try to Mock said class using Moq, NSubstitute or RhinoMocks it will throw an exception

try { new Moq.Mock<X>().Object.ToString(); } catch { /*throws InvalidProxyConstructorArgumentsException*/ }  
try { NSubstitute.Substitute.For<X>().ToString(); } catch { /*ditto*/ }  
try { Rhino.Mocks.MockRepository.GenerateStrictMock<X>().ToString(); } catch  { /*ditto*/ }  

You can avoid this by passing an object[] with values for the ctor arguemnts:

    new Moq.Mock<X>(new object[] { "" }).Object.ToString();
    NSubstitute.Substitute.For<X>(new object[] { "" }).ToString();
    Rhino.Mocks.MockRepository.GenerateStrictMock<X>(new object[] { "" }).ToString();

But if you refactor the class to add another argument, the compiler won't detect this, and your tests will break at runtime. You'll have to update the argument arrays in all your tests, which can be time-consuming.

To combat this, grab the Ctor class from this Gist and add it to your project.

public static class CTor  
{
    public static object[] Args<T>(Expression<Func<T>> construct) { ... }
    public static object[] Args<T>(Func<Type, object> create = null) { ... }
    ...
}

You can then use CTor.Arg to generate a strongly typed set of arguments. Just pass in a constructor lambda, and Ctor.Args will extract the object array from the Expression.

object[] argsForCtor = CTor.Args(() => new X("Hello")); //equivalent to new 'object[]{ "Hello" }'

new Moq.Mock<X>(argsForCtor).Object.ToString(); //OK  
NSubstitute.Substitute.For<X>(argsForCtor).ToString(); //OK  
Rhino.Mocks.MockRepository.GenerateStrictMock<X>(argsForCtor).ToString(); //OK

If you add arguments to the constructor, you will get a compile time error, and know what code you need to fix.

If you want to avoid editing your code entirely, you can use the other overload which uses reflection to find a ctor passes in default values (or you can pass a factory Func<Type, object> if you want more control).

    object[] argsForCtor2 = CTor.Args<X>();

PS FakeItEasy works out of the box. It probably uses FormatterServices.GetUninitializedObject() (which creates an object without running the ctor) under the hood somewhere when initializing it's proxies.

FakeItEasy.A.Fake<X>().ToString(); //OK!