模拟参数化异步方法

时间:2019-01-11 20:08:10

标签: c# mocking

    var controller = new Mock<JobOfferController>(context);
controller.Setup(m => m.UploadCvToAzureStorage(It.IsAny<IFormFile>()))
.Returns(Task.FromResult("cv-url"));

这部分代码返回以下错误:“ System.NotSupportedException:在非虚拟(在VB中可重写)成员成员上的无效设置:m => m.UploadCvToAzureStorage(It.IsAny())”。有任何解决方法的想法吗?

1 个答案:

答案 0 :(得分:0)

Moq不会模拟具体类的非虚拟成员,因为它无法覆盖为实现设置而运行的代码。您需要模拟该类实现的接口。

如果您有这个:

public interface IJobOfferController
{
    Task<string> UploadCvToAzureStorage(IFormFile file);
}

public class JobOfferController : IJobOfferController
{
    public Task<string> UploadCvToAzureStorage(IFormFile file) => throw new NotImplementedException();
}

那么您将被设置为:

public void SetUp()
{
    //this is trying to mock the concrete class and will fail
    var controller = new Mock<JobOfferController>(context);            
    controller.Setup(m => m.UploadCvToAzureStorage(It.IsAny<IFormFile>()))
        .Returns(Task.FromResult("cv-url"));


    //This Mocks the interface and sets up a return value for that interface
    var mockController = new Mock<IJobOfferController>();
    mockController.Setup(m => m.UploadCvToAzureStorage(It.IsAny<IFormFile>()))
        .Returns(Task.FromResult("cv-url"));
}

此外,当您在模拟异步方法时,可以删除.FromResult并仅使用ReturnsAsync

controller.Setup(m => m.UploadCvToAzureStorage(It.IsAny<IFormFile>()))
    .ReturnsAsync("cv-url");

如果您的控制器没有接口,另一种选择是使您的控制器的方法虚拟化,以便Moq可以通过您的设置覆盖它:

public class JobOfferController : IJobOfferController
{
    public virtual Task<string> UploadCvToAzureStorage(IFormFile file) => throw new NotImplementedException();
}

//now the setup works
var controller = new Mock<JobOfferController>(context);            
controller.Setup(m => m.UploadCvToAzureStorage(It.IsAny<IFormFile>()))
    .ReturnsAsync("cv-url");