Just imagine that my asp.net mvc Controller method could have this code:
testplanService.AddTestplan(testplan,template,release);
which calls the below implemented service method:
public TestplanService
{
public void AddTestplan(Testplan testplan, Template template, Release release)
{
testplan.CreatedAt = DateTime.Now;
testplan.UserId = WindowsIdentity.GetCurrent().Name;
testplan.Name = release.Name + " " + template.Name + " " + testplan.UserId + " " + testplan.CreatedAt;
_provider.AddTestplan(testplan, template, release);
}
}
How can I test the CreatedAt, UserId and the Name property in the ASSERT when I do not know
the values inside this method?
Yes I know I could pass all 3 values inside the testplan object which is anyway passed to the service method, BUT a Controller class in mvc should not have these 3 lines of logic.
So what would you do?
I don’t want to imagine anything like that. The correct way is that your controller works with abstractions, not actual implementations. So instead of depending on an actual service implementation, this
testplanServicevariable that you are using in your controller will be a simple interface or an abstract class that will be injected into the constructor of your controller.Now in your unit test you could actually mock this interface and test your controller in isolation.
Now let’s consider the actual implementation of the service:
There are a couple of issues with this method. First of all it depends on non-deterministic data such as
DateTime.Nowwhich are difficult to unit test. Martin Fowler has a nice article about non-determinism in unit tests. It also depends on the currentWindowsIdentity. All that’s hard to unit test because your method depends on actual implementations instead of working with abstractions.So you will have to abstract those notions behind providers that you can mock in your unit test. Make sure all your components are weakly coupled between them. You will find it much easier to work with them in isolation.
UPDATE:
As requested in the comments section here’s an example of how to abstract datetime retrieval:
Consider the following class:
It’s obvious that unit testing
IsWeekendSoonis very difficult as it will depend on the day your unit test is run.So in order to break the non-determinism in this method you could do the following:
Now all that you need is to configure your favorite DI framework to inject
() => DateTime.Nowinto the constructor of this object and inside your unit test you can easily mock it:You can see how in this example we are able to force the method work with whatever date we want it to in the unit test in order to verify the correct behavior of the method.