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

use*_*289 8 c# moq

界面:

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

起订量设置:

 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/")); 
                });
Run Code Online (Sandbox Code Playgroud)

错误信息是

System.ArgumentException HResult=0x80070057 Message=回调无效。具有 4 个参数的方法的设置无法调用具有不同数量参数的回调 (1)。源= Moq StackTrace:
位于 Moq.MethodCall.<>c__DisplayClass22_0.g__ValidateCallback|4(委托回调),位于 C:\projects\moq4\src\Moq\MethodCall.cs:Moq.MethodCall.SetReturnCompulatedValueBehavior(委托 valueFactory)中的第 311 行C:\projects\moq4\src\Moq\MethodCall.cs: 第 256 行位于2.Returns[T1](FuncC:\projects\moq4\src\Moq\Language\Flow\NonVoidSetupPhrase.cs 中的 Moq.Language.Flow.NonVoidSetupPhrase 2 valueExpression):第 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/")); 
                });
Run Code Online (Sandbox Code Playgroud)

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

我的问题是:为什么不起作用并返回错误消息。我究竟做错了什么?我尝试将其设置为类似于
“起订量:无效回调”。带参数的方法设置无法调用带参数的回调

谢谢

rgv*_*lee 10

您的代码不起作用,因为您正在使用Returns重载,该重载允许您获取提供给调用的参数,但您没有提供类型,也没有提供所有参数。这并不是说它们有默认值,而是您没有提供 Moq 期望的定义。

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

var adFileServiceMock = new Mock<IAdFileService>();
var expectedMockResponse = ServiceResponse<string>.Create("Json Data", "http://test.com/", "Json Data", "http://test.com/");
Run Code Online (Sandbox Code Playgroud)
  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(Task.FromResult(expectedMockResponse));
Run Code Online (Sandbox Code Playgroud)
  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(() => Task.FromResult(expectedMockResponse));
Run Code Online (Sandbox Code Playgroud)

这就是我通常做的事情。

  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));
Run Code Online (Sandbox Code Playgroud)

当我返回的内容取决于提供给调用的值/对象时,我会这样做。

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

最后,考虑到您正在返回一个任务,猜测您正在使用异步进程,因此请考虑使用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);
Run Code Online (Sandbox Code Playgroud)

工作 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 { }
Run Code Online (Sandbox Code Playgroud)