简体   繁体   English

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

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

Interface:界面:

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

Moq Setup:起订量设置:

 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/")); 
                });

Error message is错误信息是

System.ArgumentException HResult=0x80070057 Message=Invalid callback. System.ArgumentException HResult=0x80070057 消息=无效的回调。 Setup on method with 4 parameter(s) cannot invoke callback with different number of parameters (1).具有 4 个参数的方法上的设置无法使用不同数量的参数 (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.NonVoidSetupPhrase 2.Returns[T1](Func 2 valueExpression) in C:\\projects\\moq4\\src\\Moq\\Language\\Flow\\NonVoidSetupPhrase.cs:line 281在 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.NonVoidSetupPhrase 2.Returns[T1](Func 2 valueExpression) in C:\\projects\\moq4\\src\\Moq\\Language\\Flow\\NonVoidSetupPhrase.cs :第281行

I would like to use我想用

 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/")); 
                });

Since the last 3 parameters on getJSON are defaulted to null.由于 getJSON 上的最后 3 个参数默认为 null。

My question is: Why does not work and returns the error message.我的问题是:为什么不起作用并返回错误消息。 What am I doing wrong?我究竟做错了什么? I attempted to set it up similar to我尝试将其设置为类似于
Moq: Invalid callback. 最小起订量:无效的回调。 Setup on method with parameters cannot invoke callback with parameters 带参数的方法设置不能调用带参数的回调

Thank you谢谢

Your code isn't working because you are using the Returns overload that allows you to get hold of the parameters provided to the invocation, but you're not providing the type and you're not providing all of them.您的代码无法正常工作,因为您使用的是Returns重载,它允许您获取提供给调用的参数,但您没有提供类型,也没有提供所有类型。 It's not about them having default values, it's that you're not providing the definition that Moq expects.这不是关于它们具有默认值,而是您没有提供 Moq 期望的定义。

There's probably a few ways you can cut this.可能有几种方法可以解决这个问题。 Given:鉴于:

var adFileServiceMock = new Mock<IAdFileService>();
var expectedMockResponse = ServiceResponse<string>.Create("Json Data", "http://test.com/", "Json Data", "http://test.com/");
  1. Always return that specific instance:始终返回该特定实例:
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. Use a factory, (in this case I'm just returning the same instance everytime)使用工厂,(在这种情况下,我只是每次都返回相同的实例)
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));

This is what I normally do.这是我通常的做法。

  1. Specify the parameters指定参数
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));

I do this when what I return depends on the values/objects provided to the invocation.当我返回的内容取决于提供给调用的值/对象时,我会这样做。

You've got to spec the types.你必须指定类型。 I've been lazy here for brevity and used It.IsAnyType and object .为了简洁起见,我在这里很懒惰并使用了It.IsAnyTypeobject I would normally use a specific type or a generic type parameter.我通常会使用特定类型或泛型类型参数。

Finally given you're returning a task, at a guess you're using an async process so consider using ReturnsAsync最后考虑到您正在返回一个任务,猜测您正在使用异步进程,因此请考虑使用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);

Working LINQPad example:工作 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 { }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM