Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mock a method for test

Trying to mock a method that is called within another method.

// code part
public virtual bool hello(string name, int age)
{
    string lastName = GetLastName();
}

public virtual string GetLastName() 
{
    return "xxx"; 
}

// unit test part
Mock<Program> p = new Mock<Program>();
p.Setup(x => x.GetLastName()).Returns("qqq");

I want the method GetLastName to always return "qqq".

like image 689
codeislife Avatar asked Mar 31 '16 23:03

codeislife


People also ask

What is a mock for testing?

Mock Testing provides you the ability to isolate and test your code without any interference of the dependencies and other variables like network issues and traffic fluctuations. In simple words, in mock testing, we replace the dependent objects with mock objects.

How do you mock a function?

There are two ways to mock functions: Either by creating a mock function to use in test code, or writing a manual mock to override a module dependency.

How do you mock a method in Python?

How do we mock in Python? Mocking in Python is done by using patch to hijack an API function or object creation call. When patch intercepts a call, it returns a MagicMock object by default. By setting properties on the MagicMock object, you can mock the API call to return any value you want or raise an Exception .


1 Answers

This should work, assuming those are the full method implementations

public class MyProgram
{

    public bool hello(string name, int age)
    {
        string lastName = GetLastName();

        return string.Format("hello {0}", lastName);
    }

    public virtual string GetLastName() 
    {
        return "xxx"; 
    }
}

public class MyProgramTests
{

    [TestMethod]
    public void MyTest()
    {

        string stringToReturn = "qqq";
        Mock<MyProgram> name = new Mock<MyProgram>();
        name.CallBase = true;
        name.Setup(x => x.GetLastName()).Returns(stringToReturn );

        var results = name.Object.hello(It.IsAny<string>(), It.IsAny<int>());

        string expected = string.Format("hello {0}", results);

        Assert.AreEqual(expected, results);
    }
}

I'm still not quite following your comment:

What does the parameter really mean of Mock What should ?? be? excuse me, I don't quite understand the syntax. To clarify, mock means that when I put break points in my code I the breakpoints should skip the methods that I am mocking. Am I right?

Mock<T> allows you to mock a type of T - T being a generic indicator, also meaning pretty much anything that's a class. In the traditional, you would be mocking an interface, not an actual class, but in the example above, we're mocking a class. For the sample unit test posted, the purpose of the unit test is to test the implementation of hello(string, int). We know that hello(string, int) relies on another method within that class called GetLastName(). GetLastName()s implementation, while important, is not important to the scope of unit testing hello(string, int). For this reason, we mock the call and its return - in order to test the functionality of hello(string, int) without having to worry about its dependency's implementation.

I have surrounded the above with actual class names to hopefully make it more obvious that we're mocking the class MyProgram and providing a new implementation (mock) of GetLastName()

Thanks for the answer. What if I want to test a method that calls another method that calls another method? For eg. what if the method hello called another method?

The same principle applies, when you're building your unit tests (assuming they are unit tests, and not integration tests or other, you always want to concentrate on testing one public method. What's the difference between unit and integration tests?

public class Foo
{

    public string Bar()
    {
        return string.Format("{0}Bar", Baz(5));;
    }

    public virtual string Baz(int someNumber)
    {
        return string.Format("{0}Baz", DoStuff(someNumber).ToString());
    }

    public virtual int DoStuff(int someNumber)
    {
        return someNumber+1;
    }

}

If we're unit testing Bar() we do not care about the implementation of Baz(int) or even worse DoStuff(int). Note we don't care about the implementation, we do care that they return values. From Bar()s perspective, the only thing that is important is the Baz(int) returns a string. What string? It doesn't matter to Bar()s unit test.

Sample test for Bar():

[TestMethod]
public void Bar_ReturnsBazValueWithBarAppended
{
    // Arrange
    string testBazReturn = "test";
    Mock<Foo> mock = new Mock<Foo>();
    mock.CallBase = true;
    mock
        .Setup(s => s.Baz(It.IsAny<int>())
        .Returns(testBazReturn);

    // Act
    var results = mock.Object.Bar();

    // Assert
    Assert.AreEqual(string.Format("{0}{1}", testBazReturn, "Bar"), results);
    mock.Verify(v => v.Baz(It.IsAny<int>())); // Verifies that Baz was called
}

Notice in the above, our actual implementations of Baz(int), and DoStuff(int) do not matter, as we are disregarding the actual implementation of Baz(int), and DoStuff(int) doesn't even come into play.

Now, if we were to test Baz(int) we just follow the same mentality:

[TestMethod]
public void Baz_ReturnsDoStuffValueWithBazAppended
{
    // Arrange
    int testDoStuffReturn = 1;
    Mock<Foo> mock = new Mock<Foo>();
    mock.CallBase = true;
    mock
        .Setup(s => s.DoStuff(It.IsAny<int>())
        .Returns(testDoStuffReturn);

    // Act
    var results = mock.Object.Baz(5);

    // Assert
    Assert.AreEqual(string.Format("{0}{1}", results, "Baz"), results); // Validates the result
    mock.Verify(v => v.DoStuff(It.IsAny<int>())); // Verifies that DoStuff was called
}

In the above, now that we're unit testing Baz(int), we don't care about Bar(), and the only thing we care about in DoStuff(int) is that it returns a value (but not how it arrives at that value.)

And finally DoStuff(int):

[TestMethod]
public void DoStuff_ReturnsParameterPlusOne()
{
    // Arrange
    Foo foo = new Foo();
    int passed = 1;
    int expected = passed + 1;

    // Act
    var results = foo.DoStuff(passed);

    // Assert
    Assert.AreEqual(expected, results);
}
like image 153
Kritner Avatar answered Oct 12 '22 03:10

Kritner