Reputation:
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
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