Boost单元测试框架依赖性执行顺序

时间:2014-11-28 22:18:17

标签: c++ unit-testing dependencies reinterpret-cast boost-test

我正在尝试在Boost Unit Testing Framework中设置依赖项。 我发现this thread tbat有一个如何使用test_unit :: depends_on()方法的例子。到目前为止这么好,我可以写一些魔法来解决它。 但是,UTF并不尊重执行期间的测试依赖性。

场景:BOOST_AUTO_TEST_CASE A在另一个(B)之前声明,并且A depends_on()B 期望的(期望的)结果:框架检测依赖性并首先运行B,然后运行A,如果B成功。 实际结果:跳过A,因为尚未运行的B已经"失败" (即没有/错误的结果)。

现在,我的想法是对测试用例/套件进行拓扑排序,然后按排序顺序运行它们。 为此,我创建了一个test_tree_visitor来遍历套件并确定m_members test_suite成员的顺序。

但是,m_members受到保护,无法通过方法访问。 因为我无法更改标题,(会使升级到更新的版本更加困难等等),以及BOOST_ *宏"硬编码"作为test_suite的类,我正在考虑以下hackery:

class member_accessible_test_suite : public test_suite
{
public:
    const std::vector<test_unit_id> *get_members() const { return &m_members; }
};

class dependency_order_visitor : public test_tree_visitor
{
public:
    virtual void visit( test_case const& tu)
    {}

    virtual bool test_suite_start( test_suite const& tu)
    {
        const member_accessible_test_suite *psuite(reinterpret_cast<const member_accessible_test_suite*>(&tu));
        const std::vector<test_unit_id> *pmembers(psuite->get_members());
        /* do something with pmembers */
        return true;
    }

    virtual void test_suite_finish( test_suite const& tu)
    {}

};

在Coliru上查看watered down version

现在问我的问题:

  1. 升级库通常设计得很好 - 由于要求使用此功能对单元测试设计存在误解,我是否犯了一个根本性的错误?

  2. 由于member_accessible_test_suite没有数据并且只添加了函数,因此reinterpret_cast()安全还是进入UB域的快速通道? 无论哪种方式,我都担心在制作中使用这样一个可怕的黑客。

  3. 是否有更好的方法,如果有,那么这会变成XY问题?

1 个答案:

答案 0 :(得分:-1)

在处理未通过任何机制公开的基类成员时,以下方式似乎最合适(但必须访问某些关闭功能,并且不能修改基类):

链接:Access to private member variables

这个想法背后的原因可以在标准的 14.7.2p8 中找到:

  

通常的访问检查规则不适用于用于指定显式实例化的名称。             特别是,函数声明符中使用的模板参数和名称             (包括参数类型,返回类型和异常规范)可以是私有类型             或者通常不可访问的对象,模板可以是成员模板             或通常无法访问的成员函数。]

我冒昧地把它外包成两个宏,这些宏可能会在某一天再次派上用场。

与所有这些变通办法一样 - 明智地使用!

/* The ROB_PRIVATE_MEMBER_INST() macro should be used for explicit instantiation of the template at the appropriate source/compilation unit
   The ROB_PRIVATE_MEMBER_ACCESS() macro should be used for access to the variable where required
*/
#define ROB_PRIVATE_MEMBER_INST(CLASS, TYPE, MEMBER)    \
template<typename T>                                    \
struct CLASS##_##MEMBER##_rob_tag {                     \
  typedef T CLASS::*type;                               \
  friend type get(CLASS##_##MEMBER##_rob_tag);          \
};                                                      \
template<typename Tag, typename Tag::type M>            \
struct CLASS##_##MEMBER##_rob_private                   \
{                                                       \
    friend typename Tag::type get(Tag) { return M; }    \
};                                                      \
template struct CLASS##_##MEMBER##_rob_private<         \
CLASS##_##MEMBER##_rob_tag<TYPE> , &CLASS::MEMBER>;     \
/**/

#define ROB_PRIVATE_MEMBER_ACCESS(CLASS, INSTANCE, TYPE, MEMBER) \
    (INSTANCE.*get(CLASS##_##MEMBER##_rob_tag<TYPE>()))          \
/**/