最小起订量:回调无效。带参数的方法设置不能调用带参数的回调,不使用回调

Moq: Invalid callback. Setup on method with parameters cannot invoke callback with parameters not using Callback

接口:

Task<ServiceResponse<string>> GetJSON<T>(FileRequest request, FileItemsSerializer<T> serializer = null, CsvConfiguration configuration = null, ClassMap<T> mapper = null) where T: class, new();    

最小起订量设置:

 Mock<IAdFileService> mock = new Mock<IAdFileService>();
     
mock.Setup(x => x.GetJSON(
                        It.IsAny<FileRequest>(), 
                        It.IsAny<FileItemsSerializer<dynamic>>(),
                        It.IsAny<CsvConfiguration>(),
                        It.IsAny<ClassMap<dynamic>>())
            ).Returns<ServiceResponse<string>>((a) => { 
                    return Task.FromResult(ServiceResponse<string>.Create(
                       "Json Data", 
                       "http://test.com/", 
                       "Json Data", 
                       "http://test.com/")); 
                });

错误信息是

System.ArgumentException HResult=0x80070057 Message=Invalid callback. Setup on method with 4 parameter(s) cannot invoke callback with different number of parameters (1). Source=Moq StackTrace:
at Moq.MethodCall.<>c__DisplayClass22_0.g__ValidateCallback|4(Delegate callback) in C:\projects\moq4\src\Moq\MethodCall.cs:line 311 at Moq.MethodCall.SetReturnComputedValueBehavior(Delegate valueFactory) in C:\projects\moq4\src\Moq\MethodCall.cs:line 256 at Moq.Language.Flow.NonVoidSetupPhrase2.Returns[T1](Func2 valueExpression) in C:\projects\moq4\src\Moq\Language\Flow\NonVoidSetupPhrase.cs:line 281

我想用

 mock.Setup(x => x.GetJSON<dynamic>(It.IsAny<FileRequest>())
            ).Returns<ServiceResponse<string>>(
                (a) => { 
                    return Task.FromResult(ServiceResponse<string>.Create(
                       "Json Data", 
                       "http://test.com/", 
                       "Json Data", 
                       "http://test.com/")); 
                });

由于 getJSON 的最后 3 个参数默认为 null。

我的问题是:为什么不工作和returns错误信息。我究竟做错了什么?我试图将其设置为类似于
Moq: Invalid callback. Setup on method with parameters cannot invoke callback with parameters

谢谢

您的代码无法正常工作,因为您使用的是 Returns 重载,它允许您获取提供给调用的参数,但您没有提供类型,也没有提供他们都。这与它们是否具有默认值无关,而是您没有提供 Moq 期望的定义。

可能有几种方法可以解决这个问题。给定:

var adFileServiceMock = new Mock<IAdFileService>();
var expectedMockResponse = ServiceResponse<string>.Create("Json Data", "http://test.com/", "Json Data", "http://test.com/");
  1. 总是return那个特定的实例:
adFileServiceMock
   .Setup(x => x.GetJSON<It.IsAnyType>(It.IsAny<FileRequest>(), It.IsAny<FileItemsSerializer<It.IsAnyType>>(), It.IsAny<CsvConfiguration>(), It.IsAny<ClassMap<It.IsAnyType>>()))
   .Returns(Task.FromResult(expectedMockResponse));
  1. 使用工厂,(在这种情况下,我只是 return 每次都使用相同的实例)
adFileServiceMock
   .Setup(x => x.GetJSON<It.IsAnyType>(It.IsAny<FileRequest>(), It.IsAny<FileItemsSerializer<It.IsAnyType>>(), It.IsAny<CsvConfiguration>(), It.IsAny<ClassMap<It.IsAnyType>>()))
   .Returns(() => Task.FromResult(expectedMockResponse));

这是我通常做的。

  1. 指定参数
