Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to shim a class that is called more than once in the tested function using microsoft fakes

Suppose I got a class and it has a GetList() like this:

public class Foo
{
    public List<Bar> GetList(string para);
}

And the tested function is like

public ResultType TestedFunc()
{
    if( GetList("condition").count() == 1 )
    {
        //do arrange business
        if( GetList("same condition as above".count() == 2 )
        {
            //do core business
        }
        else
        {
            return ResultType;
        }
    }
    else
    {
        return ResultType
    }
}

In my test method I use ShimFoo.AllInstance.GetList to shim the GetList(). Regardless of the weird business and call logic, My question is how can I have the first GetList() call and the second GetListh() call return different results, say lists that respectively contains one and two entity.

For further discussion, I want to know the difference between the so called "fake" and what we already have - "mock"

I have read the three official article about MS Fake:

1.Isolating Code Under Test with Microsoft Fakes

2.Using stubs to isolate parts of your application from each other for unit testing

3.Using shims to isolate your application from other assemblies for unit testing

but I haven't yet found the guide that can do what I what as described above.

I've learned that behavior verification can be done on mock test, there are lot of framework that can achieve this(such as google mock). I can define how the mock class work when it is first/second/third time to be called, I can set a sequence to strictly limit the mock class. I wonder if MS Fakes can do the same thing.

Thanks guys.

like image 824
Ethan Avatar asked Oct 15 '25 18:10

Ethan


1 Answers

You could simply keep a call counter by capturing a int variable when setting up the Shim.

[TestMethod]
public void TestMethod1()
{
    using(ShimsContext.Create()) {
        int counter = 0; // define the int outside of the delegate to capture it's value between calls.

        ShimFoo sfoo = new ShimFoo();
        sfoo.GetListString = (param) =>
        {
            List<Bar> result = null;
            switch (counter)
            {
                case 0: // First call
                    result = new Bar[] { }.ToList();
                    break;
                case 1: // Second call
                    result = new Bar[] { new Bar() }.ToList();
                    break;
            }
            counter++;
            return result;
        };
        Foo foo = sfoo.Instance;

        Assert.AreEqual(0, foo.GetList("first").Count(), "First");
        Assert.AreEqual(1, foo.GetList("second").Count(), "Second");
        Assert.IsNull(foo.GetList("third"), "Third");
    }
}

Or you can check the parameter being passed and adjust the result accordingly.

[TestMethod]
public void TestMethod1()
{
    using(ShimsContext.Create()) {
        ShimFoo sfoo = new ShimFoo();
        sfoo.GetListString = (param) =>
        {
            List<Bar> result = null;
            switch (param)
            {
                case "first": // First call
                    result = new Bar[] { }.ToList();
                    break;
                case "second": // Second call
                    result = new Bar[] { new Bar() }.ToList();
                    break;
            }
            return result;
        };
        Foo foo = sfoo.Instance;

        Assert.AreEqual(0, foo.GetList("first").Count(), "First");
        Assert.AreEqual(1, foo.GetList("second").Count(), "Second");
        Assert.IsNull(foo.GetList("third"), "Third");
    }
}
like image 58
jessehouwing Avatar answered Oct 17 '25 07:10

jessehouwing



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!