问题
I just had a problem with setting up a Unit Test using xUnit
and Moq
.
My Testee
The Method TestMethod()
contains the Logic, I want to test. It is async and though returns a Task
public class Testee
{
private readonly IDoSomething _doSomething;
public Testee(IDoSomething doSomething)
{
_doSomething = doSomething;
}
public async Task TestMethod()
{
await _doSomething.DoAsync(true); // throws NullReferenceException in Unit-Test
}
}
The Interface IDoSomething
looks like this
public interface IDoSomething
{
Task DoAsync(bool aboolean);
}
The Unit-Test
Now im Setting up my Unit-Test like this.
public class TesteeTest
{
[Fact]
public async Task MyTest()
{
var mock = new Mock<IDoSomething>();
mock.Setup(x => x.DoAsync(It.IsAny<bool>())).Verifiable();
var testee = new Testee(mock.Object);
await testee.TestMethod(); // Test breaks here because it throws an exception
mock.Verify(x => x.DoAsync(true), Times.Once);
mock.Verify(x => x.DoAsync(false), Times.Never);
}
}
Why am I getting this exception?
回答1:
The mock.Setup()
is missing a return value and returns null
. So in the TestMethod()
the Task
returned by _doSomething.DoAsync(true)
is null
. null
gets awaited which of course results in a System.NullReferneceException
.
To Fix this, I'd recommend adding .Returns(Task.CompletedTask)
to the Mock-Setup.
mock.Setup(x => x.DoAsync(It.IsAny<bool>())).Returns(Task.CompletedTask).Verifiable();
As await
gets compiled using the Awaiter-Pattern, there's now a Task to call .GetAwaiter()
on it, to return a TaskAwaiter
. These principles are better explained here:
- dixin's Blog
- Marko Papic's Blog
来源:https://stackoverflow.com/questions/53882817/nullreferenceexception-in-unittest-using-verifyable-on-an-async-method