开发者

Unit testing with Moq

Let's say I have a plain class with several functions:

public class MyClass
{
    public int GetTotal(int myValue, string myString)
    {
        if (myValue > 10)
            return GetTotal(myValue);
        else
            return GetTotal(myString);
    }

    public int GetTotal(int myValue)
    {
        return myValue * 25 / 12 + 156;
    }

    public int GetTotal(string myString)
    {
        return myString.Length * 25 / 48 + 27;
    }
}

I would like to unit test my first function and "mock" the others, int GetTotal(int myValue) and int GetTotal(string myString), in order to test only the code inside the main function. I am using Moq as th开发者_StackOverflowe mocking framework. Are there some tricks which would allow me to get the code from the function I want to test and mock the inner call to the other functions? Or should I have to call a second object like this to mock everything?

public class MyCalculator
{
    public int GetTotal(int myValue)
    {
        return myValue * 25 / 12 + 156;
    }

    public int GetTotal(string myString)
    {
        return myString.Length * 25 / 48 + 27;
    }
}

public class MyClass
{
    MyCalculator _Calculator;

    public MyClass(MyCalculator calculator) { _Calculator = calculator; }
    public int GetTotal(int myValue, string myString)
    {
        if (myValue > 10)
            return _Calculator.GetTotal(myValue);
        else
            return _Calculator.GetTotal(myString);
    }
}

I know the latest is the cleanest way, but I have a lot of functions calling themselves one after the other so that would make a lot of classes to write.

Update

Mock implementation of Thomas' answer:

public class MyClass
{
    public int GetTotal(int myValue, string myString)
    {
        if (myValue > 10)
            return GetTotal(myValue);
        else
            return GetTotal(myString);
    }

    public virtual int  GetTotal(int myValue)
    {
        return myValue * 25 / 12 + 156;
    }

    public virtual int GetTotal(string myString)
    {
        return myString.Length * 25 / 48 + 27;
    }
}

[TestClass]
public class Test
{
    [TestMethod]
    public void MyClass_GetTotal()
    {
        Mock<MyClass> myMockedClass = new Mock<MyClass>() {CallBase = true};

        myMockedClass.Setup(x => x.GetTotal(It.IsAny<int>())).Returns(1);
        myMockedClass.Setup(x => x.GetTotal(It.IsAny<string>())).Returns(2);

        var actual = myMockedClass.Object.GetTotal(0,string.Empty);

        Assert.AreEqual(2,actual);
    }
}

Update 2

See Gishu answer also for a more global look on this "issue".


Sure! In Rhino Mocks you can use a partial mock for exactly that purpose. Create a new mock like this:

var mock = MockRepository.GeneratePartialMock<MyClass>();

Then you can mock or stub those two methods that you don't want called like this:

mock.Stub(x => x.GetTotal(10)).Return(42);

It requires your GetTotal methods to be virtual though.


You use mocks to abstract away troublesome dependencies. So if your class deals with files, networks, things that are difficult to control/sense, you abstract them away behind a role/interface. This allows you to fake/mock the role (isolating your tests from the test-unfriendly real implementation/dependency).

So if A depends on B and B is difficult to control/sense OR just slow. We put B behind a role R and then mock R for unit-testing A.

In your case, your A.Method1 internally calls Method2 or Method3, which I assume are not test-unfriendly. Isolating M1 from M2 and M3 is just too much cost for little benefit IMHO (unless I am not understanding some contextual details). If tomorrow you decide to refactor Method1 to use M4 instead of M3, your tests would fail even if M1 does what it is supposed to do (from the functionality p.o.v.)

You could directly write tests against Method1 without letting the tests know the implementation details (that it calls M2 and M3). So my comment was isolating objects is useful at times.. but isolating functions of the same object from each other is overkill IMHO.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