views:

203

answers:

1

I really appreciate Moq's Loose mocking behaviour that returns default values when no expectations are set. It's convenient and saves me code, and it also acts as a safety measure: dependencies won't get unintentionally called during the unit test (as long as they are virtual).

However, I'm confused about how to keep these benefits when the method under test happens to be virtual.
In this case I do want to call the real code for that one method, while still having the rest of the class loosely mocked.

All I have found in my searching is that I could set mock.CallBase = true to ensure that the method gets called. However, that affects the whole class. I don't want to do that because it puts me in a dilemma about all the other properties and methods in the class that hide call dependencies: if CallBase is true then I have to either

  1. Setup stubs for all of the properties and methods that hide dependencies -- Even though my test doesn't think it needs to care about those dependencies, or
  2. Hope that I don't forget to Setup any stubs (and that no new dependencies get added to the code in the future) -- Risk unit tests hitting a real dependency.

What I think I want is something like:
mock.Setup(m => m.VirtualMethod()).CallBase();
so that when I call mock.Object.VirtualMethod(), Moq calls into the real implementation...

Q: With Moq, is there any way to test a virtual method, when I mocked the class to stub just a few dependencies? I.e. Without resorting to CallBase=true and having to stub all of the dependencies?


Example code to illustrate
(uses MSTest, InternalsVisibleTo DynamicProxyGenAssembly2)

In the following example, TestNonVirtualMethod passes, but TestVirtualMethod fails - returns null.

public class Foo
{
    public string NonVirtualMethod() { return GetDependencyA(); }
    public virtual string VirtualMethod() { return GetDependencyA();}

    internal virtual string GetDependencyA() { return "! Hit REAL Dependency A !"; }
    // [... Possibly many other dependencies ...]
    internal virtual string GetDependencyN() { return "! Hit REAL Dependency N !"; }
}

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestNonVirtualMethod()
    {
        var mockFoo = new Mock<Foo>();
        mockFoo.Setup(m => m.GetDependencyA()).Returns(expectedResultString);

        string result = mockFoo.Object.NonVirtualMethod();

        Assert.AreEqual(expectedResultString, result);
    }

    [TestMethod]
    public void TestVirtualMethod() // Fails
    {
        var mockFoo = new Mock<Foo>();
        mockFoo.Setup(m => m.GetDependencyA()).Returns(expectedResultString);
        // (I don't want to setup GetDependencyB ... GetDependencyN here)

        string result = mockFoo.Object.VirtualMethod();

        Assert.AreEqual(expectedResultString, result);
    }

    string expectedResultString = "Hit mock dependency A - OK";
}
+1  A: 

Since nobody's answered this question for ages and I think it deserves an answer, I'm going to focus on the highest-level question you asked: how to keep these benefits when the method under test happens to be virtual.

Quick answer: you can't do it with Moq, or at least not directly. But, you can do it.

Let's say that you have two aspects of behaviour, where aspect A is virtual and aspect B is not. That pretty much mirrors what you've got in your class. B can use other methods or not; it's up to you.

At the moment, your class Foo is doing two things - both A and B. I can tell that they're separate responsibilities just because you want to mock A out and test B on its own.

Instead of trying to mock out the virtual method without mocking out anything else, you can:

  • move behaviour A into a separate class
  • dependency inject the new class with A into Foo through Foo's constructor
  • invoke that class from B.

Now you can mock A, and still call the real code for B..N without actually invoking the real A. You can either keep A virtual or access it through an interface and mock that. This is in line with the Single Responsibility Principle, too.

You can cascade constructors with Foo - make the constructor Foo() call the constructor Foo(new A()) - so you don't even need a dependency injection framework to do this.

Hope this helps!

Lunivore
Just to check: you're confirming that if the method under test is virtual, and we're using Mock<T>, we do HAVE to set CallBase to true?
Daryn
I'm suggesting that if you're calling CallBase in the first place, there's probably a different way to get the same benefit and which probably leads to a design of code that works in most contexts. Perhaps you have one of those rare contexts which absolutely requires CallBase - I don't know. Can you tell me more about why CallBase for a method would be the simplest solution to your problem?
Lunivore