开发者

How do you unit test mutually-recursive methods?

I have three functions that looks something like this:

private Node GetNode(Node parentNode)
{
    var node = new node();

    switch (parentNode.NodeType)
    {
       case NodeType.Multiple:    node = GetMultipleNode(parentNode)
       case NodeType.Repeating:   node = GetRepeatingNode(parentNode)
    }

    return node;
}

private Node GetMultipleN开发者_运维知识库ode(Node parentNode)
{
    foreach (var child in parentNode.Children)
        return GetNode(child);
}

private Node GetRepeatingNode(Node parentNode)
{
    for (int i=0; i < parentNode.Count; i++)
         return GetNode(new Node(i));  // Assume meaningful constructor for Node
}

Given that these three methods are mutually recursive, how does one go about unit testing them independently?


Normally you wouldn't need to test each method individually - you can just test that the top-level method does the right thing.

However if for some reason you want to test each method separately you can use dependency injection just as you would test any method that has dependencies. The only difference here is that the dependency is the object itself. Here is some example code to demonstrate the idea:

class NodeGetter : INodeGetter
{
    public Node GetNode(Node parentNode)
    {
        return GetNode(parentNode, this);
    } 

    public Node GetNode(Node parentNode, INodeGetter nodeGetter)
    {
        switch (parentNode.NodeType)
        {
           case NodeType.Multiple:
               return nodeGetter.GetMultipleNode(parentNode, nodeGetter);
           case NodeType.Repeating:
               return nodeGetter.GetRepeatingNode(parentNode, nodeGetter);
           default:
               throw new NotSupportedException(
                   "Node type not supported: " + parentNode.NodeType);
        }
    }

    public Node GetMultipleNode(Node parentNode, INodeGetter nodeGetter)
    {
        foreach (Node child in parentNode.Children)
        {
            return nodeGetter.GetNode(child);
        }
    }

    public Node GetRepeatingNode(Node parentNode, INodeGetter nodeGetter)
    {
        for (int i = 0; i < parentNode.Count; i++)
        {
            // Assume meaningful constructor for Node
            return nodeGetter.GetNode(new Node(i));
        }
    }
}

When testing for the nodegetter argument pass a mock.

I also changed your methods from private to public because it is better to only test the public interface of your class.


Well, you can't unit test them "independently" since they obviously depend on one another, but in principle you can certainly write separate tests for GetNode, GetMultipleNode, and GetRepeatingNode, assuming it makes sense to call each of these from the code that uses them. Sure, GetRepeatingNode calls GetNode, and so on, but that's no different from it calling some totally external function.

Incidentally, you might consider refactoring your design and use polymorphism instead of your NodeType enumeration. Just an idea :)


If it is really required, you could wrap each method with interface and create mocks for this methods (using Moq library for example) or passing methods into each other as a parameters as Mark Byers propose. But it seems that this is overcomplicated solution.

As I can see, that methods from your code are private, are you sure, that it is good idea to write unit-tests for such low-level of internal implementation details? I believe that this three methods should be tested as one unit. This logic is separated into three different methods only to improve code readabilty and this is not some kind of public API, so do you really need to test them independently?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