Asserting without Equals

Arnis suggested that implementing Equals just for NUnit was wrong so I thought I’d try doing without it.

The CollectionAssert.AreEqual method accepts an optional IComparer implementation. If specified, that will be used instead of Equals.

So I put together a class called PartComparer. Since I switched to comparing the state of the objects outside their classes, I had to expose some of that state via read-only properties. I think I can live with that.

I then deleted all of my Equals and GetHashCode methods (I wasn’t really using GetHashCode anyways).

Here’s what the test changed to:

[Test]
public void It_scans_literal_text()
{
    var scanner = new Scanner();

    var parts = scanner.Scan("foo");

    CollectionAssert.AreEqual(new Part[]
                                  {
                                      new LiteralText("foo"),
                                  },
                              parts,
                              new PartComparer());
}

It works the same as before. It just requires the extra argument.

Custom comparers works even with the newer Assert.That syntax:

[Test]
public void It_scans_literal_text()
{
    var scanner = new Scanner();

    var parts = scanner.Scan("foo");

    Assert.That(parts, Is.EqualTo(new Part[]
                                      {
                                          new LiteralText("foo"),
                                      })
                         .Using(new PartComparer()));
}

The verbosity of constructing the expected Part array is a bit much. If only C# could construct lists like JavaScript, Python, and Ruby…

I decided to try to hide that in a custom assertion method:

private static void AssertThatPartsAreEqual(
    IEnumerable<Part> actualParts,
    params Part[] expectedParts)
{
    Assert.That(actualParts, Is.EqualTo(expectedParts)
                               .Using(new PartComparer()));
}

Now my test looks like this:

[Test]
public void It_scans_literal_text()
{
    var scanner = new Scanner();

    var parts = scanner.Scan("foo");

    AssertThatPartsAreEqual(parts, new LiteralText("foo"));
}

One really nice thing about having the custom assertion method is that I can modify how parts are compared in just one spot. For example, Scan is really an iterator. NUnit’s failure messages when the collections aren’t arrays are less than ideal. With the comparisons being done in just one spot, I can modify it to convert the enumerable into an array:

private static void AssertThatPartsAreEqual(
    IEnumerable<Part> actualParts,
    params Part[] expectedParts)
{
    Assert.That(actualParts.ToArray(), Is.EqualTo(expectedParts)
                                         .Using(new PartComparer()));
}

Since I’m using .NET 3.5, I can take this one step further and use an extension method:

internal static class EnumerablePartExtensions
{
    public static void IsEqualTo(
        this IEnumerable<Part> actualParts,
        params Part[] expectedParts)
    {
        Assert.That(actualParts.ToArray(), Is.EqualTo(expectedParts)
                                             .Using(new PartComparer()));
    }
}

With that in place, my test now looks like this:

[Test]
public void It_scans_literal_text()
{
    var scanner = new Scanner();

    var parts = scanner.Scan("foo");

    parts.IsEqualTo(new LiteralText("foo"));
}

Wow, it’s like Ruby but without the monkey patching!

One thing I did leave in my code are all of the ToString overrides. Without those, NUnit’s failure messages would be much less helpful. They’re also very useful while debugging.

Thanks, Arnis. Your comment helped me find an alternative (and quite possibly better!) way to get what I want.

One thought on “Asserting without Equals”

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>