如何对相互递归方法进行单元测试?

发布于 2024-10-13 14:53:06 字数 667 浏览 4 评论 0原文

我有三个函数,看起来像这样:

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 GetMultipleNode(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
}

鉴于这三种方法是相互递归的,如何独立地对它们进行单元测试?

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 GetMultipleNode(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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

疯狂的代价 2024-10-20 14:53:06

通常,您不需要单独测试每个方法 - 您只需测试顶级方法是否执行正确的操作即可。

但是,如果由于某种原因您想要单独测试每个方法,您可以使用依赖项注入,就像测试任何具有依赖项的方法一样。这里唯一的区别是依赖项是对象本身。下面是一些示例代码来演示这个想法:

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));
        }
    }
}

当测试 nodegetter 参数时传递一个模拟。

我还将您的方法从私有更改为公共,因为最好只测试类的公共接口。

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.

撩发小公举 2024-10-20 14:53:06

好吧,你不能“独立”地对它们进行单元测试,因为它们显然相互依赖,但原则上你当然可以为 GetNode、GetMultipleNode 和 GetRepeatingNode 编写单独的测试,假设从以下代码中调用它们中的每一个是有意义的:使用它们。当然,GetRepeatingNode 调用 GetNode 等等,但这与调用一些完全外部的函数没有什么不同。

顺便说一句,您可能会考虑重构您的设计并使用多态性而不是 NodeType 枚举。只是一个想法:)

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 :)

烟若柳尘 2024-10-20 14:53:06

如果确实需要,您可以用接口包装每个方法,并为此方法创建模拟(例如使用 Moq 库),或者按照 Mark Byers 的建议将方法作为参数相互传递。但这似乎是过于复杂的解决方案。

正如我所看到的,代码中的方法是私有的,您确定为如此低级别的内部实现细节编写单元测试是个好主意吗?我认为这三种方法应该作为一个单元进行测试。这个逻辑被分成三个不同的方法只是为了提高代码的可读性,这不是某种公共API,所以你真的需要独立测试它们吗?

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?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文