【问题标题】:Boost Unit Test Framework dependencies execution orderBoost Unit Test Framework依赖执行顺序
【发布时间】:2014-11-28 22:18:17
【问题描述】:

我正在尝试在 Boost 单元测试框架中设置依赖项。 我发现this thread tbat 有一个如何使用 test_unit::depends_on() 方法的示例。到目前为止一切顺利,我可以围绕它写一些魔术来平滑它。 但是,UTF 在执行期间不尊重测试依赖项。

场景:一个 BOOST_AUTO_TEST_CASE A 在另一个 (B) 之前声明,而 A 依赖于 () B 预期(期望)结果:框架检测到依赖关系并首先运行 B,如果 B 成功则运行 A。 实际结果:A 被跳过,因为尚未运行的 B 已经“失败”(即没有/错误的结果)。

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

但是,m_members 是受保护的,不能通过方法访问。 由于我无法更改标头(会使升级到新版本更加困难,等等),并且 BOOST_* 宏将类“硬编码”为 test_suite,我正在考虑以下黑客:

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. boost 库通常设计良好 - 我是否因为对单元测试设计的误解而需要此功能而犯了根本性错误?

  2. 由于 member_accessible_test_suite 没有数据并且只添加功能,reinterpret_cast() 是安全的还是进入 UB 领域的快车道? 无论哪种方式,我都担心在生产中使用这种可怕的 hack。

  3. 有没有更好的方法,如果有,什么时候会变成 XY 问题?

【问题讨论】:

  • 我对这个 boost 库没什么好说的,但是演员阵容还可以。参见例如Type aliasing section at cppreference:the resulting pointer or reference may be accessed if ... T2 is the (possibly cv-qualified) dynamic type of the object ...。你可以直接投给参考 - reinterpret_cast&lt;const member_accessible_test_suite&amp;&gt;(tu)
  • 感谢您的链接。我认为“T2 是对象动态类型的(可能是 cv 限定的)基类”将适用,因为指针实际上是 test_suite,而不是 member_accessible_test_suite。我只是想从标准专家那里知道是否允许编译器做一些尴尬的事情,例如重新对齐或将隐藏/内部数据成员与派生类一起存储。
  • 你所描述的似乎是一个错误的级别(boost.test 正在做拓扑排序和一切)。你能把代码贴出来吗?我相信这可以很容易地解决,而不是实施已经存在的东西。

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


【解决方案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>()))          \
/**/

【讨论】:

    猜你喜欢
    • 2015-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-07
    • 2015-06-22
    • 1970-01-01
    • 2017-02-28
    相关资源
    最近更新 更多