3

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

一切正常,直到我尝试测试我的课程。

这是该问题的简单代码示例:

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++ 类?

提前致谢,

塔尔。

4

6 回答 6

4

通过将静态函数的引用(在我的情况下是外部依赖项)重构为新的私有函数并在测试的存根上覆盖它们,我在类似情况下的单元测试中取得了成功,所以我可以推荐这种方法

如果重构的函数保持私有,它们不应该对设计的复杂性产生很大影响,并且它们应该足够小,不会对代码的可读性产生负面影响。

于 2010-11-01T23:19:11.930 回答
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 而不是 Ao 。

g++ -Wall B_test.cpp B.cpp A_mock.cpp
于 2010-11-02T00:02:55.000 回答
0

您可以将指向该函数的指针传递给类 A 的构造函数。然后,为了进行测试,您可以将一些指针传递给一个模拟函数,在那里您可以做任何您想做的事情。

于 2010-11-02T08:39:53.737 回答
0

为什么是静态函数?我建议不要让它成为静态的。

然后,您可以为 A 类(在 C++ 中这意味着只有纯虚函数头的类)创建一个名为 AInterface 的接口。A 类将实现(继承)AInterface 并实现这个虚函数。

然后将指向该接口的指针传递给类 B 的构造函数,并将其存储在名为 m_A 的成员变量中。然后在您的测试中,创建实现 AInterface 的 MockClassA。将 MockClassA 传递给 B 类构造函数并将 m_A 设置为输入。

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;
}

测试代码

class MockClassA : public AInterface
{
    String getSometing() {
        return String("Whatever I want. This is a test");
    }
}   

void test ()
{
   // "MockClassA" would just be "A" in regular code
   auto instanceOfB = B(MockClassA());

   String returnValue = instanceOfB.runSomething("something");
   :
   :
}
于 2017-05-26T17:25:44.843 回答
-1

我会说,“伙计,有些人把单元测试做得太过分了!”

只需将这两个类作为一个单元进行测试。无论如何,A 类都被硬编码到 B 类中。

于 2010-11-01T23:19:18.360 回答
-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!
    }
}

模板的奇迹永远不会停止让我感到惊讶。

于 2010-11-01T23:41:33.500 回答