авто регистрация unit test функций (C++)
От: alexeiz  
Дата: 25.06.06 06:20
Оценка: 22 (2)
Проблема: в C++ приходится явно регистрировать unit test функции, перед их выполнением. Другой пример: обработчики UI событий приходится регистрировать явно. При добавлении новых функций в первом или втором примере, их нужно явно вписывать в то место, где они все регистрируются.

Данный код показывает основную идею для создания автоматических регистраторов на примере регистрации unit test функций.

Для начала, сразу приведу пример использования:
// file test1.cpp

#include "autoreg.hpp"
#include <iostream>

register_func foo()
{
    std::cout << "test foo\n";
    return REGISTER(&foo);
}

// file test2.cpp

#include "autoreg.hpp"
#include <iostream>

register_func bar()
{
    std::cout << "test bar\n";
    return REGISTER(&bar);
}

// file main.cpp

#include "autoreg.hpp"

int main()
{
    suite_obj().execute();  // <- Всё!  Здесь выполняются тесты из файлов test1.cpp и test2.cpp
                            // без необходимости их явного регистрирования
}

Соответственно, расширяется этот код новыми тестами элементарно. Пишем новую тест функцию, в конце которой стоит return REGISTER(...), и этого достаточно, чтобы она добавилась в общий набор тестов.

А теперь код autoreg.hpp, который делает это возможным:
#if !defined(AUTOREG_HPP_2974920)
#define AUTOREG_HPP_2974920

#include <vector>
#include <algorithm>
#include <boost/function.hpp>
#include <boost/bind.hpp>

typedef boost::function<void ()> test_func_type;

class suite
{
public:
    void add(test_func_type test)
    {
        tests_.push_back(test);
    }

    void execute()
    {
        std::for_each(tests_.begin(), tests_.end(), boost::mem_fn(&test_func_type::operator()));
    }

private:
    std::vector<test_func_type> tests_;
};

inline
suite & suite_obj()
{
    static suite s;
    return s;
}


class register_func {};

template <typename T, T func>
class register_impl : public register_func
{
public:
    register_impl()
    {
        suite_obj().add(func);
    }
};

template <typename T>
class func_type
{
public:
    template <T func>
    class func_type_param
    {
    public:
        static register_impl<T, func> s_reg;
    };
};

template <typename T>
template <T func>
register_impl<T, func> func_type<T>::func_type_param<func>::s_reg;

template <register_func (*F)(), typename T>
register_func make_register_func(T func)
{
    return func_type<T>::func_type_param<F>::s_reg;
}

#define REGISTER(func) make_register_func<func>(func);

#endif  // AUTOREG_HPP_2974920

Вся фишка заключается в генерации уникальных статических переменных для каждого теста. В конструкторах соответствующих уникальных классов производится необходимая регистрация (процесс которой в данном случае предельно упрощён). Идея содрана из библиотеки win32gui-lib (http://www.torjo.com/win32gui/).
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.