c# - 带有 moq 的模拟方法返回 null throws NullReferenceException

标签 c# unit-testing moq

我正在为我的项目使用 .Net Core 2.0,并将 Moq v4.7.145 作为我的模拟框架。

我有这个 protected 虚拟方法,它通常将字节上传到云服务。为了能够对其进行单元测试,我想模拟这种适用于所有其他场景的方法。

当我想让这个方法返回null 时出现问题。这是为了模拟服务关闭或它实际上返回 null。我已经检查了几个关于 SO 的问题,但似乎都没有用。

我曾经这样 mock 过我的图片提供者。 mockProvider 是云服务的模拟,LoggerMock 是 well... 记录器的模拟。

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 方法中的 protected (模拟)方法时,它都会抛出一个 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);
}

关于c# - 带有 moq 的模拟方法返回 null throws NullReferenceException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47883236/

相关文章:

c++ - 存储测试数据

c# - Windows 8 - 自定义动态磁贴

c# - 如何在 C# 中使泛型参数 T 可空?

c# - 如何使用ASP.NET和C#将录音上传到Sound Cloud?

java - 对 Java 多线程网络应用程序进行单元测试

multithreading - JUnit 线程测试

c# - 使用 Moq 的 ElasticClient 的代码覆盖率

unit-testing - 如何在使用 Moq 的测试中引发事件?

c# - 模拟调用异常为 0 次,但我可以正确看到执行的调用

c# - 调用相同对象的多个线程同时运行。它会引起问题吗?