谷歌测试中的数组比较?


Answers:


115

我真的建议您看看Google C ++模拟框架。即使您不想模拟任何东西,它也可以让您轻松编写相当复杂的断言。

例如

//checks that vector v is {5, 10, 15}
ASSERT_THAT(v, ElementsAre(5, 10, 15));

//checks that map m only have elements 1 => 10, 2 => 20
ASSERT_THAT(m, ElementsAre(Pair(1, 10), Pair(2, 20)));

//checks that in vector v all the elements are greater than 10 and less than 20
ASSERT_THAT(v, Each(AllOf(Gt(10), Lt(20))));

//checks that vector v consist of 
//   5, number greater than 10, anything.
ASSERT_THAT(v, ElementsAre(5, Gt(10), _));

在每种可能的情况下都有很多匹配器,您可以将它们组合起来以实现几乎所有目的。

我告诉你,ElementsAre只需要iteratorssize()方法上的一类工作?因此,它不仅适用于STL中的任何容器,还适用于自定义容器。

Google Mock声称其可移植性几乎与Google Test一样,坦率地说,我不明白为什么您不使用它。真是太棒了。


7
我确实使用Google模拟。我同意这太棒了。我从没想到会在C ++中看到类似的东西。
Tobias Furuholm,2010年

2
ElementsAreArray最好比较数组,因为数组ElementsAre最多可以包含10个元素。
2015年

2
请注意,您可能需要在测试中使用EXPECT_THAT而不是ASSERT_THAT。
arhuaco

如果Elements是std :: string怎么办?我收到testing::Matcher<std::string const&>::Matcher(char const*)未定义的链接器错误
Frank Liu

1
就像BЈовић提到的ElementsAreArray一样,这是一个使用它的示例:EXPECT_THAT(v, ElementsAreArray(u));与当前示例相比,我使用得更多。
Zitrax

18

如果只需要检查数组是否相等,则蛮力也可以起作用:

int arr1[10];
int arr2[10];

// initialize arr1 and arr2

EXPECT_TRUE( 0 == std::memcmp( arr1, arr2, sizeof( arr1 ) ) );

但是,这并不能告诉您哪个元素有所不同。


15

如果您想使用Google Mock将C样式的数组指针与数组进行比较,则可以遍历std :: vector。例如:

uint8_t expect[] = {1, 2, 3, 42};
uint8_t * buffer = expect;
uint32_t buffer_size = sizeof(expect) / sizeof(expect[0]);
ASSERT_THAT(std::vector<uint8_t>(buffer, buffer + buffer_size), 
            ::testing::ElementsAreArray(expect));

Google Mock的ElementsAreArray还接受指针和长度,以允许比较两个c样式数组指针。例如:

ASSERT_THAT(std::vector<uint8_t>(buffer, buffer + buffer_size), 
            ::testing::ElementsAreArray(buffer, buffer_size));

我花了太长时间试图拼凑而成。感谢此StackOverflow帖子,提醒您有关std :: vector迭代器初始化的信息。请注意,此方法将在比较之前将缓冲区数组元素复制到std :: vector中。


1
如果被测代码中的错误恰好是that buffer_size,从被测代码返回的值被错误地设置为(size_t)-1,这不是常见错误,那么向量构造函数将尝试制作一个非常大的向量!测试程序可能会由于资源限制或内存不足错误而被杀死,或者仅仅是简单的崩溃,而不是测试断言失败。在C ++ 20中,使用std::span代替vector可以避免这种情况,因为它不需要将缓冲区复制到新容器中。
TrentP

通过重新解释将实际数据转换为std :: array <type,size>指针并取消引用ptr,可以实现类似的效果。在断言中。喜欢的东西:gist.github.com/daantimmer/...
大安蒂莫

13
ASSERT_EQ(x.size(), y.size()) << "Vectors x and y are of unequal length";

for (int i = 0; i < x.size(); ++i) {
  EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " << i;
}

资源


我有点像这样 它不需要将数据复制到stl容器,而且非常简单。将其包装在宏中以进行常见类型的数组比较(如矢量或矩阵)即可完成工作。
johnb003

9

我有完全相同的问题,所以我写了几个宏来比较两个通用容器。它是可扩展到具有任何容器const_iteratorbeginend。如果失败,它将显示一条详细的消息,指出数组出了问题的地方,并将针对每个失败的元素进行处理。这将确保它们的长度相同;并且代码中报告为失败的位置与您调用的位置相同EXPECT_ITERABLE_EQ( std::vector< double >, a, b)

//! Using the google test framework, check all elements of two containers
#define EXPECT_ITERABLE_BASE( PREDICATE, REFTYPE, TARTYPE, ref, target) \
    { \
    const REFTYPE& ref_(ref); \
    const TARTYPE& target_(target); \
    REFTYPE::const_iterator refIter = ref_.begin(); \
    TARTYPE::const_iterator tarIter = target_.begin(); \
    unsigned int i = 0; \
    while(refIter != ref_.end()) { \
        if ( tarIter == target_.end() ) { \
            ADD_FAILURE() << #target " has a smaller length than " #ref ; \
            break; \
        } \
        PREDICATE(* refIter, * tarIter) \
            << "Containers " #ref  " (refIter) and " #target " (tarIter)" \
               " differ at index " << i; \
        ++refIter; ++tarIter; ++i; \
    } \
    EXPECT_TRUE( tarIter == target_.end() ) \
        << #ref " has a smaller length than " #target ; \
    }

