我目前正在使用另一个只有静态函数的类。
在我尝试测试课程之前,一切正常。
以下是问题的简单代码示例:
class A {
static String getSometing() {
return String("Something: ") + heavyCalculation().asString();
}
}
class B {
B() {}
~B() {}
String runSomething(const String& name) {
if(name.equals("something")) {
return A::getSomething();
} else {
return "Invalid name!";
}
}
}
假设A类工作正常(并且已经过单元测试测试),我想检查B类中的 runSomething 函数。
我的第一个选择是为内部类创建模拟(在此示例中 - 类A),但在这种情况下,它将不会从A继承任何内容,因为它只有静态函数。
我的第二个选择是将A类的调用封装在B内的私有函数中,这样我就可以控制它们的返回值(尽管选择这个选项会使这个优点变得更复杂)。
我的问题是:是否有更好的方法来测试依赖于静态类/函数的C ++类而不是我当前的选项?
提前致谢,
塔尔。
答案 0 :(得分:3)
通过将对静态函数的引用(在我的情况下是外部依赖项)重构为新的私有函数并在测试的存根上覆盖它,我在类似情况下的单元测试中取得了成功,所以我可以推荐这种方法< / p>
如果重构函数保持私有,它们不应对设计的复杂性产生很大影响,它们应该足够小,不会对代码的可读性产生负面影响。
答案 1 :(得分:1)
如果您没有使用单片测试套件,那么很容易。我假设你在A.cpp中有A类,在B.cpp中有B类,B的测试在B_test.cpp中。
创建一个名为A_mock.cpp的文件
class A
{
static String getSometing() {
return String("Expected Something");
}
};
然后在编译B_test文件时,只需链接A_mock.o而不是A.o。
g++ -Wall B_test.cpp B.cpp A_mock.cpp
答案 2 :(得分:0)
您可以将指向该函数的指针传递给A类的构造函数。然后,为了进行测试,您可以将一些指针传递给模拟函数,您可以在其中执行任何操作。
答案 3 :(得分:0)
为什么静态功能?我建议不要让它静止。
然后,您可以为A类(在C ++中,这意味着只有纯虚函数头的类)创建一个名为AInterface的接口。 A类将实现(继承)AInterface并实现此虚函数。
然后将指向此接口的指针传递给B类的构造函数,并将其存储在名为m_A的成员变量中。然后在测试中,创建实现AInterface的MockClassA。将MockClassA传递给B类构造函数,并将m_A设置为输入。
server
测试代码
class AInterface
{
virtual String getSomething() = 0;
}
class A : public AInterface
{
String getSometing() {
return String("Something: ") + heavyCalculation().asString();
}
}
class B
{
B(AInterface A) : { m_A = A; }
~B() {}
String runSomething(const String& name) {
if(name.equals("something")) {
return m_A.getSomething();
} else {
return "Invalid name!";
}
}
AInterface m_A;
}
答案 4 :(得分:-1)
我会说,“伙计,有些人采用单位测试的方式太过分了!”
将这两个类作为一个单元进行测试。无论如何,A类都被硬编码到B类中。
答案 5 :(得分:-1)
您应该通过模板获取类,并显式导出该实例化(B<A>
)以避免链接器问题(如果以前不是所有内联的已发布)。这样,您可以根据需要插入其他类以进行测试,无论如何都是良好的做法。我也很好奇为什么你的例子看起来像Java一样 - 在确定它实际是 C ++之前我必须阅读它大约五次。
template<typename T> class BImpl {
String runSomething(const String& name) {
if(name.equals("something")) {
return T::getSomething();
} else {
return "Invalid name!";
}
}
};
typedef BImpl<A> B; // Just plugs in to existing code.
现在你可以用一个模拟类代替A,即使你不能从它继承。事实上,这也可以用另一种方式扩展 - CRTP。
class A : public BImpl<A> {
String getSomething() {
// Now it's non-static! IT'S A MIRACLE!
}
}
模板的奇迹永远不会让我惊讶。