Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setup Method With Params Array

Tags:

c#

moq

nunit

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?

like image 651
Luis Aguilar Avatar asked Nov 01 '11 14:11

Luis Aguilar


3 Answers

I believe the params string has to be matched by It.IsAny<string[]>() rather than It.IsAny<string>()

like image 32
Wiktor Zychla Avatar answered Oct 03 '22 03:10

Wiktor Zychla


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.

like image 121
Jon Skeet Avatar answered Oct 03 '22 05:10

Jon Skeet


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);
like image 39
Ben Wesson Avatar answered Oct 03 '22 04:10

Ben Wesson