如果我举例说明我想要实现的目标,我认为这是最简单的。
让我们说我想实现一个单元测试环境,其中实现一个新的单元测试将涉及从给定的基类派生,并且(可能)遵循涉及添加其他宏的指导。然后,这样的新测试将自动添加到测试列表中,在某个时刻一个接一个地运行。然而有两件事:
我尝试尽可能快速轻松地创建每个新测试,特别是在使用测试本身修改文件以外的文件时。一个完美的情况就是这样,实施一个新的测试不需要触摸项目中的任何其他文件。这可以通过单例和可能的CRTP实现,但现在是第2点,
目标是具有有限RAM量的MCU(通常ROM不是问题),我希望能够直接在目标平台上运行测试。因此,在整个应用程序生命周期中占用内存的静态对象是不可接受的。相反,我希望能够在需要运行时单独创建和删除每个测试。
基本上,问题归结为一种自动将派生类型(或创建者方法)注册到具有最小RAM开销的工厂的方法(我假设会有一些,即至少指向所述方法的指针)。
很抱歉没有代码示例,但如果没有提交给定的实现,那么这里没有什么可以显示的。
答案 0 :(得分:1)
你能创建一个函数指针的静态/全局向量吗?这些将指向每个测试类的创建者/工厂函数。工厂函数返回指向基本测试类的指针。我打算尝试写出来,但我认为代码更容易编写和理解。
class TestBase
{
public:
static char registerTest(<function ptr type> creator) {
testCreators.push_back(creator);
return 1;
}
static void runTests()
{
for (auto creator : testCreators)
{
auto newTestClass = creator();
newTestClass->tests();
delete newTestClass;
}
}
private:
void tests() = 0;
std::vector<function ptr type> testCreators;
};
然后是派生类。
class SpecificTest : public TestBase
{
// Pretend test code is here.
private:
static char dummy;
};
// Plan old C function. Need to establish naming conventions so as
// not to get multiple symbol errors during linking. Kind of fragile.
TestBase* specificTestCreator()
{
return new SpecificTest();
}
在SpecificTest的.cpp文件中
char SpecificTest::dummy = TestBase::registerTest(specificTestCreator);
我试图编译或运行它,但我认为它基本上是合理的。
答案 1 :(得分:1)
我根据Michael提供的答案创建了一个示例,编译并运行它。在下面发布代码。
TestBase.h:
#ifndef TESTBASE_H_
#define TESTBASE_H_
#include <vector>
class TestBase {
public:
TestBase();
virtual ~TestBase();
static void RunAllTests();
protected:
virtual void test() = 0;
static char addTestCreator(TestBase* (*creator)());
private:
static std::vector<TestBase* (*)()> &getTests();
};
#endif /* TESTBASE_H_ */
TestBase.cpp
#include "TestBase.h"
TestBase::TestBase() {
}
TestBase::~TestBase() {
}
char TestBase::addTestCreator(TestBase* (*creator)())
{
getTests().push_back(creator);
return 0;
}
void TestBase::RunAllTests()
{
for(std::vector<TestBase* (*)()>::iterator it = getTests().begin(); it != getTests().end(); it++)
{
TestBase *t = (*it)();
t->test();
delete t;
}
}
std::vector<TestBase* (*)()> &TestBase::getTests()
{
static std::vector<TestBase* (*)()> v;
return v;
}
ConcreteTest1.h:
#ifndef CONCRETETEST1_H_
#define CONCRETETEST1_H_
#include "TestBase.h"
class ConcreteTest1: public TestBase {
public:
ConcreteTest1();
virtual ~ConcreteTest1();
protected:
void test();
private:
// both here can be expanded with a macro to make it
// easier as they'll be same for all derived classes
static char dummy;
static TestBase *creator();
};
#endif /* CONCRETETEST1_H_ */
ConcreteTest1.cpp:
#include "ConcreteTest1.h"
#include <iostream>
// can be expanded with a macro
char ConcreteTest1::dummy = TestBase::addTestCreator(ConcreteTest1::creator);
// can be expanded with a macro
TestBase* ConcreteTest1::creator()
{
return new ConcreteTest1();
}
ConcreteTest1::ConcreteTest1()
{
std::cout << "Creating test 1" << std::endl;
}
ConcreteTest1::~ConcreteTest1()
{
std::cout << "Deleting test 1" << std::endl;
}
void ConcreteTest1::test()
{
std::cout << "Running test 1" << std::endl;
}
类似ConcreteTest2.cpp / .h。
从main调用:
TestBase::RunAllTests();
输出是:
Creating test 1
Running test 1
Deleting test 1
Creating test 2
Running test 2
Deleting test 2
这正是我想要实现的目标。