7

I have a public method in a class that internally calls a particular private method within that class. It looks something like this :

public class MyClass : IMyClassInterface
{
    public List<int> MyMethod(int a, int b)
    {
        MyPrivateMethod(a, b, ref varList, ref someVal);
    }
    private void MyPrivateMethod(int a, int b, ref List<int> varList, ref double someval)
    {
    }
}

Now, I basically want to test this public method using NUnit. I am using NMock 2.0 for mocking. How do I do it? Since, it internally calls this private method which I do not want to make public. Or is there a way to do it if I turn the private method to protected instead?

Siddhant
  • 571
  • 1
  • 8
  • 32
  • 1
    The private method is an implementation detail of the public method. You should be testing it as part of testing the public method. If the method didn't do anything, would you still consider your tests of the public method to be valid? If so, why are you calling it? – forsvarir Jul 09 '15 at 05:55
  • I was not sure If generally we should test the private method as part of public method or not. It makes sense to test it as part of public method. – Siddhant Jul 09 '15 at 05:58
  • Still, if in case I just wanted to check whether that private method is called or not then making it protected would certainly help. – Siddhant Jul 09 '15 at 05:59
  • 1
    It might help in the short term, but the trade off is that you tightly couple you're tests to your implementation which makes it more difficult to refactor your code in the future. If it feels like this might be the right thing to do, then it could be that you have discovered a dependency in your class that could be extracted to be tested in isolation and injected into your class. – forsvarir Jul 09 '15 at 07:09

3 Answers3

7

Now, I basically want to test this public method (...)

This is great. This is what you should be doing. Forget about internal details for a moment. From public method point of view, is there any difference between these two snippets?

// Your current implementation
public void MyMethod(int a, int b)
{
    MyPrivateMethod(a, b);
}
private void MyPrivateMethod(int a, int b)
{
    var c = a + b;
    // some more code
}

// Private method inlined
public void MyMethod(int a, int b)
{
    var c = a + b;
    // some more code
}

Whoever calls (public) MyMethod will not be able to notice any difference between these two. End result is the same. It doesn't matter there is a private method call, because as far a public API is concerned it is irrelevant. You could inline said private method, make it gone forever, and from public consumer point of view nothing changes. End result is the only thing that's important. You test end result observable by code consumer. Not some internal gibberish.

Important realization is this:

Properly designed SOLID code will never put you in a position which will require you to do private mocking. Source of the problem? Bad design.

Source: How to mock private method - solutions

Yep. Sad but true, your design is not that great. Depending on whether you want to change that or not, there are few approaches you could take:

  • don't try to mock private details, focus on public API (doesn't help with design issue)
  • extract private method to class, introduce dependency (long-term solution, improves design and makes code easily testable)
  • make private method protected, override in test as suggested in other answer (doesn't help with design issue, might not yield valuable test)

Whichever you chose I leave up to you. However, I'll emphasize it one more time - mocking private method is not unit testing, library or tools problem - it is a design problem and is best solvable as such.


On a side note, (if you can) don't use NMock2. It's a library with last changes from 2009. It's like having a 30 year old car which was last serviced 15 years ago. There are much better ones nowadays (FakeItEasy, Moq, NSubstitute).

k.m
  • 30,794
  • 10
  • 62
  • 86
5

Yes the "trick" is to use protected instead of private and then inherit the class and run the test on the new class that executes the protected method. This is a very common way to make brownfield and legacy code testable.

    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            MyClassTestWrapped t = new MyClassTestWrapped();
            Assert.IsTrue(t.MyPrivateMethod(...));
            Assert.IsTrue(t.MyMethod(...));

            MockFactory _factory = new MockFactory();
            Mock<MyClassTestWrapped> mock;

            mock = _factory.CreateMock<MyClass>();
            mock.Expects.One.MethodWith(d => d.MyPrivateMethod());  // do the nmock magic here


        }
    }

    public class MyClass : IMyClassInterface
    {
        public List<int> MyMethod(int a, int b)
        {
            MyPrivateMethod(a, b, ref varList, ref someVal);
        }
// here change to protected
        protected void MyPrivateMethod(int a, int b, ref List<int> varList, ref double someval)
        {
        }
    }

    public interface IMyClassInterface
    {

    }

    public class MyClassTestWrapped : MyClass
    {
        public List<int> MyMethod(int a, int b)
        {
            base.MyMethod(a, b);
        }

        public List<int> MyPrivateMethod(int a, int b,ref List<int> varList, ref double someval)
        {
            base.MyPrivateMethod(a, b, ref varList, ref someval);
        }

    }
Thorarins
  • 1,836
  • 16
  • 21
  • Thanks. That should help.. Although could you tell me how do I mock the protected method using NMock when I am testing my public method. The public method calls it from within its definition. Or could you guide me to a website that could further provide me information on the same. – Siddhant Jul 09 '15 at 05:05
  • As far as i know you have to mock the testwrapped class using nmock ( Mock mock; and then do the nmock magic on that one. – Thorarins Jul 09 '15 at 05:34
  • Thanks. I'll try it out. – Siddhant Jul 09 '15 at 05:55
1

While currently you have to refactor your code to lose the private modifier ( wrappers and what not), You can do it fairly easy with tools Like Typemock Isolator.

I added some code to your example to write the test:

public class MyClass 
{
    public List<int> MyMethod(int a, int b)
    {
        List<int> varList = new List<int>();
        double someVal = 0;

        MyPrivateMethod(a, b, ref varList, ref someVal);

        return varList;
    }

    private void MyPrivateMethod(int a, int b, ref List<int> varList, ref double someval)
    {
    }
}

With this straight forward approach you just fake the private method as it is in your code (no changes in the production), even it's ref parameters:

[Test]
public void TestMethod1()
{
    //Arrange
    var myClass = new MyClass();
    var expectedVarList = new List<int> {1,2,3};

    Isolate.NonPublic.WhenCalled(myClass, "MyPrivateMethod")
        .AssignRefOut(expectedVarList, 0.0)
        .IgnoreCall();

    //Act
    var resultVarList = myClass.MyMethod(0, 0);

    //Assert
    CollectionAssert.AreEqual(expectedVarList, resultVarList);

}
Niels R.
  • 7,260
  • 5
  • 32
  • 44
JamesR
  • 745
  • 4
  • 15