Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 the 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".

like image 969
Arthis Avatar asked Jun 07 '11 08:06

Arthis


People also ask

How do you use unit testing in Moq?

You can use Moq to create mock objects that simulate or mimic a real object. Moq can be used to mock both classes and interfaces. However, there are a few limitations you should be aware of. The classes to be mocked can't be static or sealed, and the method being mocked should be marked as virtual.

Is Moq a unit test?

The Moq framework is an open source unit testing framework that works very well with . NET code and Phil shows us how to use it.

What is Moq testing in C#?

Moq is a mocking framework for C#/. NET. It is used in unit testing to isolate your class under test from its dependencies and ensure that the proper methods on the dependent objects are being called.

How do you mock a method in Moq?

First, we instantiate the FakeDbArticleMock class and indicate which setup we want to use for this test. Then, it is necessary to instantiate the repository we want to test and inject the mock instance into it. Finally, we call the method we are testing and assert the results.


1 Answers

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.

like image 151
ThomasArdal Avatar answered Oct 13 '22 01:10

ThomasArdal