我使用.Net Core 2.0
作为我的项目,Moq v4.7.145
作为我的模拟框架。
我有这种受保护的虚拟方法,通常将字节上传到云服务。为了能够对此进行单元测试,我想模拟这种适用于所有其他场景的方法。
当我想让这个方法返回null
时出现问题。这是为了模拟服务正在下降或它实际返回null
。我已经检查了几个关于SO的问题,但似乎都没有。
我像这样嘲笑我的图片提供者。 mockProvider
是云服务的模拟,而LoggerMock
是模拟井......记录器。
PictureProvider = new Mock<CloudinaryPictureProvider>(mockProvider.Object, LoggerMock.Object)
{
// CallBase true so it will only overwrite the method I want to be mocked.
CallBase = true
};
我已经设置了这样的模拟方法:
PictureProvider.Protected()
.Setup<Task<ReturnObject>>("UploadAsync", ItExpr.IsAny<ImageUploadParams>())
.Returns(null as Task<ReturnObject>);
我已尝试以各种方式转换返回对象,但到目前为止还没有任何工作。
我嘲笑的方法看起来像这样:
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
};
}
调用上面模拟方法的方法如下所示:
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
}
}
每次它到达我的public UploadImageAsync
方法中的受保护(模拟)方法时,它会抛出一个NullReferenceException
:
Message: Test method {MethodName} threw exception:
System.NullReferenceException: Object reference not set to an instance of an object.
我假设我在模拟方法的设置中遗漏了一些东西,我只是无法弄清楚它是什么。如果我错过了提及/展示的东西,请告诉我!
使用ReturnsAsync((ReturnObject)null)
而不是Returns(null as Task<ReturnObject>)
。你可以使用Returns(Task.FromResult((ReturnObject)null))
我怀疑正在发生的是Returns
期望不是空值。使用ReturnsAsync
时,它会在内部创建返回任务的Task.FromResult
。
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);
}