包装代码以避免重复的技术?

时间:2015-11-04 07:58:19

标签: c++ macros

我在测试用例中使用了这个C ++代码来强制异常并增加覆盖率:

    bool exceptionThrown(false);

     try {

         /* One or multiple lines of code */

     } catch (std::runtime_error& e) {
         std::cerr << "    Exception caught: " << e.what() << "\n";
         exceptionThrown = true;
     }

     if (exceptionThrown) {
         std::cerr << "    OK: Exception has been thrown\n";
     } else {
         std::cerr << "    FATAL: Exception should have been thrown\n";
         return(1);
     }

可以想象,随着测试次数的增加,这段代码重复了很多,我根本不喜欢。我一直在考虑用这种方法包装这个代码的方法。宏,但我不确定这是不是一个好习惯。在这种情况下,您是否有任何建议避免代码重复?

1 个答案:

答案 0 :(得分:2)

除了明显的问题,例如“为什么不使用谷歌测试?”和“为什么不使用升压测试框架?”等

这是一种做你想做的事情的方法: (编辑:更新以减少测试体中的输入 - 这个版本是单线程的,一个简单的修改可以使它线程安全)

#include <iostream>
#include <stdexcept>

namespace detail {
    struct try_base {
        virtual ~try_base() = default;
        virtual const std::string& message() const = 0;

        static std::unique_ptr<try_base>& last() {
            struct empty : try_base {
                const std::string& message() const override { return _message; }
                std::string _message = "no exception";
            };
            static std::unique_ptr<try_base> _p = std::make_unique<empty>();
            return _p;
        }

        bool threw() const { return _threw; }
        operator bool() const { return !threw(); }
        bool operator!() const { return threw(); }

        bool _threw = false;
    };

    template<class F, class...Args>
    struct try_exec
    : try_base {
        try_exec(F&& f, Args&&...args)
        {
            try {
                f(std::forward<Args>(args)...);
            }
            catch(const std::exception& e) {
                _threw = true;
                _message = e.what();
            }
        }

        const std::string& message() const override { return _message; }

        std::string _message;

    };
}

template<class F, class...Args>
const auto& try_exec(F&& f, Args&&... args)
{
    auto& last = detail::try_base::last();
    last = std::make_unique<detail::try_exec<F, Args...>>(std::forward<F>(f),
                                                          std::forward<Args>(args)...);
    return *last;
}

bool report()
{
    std::cout << detail::try_base::last()->message() << std::endl;
    return true;
}

void example2(int x, int y)
{
    using namespace std;
    if (x < 6) {
        throw std::logic_error("example 2 throws with "s + to_string(x) + " and " + to_string(y));
    }
}

auto main() -> int
{
    try_exec([] {
        throw std::runtime_error("foo");
    }) or report();

    try_exec(&example2, 5, 4) or report();

    try_exec([]{
        example2(5, 4);
    }) or report();



    return 0;
}

预期产出;

test 1 threw: foo
test 2 threw: example 2 throws with 5 and 4
test 3 threw: example 2 throws with 5 and 4