0
votes

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
I feel although it's not an exact duplicate, it's as close as could be for the given scenario.. I don't think it's useful to have this question when the dupe target covers a lot of the required code and the NullReferenceException canonical exists - A Friend
I agree on the similarity, the difference is indeed that the suggested duplicate was missing the Task completion, while my question was missing the Task at all. This makes it different, because ususally, you would use .ReturnsAsync? to return something asynchronous, which wasn't an option, as you cannot call ReturnsAsinc with void. - LuckyLikey
@everyone As I've also marked this question as duplicate, I clearly agree with the similarity. However I don't get the reason of the downvote on this question. If someone might take the time to help me understand how to better write such a question next time. - LuckyLikey
I think it's an excellent question. The other questions are "how to". This one's "why null reference". I changed a method returning void to being tested from asynchronous returning Task and all my unit tests broke because I didn't do this setup - Colin

1 Answers

4
votes

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: