Moq + Unit Testing - System.Reflection.TargetParameterCountException: Parameter count mismatch - c#

I'm tring to use a lambda with a multiple-params function but Moq throws this exception at runtime when I attempt to call the mock.Object.Convert(value, null, null, null); line.
System.Reflection.TargetParameterCountException: Parameter count mismatch
The code is:
var mock = new Mock<IValueConverter>();
mock.Setup(conv => conv.Convert(It.IsAny<Object>(), It.IsAny<Type>(),
It.IsAny<Object>(), It.IsAny<CultureInfo>())).Returns((Int32 num) => num + 5);
var value = 5;
var expected = 10;
var actual = mock.Object.Convert(value, null, null, null);
What is the proper way to implement it?

It's your Returns clause. You have a 4 parameter method that you're setting up, but you're only using a 1 parameter lambda. I ran the following without issue:
[TestMethod]
public void IValueConverter()
{
var myStub = new Mock<IValueConverter>();
myStub.Setup(conv => conv.Convert(It.IsAny<object>(), It.IsAny<Type>(), It.IsAny<object>(), It.IsAny<CultureInfo>())).
Returns((object one, Type two, object three, CultureInfo four) => (int)one + 5);
var value = 5;
var expected = 10;
var actual = myStub.Object.Convert(value, null, null, null);
Assert.AreEqual<int>(expected, (int) actual);
}
No exceptions, test passed.

Not an answer for OP but perhaps for future googlers:
I had a Callback that didn't match the signature of the method being setup
Mock
.Setup(r => r.GetNextCustomerNumber(It.IsAny<int>()))
.Returns(AccountCounter++)
.Callback<string, int>(badStringParam, leadingDigit =>
{
// Doing stuff here, note that the 'GetNextCustomerNumber' signature is a single int
// but the callback unreasonably expects an additional string parameter.
});
This was the result of some refactoring and the refactoring tool of course couldn't realise that the Callback signature was incorrect

Perhaps it's because you are passing null but It.IsAny<Object>() is expecting any object except null? What happens if you do the following?:
var actual = mock.Object.Convert(value, new object(), typeof(object), CultureInfo.CurrentCulture);
This is just a stab in the dark from me, I'm more familiar with Rhino.Mocks.
My 2nd guess:
Having looked at the Moq.chm that comes with the download,
You are using the Setup(Expression<Action<T>>) method which "Specifies a setup on the mocked type for a call to a void method."
You want te Setup<TResult>(Expression<Func<T,TResult>>) method that "Specifies a setup on the mocked type for a call to a value returning method".
So you could try:
mock.Setup<Int32>(
conv => {
conv.Convert(
It.IsAny<Object>(),
It.IsAny<Type>(),
It.IsAny<Object>(),
It.IsAny<CultureInfo>());
return num + 5;
});

In my case, I thought that the type in Returns<> is the output type, but in fact it was the input type(s).
So if you have a method
public virtual string Foo(int a, int b) { ... }
The correct clause is .Returns<int, int>(...), NOT .Returns<string>(...) which is what I thought initially.
My mistake was because I was testing a function with the same input and return type initially - for example public virtual string Foo(string a).

Related

Moq - Generic set up don't return expected value

I am new to Moq, here I have two setups.
var settingsMock = new Mock<IECSConfigSettings>();
settingsMock.Setup(m => m.GetRootValue("ss", It.IsAny<string>())).Returns("aaa");
And another one is
private static void BuildSettingCacheForMock<T>(Mock<IECSConfigSettings> mock, string key, T value)
{
mock.Setup(m => m.GetRootValue<T>(key, It.IsAny<T>())).Returns(value);
mock.Setup(m => m.GetValue<T>(key, It.IsAny<T>())).Returns(value);
mock.Setup(m => m.TryGetValue<T>(key, out value)).Returns(true);
mock.Setup(m => m.TryGetRootValue<T>(key, out value)).Returns(true);
}
var settingsMock = new Mock<IECSConfigSettings>();
BuildSettingCacheForMock<string>(settingsMock, "sss", "aaa1");
Finally when I invoke both of them
var s1 = new SettingsETag(settingsMock.Object, etag: "ETag", null).Settings.GetRootValue("ss"); // gives "aaa"
var s2 = new SettingsETag(settingsMock.Object, etag: "ETag", null).Settings.GetRootValue("sss"); // gives null
Interface details
Interface code
I do not know what is the differences between these and why the result for the second one is null. Appreciate your thoughts on this!
You have set up a return value for the specific call settingsMock.Setup(m => m.GetRootValue("ss", It.IsAny<string>())).Returns("aaa"); - that is when called with the key "ss", no other values. The second call does not have a set up return value, so you get the default return value null.
In general I think it helps to create mocks with MockBehavior.Strict. This gives you information about unexpected calls when running your unit tests. The constructor looks like this;
var settingsMock = new Mock<IECSConfigSettings>(MockBehavior.Strict);
If you want to return the same value regardless of the parameter value you can use It.IsAny<string>() for the first parameter too.
settingsMock.Setup(m => m.GetRootValue(It.IsAny<string>(), It.IsAny<string>())).Returns("aaa");

