Search code examples
c#unit-testingmicrosoft-fakes

Do I shim out public methods in my tested method using shims?


I'm still trying to figure out what Shims in Microsoft Fakes is used for correctly. I understand it is for runtime method interceptors and it allows you to provide your own implementaion for almost any method but let me ask a more unit testy type question. In the method below, should I shim out the PUBLIC STATIC method and stub out the overridable method base.ResolveDate(comparisonSeries, targetDate)? Should I just test whats inside ResolveDate() and nothing else? It seems like this is the way you properly test a method using unit tests. Just test the method UNLESS the method has nested private method calls, in which case you would run the unit test through those private methods (According to "The Art of Unit Testing" by Roy Osherove you don't test private method independantly).

public override DateTime ResolveDate(ISeries comparisonSeries, DateTime targetDate)
{
   if (comparisonSeries == null)
   {
      throw new ArgumentNullException("comparisonSeries");
   }

   switch (comparisonSeries.Key)
   {               
      case SeriesKey.SomeKey1:
      case SeriesKey.SomeKey2:
      case SeriesKey.SomeKey3:
      case SeriesKey.SomeKey4:
      case SeriesKey.SomeKey5:
      return DateHelper.PreviousOrCurrentQuarterEnd(targetDate);
   }
   return base.ResolveDate(comparisonSeries, targetDate);
}

Solution

  • In most cases, it should not be necessary to isolate the target method from the private classes or members it calls. Assuming that DateHelper.PreviousOrCurrentQuarterEnd and base.ResolveDate have their own unit tests, the overridden ResolveDate method can be unit tested to verify that

    a) for special values of the SeriesKey, it returns a result that would be expected from the DateHelper.PreviousOrCurrentQuarterEnd. b) for all other values of the SeriesKey, it returns a result that would be expected from the base.ResolveDate.

    However, if the dependencies of the target method are hard to setup, such as when working with legacy code, you can use Fakes to isolate the target method from its dependencies instead. In this example, you can stub the ISeries interface and shim the DateHelper.PreviousOrCurrentQuarterEnd method or the base.ResolveDate method. As a rule of thumb, start unit testing with real objects and resort to stubs or shims only if the real objects have dependencies that would make a unit test too slow, fragile or complex. Consider refactoring those dependencies that are under your control to enable testing without fakes.