1

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?

John Källén
  • 7,551
  • 31
  • 64

2 Answers2

1

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;
    });
}
k.m
  • 30,794
  • 10
  • 62
  • 86
  • indeed, this is close to what I ended up writing. I now have a utility method that performs verification of the contents of the dictionary for an arbitrary number of key-value pairs, called with the Rhino.Mocks .Do() extension method. – John Källén Jul 04 '13 at 23:55
0

For small fixed number of expecte item in a dictionary I think simple check for Count and particular entries is expressive enough. Test will fail if values are wrong...

 items.Count() == 1 && items["Date"]== new DateTime(1972,1,2);

You can also use collection comparisons as covered in Comparing two collections for equality irrespective of the order of items in them.

Community
  • 1
  • 1
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179