Search code examples
c#unit-testingmicrosoft-fakesstubs

Do I Stub or Shim a method inside my test method?


I have a method base.ResolveDate() inside my test method that's coming from a base class and its public and virtual. I want to stub/shim this method with my own, so do I stub or shim? Stub or Shim, how would I go about doing it? From my experience with MS Fakes it seems like it would be a Stub because Stub can only influence overridable methods. - ALM 2012

Here is the test method:

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);
    }

Here is the method from the base class I want to Stub/Shim?

public virtual DateTime ResolveDate(ISeries comparisonSeries, DateTime targetDate)
    {            
        if (this.key == comparisonSeries.Key)
            return targetDate;

        return DateHelper.FindNearestDate(targetDate, comparisonSeries.AsOfDates);
    }

Solution

  • To test a derived method in isolation from its base implementation, you need to shim it. Given the following system under test:

    namespace ClassLibrary7
    {
        public class Parent
        {
            public virtual string Method()
            {
                return "Parent";
            }
        }
    
        public class Child : Parent
        {
            public override string Method()
            {
                return base.Method() + "Child";
            } 
        }
    }
    

    You can write the following test for the Child.Method().

    using ClassLibrary7;
    using ClassLibrary7.Fakes;
    using Microsoft.QualityTools.Testing.Fakes;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    
    namespace Test
    {
        [TestClass]
        public class UnitTest1
        {
            [TestMethod]
            public void TestMethod1()
            {
                using (ShimsContext.Create())
                {
                    var child = new Child();
    
                    var shim = new ShimParent(child);
                    shim.Method = () => "Detour";
    
                    string result = child.Method();
    
                    Assert.IsFalse(result.Contains("Parent"));
                    Assert.IsTrue(result.Contains("Detour"));
                    Assert.IsTrue(result.Contains("Child"));
                }
            }
        }
    }
    

    Note that the first two Asserts are included only to illustrate how the parent method is detoured. In a real test only asserts for the child method would be needed.