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.
I see three aspects here:
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.
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());
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.