rob23 rob23 - 1 month ago 9
C# Question

Using Moq, How do you Mock a method that uses local variables

New to Moq and this is a very simple example. I want to Mock the call to my "int smokeTest(int a, int b)" method which is used within my method "string getCode(int someID)". Variables for smokeTest are declared and set within getCode. The issue is when I mock the method call to smokeTest I always get a result of "0" within getCode but I want to see my predefined result of "20". The only work around I've found is to overload the method and pass in all variables. However, I do not want to do this because many of the methods I want to test declare and use local variables. What's the best way to test this method using Moq? Thanks

// Example A
public string getCode(int someID)
{
int x = 5;
int y = 5;
int z = _dataAccess.smokeTest(x, y);

return _dataAccess.getCode(someID);
}

// NOTE: Doesn't work as wanted
[Test]
public void test_getCode_TestB()
{
var x = It.IsAny<int>();
var y = It.IsAny<int>();

// NOTE: "20" is not returned, 0 is returned instead because local variables are used
_mockDataAccess.Setup(m => m.smokeTest(x, y)).Returns(20);
_mockDataAccess.Setup(m => m.getCode(234)).Returns("def345");

var result = _businessLogic.getCode(234);

Assert.IsTrue(result == "def345");
}

// Example B

// NOTE: Workaround - pass in variables
public string getCode(int someID, int a, int b)
{
var c = _dataAccess.smokeTest(a, b);
return _dataAccess.getCode(someID);
}

[Test]
public void test_getCode_TestC()
{
var x = It.IsAny<int>();
var y = It.IsAny<int>();

// NOTE: "20" is returned as wanted
_mockDataAccess.Setup(m => m.smokeTest(x, y)).Returns(20);
_mockDataAccess.Setup(m => m.getCode(234)).Returns("def345");

var result = _businessLogic.getCode(234, x, y);
Assert.IsTrue(result == "def345");
}

Answer

It will only work if you pass It.IsAny<int>() directly into the moq setup:

_mockDataAccess.Setup(m => m.smokeTest(It.IsAny<int>(), It.IsAny<int>())).Returns(20);

I was browsing moq source code to found out that doing this:

int x = It.IsAny<int>();
int y = It.IsAny<int>();
_mockDataAccess.Setup(m => m.smokeTest(x, y)).Returns(20);

will assigened x and y to be the deafult value of int which is 0, so your setup is equivalent to this:

_mockDataAccess.Setup(m => m.smokeTest(0, 0)).Returns(20); 

this setup tells the moq to return 20 if the parameters are 0 and 0, otherwise it will return the deafult value of int which is 0 again. This is not the behavior you intended to create so you should not assigned It.IsAny<int>() into x and y before you pass them into the moq setup.

As @Rob comment indicates It.IsAny<T> is a kind of stub that you can pass into the setup, the setup method will know how to deal with it using Expression Trees , but the value that this method actually returns is always the deafult of T.