Reputation: 307
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.
Upvotes: 1
Views: 2898
Reputation: 3952
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.
Upvotes: 0
Reputation: 56004
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());
}
}
Upvotes: 3
Reputation: 31464
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.
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.
Upvotes: 1
Reputation: 38179
You can use the InternalsVisibleTo attribute to allow the unit tests to see your method while keeping it private for the rest of the world.
Upvotes: 4