user4189129
user4189129

Reputation:

Mocked method with moq to return null throws NullReferenceException

I am using .Net Core 2.0 for my project, and Moq v4.7.145 as my mocking framework.

I have this protected virtual method, which normally uploads bytes to a cloud service. To be able to unit test this, I wanted to mock this method which works fine for all other scenarios.

The problem occurred when I want to make this method return null. This to simulate the service being down or it actually returns null. I have checked a few questions on SO, but none seems to work.

I have mocked my picture provider like this. The mockProvider is a mock of the cloud service, and the LoggerMock is a mock of well... the logger.

PictureProvider = new Mock<CloudinaryPictureProvider>(mockProvider.Object, LoggerMock.Object)
{
    // CallBase true so it will only overwrite the method I want to be mocked.
    CallBase = true
};

I have set up my mocked method like this:

PictureProvider.Protected()
            .Setup<Task<ReturnObject>>("UploadAsync", ItExpr.IsAny<ImageUploadParams>())
            .Returns(null as Task<ReturnObject>); 

I have tried casting the return object in every way, but none has worked so far.

The method which I'm mocking looks like this:

protected virtual async Task<ReturnObject> UploadAsync(ImageUploadParams uploadParams)
{
    var result = await _cloudService.UploadAsync(uploadParams);

    return result == null ? null : new ReturnObject
    {
        // Setting values from the result object
    };
}

The method that calls the mocked method above, looks like this:

public async Task<ReturnObject> UploadImageAsync(byte[] imageBytes, string uploadFolder)
{
    if (imageBytes == null)
    {
        // Exception thrown
    }

    var imageStream = new MemoryStream(imageBytes);

    // It throws the NullReferenceException here.
    var uploadResult = await UploadAsync(new ImageUploadParams
    {
        File = new FileDescription(Guid.NewGuid().ToString(), imageStream),
        EagerAsync = true,
        Folder = uploadFolder
    });

    if (uploadResult?.Error == null)
    {
        // This is basically the if statement I wanted to test.
        return uploadResult;
    }

    {
        // Exception thrown
    }
}

Every time it reaches the protected (Mocked) method in my public UploadImageAsync method, it throws a NullReferenceException:

Message: Test method {MethodName} threw exception:   
System.NullReferenceException: Object reference not set to an instance of an object.

I assume I'm missing something in my setup of the mocked method, I just can't figure out what it is. If I missed to mention/show something, please let me know!

Upvotes: 6

Views: 3152

Answers (1)

FCin
FCin

Reputation: 3925

Use ReturnsAsync((ReturnObject)null) instead of Returns(null as Task<ReturnObject>). You can altenatively use Returns(Task.FromResult((ReturnObject)null))

What I suspect is happening there is that Returns expects not null value. When using ReturnsAsync it internally creates Task.FromResult which returns a task.

public static IReturnsResult<TMock> ReturnsAsync<TMock, TResult>(this IReturns<TMock, Task<TResult>> mock, Func<TResult> valueFunction) where TMock : class
{
    return mock.Returns(() => Task.FromResult(valueFunction()));
}

public static IReturnsResult<TMock> ReturnsAsync<TMock, TResult>(this IReturns<TMock, Task<TResult>> mock, TResult value) where TMock : class
{
    return mock.ReturnsAsync(() => value);
}

Upvotes: 6

Related Questions