Mocking local variables within the method-under-test

1 Answer 9700 Views
General Discussions
Asim
Top achievements
Rank 1
Asim asked on 26 Jul 2011, 10:54 PM
Hi!

Suppose my method-under-test looks like this:

public void TestMe()
{
    DataSet d1 = null;
    DataSet d2 = null;
    bool process = false;
    Helper helper = new Helper();
    process = helper.LoadFromDB(out d1, out d2) && d1 != null && d1.Tables[0] != null && d1.Tables[0].Count > 0

    if (process)
    {
        [...run business logic here...]
    }
    else
    {
        throw new Exception("Failed to load data from the db");
    }
}

In order to circumvent using a physical database, I mock "helper.LoadFromDB" in my unit test. The delegate I use in the "DoInstead" method populates the test1DS and test2DS datasets with made-up data, and the "Returns" in my arrange returns true.

 


Mock
.Arrange(() =>  helper.LoadFromDB(out test1DS, out test2DS))

.DoInstead(someDelegate)

.Returns(true);

 
The problem is that the data sets the mock implementation populates are the ones declared within the unit test, not the ones declared in the method-under-test. So the process flag in the code snippet above still returns false (due to d1 being null), and the business logic I wanted to test (within the "if (process)" block above) never gets run.

Is there a way to map (for lack of a better word) the test1DS and test2DS (that I declared in the unit test code and populated in my DoInstead delegate) to the data sets d1 and d2 declared within the method-under-test, so as to allow the process flag to evaluate to true once the mocked implementation has run?

Thanks,
Asim

Asim
Top achievements
Rank 1
commented on 28 Jul 2011, 05:43 PM

Update: I managed to find a solution to the issue in the original message. The trick was to not use a DoInstead in my Arrange statement. Instead, I pulled all the logic that I had originally put into the body of my DoInstead delegate into the body of the unit test method itself, and just used the Returns call in the Arrange, minus any DoInstead, like so:

 

Mock.Arrange(() => helper.LoadFromDB(out testDS1, out testDS2)).Returns(true);

 
After that, the " && d1 != null && d1.Tables[0] != null && d1.Tables[0].Count > 0" test (in the method-under-test) did pass.

This raises a very interesting question: Why is it that when I put the logic to instantiate and populate out parameters testDS1 and testDS2 in the body of the unit test method itself, the mocking works fine, but when I put the logic to instantiate and populate out parameters testDS1 and testDS2 in the Action delegate used in the "DoInstead", the method-under-test (that invokes the method that was mocked) sees these out parameters as null (i.e., un-initialized)? Is it a bug or by design?

Thanks,
Asim

1 Answer, 1 is accepted

Sort by
0
Ricky
Telerik team
answered on 01 Aug 2011, 01:24 PM
Hi Asim,

Thanks again for bringing the question. Out parameter is set as expected value which is basically a result value to be assigned once the method is executed. Therefore during Mock.Arrange, you are specifying to return the  expected out value once the method is executed rather what is set from the method itself.

In that case the following setup is specifying to set testDS1 and testDS2 for the out params and return the expected true value as well.

Mock.Arrange(() => helper.LoadFromDB(out testDS1, out testDS2)).Returns(true

While this is much cleaner than creating an extra Delegate and moving your test code there from the test method. However DoInstead is intended to perform tasks based on input (Action delegate). This is a similar behavior can be found with other mocking tools therefore keeps the consistency as well.

Hope that answers your question.

Kind regards,
Mehfuz
the Telerik team

Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get now >>

Tags
General Discussions
Asked by
Asim
Top achievements
Rank 1
Answers by
Ricky
Telerik team
Share this question
or