使用moq返回null的模拟方法抛出NullReferenceException

时间:2017-12-19 08:58:29

标签: c# unit-testing moq

我正在使用.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.

我认为我在模拟方法的设置中遗漏了一些东西,我无法弄清楚它是什么。如果我错过了提及/展示的东西,请告诉我!

1 个答案:

答案 0 :(得分:4)

使用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);
}