Reputation: 14540
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);
}
Upvotes: 0
Views: 748
Reputation: 1312
One of the best uses of Microsoft Fakes is to make tests that would be integration tests unit tests instead. For example, a method which prepares some data and writes it to a file (technically too complex by some standards) could have a shim reroute the File.Write method, allowing you to test only the preparation code in isolation.
On the other hand, a design which requires shims is technically a bad one. In many cases it will happen, but when possible, methods should only do one thing and use dependency injection to keep the unrelated parts separate. You might then have a method such as SaveFile(SomeObject source, IFileManager manager)
where you pass in a stub for the writing logic.
In your case, this is one of the more difficult parts of unit testing. The base class is probably tested somewhere else, and you don't want to test it's code within your method's test - and the same is true of the DateHelper call.
The problem, however, is that your test will rely on the shims for both methods. If the implementation changes, but the result doesn't, your test could fail. That's something that should be avoided when testing. A change in results should break tests, but a refactor or optimization should not.
At the same time, given the scope of your method, I'd probably use shims anyway.
Upvotes: 0
Reputation: 6558
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.
Upvotes: 1