为什么在测试DateTime相等性时,这个单元测试会失败?

8

在.NET 3.5上使用NUnit 2.2时,使用DateTime.Equals时以下测试失败。为什么?

[TestFixture]
public class AttributeValueModelTest
{
    public class HasDate
    {
        public DateTime? DateValue
        {
            get
            {
                DateTime value;
                return DateTime.TryParse(ObjectValue.ToString(), out value) ? value : new DateTime?();
            }
        }

        public object ObjectValue { get; set; }
    }

    [Test]
    public void TwoDates()
    {
        DateTime actual = DateTime.Now;
        var date = new HasDate {ObjectValue = actual};
        Assert.IsTrue(date.DateValue.Value.Equals(actual));
    }
}

只是好奇,坚持使用 NUnit 2.2 的原因是什么?2.8 似乎是最新的版本。 - Perpetualcoder
我并没有努力坚持使用2.2版本。它只是因为TestDriven.NET与2.4一起安装在我的电脑上。我错过了什么? - flipdoubt
5个回答

16

日期不相等。TryParse会丢失一些滴答声。比较Tick值。

对于一个测试运行:

Console.WriteLine(date.DateValue.Value.Ticks);
Console.WriteLine(actual.Ticks);

输出:

633646934930000000
633646934936763185

我花了一点时间,在两个日期之间创建TimeSpan后,我终于弄明白了。+1给你。 - flipdoubt

3

问题并不在于TryParse,而是ToString()。

DateTime对象的精度(如果不考虑准确性)可达百万分之一秒。ToString()将其转换为字符串,只能保留到秒的精度。

TryParse会尽其所能处理所给定的内容。

如果您添加一个格式说明符(例如"yyyy-MM-dd HH:mm:ss.ffffff"),它应该可以工作。


嗯,Object.ToString()不接受格式说明符。有什么建议吗? - flipdoubt

1

要指定包含所有精度的格式,您可以使用String.Format()方法。James给出的示例如下:

String.Format("{0:yyyy-MM-dd HH:mm:ss.ffffff}", ObjectValue);

我不知道当你传递一个不是日期的东西时会发生什么。

也许一个更简单的方法是在你已经有一个日期对象的情况下添加一个特殊情况:

    public DateTime? DateValue
    {
        get
        {
            DateTime value = ObjectValue as DateTime;
            if (value != null) return value;
            return DateTime.TryParse(ObjectValue.ToString(), out value) ? value : new DateTime?();
        }
    }

0

我不知道在.NET中是否相同,但在Java中,equals通常只会比较实例是否相同,而不是值是否相同。你应该使用compareTo。


不,Java中“==”运算符用于引用相等性比较,而“equals()”方法用于值相等性比较。 - Adam Rosenfield
@Adam:默认情况下不行。你必须重写Object的equals方法才能获得你所描述的行为。 - Bill the Lizard
在苏联,== 等同于 Object.Equals。 - Amy B
@Adam。在编程时,保守地假设它比较实例,因为这是最常见的情况。反过来做有时会让你陷入麻烦并花费很长时间进行调试。只有当你绝对确定时才应该使用equals()。 - Stephane Grenier

0
公共日期时间? DateValue         {             获取             {                 DateTime value;                 bool isDate = DateTime.TryParse(ObjectValue.ToString(),out value);                 返回isDate?new DateTime?(value):new DateTime?();             }         }

我还没有运行代码,这只是根据外观判断的。如果我没有帮到你,我很抱歉。 - shahkalpesh
抱歉,问题出在TryParse上。 - flipdoubt
谢谢。当我查看代码时,它似乎返回DateTime(当TryParse成功时)而不是DateTime?。我在这里学到的一件事是,您可以将DateTime的实例分配给DateTime? :) - shahkalpesh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接