2011-02-07 4 views
1

Я разрабатываю тестовую структуру. Существует несколько наборов тестов, каждый из которых представляет собой класс с набором функций-членов для каждого отдельного теста.Список вызовов методов в производном классе

Я хотел бы найти способ динамической итерации всех тестов в классе.

Идеализированной установка может выглядеть примерно так:

class A : public Test 
{ 
public: 
    A() { 
     addTest(a); 
     addTest(b); 
     addTest(c); 
    } 

    void a() { cout << "A::a" << endl; } 
    void b() { cout << "A::b" << endl; } 
    void c() { cout << "A::c" << endl; } 
}; 

addTest() метод будет добавить свой параметр в списке; этот список повторяется в более поздней точке, и каждый метод запускается.

Есть ли способ достичь этого? Ближе мы придумали до сих пор это:

class Test 
{ 
public: 
    template <typename T> 
    struct UnitTest 
    { 
     typedef void (T::*P)(); 
     P f; 
     UnitTest(P p) : f(p) {} 
    }; 
    // (this struct simplified: we also include a name and description) 

    virtual void run(int testId) = 0; 
}; 

class A : public Test 
{ 
public: 
    A() { 
     mTests.push_back(UnitTest<A>(&A::a)); 
     mTests.push_back(UnitTest<A>(&A::b)); 
     mTests.push_back(UnitTest<A>(&A::c)); 
    } 

    void a() { cout << "a" << endl; } 
    void b() { cout << "b" << endl; } 
    void c() { cout << "c" << endl; } 

    // not ideal - this code has to be repeated in every test-suite 
    void run(int testId) 
    { 
     (this->*(mTests[testId].f))(); 
    } 
    vector<UnitTest<A>> mTests; 
}; 

Чтобы вызвать один тест за итерации основного выполнения цикла:

a->run(mTestId++); 

Это не идеально, потому что каждый тест-люкс (класс) должен повторить код run() и иметь свой собственный член mTests.

Есть ли способ приблизиться к идеалу?

+0

Итак ... почему бы просто не реализовать эту реализацию в базовом классе? –

ответ

1

Проведите каждое испытание a functor или Функциональный объект. Создайте контейнер с указателями на тесте, а затем перейдите по контейнеру:

struct Test_Base_Class 
{ 
    virtual bool Execute(void) = 0; 
}; 

typedef std::vector<Test_Base_Class *> Container_Of_Tests; 

struct Test_Engine 
{ 
    Container_Of_Tests tests_to_run; 

    void Add_Test(Test_Base_Class * p_new_test) 
    { 
    tests_to_run.push_back(p_new_test); 
    } 

    void Run_Tests(void) 
    { 
    Container_Of_Tests::iterator iter; 
    for (iter = tests_to_run.begin(); 
     iter != tests_to_run.end(); 
     ++iter) 
    { 
     (*iter)->Execute(); // Invoke the Execute method on a test. 
    } 
    return; 
    } 
} 

Это фундамент. В настоящее время я использую этот шаблон, но его расширили, включив метод Resume() и отчет о состоянии.

+0

+1, наследование от общего базового класса и виртуальных функций - это путь! – Xeo

+0

Томас, спасибо за ваш ответ! Это просто, но я думаю, что для проверки состояния между тестами требуется дополнительный объект. – cachvico