Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When mocking a class with Moq, how can I CallBase for just specific methods?

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"; } 
like image 890
Daryn Avatar asked May 12 '10 21:05

Daryn


People also ask

Can you mock a class with Moq?

You can use Moq to create mock objects that simulate or mimic a real object. Moq can be used to mock both classes and interfaces. However, there are a few limitations you should be aware of. The classes to be mocked can't be static or sealed, and the method being mocked should be marked as virtual.

What does Moq CallBase do?

CallBase , when initialized during a mock construction, is used to specify whether the base class virtual implementation will be invoked for mocked dependencies if no setup is matched. The default value is false . This is useful when mocking HTML/web controls of the System.

What can be mocked with Moq?

Unit testing is a powerful way to ensure that your code works as intended. It's a great way to combat the common “works on my machine” problem. Using Moq, you can mock out dependencies and make sure that you are testing the code in isolation. Moq is a mock object framework for .

How do you call an original method in mock?

Set CallBase to true on your mock. This will call the original virtual methods or properties if they exist, and haven't been set up to return a canned value.


1 Answers

I believe Lunivore's answer was correct at the time it was written.

In newer versions of Moq (I think since version 4.1 from 2013) it is possible to do what you want with the exact syntax you propose. That is:

mock.Setup(m => m.VirtualMethod()).CallBase(); 

This sets up the loose mock to call the base implementation of VirtualMethod instead of just returning default(WhatEver), but for this member (VirtualMethod) only.


As user BornToCode notes in the comments, this will not work if the method has return type void. When the VirtualMethod is non-void, the Setup call gives a Moq.Language.Flow.ISetup<TMock, TResult> which inherits the CallBase() method from Moq.Language.Flow.IReturns<TMock, TResult>. But when the method is void, we get a Moq.Language.Flow.ISetup<TMock> instead which lacks the desired CallBase() method.

Update: andrew.rockwell notes below that it works now for void methods, and apparently that was fixed in version 4.10 (from 2018).

like image 168
Jeppe Stig Nielsen Avatar answered Sep 30 '22 22:09

Jeppe Stig Nielsen