Question

I'm using Machine.Fakes.NSubstitute and want to "fake" a return value such that if the input parameter matches a specific value it returns the mock object, otherwise it returns null.

I tried the following:

host.WhenToldTo(h => h.GetTenantInstance(Param.Is(new Uri("http://foo.bar"))))
    .Return(new TenantInstance());

But it throws the following exception:

System.InvalidCastException: Unable to cast object of type 'System.Linq.Expressions.NewExpression' to type 'System.Linq.Expressions.ConstantExpression'.

My current workaround is to do the following:

host.WhenToldTo(h => h.GetTenantInstance(Param.IsAny<Uri>()))
    .Return<Uri>(uri => uri.Host == "foo.bar" ? new TenantInstance() : null);

Which is a bit smelly.

Was it helpful?

Solution

I see three aspects here:

  1. When a method with a reference type return value is called on a mock object and no behavior has been set up for the call, the mock object will return a mock. If you want it to return null instead, you have to configure that explicitly. Thus, it is not enough to set up

    host.WhenToldTo(h => h.GetTenantInstance(Param.Is(new Uri("http://foo.bar"))))
        .Return(new TenantInstance());
    

    You also have to set up the other case with something like this:

    host.WhenToldTo(h => h.GetTenantInstance(Param<Uri>.Matches(x => !x.Equals(new Uri("http://foo.bar")))))
        .Return((TenantInstance)null);
    

    I find your "workaround" solution more elegant than these two setups.

  2. When you match a method call argument for equality, there is no need to use Param.Is(). You can simply set up the behavior with

    host.WhenToldTo(h => h.GetTenantInstance(new Uri("http://foo.bar")))
        .Return(new TenantInstance());
    
  3. The fact that you get an exception when using Param.Is() here is a shortcoming of Machine.Fakes. I see not reason why this should not work. I will correct that at some point and let you know.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top