106

I have the following method:

public CustomObect MyMethod()
{
    var lUser = GetCurrentUser();
    if (lUser.HaveAccess)
    {
        //One behavior
    }
    else 
    {
        //Other behavior
    }

    //return CustomObject
}

I want to mock IMyInterface.GetCurrentUser, so that while calling MyMethod I could get to one of the code paths to check it. How to do that with Moq?

I'm doing the following thing:

var moq = new Mock<IMyInterface>();
moq.Setup(x => x.GetCurrentUser()).Returns(lUnauthorizedUser);

//act
var lResult = moq.Object.MyMethod();

But for some reason lResult is always null, and when I'm trying to get into MyMethod in debug, I'm always skipping to the next statement.

Pang
  • 9,564
  • 146
  • 81
  • 122
Yaroslav Yakovlev
  • 6,303
  • 6
  • 39
  • 59
  • 1
    Where do you have `lUnauthorizedUser` initialized? I would imagine you would want something like `moq.Setup(x => x.GetCurrentUser()).Returns(new User() { HaveAccess = false });` – Tyler Treat Jan 22 '11 at 22:30
  • 1
    Tyler, sure I`m setting it in the above code, just didn`t pasted it to keep the code short. – Yaroslav Yakovlev Jan 23 '11 at 04:08

4 Answers4

196

This is called a partial mock, and the way I know to do it in Moq requires mocking the class rather than the interface and then setting the CallBase property on your mocked object to true.

This will require making all the methods and properties of the class you are testing virtual. Assuming this isn't a problem, you can then write a test like this:

var mock = new Mock<YourTestClass>();
mock.CallBase = true;
mock.Setup(x => x.GetCurrentUser()).Returns(lUnauthorizedUser);
mockedTest.Object.MyMethod();
Community
  • 1
  • 1
lee
  • 2,158
  • 1
  • 14
  • 16
  • 5
    I've seen similar answers, but they forget to mention to set `CallBase` to true, veeerrrry essential part, thanks! – Mike de Klerk Jul 19 '18 at 07:42
  • 3
    I hear its a code smell to modify your application code just for a test. What do you think of this scenario in this light? In my case, right now, I'm just testing an ASP.Net REST controller, so I don't see any foreseeable reason to subclass the controller, but it also doesn't seem like a problem to just add 'virtual' to my methods? – Evan Sevy Jun 13 '19 at 21:10
  • 1
    @RuneStar retrofitting tests is a tricky thing - if you modify the code to make it testable then it doesn't have tests so you're not protected against regressing it. marking stuff as virtual is pretty safe as these things go. If you really wanted to you could wrap your class in an interface (which you should be doing in TDD anyways), then setup the method call(s) you want to mock to call the real methods. overkill in my opinion but worth having in the tool box in some situations (e.g., you just want to have one method call be the real implementation and the rest are mocked). – lee Oct 29 '19 at 04:46
  • This worked for me. I made my `protected` method `virtual`, but I did not need `mock.CallBase = true;` I like Charles W's answer better. – JohnB Apr 08 '21 at 17:01
54

Expanding on lee's answer,

You do not need to make all of the methods and properties on your class virtual, only the ones you wish to mock.

Also, it should be noted that you should be mocking the concrete implementation of your class.

var mock = new Mock<YourTestClass>(); // vs. var mock = new Mock<IYourTestInterface>();

If your class does not have a default constructor, you will also need to specify arguments to pass in to it via:

var mock = new Mock<YourTestClass>(x, y, z);
// or
var mock = new Mock<YourTestClass>(MockBehavior.Default, x, y, z);

Where x, y, z are the first, second, and third parameters to your constructor respectively.

And lastly, if the method you are looking to mock is protected, you will need to include Moq.Protected

using Moq.Protected;

TReturnType returnValue = default(TReturnType);

mock.Protected()
    .Setup<TReturnType>("YourMockMethodName", It.IsAny<int>()) // methodname followed by arguments
    .Returns(returnValue);
Pang
  • 9,564
  • 146
  • 81
  • 122
Charles W
  • 2,262
  • 3
  • 25
  • 38
  • 8
    It's worth noting that you can use `nameof(YourTestClass.YourMockMethodName)` instead of "YourMockMethodName". Due to this when you refactor method name test will still work. – Shoter Nov 02 '17 at 07:43
54

I had a similar case. I found the following code gave me more flexibility to use both mocked methods and actual methods from some specific implementation of an interface:

var mock = new Mock<ITestClass>(); // Create Mock of interface

// Create instance of ITestClass implementation you want to use
var inst = new ActualTestClass();

// Setup to call method of an actual instance
// if method returns void use mock.Setup(...).Callback(...)
mock.Setup(m => m.SomeMethod(It.IsAny<int>())
    .Returns((int x) => inst.SomeMethod(x));

Now you can use the actual method but also use things like Verify to see how many times it has been called.

Pang
  • 9,564
  • 146
  • 81
  • 122
Brandon Rader
  • 916
  • 9
  • 24
  • 2
    This is really interesting work around, we can achieve the same without making virtual of class method. – Harshad Vekariya Jun 20 '18 at 13:41
  • 1
    Do you know of a way to set this up for all methods/properties of an instance, like automatically, and not one-by-one? – veljkoz Jan 09 '20 at 09:07
  • This is exactly how I did it also, most of the methods I wanted mocked and it was only a couple that were just pure functions anyway that I wanted to call the actual versions of. I called into them statically like this, rather than write out returns that would essentially just duplicate what they did. – Detail Apr 05 '21 at 13:42
11

Since this was a top result when searching, expanding on lee's answer, you can avoid having to use virtual methods by using the As<T>() method to assign an interface.

var mock = new Mock<YourTestClass>().As<IYourTestClass>();
mock.CallBase = true;

var realResult = mock.Object.YourMethod();

mock.Setup(c => c.YourMethod()).Returns("FAKE");

var fakeResult = mock.Object.YourMethod();

Note however that if your class internally uses a method you mock in this fashion, it will still call the real method as it has no awareness of the mocked type and is calling from this. This reduces the usability of this approach and may lead you (as it did me) to understand why there is little documentation on this pattern.

Kyle Cooley
  • 115
  • 2
  • 7
  • Excellent tip. Like you mentioned, the fact that "internal calls" to a mocked method won't work is a limitation, but I think this setup is very useful when the concrete method calls injected dependencies which can then easily be mocked. If your concrete class takes constructor parameters, remember to pass those to the `Mock` constructor (e.g. `new Mock("Test", mockedDependency).As()`) – Anders Aug 31 '23 at 15:06