Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSubstitute ambiguous call when following documentation example (but with async method)

So I tried copying an example about exception throwing from the documentation, and added this to one of my methods:

.Returns( x => { throw new Exception(); });

But this results in the following compiler error:

Error CS0121 The call is ambiguous between the following methods or properties: 'SubstituteExtensions.Returns(T, Func, params Func[])' and 'SubstituteExtensions.Returns(Task, Func, params Func[])'

The method I'm using is an async method. I tried awaiting the method first, but that returns a different error, saying that it

can not return value of type X for (expected type Task`1)

UPDATE: I can change the lambda in the returns to be async as a way to get around the compiler error, but this results in a warning. So I guess the question now is more about whether or not there's a way to bypass this without having the warning show up, and without adding needless await code inside the lambda itself?

Is there a way to avoid this? I'm using NSubstitute 2.0.3

Thank you for any help.

like image 347
Kolichikov Avatar asked Jun 27 '17 19:06

Kolichikov


2 Answers

The compiler error in your question looks like you are calling something that returns Task rather than Task<T>? This sample works for me:

public interface ISample {
    Task DoStuff(string name);
}

[Test]
public async Task SampleTest()
{
    var sample = Substitute.For<ISample>();
    sample.DoStuff("test").Returns(x => { throw new Exception("doh"); });
    // ...
}

I tend to get that error when I have a generic Task<T>, which can be fixed by specifying the return type in the .Returns() call like this:

public interface IRepository {
    Task<int> FindId(string name);
}

[Test]
public async Task SampleTest2()
{
    var sample = Substitute.For<IRepository>();
    sample.FindId("test").Returns<int>(x => { throw new Exception("doh"); });
    // ...
}

In the example above I've removed the ambiguity by using .Returns<int>(...) which will pick the first overload mentioned in the compiler error.

If that does not help could you post the signature of the method being tested?

like image 104
David Tchepak Avatar answered Nov 10 '22 23:11

David Tchepak


Adding to Davids accepted answer if you want the Task method because your method does actually return a Task then you simply need to specify Returns<Task>.

object.Method().Returns<Task>(x => { throw new Exception("You messed up"); });

It's not necessary to specify the full return type i.e. don't do this -> Task<IEnumerable<YourClass>>

like image 4
m12lrpv Avatar answered Nov 10 '22 23:11

m12lrpv