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

发布于 2024-09-30 01:22:55 字数 794 浏览 0 评论 0原文

我目前正在开发一个类,该类使用另一个仅具有静态函数的类。

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

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

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

提前致谢,

Tal。

I am currently working on a class that uses another class which has only static functions.

Everything worked fine until I tried testing my class.

Here is a simple code example of the problem:

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

Assuming class A is working correctly (and has been tested by its unit tests), I would like to check the runSomething function in class B.

My first option would be creating mocks for the inner classes (In this sample - class A), but in that case it will give me nothing to inherit from A because it has only static functions.

My second option is to encapsulate the calls for A class in private functions inside B so I could control their return values (although choosing this option will make the good a little bit more complex).

My question to you is: Are there in better ways to test C++ classes that depends on static classes/functions than my current options?

Thanks in advance,

Tal.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

ˉ厌 2024-10-07 01:22:55

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

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

I have had success in unit testing in similar situations by refactoring out the references to the static functions (in my case it was external dependencies) into new private functions and overwriting them on the tested stub, so I can recommend this approach

If the refactored functions remain private, they should not impact greatly on the complexity of the design and they should be small enough not to negatively impact on the readability of the code.

撩心不撩汉 2024-10-07 01:22:55

如果您不使用整体测试套件,那么这很容易。我假设您在 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

If you're not using a monolithic test suite, then its easy. I Assume that you have class A in A.cpp and class B in B.cpp, and the tests for B are in B_test.cpp.

Create a file called A_mock.cpp

class A
{
    static String getSometing() {
        return String("Expected Something");
    }
};

Then when compiling your B_test file, just link with A_mock.o rather than A.o .

g++ -Wall B_test.cpp B.cpp A_mock.cpp
嗳卜坏 2024-10-07 01:22:55

您可以将指向该函数的指针传递给类 A 的构造函数。然后为了测试,您可以将一些指针传递给模拟函数,您可以在其中执行任何您想要的操作。

You could pass a pointer to the function to the constructor of the class A. Then for testing, you can pass some the pointer to a mock function where you can do whatever you want.

风轻花落早 2024-10-07 01:22:55

为什么是静态函数?我建议不要将其设为静态。

然后,您可以为类 A 创建一个名为 AInterface 的接口(在 C++ 中,这意味着只有纯虚函数头的类)。 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");
   :
   :
}

Why the static function? I would suggest not making it static.

You could then create an interface for class A (in C++ this means a class with only pure virtual function headers) named AInterface. Class A would implement (inherit) AInterface and implement this virtual functions.

Then pass a pointer to this interface into class B's constructor and store it in a member variable named m_A. Then in your test, create MockClassA that implements AInterface. Pass MockClassA into class B constructor and set m_A to the input.

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

Test code

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");
   :
   :
}
洛阳烟雨空心柳 2024-10-07 01:22:55

您应该通过模板获取该类,并显式导出该实例化 (B),以避免链接器问题(如果它之前并非如发布的那样全部内联)。通过这种方式,您可以根据需要插入其他类以进行测试,无论如何这是一个很好的做法。我也很好奇为什么你的示例看起来如此像 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!
    }
}

模板的奇迹永远让我惊叹不已。

You should take the class via template, and explicitly export that instantiation (B<A>) to avoid linker issues if it was not previously all inline as posted. This way, you can insert other classes for the purposes of testing as you require and is good practice anyway. I'm also curious as to why your example looks so much like Java - I had to read it about five times before determining that it actually was C++ as stated.

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.

Now you can substitute a mock class for A, even though you can't inherit from it. Infact, this is ALSO extendable in another way - CRTP.

class A : public BImpl<A> {
    String getSomething() {
        // Now it's non-static! IT'S A MIRACLE!
    }
}

The wonders of templates never, ever cease to amaze me.

从﹋此江山别 2024-10-07 01:22:55

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

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

I would say, "Man, some people take unit testing way too far!"

Just test the two classes as a single unit. Class A is hard coded into class B anyway.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文