I’m doing some TDD practice for my own learning.
I’m trying to figure out how to transparently set up private properties of an object to support testing.
I have a binary tree node:
internal class Node : INode
{
public int Height { get; private set; }
public int Data { get; }
public INode? Left { get; private set; }
public INode? Right { get; private set; }
public Node(int data)
{
Data = data;
}
public INode? Find(int value)
{
if (value == Data) return this;
if(value < Data)
return Left?.Find(value);
else
return Right?.Find(value);
}
public void Insert(int value)
{
if (value < Data)
{
InsertOnLeft(value);
}
else if (value > Data)
{
InsertOnRight(value);
}
}
...
}
I want to be able to set the left and right nodes as mocks, so that I can use things like verify to check that the left node is called by Find when the value is less than Data. (there are other reasons, and quite frankly, this is a toy problem – please grant the assumption that putting mocks on left and right would be useful).
I have come up with three options for accessing the properties:
- Change the accessors from private to protected and have the test project use inheritance to allow the values to be set:
internal class TestableNode : Node
{
public void SetLeft(INode? node) { Left = node; }
public void SetRight(INode? node) { Right = node; }
}
- Make the accessors public in the class but not the interface. This will keep classes outside the library from seeing the accessor, but it makes me feel wrong.
- Changing/overloading the insert method to take a node instead of an integer value. This doesn’t feel right.
- Adding an internal insert method to Node that allows me to insert nodes to specific places. This makes me feel very wrong.
I feel that fundamentally changing the code to allow testing is really wrong – so options 2-4 are escalating degrees of worse on that scale. 1 is a relatively minor change – although it does prevent me from sealing the class.
I feel least bad about option one. Is there a good option that I haven’t thought of?
mike1952 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.