Search code examples
c#unit-testingrhino-mocks

How do you express expectations about a collection being passed as a parameter?


I have an interface method whose signature is as follows:

void SetValues(IDictionary<string, object> the_values);

I have a client class that uses that method. I want The unit test for that class to verify that, in a particular case, a specific key and value pair are passed in. Right now, if I want to express that I'm expecting the SetValues method to be called with the single key-value pair { "Date", DateTime(1972,1,2) } I write the following:

item.Expect(i => i.SetValues(
            Arg<IDictionary<string, object>>.Matches(
                (items) => (items.Count() == 1 &&
                    items.First().Key == "Date" &&
                    (DateTime) items.First().Value == new DateTime(1972,1,2))));

The expectation seems to work, but my does that look ugly. Is there a better way to express expectations about the contents of a collection being passed in as a parameter?


Solution

  • Most likely no. I agree this is border line ugly. But what's even more important, it produces undecipherable exception message, like this:

    IInterface.SetValues(items => items.Count() == 1 && items.First().Key == "Date" && (DateTime) items.First().Value == new DateTime(1972,1,2)); Expected #1, Actual #0.

    Yeah, you'll know it failed. Not very useful information in 2 weeks time. Truth to be told, when this happens you'll most likely have to debug it to get to know what's going on. Instead, I suggest doing this:

    item.Expect(i => i.SetValues(Arg<IDictionary<string, object>>.Is.Anything))
        .WhenCalled(invocation =>
        {
            var items = invocation.Arguments
                .OfType<IDictionary<string, object>>()
                .First();
            Assert.That(items.Count(), Is.EqualTo(1));
            Assert.That(items.First().Key, Is.EqualTo("Date");
            // ...
        });
    

    Or, putting verification into it's own method altogether:

    item.Expect(i => i.SetValues(IsCalledWithCorrectPair()));
    
    // ... 
    
    private IDictionary<string, object> IsCalledWithCorrectPair()
    {
        return Arg<IDictionary<string, object>>.Matches(items =>
        {
            Assert.That(items.Count(), Is.EqualTo(1));
            Assert.That(items.First().Key, Is.EqualTo("Date");
            // ...
            return true;
        });
    }