74

I'm wondering if anybody's found a good solution to this:

In our unit tests; we commonly use Assert.AreEqual() to validate our results. All is well and good; until we start trying to use this on DateTime properties.

Although the times are very similar, sometimes they are off by milliseconds, which causes the tests to fail. In our application; as long as they're accurate to the second; that's good enough for us.

Has anybody found a good way to somehow implement tolerances in this case? Typically our workaround is to split it into 2 separate statements; one which checks the .ToShortDateString(), and another that checks .ToShortTimeString(), but this looks sloppy in my opinion.

Jim B
  • 8,344
  • 10
  • 49
  • 77

3 Answers3

107

Use Assert.That and Is.Equal constraint instead of Assert.AreEqual. Below is a code sample from the Nunit website itself

DateTime now = DateTime.Now;
DateTime later = now + TimeSpan.FromHours(1.0);

Assert.That(now, Is.EqualTo(now) );
Assert.That(later, Is.EqualTo(now).Within(TimeSpan.FromHours(3.0)));
Assert.That(later, Is.EqualTo(now).Within(3).Hours);
Andrey Marchuk
  • 13,301
  • 2
  • 36
  • 52
Rajeesh
  • 4,377
  • 4
  • 26
  • 29
  • 1
    Much cleaner solution. If this Assert fails, the message produced will clearly indicate the cause of the failure. – GuiSim Apr 20 '12 at 17:32
  • 2
    Why use `Assert.That` instead of `Assert.AreEqual`? Could you give some explanation? – kuskmen Aug 29 '17 at 14:38
  • @kuskmen check out the discussion at https://stackoverflow.com/questions/16086870/assert-that-vs-assert-true `Assert.That` give you more extensibility and better logging if done correctly. – brianfeucht Aug 21 '18 at 16:44
99

You can check tolerances with something like:

Debug.Assert((date1 - date2) < TimeSpan.FromSeconds(1));

If you are unsure which date is newer, use

Debug.Assert(Math.Abs((date1 - date2).TotalSeconds) < 1)

NUnit has also added built in support for this using the Within keyword

DateTime now = DateTime.Now;
DateTime later = now + TimeSpan.FromHours(1.0);

Assert.That(later, Is.EqualTo(now).Within(TimeSpan.FromHours(3.0)));
Assert.That(later, Is.EqualTo(now).Within(3).Hours);
Andrey Marchuk
  • 13,301
  • 2
  • 36
  • 52
SwDevMan81
  • 48,814
  • 22
  • 151
  • 184
  • Very nice. Never thought to implement it this way – Jim B Aug 26 '10 at 17:51
  • But don't you really mean `<`? – Dan Tao Aug 26 '10 at 17:51
  • @Dan Tao - Yeah, had my assert thinking was backward, yeah if u want it to error, then it should – SwDevMan81 Aug 26 '10 at 17:56
  • 4
    This will fail if date2 is larger than date1 by more than a second. Should check the absolute value of the total seconds of the difference. e.g. `Debug.Assert(Math.Abs((date1 - date2).TotalSeconds) < 1)` – Nathan Ernst Aug 26 '10 at 18:31
  • 2
    NUnit has in-built support for this, see my answer below http://stackoverflow.com/questions/3577856/nunit-assert-areequal-datetime-tolerances/7601507#7601507 – Rajeesh Sep 30 '11 at 06:52
10

To correctly check if any 2 arbitrary dates are equals to within a 1 second tolerance, the following is a correct solution:

Debug.Assert(Math.Abs((date1 - date2).TotalSeconds) < 1)

I figured I'd add this as a solution since the accepted solution was incorrect when date2 is larger than date1 by more than a second, and the solution has not been updated following my comment to @SwDevMan81.

Nathan Ernst
  • 4,540
  • 25
  • 38