Reputation: 377
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. 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](Func
2 valueExpression) in C:\projects\moq4\src\Moq\Language\Flow\NonVoidSetupPhrase.cs:line 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.
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
Upvotes: 11
Views: 13781
Reputation: 3193
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. It's not about them having default values, it's that you're not providing the definition that Moq expects.
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/");
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));
This is what I normally do.
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
. 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
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:
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 { }
Upvotes: 14