Reputation: 3121
The problem:
The code below does not allow me to modify the parameters that I pass into a method that has been mocked with Moq.
Additional details:
I am attempting to mock a generic data access object that provides a method called ExecuteStoredProcedureWithParameters
. The method accepts two parameters: a stored procedure name and a collection of SqlParameter
objects. I have stored procedures that return values via output parameters, so I am attempting to mock the data access method and modify the value of the output parameter (which is a member of the SqlParameter
collection that gets passed in). From my research, the code I have below seems like it should work (I'm just attempting to modify the input parameters by setting them to empty/null for testing purposes). The return value I specified in my mock setup gets returned and stored in retval
, however the values of testProcedure
and testParameters
remain unchanged after the mock method is executed. What am I doing wrong and how can I modify the objects that are passed into my mock method?
My interface:
public interface IGenericDAO
{
int ExecuteStoredProcedureWithParameters(string procedureName, Collection<SqlParameter> parameters);
}
Test method:
// Create a mock generic DAO
var mock = new Mock<IGenericDAO>();
mock.Setup(x => x.ExecuteStoredProcedureWithParameters("TestProcedure", It.IsAny<Collection<SqlParameter>>()))
.Returns(111)
.Callback<string, Collection<SqlParameter>>((proc, prms) => { proc = string.Empty; prms = null; });
// Execute the mocked method with dummy parameters
var testProcedure = "TestProcedure";
var testParameters = new Collection<SqlParameter>();
var retval = mock.Object.ExecuteStoredProcedureWithParameters(testProcedure, testParameters);
Upvotes: 2
Views: 1892
Reputation: 7271
You are setting the local variable prms
to null. This has no effect on the actual testParameters
variable because of standard pass-by-value semantics. The Collection
is passed by value into the function and so is shallow-copied like any other variable. What you are doing is similar to this trivial example:
void A()
{
int x = 10;
B(x);
Console.WriteLine(x); // 'x' is still 10
}
void B(int x) // input argument copied into local 'x'
{
x = 20; // local 'x' modified
} // local 'x' discarded
This will print out 10, because only the local copy x
is modified and then thrown away at the end of the function.
In your actual example, if do something like prms.Add(new SqlParameter(...))
then, at the end of the call, testParameters
will contain the added value.
Upvotes: 3