Paul Hicks Paul Hicks - 25 days ago 11
C# Question

Can I compare objects of different types using NUnit's EqualTo().Using()?

I want to be able to compare any two things that are

IConvertible
to
DateTime
using NUnit's
Assert.That
, preferably without creating a custom constraint. I have a simple
IComparer
that does the trick nicely. It works with
EqualTo().Using()
, so long as both the actual and expected are of the same type. It looks like the
EqualsConstraint
's
AdjustArgumentIfNeeded
method is failing the assertion before my
IComparer
gets to do its job.

What can I do to allow any test of the form
Assert.That(actual, Is.EqualTo(expected).Using(DateTimeComparer.Instance));
to pass if actual and expected can be converted to the same date time, and fail otherwise?

Here's an MCVE which shows two tests passing when I compare dates converted from different format strings, but failing when comparing a converted date with a real DateTime.

using NUnit.Framework;
namespace NunitTest
{
public class DateTimeComparer : IComparer
{
public static readonly DateTimeComparer Instance = new DateTimeComparer();

public int Compare(object x, object y)
{
var dateTime1 = Convert.ToDateTime(x);
var dateTime2 = Convert.ToDateTime(y);
return dateTime1.CompareTo(dateTime2);
}
}

[TestFixture]
public class DateTimeComparerTest
{
[Test]
public void TestComparerUsingString()
{
// Passes
Assert.That("2 August 2016",
Is.EqualTo("02/08/2016")
.Using(DateTimeComparer.Instance));
}

[Test]
public void TestComparerUsingDateTime()
{
// Passes
Assert.That(new DateTime(2016, 8, 2),
Is.EqualTo(new DateTime(2016, 8, 2))
.Using(DateTimeComparer.Instance));
}

[Test]
public void TestComparerUsingExpectedDateTime()
{
// Fails
Assert.That("2 August 2016",
Is.EqualTo(new DateTime(2016, 8, 2))
.Using(DateTimeComparer.Instance));
}

[Test]
public void TestComparerUsingActualDateTime()
{
// Fails
Assert.That(new DateTime(2016, 8, 2),
Is.EqualTo("2 August 2016")
.Using(DateTimeComparer.Instance));
}
}
}


Debugging shows that the
Compare
method is entered in the two passing cases and is not entered in the two failing cases.

Answer

After further investigation, I found that the correct behaviour was already implemented, just not in the default EqualityAdapter. Using any of the generic adapters works. That is, changing the comparer in the question to this makes the tests pass:

public class DateTimeComparer : IComparer<IConvertible>
{
    public static readonly DateTimeComparer Instance = new DateTimeComparer();

    public int Compare(IConvertible x, IConvertible y)
    {
        var str1 = Convert.ToString(x, CultureInfo.InvariantCulture);
        var str2 = Convert.ToString(y, CultureInfo.InvariantCulture);
        return string.Compare(str1, str2, StringComparison.Ordinal);
    }
}
Comments