How to mock DateTime.Now in unit tests?

The normal solution is to hide it behind the interface.

public class RecordService { private readonly ISystemTime systemTime; public RecordService(ISystemTime systemTime) { this.systemTime = systemTime; } public void RouteRecord(Record record) { if (record.Created < systemTime.CurrentTime().AddMonths(-2)) { // process old record } // process the record } } 

In unit test, you can use a mock object and decide what to return

 [TestClass] public class When_old_record_is_processed { [TestMethod] public void Then_it_is_moved_into_old_records_folder() { var systemTime = A.Fake<ISystemTime>(); A.CallTo( () => system.Time.CurrentTime()) .Returns(DateTime.Now.AddYears(-1)); var record = new Record(DateTime.Now); var service = new RecordService(systemTime); service.RouteRecord(record); // Asserts... } } 

I do not want to introduce another interface in my class to get the current time. This is too difficult a solution for such a small problem. The solution is to use a static class with a public function.

 public static class SystemTime { public static Func<DateTime> Now = () => DateTime.Now; } 

Now we can remove the ISystemTime injection, and the RecordService looks like

 public class RecordService { public void RouteRecord(Record record) { if (record.Created < SystemTime.Now.AddMonths(-2)) { // process old record } // process the record } } 

In unit tests, we can just as easily make fun of system time.

 [TestClass] public class When_old_record_is_processed { [TestMethod] public void Then_it_is_moved_into_old_records_folder() { SystemTime.Now = () => DateTime.Now.AddYears(-1); var record = new Record(DateTime.Now); var service = new RecordService(); service.RouteRecord(record); // Asserts... } } 

Of course, there is a flaw in all of this. You use public fields (HORROR!), So no one stops you from writing such code.

 public class RecordService { public void RouteRecord(Record record) { SystemTime.Now = () => DateTime.Now.AddYears(10); } } 

I also think that it’s better to train developers than to create abstractions to protect them from any errors. Other possible problems are related to testing. If you forget to restore the function back to its original state, this may affect other tests. It depends on how the unit test runner runs the tests. You can use the same logic to perform file system operations

 public static class FileSystem { public static Action<string, string> MoveFile = File.Move; } 

In my opinion, the implementation of such functions (from time to time, simple operations with the file system) using public functions is quite acceptable. This simplifies code reading, reduces dependency, and can easily be a mockery in unit tests.

+8
c # unit-testing mocking
source share
3 answers

You do not need to do this manually. You can use the Moles framework for this. channel 9

+3
source share

I would not say that the current time was such a small task that if your application becomes international and is used in several time zones, in what time zone you get the current time, most likely you will need to use one common time zone, regardless of your region?

The interface allows you to distract this knowledge; I believe that the “current” time is quite a challenge.

+3
source share

Given that we are talking about idiomatic C #, I do not quite understand the problems with the ceremony behind the interface. In essence, you have a TimeProvider that you enter as a dependency in the constructor, and you provide it with a stub to control the logic of the corresponding code under test.

I don’t think that your other approaches provide benefits, and they have a negative aspect of not idioms, as well as eliminating the useful aspects of dependency injection (documenting dependencies, bullying, inversion of control, etc.)

0
source share

All Articles