单元测试私有方法,使它们成为自由函数

Bob*_*ane 2 c++ unit-testing private-methods non-member-functions

在2017年的cppcon视频中,我遇到了Klaus Iglberger的一个名为" Free Your Functions! " 的演讲.在这次演讲中,演讲者谈到了如何切换到自由函数可以简化测试私有方法的过程(参见19:00).这个想法是你将私有方法拉出类(你使它成为一个自由函数),它变得可测试.

起初,我觉得这个想法很有意思,但是我想的越多,我就越不了解这实际上应该如何工作.例如,假设我有以下(虚拟)类:

class SomeClass
{
public:
    SomeClass();
    ~SomeClass();

    void someTask();

private:

    void someComplexTask();
    void someOtherComplexTask();

};

void SomeClass::someTask()
{
    someComplexTask();
    someOtherComplexTask();
}

// private tasks implementations...
Run Code Online (Sandbox Code Playgroud)

然后someComplexTask()someOtherComplexTask()是私有方法.这意味着它们是实现细节,即它们只能在内部SomeClass(或朋友)调用.在我看来,如果你让它们成为自由函数,是的它们变得可测试,但它们不再是私有的,也不仅仅是特定的实现细节SomeClass.实际上,它们可以从代码中的任何地方调用......

所以我的问题是:为什么Iglberger先生的观点有效?

bol*_*lov 6

这清楚地表明您存在设计缺陷.如果你有一个私人功能,你需要测试,你必须向后弯曲使其工作,然后出现问题.你错过了什么.你的设计不起作用.

他的观点不仅仅是让私人职能免费.他并没有说:"获取所有私人功能并使其成为免费功能".他说,需要测试的功能不应该是一个实现细节,因为如果你需要测试它,这表明功能是有用的.

请密切关注他对代码所做的转换:

初始代码:

class X
{
public:
 void doSomething( ... ) {
    ...
    resetValues();
    ...
 }
 ...
private:
 void resetValues() {
     for( int& value : values_ )
        value = 0;
 }
 std::vector<int> values_;
};
Run Code Online (Sandbox Code Playgroud)

resetValues退出了,X 它使它在a std::vector<T>上运行,而不是X:

void resetValues( std::vector<int>& vec )
{
 for( int& value : vec )
   value = 0;
}
Run Code Online (Sandbox Code Playgroud)

现在resetValues是一个可以重用和测试的功能.因为它确实与之无关X,但是通过重置向量的所有值,使其成为自由函数而不是私有X方法是有效的设计.

我喜欢Rann Lifshitz在评论中的表述:

我认为更好的方法是了解一些私有函数实际上是常用的函数

  • @RannLifshitz:*"在通用实用程序类中应公开的常用实用程序函数"* - 对于不共享数据或职责的函数,实用程序命名空间比类更适合:它们将逻辑分组与头文件分离并且 - 为了更好或更坏 - 让客户端程序员可以自由决定是使用命名空间还是特定功能,或者在客户端代码中将它们显式化. (3认同)