adFileServiceMock
   .Setup(x => x.GetJSON<It.IsAnyType>(It.IsAny<FileRequest>(), It.IsAny<FileItemsSerializer<It.IsAnyType>>(), It.IsAny<CsvConfiguration>(), It.IsAny<ClassMap<It.IsAnyType>>()))
   .Returns((FileRequest providedFileRequest, object providedFileItemsSerializer, CsvConfiguration providedCsvConfiguration, object providedClassMap) => Task.FromResult(expectedMockResponse));

当我 return 取决于提供给调用的 values/objects 时,我会这样做。

您必须指定类型。为了简洁起见,我在这里偷懒并使用了 It.IsAnyTypeobject。我通常会使用特定类型或泛型类型参数。

最后,鉴于您正在 return 执行一项任务,我猜您正在使用异步进程,因此请考虑使用 ReturnsAsync

adFileServiceMock
   .Setup(x => x.GetJSON<It.IsAnyType>(It.IsAny<FileRequest>(), It.IsAny<FileItemsSerializer<It.IsAnyType>>(), It.IsAny<CsvConfiguration>(), It.IsAny<ClassMap<It.IsAnyType>>()))
   .ReturnsAsync(() => expectedMockResponse);

工作 LINQPad 示例:

async void Main()
{
    var adFileServiceMock = new Mock<IAdFileService>();
    var expectedMockResponse = ServiceResponse<string>.Create("Json Data", "http://test.com/", "Json Data", "http://test.com/");

//  adFileServiceMock
//      .Setup(x => x.GetJSON<It.IsAnyType>(It.IsAny<FileRequest>(), It.IsAny<FileItemsSerializer<It.IsAnyType>>(), It.IsAny<CsvConfiguration>(), It.IsAny<ClassMap<It.IsAnyType>>()))
//      .Returns(Task.FromResult(expectedMockResponse));
//
//  adFileServiceMock
//      .Setup(x => x.GetJSON<It.IsAnyType>(It.IsAny<FileRequest>(), It.IsAny<FileItemsSerializer<It.IsAnyType>>(), It.IsAny<CsvConfiguration>(), It.IsAny<ClassMap<It.IsAnyType>>()))
//      .Returns(() => Task.FromResult(expectedMockResponse));
//
//  adFileServiceMock
//      .Setup(x => x.GetJSON<It.IsAnyType>(It.IsAny<FileRequest>(), It.IsAny<FileItemsSerializer<It.IsAnyType>>(), It.IsAny<CsvConfiguration>(), It.IsAny<ClassMap<It.IsAnyType>>()))
//      .Returns((FileRequest providedFileRequest, object providedFileItemsSerializer, CsvConfiguration providedCsvConfiguration, object providedClassMap) => Task.FromResult(expectedMockResponse));

    adFileServiceMock
        .Setup(x => x.GetJSON<It.IsAnyType>(It.IsAny<FileRequest>(), It.IsAny<FileItemsSerializer<It.IsAnyType>>(), It.IsAny<CsvConfiguration>(), It.IsAny<ClassMap<It.IsAnyType>>()))
        .ReturnsAsync(() => expectedMockResponse);

    var adFileService = adFileServiceMock.Object;

    var mockResponse = await adFileService.GetJSON(new FileRequest(), new FileItemsSerializer<Foo>(), new CsvConfiguration(), new ClassMap<Foo>());

    mockResponse.Should().BeSameAs(expectedMockResponse);
}

// You can define other methods, fields, classes and namespaces here
public interface IAdFileService
{
    Task<ServiceResponse<string>> GetJSON<T>(FileRequest request, FileItemsSerializer<T> serializer = null, CsvConfiguration configuration = null, ClassMap<T> mapper = null) where T : class, new();
}

public class ServiceResponse<T>
{
    public static ServiceResponse<T> Create(string a, string b, string c, string d)
    {
        return new ServiceResponse<T>();
    }
}

public class FileRequest { }

public class FileItemsSerializer<T> { }

public class CsvConfiguration { }

public class ClassMap<T> { }

public class Foo { }