【问题标题】:Trigger added methods of derived class by method in base class通过基类中的方法触发派生类的添加方法
【发布时间】:2021-11-01 05:19:18
【问题描述】:

我想实现一个简单的测试结构。以下是我创建基类和派生类的方法。

testBase.h:

class TestBase {
public:
    TestBase() {}
    virtual void TestStart() = 0;
    virtual void TestEnd() = 0;
    void RunTest() {  
        // I need code here to trigger a chain of calls
    }
};

classifierTest.h:

#include "testBase.h"

class ClassifierTest: public TestBase
{
public:
    ClassifierTest() {
    
    }
    void TestStart();
    void TestEnd();

    void Test1();
    void Test2();
    void Test3();
};

classifierTest.cpp:

#include "classifierTest.h"

void ClassifierTest::TestStart() {

}

void ClassifierTest::TestEnd() {

}

void ClassifierTest::Test1(){

}

void ClassifierTest::Test2(){

}

void ClassifierTest::Test3(){

}

主要功能:

ClassifierTest *classifierTest = new ClassifierTest();
classifierTest->RunTest();

假设Test1()Test2()Test3()是我的测试方法,我以后可能会在这里添加更多测试。 我的目标是,当我在main函数中调用RunTest()时,然后在TestStart()之后和TestEnd()之前,这些测试方法被一一调用。

所以他们会像这样运行:

  • TestStart()
  • Test1()
  • TestEnd()
  • TestStart()
  • Test2()
  • TestEnd()
  • TestStart()
  • Test3()
  • TestEnd()

我不想在基类中专门添加测试方法。但问题是如何从 RunTest() 触发这些调用链。所以它不知道的基本触发方法。

我相信它应该像 .net 中的反射?

【问题讨论】:

  • 您对此有疑问吗?不清楚你在问什么。
  • 顺便说一句,创建自己的测试框架可能很有趣,但很快你就会发现你正在重新发明一个轮子。有很多很好的现有解决方案
  • 我希望测试代码尽可能的简约。如果这不起作用,我可能会开始使用一个。有什么轻便的建议吗?
  • @AryanFirouzian 一个轻便的什么?测试库?
  • 有两个著名的库,一个来自 Google(我相信是 gtest)和一个来自 Boost。在任何情况下,测试函数的自动发现都需要反射,而这在 C++ 中是没有的。您也许可以在基类中注册这些函数,前提是它们都具有相同的签名。只需将函数指针存储在容器中。或者,采取另一个步骤并在那里注册std::function 对象。这些和 lambdas 甚至可以完全消除对派生类的要求。

标签: c++ testing inheritance virtual-functions


【解决方案1】:

您基本上是在要求 C++ 中不存在的反射(还)。现在的问题是你愿意做出什么样的妥协。

如果您可以编写一些代码来手动注册测试函数,那么它们不需要成为成员,一个可能的解决方案是:

#include <functional>
#include <vector>
#include <iostream>
class TestBase {
public:
    TestBase() {}
    virtual void TestStart() = 0;
    virtual void TestEnd() = 0;
    
    void RunTest() {  
        for (const auto& test_fun : test_functions){
            TestStart();
            test_fun();
            TestEnd();
        }
    }
    using test_function = std::function<void()>;
    void register_test(const test_function& fun){ test_functions.push_back(fun); }
private:
    
    std::vector<test_function> test_functions;
};

class ClassifierTest: public TestBase
{
public:
    ClassifierTest() {
        register_test([](){ std::cout << "test 1\n";});
        register_test([](){ std::cout << "test 2\n";});
    }
    void TestStart() { std::cout << "test start\n";}
    void TestEnd() { std::cout << "test end\n";}
};

int main() {
    ClassifierTest{}.RunTest();
}

Output:

test start
test 1
test end
test start
test 2
test end

请注意,如果您捕获this,则 lambda 可以使用成员,因此与您的初始方法没有太大区别,并且编写的代码量也相当:

class ClassifierTest2: public TestBase
{
public:
    ClassifierTest2() {
        register_test([this](){ std::cout << "test 1, x = " << x << "\n";});
        register_test([this](){ std::cout << "test 2, x = " << x << "\n";});
    }
    void TestStart() { ++x;std::cout << "test start\n";}
    void TestEnd() { std::cout << "test end\n";}
private:
    int x = 0;
};

int main() {
    ClassifierTest2{}.RunTest();
}

Output:

test start
test 1, x = 1
test end
test start
test 2, x = 2
test end

正如评论中已经提到的,如果您手动注册TestStartTestEnd,则不需要派生类。它可能只是一个带有register_test_start(std::function&lt;void()&gt;)register_test_end(std::function&lt;void()&gt;) 的类Test,或者将它们作为参数传递给构造函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-02-06
    • 2018-05-16
    • 2021-07-06
    • 1970-01-01
    • 1970-01-01
    • 2011-04-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多