使用 Moq 只模拟一些方法

我有以下方法:

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


//return CustomObject
}

我想模拟 IMyInterface.GetCurrentUser,这样在调用 MyMethod时,我就可以找到一个代码路径来检查它。怎么对付莫克?

我要做的是:

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


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

但由于某些原因,lResult总是 null,当我试图进入 MyMethod调试时,我总是跳到下一个语句。

69908 次浏览

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

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

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.

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.