通过使它们成为自由函数来对私有方法进行单元测试
Unit test private methods by making them free functions
在 2017 年的 cppcon 视频中,我看到了 Klaus Iglberger 的演讲,题目是“Free Your Functions!”。
在这次演讲中,演讲者谈到了如何切换到免费功能
简化测试私有方法的过程(参见 19:00)。这个想法是你拉
class 中的私有方法(你使它成为一个自由函数)并且它变得可测试。
起初,我觉得这个想法很有趣,但后来
我想得越多,就越不了解这实际上应该如何工作。例如,
假设我有以下(虚拟)class:
class SomeClass
{
public:
SomeClass();
~SomeClass();
void someTask();
private:
void someComplexTask();
void someOtherComplexTask();
};
void SomeClass::someTask()
{
someComplexTask();
someOtherComplexTask();
}
// private tasks implementations...
那么someComplexTask()
和someOtherComplexTask()
就是私有方法。这意味着他们
是实现细节,即它们只能在 SomeClass
(或朋友)内部调用。它
在我看来,如果你让它们成为自由函数,是的,它们会变得可测试,但它们不再是
私有的,也不仅仅是特定于 SomeClass
的实现细节。事实上,它们可以在代码的任何地方被调用...
所以我的问题是:为什么 Iglberger 先生的观点有效?
我也看了视频。但是,我有一些不同意见。
1- 您的方法是否需要访问字段?如果不是,则不属于class。但如果是这样,他们就需要这些字段。除非您将它们作为函数参数传递,否则自由函数无法访问这些字段。请注意,自由函数不应被视为 public 函数。
2- 并非所有功能都应该是自由功能。但最好避免在不需要时将所有内容都放在 class 中。
3- 私有函数不应该经常被测试。但如果你坚持,你也许可以执行诸如无效的黑客攻击(这并不总是像评论中提到的那样有效):
#define class struct
#define private public
#define protected public
#include "library.h"
#undef class
#undef private
#undef protected
释放你的函数更简洁,但并不更可行。
This is a clear indication that you have a design flaw. If you have a
private function that you need to test and you have to bend backwards
to make it work then something is wrong. You have missed something.
Your design doesn't work.
他的意思不仅仅是让私有函数免费。他不是在说:"get all your private functions and make them free functions"。他说需要测试的功能不应该是实现细节,因为如果您需要测试它,则表明该功能有用。
请关注他对代码的改造:
初始代码:
class X
{
public:
void doSomething( ... ) {
...
resetValues();
...
}
...
private:
void resetValues() {
for( int& value : values_ )
value = 0;
}
std::vector<int> values_;
};
他将 resetValues
从 X
中拉出来,但是 它使它在 std::vector<T>
上运行,而不是在 X
上运行:
void resetValues( std::vector<int>& vec )
{
for( int& value : vec )
value = 0;
}
现在 resetValues
是一个可以重复使用和测试的功能。因为它确实与 X
无关,但是通过重置向量的所有值,使其成为自由函数而不是私有 X
方法是一种有效的设计。
我喜欢 Rann Lifshitz 在评论中的表达方式:
I think the better way to go here is to understand that some private
functions are, in fact, common utility functions
在 2017 年的 cppcon 视频中,我看到了 Klaus Iglberger 的演讲,题目是“Free Your Functions!”。 在这次演讲中,演讲者谈到了如何切换到免费功能 简化测试私有方法的过程(参见 19:00)。这个想法是你拉 class 中的私有方法(你使它成为一个自由函数)并且它变得可测试。
起初,我觉得这个想法很有趣,但后来 我想得越多,就越不了解这实际上应该如何工作。例如, 假设我有以下(虚拟)class:
class SomeClass
{
public:
SomeClass();
~SomeClass();
void someTask();
private:
void someComplexTask();
void someOtherComplexTask();
};
void SomeClass::someTask()
{
someComplexTask();
someOtherComplexTask();
}
// private tasks implementations...
那么someComplexTask()
和someOtherComplexTask()
就是私有方法。这意味着他们
是实现细节,即它们只能在 SomeClass
(或朋友)内部调用。它
在我看来,如果你让它们成为自由函数,是的,它们会变得可测试,但它们不再是
私有的,也不仅仅是特定于 SomeClass
的实现细节。事实上,它们可以在代码的任何地方被调用...
所以我的问题是:为什么 Iglberger 先生的观点有效?
我也看了视频。但是,我有一些不同意见。
1- 您的方法是否需要访问字段?如果不是,则不属于class。但如果是这样,他们就需要这些字段。除非您将它们作为函数参数传递,否则自由函数无法访问这些字段。请注意,自由函数不应被视为 public 函数。
2- 并非所有功能都应该是自由功能。但最好避免在不需要时将所有内容都放在 class 中。
3- 私有函数不应该经常被测试。但如果你坚持,你也许可以执行诸如无效的黑客攻击(这并不总是像评论中提到的那样有效):
#define class struct
#define private public
#define protected public
#include "library.h"
#undef class
#undef private
#undef protected
释放你的函数更简洁,但并不更可行。
This is a clear indication that you have a design flaw. If you have a private function that you need to test and you have to bend backwards to make it work then something is wrong. You have missed something. Your design doesn't work.
他的意思不仅仅是让私有函数免费。他不是在说:"get all your private functions and make them free functions"。他说需要测试的功能不应该是实现细节,因为如果您需要测试它,则表明该功能有用。
请关注他对代码的改造:
初始代码:
class X
{
public:
void doSomething( ... ) {
...
resetValues();
...
}
...
private:
void resetValues() {
for( int& value : values_ )
value = 0;
}
std::vector<int> values_;
};
他将 resetValues
从 X
中拉出来,但是 它使它在 std::vector<T>
上运行,而不是在 X
上运行:
void resetValues( std::vector<int>& vec )
{
for( int& value : vec )
value = 0;
}
现在 resetValues
是一个可以重复使用和测试的功能。因为它确实与 X
无关,但是通过重置向量的所有值,使其成为自由函数而不是私有 X
方法是一种有效的设计。
我喜欢 Rann Lifshitz 在评论中的表达方式:
I think the better way to go here is to understand that some private functions are, in fact, common utility functions