【问题标题】:Can I compare objects of different types using NUnit's EqualTo().Using()?我可以使用 NUnit 的 EqualTo().Using() 比较不同类型的对象吗?
【发布时间】:2016-08-02 03:25:12
【问题描述】:

我希望能够使用 NUnit 的 Assert.That 比较 IConvertibleDateTime 的任意两件事,最好不要创建自定义约束。我有一个简单的IComparer 可以很好地解决问题。它适用于EqualTo().Using()只要实际和预期的类型相同。看起来EqualsConstraintAdjustArgumentIfNeeded 方法在我的IComparer 开始工作之前使断言失败。

如果实际和预期可以转换为相同的日期时间,我该怎么做才能让Assert.That(actual, Is.EqualTo(expected).Using(DateTimeComparer.Instance)); 形式的任何测试通过,否则失败?

这是一个 MCVE,它显示当我比较从不同格式字符串转换的日期时通过了两个测试,但在比较转换后的日期与实际 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));
        }
    }
}

调试显示,两个通过的情况下都输入了Compare方法,两个失败的情况下都没有输入。

【问题讨论】:

  • 我目前的解决方法是致电ToString() 了解我所有的实际情况和预期。这显然是 hacky,并且让我接触到可能的文化问题(因为仍然有一些人在 2 月的某个时间阅读“02/08/2016”......),但它现在正在工作。

标签: c# nunit icomparer


【解决方案1】:

这是一个您必须在 NUnit 中提交才能完全解决的问题。我相信观察到的行为的原因可以在 CanCompare 方法的EqualityAdapter.cs 中找到:

public virtual bool CanCompare(object x, object y)
{
    if (x is string && y is string)
        return true;

    if (x is IEnumerable || y is IEnumerable)
        return false;

    return true;
}

如果参数都是字符串或都不是字符串,则返回 true,但如果一个是字符串而另一个不是(字符串是通过 IEnumerable<char> 的 IEnumerable),则返回 true。如果 CanCompare 返回 false 它甚至不会进入您的自定义比较器以查看参数是否相等,并且框架将运行默认比较逻辑。我不相信 CanCompare 在与任何基本的Using(IComparer) 类型约束一起使用时会被覆盖。

【讨论】:

  • 是的,我敢打赌这不是查理对那段代码的想法。也许应该是“如果其中一个是 IEnumerable 而另一个不是”。即使这样,如果提供了Using,则应该跳过CanCompare
  • 好收获!有人把它归档。 :-)
  • 归档于GitHub。抱歉,拖了这么久,我完全忘记了!目前我工作不足,所以我会尝试构建 NUnit,编写一些测试等。不过,在我可以构建之前,我不会提出问题。
  • 抱歉不接受。你的回答还是有帮助的。但是另一种实现方式(使用通用适配器而不是普通适配器)对未来的答案寻求者更有帮助。
【解决方案2】:

经过进一步调查,我发现正确的行为已经实现,只是不在默认的EqualityAdapter中。使用任何通用适配器都可以。也就是说,将问题中的比较器更改为 this 会使测试通过:

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

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

【讨论】:

  • 使用IComparer&lt;object&gt; 都有帮助(当没有其他共同祖先时)。
猜你喜欢
  • 2012-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多