0

I am trying to test that calling SendMessage after a set amount of time (in my case 1300ms) will give the correct result in the event handler. However Thread.Sleep(1300) is not waiting 1300ms, it only waits for about 300ms.

Unit Test

using System;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using mvce;

namespace mvceTest
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            Class1 c = new Class1();

            string finalResult = "";

            c.AnEvent += (o, entry) => { finalResult = entry; };

            DateTime start = DateTime.Now;

            while (finalResult == "")
            {
                Thread.Sleep(1300);
                c.SendMessage("message");
            }

            DateTime end = DateTime.Now;

            Assert.AreEqual(1300, (end - start).Milliseconds);

            Assert.AreEqual("message", finalResult);
        }
    }
}

Class1

using System;

namespace mvce
{
    public class Class1
    {
        private readonly object _lock = new object();

        private event EventHandler<string> _anEvent;

        public event EventHandler<string> AnEvent
        {
            add
            {
                lock (_lock)
                {
                    _anEvent += value;
                }
            }
            remove
            {
                lock (_lock)
                {
                    _anEvent -= value;
                }
            }
        }

        public void SendMessage(string message)
        {
            _anEvent?.Invoke(this, message);
        }

    }
}

The output I get is

Assert.AreEqual failed. Expected:<1300>. Actual:<302>.

Obviously I don't expect them to be equal, this is just for the example.

I have also tried System.Threading.Tasks.Task.Delay(1300).Wait();, but I get the same result.

How can I get the test thread to wait the right amount of time? Why doesn't Thread.Sleep work?

Matt Ellen
  • 11,268
  • 4
  • 68
  • 90
  • 1
    How did you measure `~300ms`? – SᴇM Jul 16 '19 at 10:54
  • @SeM it's what the assert tells me. – Matt Ellen Jul 16 '19 at 10:54
  • @MattEllen This might be an [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). What is it you are actually trying to achieve? – Nkosi Jul 16 '19 at 10:56
  • @Nkosi I have to test that the result of the event is affected by how long it takes for `SendMessage` to be called. – Matt Ellen Jul 16 '19 at 10:59
  • 1
    @MattEllen then I suggest you edit the question to clarify that. You would get better responses if that is made clear. Right now you are focusing more on the `Thread.Sleep` issue, which would put attention away from the actual problem. Provide a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) – Nkosi Jul 16 '19 at 11:00
  • Also I don't think `DateTime start = DateTime.Now;` and then using `(end - start).Milliseconds` will give you an accurate result. – SᴇM Jul 16 '19 at 11:03
  • @sem but will it be 1 second out? I'm open to suggestions. – Matt Ellen Jul 16 '19 at 11:03
  • @SᴇM Good catch. That is a very useful question. – Matt Ellen Jul 16 '19 at 11:12
  • @Nkosi if my example isn't minimal I don't know what you expect tbh. – Matt Ellen Jul 16 '19 at 11:14

2 Answers2

3

In your assert you're using:

Assert.AreEqual(1300, (end - start).Milliseconds);

Try using the following instead:

Assert.AreEqual(1300, (end - start).TotalMilliseconds);

TimeSpan.TotalMilliseconds :

Gets the value of the current TimeSpan structure expressed in whole and fractional milliseconds.

TimeSpan.Milliseconds :

Gets the milliseconds component of the time interval represented by the current TimeSpan structure.

The reason it is returning 300ms is because milliseconds component of your TimeSpan is in fact 300 milliseconds, but also the seconds component of your TimeSpan is 1 second.

Cotta
  • 130
  • 7
1

You should use TotalMilliseconds instead of Milliseconds. Also, it's better to measure time using Stopwatch.

This code shows that thread is indeed sleeping for 1300ms:

 static void Main(string[] args)
    {
        Class1 c = new Class1();

        string finalResult = "";

        c.AnEvent += (o, entry) => { finalResult = entry; };

        Stopwatch sw = new Stopwatch();
        DateTime start = DateTime.Now;

        while (finalResult == "")
        {
            sw.Start();
            Thread.Sleep(1300);
            var ms = sw.ElapsedMilliseconds;
            Console.WriteLine(ms);
            c.SendMessage("message");
        }
        DateTime end = DateTime.Now;
        Console.WriteLine((end - start).TotalMilliseconds);
}