Moq - passing arguments from setup() to returns()

I am not sure how to pass arguments from Setup() to Returns() in Moq.
Here is an example:
public static IInterfaceHandler GetInterfaceHandlerMoq()
{
// Defining the moq
var moq = new Mock<IInterfaceHandler>();
// Trying to set up a moq using another moq
moq.Setup(m => m.CreateCommunicationInterface(It.IsAny<Guid>(), It.IsAny<string>()))
.Returns((Guid guid, string value) => GetProgrammerMoq(guid, value));
// Return mocked object
return moq.Object;
}
Note that GetProgrammerMoq() is a library that will return another Moq. Here is the code:
public static IProgrammer GetProgrammerMoq(Guid guid, string instName)
{
// Create Moq
var moq = new Mock<IProgrammer>();
// Set up the returnables
moq.Setup(o => o.InstanceName).Returns(programmer + "_" + instName);
moq.Setup(o => o.Guid).Returns(guid);
// Return mocked object
return moq.Object;
}
See here that GetProgrammerMoq() needs its arguments to be set up based on what is passed to CreateCommunicationInterface().
My test then tries to get and use the Moq, but "p" is returned as null (because, I guess, my arguments are not passed properly to Returns()).
Here is a draft of what the test is to look like:
[Fact]
public void DoSomething()
{
IInterfaceHandler test = ProgrammerMoqs.GetInterfaceHandlerMoq();
Guid? g = new Guid();
IProgrammer p = test.CreateCommunicationInterface(g, "test-boff");
...
}
Try this:
var moq = new Mock<IInterfaceHandler>(MockBehavior.Strict);
MockBehavior.Strict: if you get NULLs from Mock, then always try MockBehavior.Strict. When some setup is not prepared, Moq by default returns NULL. But with MockBehavior.Strict, it will throw an exception. Every single attempt to call anything from the mock object, if it lacks proper setup, will throw.
If you get an exception when trying MockBehavior.Strict, then it means that the:
.Setup(m => m.CreateCommunicationInterface(It.IsAny<Guid>(), It.IsAny<string>()))
failed to catch the invocatio, so the mock returned NULL by default.
Why did it fail to catch the invocation? There are several options:
CreateCommunicationInterface may be overloaded and your setup matched another overload that you did not expect
filters (It.IsAny..) didn't match the actual arguments
(..)
Klaus Gütter noted in the comments about the difference of Guid and Guid?. In fact, the filter you are using is It.IsAny() while in the test you pass:
Guid? g = new Guid();
g is not an object of type Guid, it's Nullable<Guid>, hence the filter looking for any-Guid did not match. The code compiled, because the result of the expression It.IsAny<Guid>() fits Guid? wanted by the method, but still the types don't match.
If you try It.IsAny<Guid?>() it will probably match fine and return what you wanted.
moq.Setup(m => m.CreateCommunicationInterface(It.IsAny<Guid?>(), It.IsAny<string>()))
.Returns((Guid? guid, string value) => GetProgrammerMoq(guid, value));

Faking a call to an array for a particular index raises an exception

