免费功能和单元测试

时间:2013-04-29 13:31:51

标签: c++ unit-testing boost tdd visitor-pattern

我有兴趣测试下面的函数navigateFoo:

virtual void navigateFoo(const vector<Node>& nodes) 
{
    // find the foo node in the list of nodes
    Nodes::const_iterator fooNodeI = findFooNode(nodes);

    // if we have found the foo node
    if(fooNodeI!=nodes.end()) 
    {
        // the id for retrieving the associated Foo Container from the cache 
        std::string id = getCacheIdentifier(*fooNodeI);
        // the Foo Container associated with the Foo Node
        FooContainer& container = _fooContainerCache->get(id);

        // the name of the Foo item within the Foo Container
        std::string name = getName(*fooNodeI);
        // if foo is not found in the associated container, add it
        if(findFoo(name, container)==container.end()) 
        {
            container.push_back( createFoo(getData(*fooNodeI)) );
        }
    }
}

Node的类型为boost :: variant,其中此变体包含Foo1,Foo2,Bar1和Bar2等类型。

自由函数findFooNode使用访问者模式来定位Foo节点(类型为Foo1或Foo2)

自由函数getCacheIdentifier还使用访问者模式来定位Foo节点的缓存标识符。

_fooContainerCache是一个依赖注入,在我的单元测试中被模拟。

getName也是一个自由函数,createFoo也是如此。

所有免费功能本身都经过单元测试,并在我的代码中用于其他功能。

事情很容易在线上进行测试:

FooContainer& container = _fooContainerCache->get(id);

因为我只需要在模拟中检查期望的id是否被呈现给get函数。

但是,要在此行之后测试代码,我需要检查对我的模拟引用返回的FooContainer所做的更改。但是,如果createFoo将来要改变,我知道它会改变,这导致我必须更改createFoo和navigateFoo的单元测试。但是,如果我依赖注入一个FooFactory,我会避免这个问题,而是这样做:

container.push_back( _fooFactory->create( getData(*fooNodeI) ));

然后我也可以在我的单元测试中模拟这个功能。如果此接口背后的行为发生变化,那么它不会导致我必须重写navigateFoo的测试。

然而,当我编写createFoo时,我从未觉得应该将其作为接口实现,所以现在我觉得我只是为了能够编写更好的测试而添加一个接口。然后问题出现了,我应该为任何其他免费功能提供界面吗?在这方面有没有经验法则?

1 个答案:

答案 0 :(得分:1)

  

然后出现了问题,我是否应该为其他任何免费功能提供界面?

SOLID每个类都应该有一个接口是必不可少的。我个人并不是100%遵循这条规则。

  

这方面有没有经验法则?

遵循你的直觉。如果您觉得您需要一个类需要一个接口来简化单元测试,那么只需添加一个接口即可。它将简化您和维护者的生活。

但请注意YAGNI


此外,this question可能会产生一些疑问。