测试依赖于另一个类的静态函数的类

时间:2010-11-01 23:05:41

标签: c++ unit-testing static-methods cxxtest

我目前正在使用另一个只有静态函数的类。

在我尝试测试课程之前,一切正常。

以下是问题的简单代码示例:

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 ++类而不是我当前的选项?

提前致谢,

塔尔。

6 个答案:

答案 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!
    }
}

模板的奇迹永远不会让我惊讶。