//! Check that all elements of two same-type containers are equal
#define EXPECT_ITERABLE_EQ( TYPE, ref, target) \
    EXPECT_ITERABLE_BASE( EXPECT_EQ, TYPE, TYPE, ref, target )

//! Check that all elements of two different-type containers are equal
#define EXPECT_ITERABLE_EQ2( REFTYPE, TARTYPE, ref, target) \
    EXPECT_ITERABLE_BASE( EXPECT_EQ, REFTYPE, TARTYPE, ref, target )

//! Check that all elements of two same-type containers of doubles are equal
#define EXPECT_ITERABLE_DOUBLE_EQ( TYPE, ref, target) \
    EXPECT_ITERABLE_BASE( EXPECT_DOUBLE_EQ, TYPE, TYPE, ref, target )

希望这对您有用(并且在提交问题两个月后您实际上检查了此答案)。


那是个好方法!也许您可以将其提供给Google,以便他们将其添加到框架中?
Tobias Furuholm,2009年

2
他们说(code.google.com/p/googletest/issues/detail?id=231)不鼓励添加宏,并且Google Mock框架在某种程度上可以使用此功能。
赛斯·约翰逊

5

我在Google测试中比较数组时遇到了类似的问题。

由于我需要与Basicvoid*char*(用于低级代码测试)进行比较,因此我不认为Google模拟(我也在项目中使用过)或Seth的宏都可以在特定情况下帮助我。我写了以下宏:

#define EXPECT_ARRAY_EQ(TARTYPE, reference, actual, element_count) \
    {\
    TARTYPE* reference_ = static_cast<TARTYPE *> (reference); \
    TARTYPE* actual_ = static_cast<TARTYPE *> (actual); \
    for(int cmp_i = 0; cmp_i < element_count; cmp_i++ ){\
      EXPECT_EQ(reference_[cmp_i], actual_[cmp_i]);\
    }\
    }

void*与其他内容相比,强制转换可以使宏可用:

  void* retrieved = ptr->getData();
  EXPECT_EQ(6, ptr->getSize());
  EXPECT_ARRAY_EQ(char, "data53", retrieved, 6)

Tobias在评论中建议强制void*转换char*并使用EXPECT_STREQ,我之前不知怎地错过了一个宏-看起来是一个更好的选择。


2
我更喜欢将void *转换为char *并使用EXPECT_STREQ。那还行吗?
Tobias Furuholm 2012年

我发布答案的原因之一是,我希望有人会提出更好的选择。Tobias,看来您确实做到了:)
nietaki 2012年

EXPECT_STREQ不适用于包含零元素的任意数组。我仍然会投票支持@nietaki的解决方案。
Mohammad Dashti

4

下面是我写来比较两个浮点数组[片段]的断言:

/* See
http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
for thorough information about comparing floating point values.
For this particular application we know that the value range is -1 to 1 (audio signal),
so we can compare to absolute delta of 1/2^22 which is the smallest representable value in
a 22-bit recording.
*/
const float FLOAT_INEQUALITY_TOLERANCE = float(1.0 / (1 << 22));


template <class T>
::testing::AssertionResult AreFloatingPointArraysEqual(
                                const T* const expected,
                                const T* const actual,
                                unsigned long length)
{
    ::testing::AssertionResult result = ::testing::AssertionFailure();
    int errorsFound = 0;
    const char* separator = " ";
    for (unsigned long index = 0; index < length; index++)
    {
        if (fabs(expected[index] - actual[index]) > FLOAT_INEQUALITY_TOLERANCE)
        {
            if (errorsFound == 0)
            {
                result << "Differences found:";
            }
            if (errorsFound < 3)
            {
                result << separator
                        << expected[index] << " != " << actual[index]
                        << " @ " << index;
                separator = ", ";
            }
            errorsFound++;
        }
    }
    if (errorsFound > 0)
    {
        result << separator << errorsFound << " differences in total";
        return result;
    }
    return ::testing::AssertionSuccess();
}

Google测试框架中的用法是:

EXPECT_TRUE(AreFloatingPointArraysEqual(expectedArray, actualArray, lengthToCompare));

如果发生错误,将产生类似以下输出的内容:

..\MyLibraryTestMain.cpp:145: Failure
Value of: AreFloatingPointArraysEqual(expectedArray, actualArray, lengthToCompare)
  Actual: false (Differences found: 0.86119759082794189 != 0.86119747161865234 @ 14, -0.5552707314491272 != -0.55527061223983765 @ 24, 0.047732405364513397 != 0.04773232713341713 @ 36, 339 differences in total)
Expected: true

有关一般比较浮点值的详尽讨论,请参阅


3

我对所有元素使用了经典循环。您可以使用SCOPED_TRACE来读取数组元素在哪个迭代中有所不同。与其他方法相比,这为您提供了更多信息,并且易于阅读。

for (int idx=0; idx<ui16DataSize; idx++)
{
    SCOPED_TRACE(idx); //write to the console in which iteration the error occurred
    ASSERT_EQ(array1[idx],array2[idx]);
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.