简体   繁体   中英

Unit testing private method

First of all, I know there is a lot of questions about this topic. I've read most of them, but I really don't know whether it's lack of proper OO programming, or if I'm missing something.

So I have a class xmlRead that reads in an XML file into some lists. I want to unit test this class. I reckon the easiest way to start of is to test addDataToList() . But that's a private method. So I'm wondering if I should make it public, or test the public method ReadTheXmlFile().

public class xmlRead 
{
    List<string> ... // A couple of lists that need to filled with data from the XML document
    xmlDocument xDoc = new xmlDocument

    public void ReadTheXmlFile()
    {
        // Find default file, if it doesn't exist, ask user for file through Openfiledialog
        // and open XMLDocument + error handling if XMLdocument is empty etc.
        xDoc.load(filepath);
        takeInXmlData();
    }

    private void takeInXmlData()
    {
        addDataToList(list<string> list1, xmlNode 1);
        // More addDataToList for different lists
        ...
        addDataToList(list<string> list2, xmlNode 2);
    }

    private void addDataToList(list<string> inputList, xmlNode)
    {
         foreach (XmlNode node in xmlDoc.SelectNodes(xmlNode))
         {
             inputList.Add(node.SelectSingleNode("Specific name of node").InnerText);
         }
    }

So I tried to separate things as much as possible. But this also means my method addDataToList is very small, but easy to unit test. But I also feel it shouldn't be a public method either. I could of course test the public method ReadTheXmlFile() , but then I'd have to make specific test cases for each outcome of error detection, and in my opinion I wouldn't properly test the actual intake of data into the list.

Am I just too overprotective and should I make addDateToList (or takeInXmlData ) public? Or should I just test the public method ReadTheXmlFile until I've taken into account all the possible ways?

It just feels like a lot of work, which sort of goes against the principle of short, simple unit tests.

PS: No need to worry about the fact that I load xDoc directly here, I have an Interface that manages the loading of the XML document (which I can stub later to break the dependencies). The focus is on the private methods here.

您可以使用InternalsVisibleTo属性来使单元测试看到您的方法,同时将其私有化。

Reflection allows you to call private methods and read or write private fields from outside of the class, but is really verbose to write.

In C# 4.0, this problem can be solved in a neat way using dynamic typing.

If you can use use C# 4.0 in your unit tests, check out this article:

Testing private methods with C# 4.0

A simple usage:

public class Service {
    private int Step1() {
        return 1;
    }
}

[TestClass]
public class TransparentObjectTests {
    [TestMethod]
    public void PrivateMethod() {
        dynamic s = new Service().AsTransparentObject();
        Assert.AreEqual(1, s.Step1());
    }
}

Your addDateToList method is implementation detail. What you want and should test is ReadTheXmlFile method. You even already spotted what should be tested:

Find default file, if it doesn't exist, ask user for file through Openfiledialog and open XMLDocument + error handling if XMLdocument is empty etc.

  • test what happens when find fails (this sounds like external dependecy job tho)
  • test error handling
  • test XML document being empty
  • test propert XML is returned upon success (this will implicitly test private methods)

And about this:

I could of course test the public method ReadTheXmlFile(), but then I'd have to make specific test cases for each outcome of error detection, and in my opinion I wouldn't properly test the actual intake of data into the list.

That's what you should indeed do. If your method has multiple possible error outcomes, each should be tested. It doesn't get any simplier than that. Most frameworks make this (multiple input/output testing) really easy with attributes such as NUnit's TestCase .

On a sidenote, if you find yourself in strong need of testing private method, it's usually good indicator that your class is doing too much stuff and extracting private method's functionality to external object might be worth considering.

you can try,

Open the AssemblyInfo.cs file. Add this code,

[assembly: InternalsVisibleTo("Your Test Library Name")]

Then, change private - to - internal

you can write test for your internal methods in XmlRead class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM