Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is unit testing timed-interval actions with Thread.Sleep bad?

If I have an subject under test with a timer that causes some action to be taken at a timed interval, what's a good way to test that?

One method is to wrap the timer in an interface and inject it as a dependency.

However, I'd like to avoid creating yet another abstraction. It seems I can avoid that by injecting the update interval rather than the timer. Then in my test (assuming the AAA style of testing), I put a Thread.Sleep after Act and before Assert, using a very small time value so the test doesn't take long to run.

Is that a bad idea? I know it probably doesn't fully follow the principles of TDD, but it seems like there has to be a line where you stop surrounding everything with a contract and injecting it.

like image 232
Jeff B Avatar asked Feb 02 '12 22:02

Jeff B


People also ask

How long should unit tests run?

Some developers will be happy to run their extensive test suite in three minutes, while others want to go the more radical route and keep it under 60 seconds.

How often should unit tests be executed?

Run all your unit tests as often as possible, ideally every time the code is changed. Make sure all your unit tests always run at 100%. Frequent testing gives you confidence that your changes didn't break anything and generally lowers the stress of programming in the dark.

What does the timely rule of unit testing mean?

Timely: Unit tests should be written just before the production code that makes the test pass. This is something that you would follow if you were doing TDD (Test Driven Development), but otherwise it might not apply. I personally do not use TDD and therefore I always write my tests after writing my production code.


2 Answers

If the amount you sleep doesn't have any significance on the test and you can set i to 1 millisecond then is should be fine to simply sleep for 1 millisecond in your test.

However, if you want to test complex timing behavior with timeouts and specific actions being taken at specific points in time it quickly becomes easier to abstract the concept of time and inject it as a dependency. Then your tests can operate in virtual time and execute without delay even though the code operates as if real time was passing.

A simple way to virtualize time is to use something like this:

interface ITimeService {

  DateTime Now { get; }

  void Sleep(TimeSpan delay);

}

class TimeService : ITimeService {

  public DateTime Now { get { return DateTime.UtcNow; } }

  public void Sleep(TimeSpan delay) { Thread.Sleep(delay); }

}

class TimeServiceStub : ITimeService {

  DateTime now;

  public TimeServiceStub() {
    this.now = DateTime.UtcNow;
  }

  public DateTime Now { get { return this.now; } }

  public void Sleep(TimeSpan delay) {
    this.now += delay;
  }

}

You will have to extend this idea if you require more reactive behavior like timers firing etc.

like image 59
Martin Liversage Avatar answered Sep 30 '22 14:09

Martin Liversage


Dependancy injection is the way to go to completely avoid having any "test" code within your production code (such as setting the interval just for unit testing).

However, in this case, I would use the set interval code, but use it in both unit tests and production. Have production set it to whatever, and unit tests set it to a very small amount (10ms?). Then you won't have any dead code hanging around in production.

If you set the interval, I don't see why you need the Thread.Sleep? Just have your unit test block until you get the event from the subject (or continuously poll the subject). Whatever method you are using.

like image 30
peterept Avatar answered Sep 30 '22 15:09

peterept