Having the following unit test:
public interface ITestMe
{
object[] Values { get; }
}
[Test]
public void Test ()
{
var sut = A.Fake<ITestMe> ();
A.CallTo (() => sut.Values[0]).Returns (4);
Assert.That (sut.Values[0], Is.EqualTo (4));
}
results in the following exception:
System.InvalidCastException : Unable to cast object of type 'System.Linq.Expressions.SimpleBinaryExpression' to type 'System.Linq.Expressions.InvocationExpression'.
at FakeItEasy.Expressions.CallExpressionParser.Parse(LambdaExpression callExpression)
at FakeItEasy.Configuration.FakeConfigurationManager.AssertThatMemberCanBeIntercepted(LambdaExpression callSpecification)
at FakeItEasy.Configuration.FakeConfigurationManager.CallTo(Expression1 callSpecification) at FakeItEasy.A.CallTo(Expression1 callSpecification)
Or maybe I do not know how to specify a fake for an indexer?
The problem arises from the fact that Values isn't an indexer.
It's a property that returns an array.
An unconfigured Values will return a zero-length array (because arrays aren't fakeable). That's what's happening here, and ()=>sut.Values[0] would fail if it were ever executed (which FakeItEasy doesn't do).
So the real takeaway here is that since Values is an array, which is not fakeable (see What can be faked?), there's no way to have FakeItEasy choose a return value for a particular offset. The best that can be done is to have Values return an array of your choosing, as #CharlesMager suggests. For example:
var myArray = new object[100];
myArray[0] = 4;
myArray[50] = 17;
A.CallTo(() => sut.Values).Returns(myArray);

IsType<T> and IsType(object, object) throwing IsTypeException

I am attempting to assert that an object being returned by a method call is of the type List<MyClass>, so using xUnit I have tried the following:
var expected = typeof(List<MyClass>);
var actual = typeof(method());
Assert.IsType<List<MyClass>>(actual);
Assert.IsType(expected, actial);
Both of the above throw the IsTypeException however if I perform:
var areSameType = expected == actual
areSameType is true. So is there something going on deeper down that I am not accounting for?
Docs:
http://www.nudoq.org/#!/Packages/xunit.extensions/xunit.extensions/Assertions/M/IsType(T)
http://www.nudoq.org/#!/Packages/xunit.extensions/xunit.extensions/Assertions/M/IsType
The first argument for Assert.IsType should be the object itself not its type, the following should not throw:
var expected = typeof(List<MyClass>);
var actual = Method();
Assert.IsType<List<MyClass>>(actual);
Assert.IsType(expected, actual);

Setup Method With Params Array

I am developing tests for an application. There's a method that has a params array as a parameter. I have set up the method using Moq but when I run the test, the return value of the method is null, which means it is not being mocked.
Here's a code sample:
public interface ITicketManager {
string GetFirstTicketInQueueIfMatches(params string[] ticketsToMatch);
}
public class TicketManager : ITicketManager {
private Queue<string> ticketQueue = new Queue<string>();
public string GetFirstTicketInQueueIfMatches(params string[] ticketsToMatch) {
var firstQueuedTicket = ticketQueue.Peek();
var firstQueuedTicketMatchesAnyOfRequested = ticketsToMatch.Any(t => t == firstQueuedTicket);
if(firstQueuedTicketMatchesAnyOfRequested)
return firstQueuedTicket;
return null;
}
}
The mock code looks like this:
var mock = new Mock<ITicketManager>();
mock.Setup(m => m.GetFirstTicketInQueueIfMatches(It.IsAny<string>()))
.Returns(p => {
if(p.Contains("A"))
return "A";
return null;
});
Why is it never hitting the mocked method?
You're trying to call a method taking a single string, rather than an array. Bear in mind that it's the C# compiler which handles the params part, converting calling code which just specifies individual values into a call passing in an array. As far as the method itself is concerned, it's just getting an array - and that's what you're mocking.
The compiler is actually turning your code into:
mock.Setup(m => m.GetFirstTicketInQueueIfMatches
(new string[] { It.IsAny<string>() }))
which isn't what you want.
You should use:
mock.Setup(m => m.GetFirstTicketInQueueIfMatches(It.IsAny<string[]>()))
If you need to verify that it only gets given a single value, you'll need to do that in the same way you would for a non-params parameter.
Basically, params only makes a difference to the C# compiler - not to moq.
I believe the params string has to be matched by It.IsAny<string[]>() rather than It.IsAny<string>()
Using Moq, the code below works to setup a callback on a method with a params argument. Defining the second argument as an array does the trick.
MockLogger
.Setup(x => x.Info(It.IsAny<string>(), It.IsAny<object[]>()))
.Callback<string, object[]>((x, y) => _length = x.Length);

Categories

Resources