给定两个类,我如何概率地测试等效行为

比方说,我有两个实现相同基本API的类,并且我想至少在一部分方法上测试它们是否“随机等效” 1

例如,我编写了自己的“列表”类foo:list,而不是费心地为此编写一堆单元测试,而是想将其与std::list进行比较。也就是说,foo::list上的任何操作序列都应产生与std::list相同序列的结果相同。

我可以列出这些操作的名称,但希望不会比这多得多。可以应用于其他两对“行为等效”类的通用解决方案是理想的。


1 “随机等效”是指在许多系列操作中均未观察到差异,这显然没有完整的等效证明。

greattable 回答:给定两个类,我如何概率地测试等效行为

简而言之

构造一个foo::list和一个std::list,然后在对它们执行操作时将它们进行比较。实际上,与常规单元测试的唯一区别是您有两个容器,而不是对要测试的类型的每个操作直接使用REQUIRE(),而是对要测试的类型和引用类型执行操作,并且然后比较它们。为此,我们假设std::list或没有错误的任何东西。然后,我们将其用作未失败的参考点。换句话说,如果操作以std::list成功并以foo::list成功,并且它们比较相等,则操作成功。

一个例子

您知道可以用来比较状态的操作子集是什么,而我不知道,所以这是一个模拟比较功能

template <class T,class U>
bool compare_types(const T &t,const U &u)
{
    bool equivalent = true;
    //Generic comparisons here,like iterating over the elements to compare their values.
    //Of course update equal or just return false if the comparison fails.
    //If your types are not containers,perform whatever is needed to test equivalent state.
    return equivalent;
}

正如Jarod42所指出的,这可以带来更多的乐趣和更多的通用性,尤其是如果下面的Op f是lambda(通用lambda所需的C ++ 14):

template <class ValueT,class RefT,class TestT,class Op>
bool compare_op_with_value(RefT &t,TestT &u,Op f,const ValueT &value)
{
    if (!compare_types(t,u))
        return false;
    f(t,value);
    f(u,value);
    return compare_types(t,u);
}

您的函数可能返回一个值:

template <class ValueT,class Op>
bool compare_op_with_ret(RefT &t,Op f)
{
    if (!compare_types(t,u))
        return false;
    ValueT ret1 = f(t);
    ValueT ret2 = f(u);
    return ret1 == ret2 && compare_types(t,u);
}

...等等,用于可引用的返回类型,等等。您需要为每种测试编写一个新的比较函数,但这非常简单。您需要为不同的返回类型(例如迭代器)添加另一个模板参数。

然后,您需要您的测试用例(我在std::vector中以foo::list的身份入帐)...

TEMPLATE_TEST_CASE("StdFooCompare","[list]",int)
{
    using std_type = std::list<TestType>;
    using foo_type = std::vector<TestType>;

    auto initializer = {0,1,2,3,4};
    std_type list1 = initializer;
    foo_type list2 = initializer;

    //testing insertion,using auto since insert() returns iterators
    auto insert_f = [](auto list,TestType value) -> auto {
        return list.insert(list.begin(),value);
    };
    REQUIRE(compare_op_with_value(list1,list2,insert_f,-1));

    //testing front(),being explicit about the return type rather than using auto
    auto front_f = [](auto list) -> TestType & {
        return list.front();
    };
    REQUIRE(compare_op_with_ret<TestType>(list1,front_f));

    //continue testing along these lines
}

我可以花更多时间来解决这个问题,但我希望你能明白。我花了更多时间来解决这个问题。

注意:我实际上并没有运行此代码,因此请考虑使用所有伪代码来理解该想法,例如我可能错过了分号或类似的内容。

本文链接:https://www.f2er.com/3135965.html

大家都在问