8

I have a base class:

public abstract class MyBaseClass
{
    protected virtual void Method1()
    {    
    }
} 

and a derived class:

public class MyDerivedClass : MyBaseClass
{
    public void Method2()
    {
        base.Method1();
    }
}

I want to write a unit test for Method2 to verify that it calls Method1 on the base class. I'm using Moq as my mocking library. Is this possible?

I came across a related SO link:

Mocking a base class method call with Moq

in which the 2nd answer suggests it can be achieved by setting CallBase property to true on the mock object. However it's not clear how this would enable the call to the base class method (Method1 in the above example) to be verified.

Appreciate any assistance with this.

Community
  • 1
  • 1
aw1975
  • 1,669
  • 3
  • 20
  • 35
  • 2
    Why is it a requirement that the base method is called? If you mock it, all you are verifying that the _mock_ calls the base method. Are you just verifying that the `base.` syntax works or do you _need_ inherited classes to call the base? – D Stanley Apr 19 '16 at 18:37
  • 2
    Also, you should only be testing that the _results_ are correct. Testing that a particular _implementation_ is used is generally an indication of a bad design. – D Stanley Apr 19 '16 at 18:39
  • 1
    Does the base method have side effects that you can verify? – D Stanley Apr 19 '16 at 18:40
  • @DStanley Yes there are side effects that can be verified and I think that's probably the route I'll take. I was just wondering if it's indeed possible using mocking libraries such as Moq to verify that a base class method is called from a derived class. – aw1975 Apr 19 '16 at 18:45
  • Possibly, but it makes a lot more sense to verify the _results_ rather than the _implementation_. Plus it frees you up to change the implementation without having to re-write your tests (so long as the _results_ are correct). – D Stanley Apr 19 '16 at 18:48
  • In your current implementation, you can't intercept the call with Moq, however since `MyDerivedClass` doesn't implement `Method1`, you could remove the `base.` prefix from the call and then you would be able to intercept the call. This is likely to be the *right* thing to do anyway, since otherwise you're cutting derived implementations of `Method1` out which feels wrong. Further reading: http://stackoverflow.com/a/31201708/592182 and http://stackoverflow.com/a/31062287/592182 – forsvarir Apr 20 '16 at 07:32
  • Possible duplicate of [Original method still getting called in Moq even after CallBase = true/false](http://stackoverflow.com/questions/31198854/original-method-still-getting-called-in-moq-even-after-callbase-true-false) – forsvarir Apr 20 '16 at 07:33

3 Answers3

17

Unit tests should verify behavior, not implementation. There are several reasons for this:

  • The results are the goal, not how you get the results
  • Testing results allows you to improve the implementation without re-writing your tests
  • Implementations are harder to mock

You might be able to put in hooks or create mocks that verify that the base method was called, but do you really care how the answer was achieved, or do you care that the answer is right?

If the particular implementation you require has side effects that you can verify, then that is what you should be validating.

D Stanley
  • 149,601
  • 11
  • 178
  • 240
  • 2
    Good answer(+1)... One more important thing for the OP: If you won't verify the expected behavior of the method under test then future changes in the base class may break the CUT behavior without and notification... – Old Fox Apr 19 '16 at 22:34
  • If you are not testing for implementation details then how do you enforce new changes don't break critical steps that need to be taken. EG. `class Query` calls `Execute` which itself calls two methods `Where` and `Sort`. Say I'm a new hire and I go and remove the call to `Sort` now my class is not performing as expected. – Adrian Aug 28 '18 at 19:09
  • @Adrian The unit test should verify that the _results_ are still correct (meaning that they are properly sorted in this case). My point is you should not care (from a unit test perspective) that the specific `Sort` method is called or whether a different `Sort` method is called, or just sorted within the `Execute` method. – D Stanley Aug 28 '18 at 19:16
  • Ok, that makes total sense. This has actually helped me think about unit testing in a different light. Thank you – Adrian Aug 29 '18 at 20:05
6

Mocking the base class from the perspective of the derived class is not possible. In your simple example, I would suggest one of the two options.

Option 1: In the event that MyDerivedClass really shouldn't care what MyBaseClass is up to, then use dependency injection! Yay abstraction!

public class MyClass
{
    private readonly IUsedToBeBaseClass myDependency;

    public MyClass(IUsedToBeBaseClass myDependency){
        _myDependency = myDependency;
    }

    public void Method2()
    {
        _myDependency.Method1();
    }
}

Elsewhere in test land...

[TestClass]
public class TestMyDependency {
    [TestMethod]
    public void TestThatMyDependencyIsCalled() {
        var dependency = new Mock<IUsedToBeBaseClass>();
        var unitUnderTest = new MyClass(dependency.Object);
        var unitUnderTest.Method2();
        dependency.Verify(x => x.Method1(), Times.Once);
    }
}

Option 2: In the event that MyDerivedClass NEEDS to know what MyBaseClass is doing, then test that MyBaseClass is doing the right thing.

In alternative test land...

[TestClass]
public class TestMyDependency {
    [TestMethod]
    public void TestThatMyDependencyIsCalled() {
        var unitUnderTest = new MyDerivedClass();
        var unitUnderTest.Method2();
        /* verify base class behavior #1 inside Method1() */
        /* verify base class behavior #2 inside Method1() */
        /* ... */
    }
}
Frank Bryce
  • 8,076
  • 4
  • 38
  • 56
4

What you're describing is not a test of your code, but a test of the behavior of the language. That's fine, because it's a good way to ensure that the language behaves the way we think it does. I used to write lots of little console apps when I was learning. I wish I'd known about unit testing then because it's a better way to go about it.

But once you've tested it and confirmed that the language behaves the way you expect, I wouldn't keep writing tests for that. You can just test the behavior of your code.

Here's a real simple example:

public class TheBaseClass
{
    public readonly List<string> Output = new List<string>();

    public virtual void WriteToOutput()
    {
        Output.Add("TheBaseClass");
    }
}

public class TheDerivedClass : TheBaseClass
{
    public override void WriteToOutput()
    {
        Output.Add("TheDerivedClass");
        base.WriteToOutput();
    }
}

Unit test

    [TestMethod]
    public void EnsureDerivedClassCallsBaseClass()
    {
        var testSubject = new TheDerivedClass();
        testSubject.WriteToOutput();
        Assert.IsTrue(testSubject.Output.Contains("TheBaseClass"));
    }
Scott Hannen
  • 27,588
  • 3
  • 45
  • 62