グーグルテストでの配列の比較?


84

私はグーグルテストで2つの配列を比較しようとしています。UnitTest ++では、これはCHECK_ARRAY_EQUALを介して行われます。あなたはグーグルテストでそれをどのように行いますか?

回答:


119

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の任意のコンテナーだけでなく、カスタムコンテナーでも機能します。

GoogleMockはGoogleTestとほぼ同じくらいポータブルであると主張しており、率直に言って、なぜそれを使用しないのかわかりません。それは純粋に素晴らしいです。


7
私はグーグルモックを使用します。そして、私はそれが素晴らしいことに同意します。私はC ++でそのようなものが見られるとは思っていませんでした。
Tobias Furuholm 2010年

2
ElementsAreArrayElementsAre10要素の制限があるため、配列を比較することをお勧めします。
BЈовић

2
テストでは、ASSERT_THATの代わりにEXPECT_THATを使用することをお勧めします。
arhuaco 2016年

1
BЈовићが述べたように、ElementsAreArrayはそれを使用するための例です:EXPECT_THAT(v, ElementsAreArray(u));私は現在の例よりも多く使用しています。
Zitrax 2017年

1
それらはgmockプロジェクトの一部ですか?それともGtestプロジェクトだけですか?
TsakiroglouFotis19年

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は、2つのcスタイルの配列ポインターの比較を可能にするポインターと長さも受け入れます。例えば:

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

私はこれをつなぎ合わせるのに非常に長い時間を費やしました。std :: vectorイテレータの初期化に関するリマインダーを提供してくれたこのStackOverflowの投稿に感謝します。このメソッドは、比較の前にバッファ配列要素をstd :: vectorにコピーすることに注意してください。


1
テスト対象のコードのバグが、テスト対象buffer_sizeのコードから返された値が誤ってに設定されること(size_t)-1である場合、これは珍しいエラーではありません。ベクトルコンストラクターは非常に大きなベクトルを作成しようとします。テストプログラムは、テストアサーションが失敗するのではなく、リソース制限またはメモリ不足エラー、あるいは単なるクラッシュで強制終了される可能性があります。C ++ 20std::spanでは、ベクターの代わりに使用すると、バッファーを新しいコンテナーにコピーする必要がないため、これを防ぐことができます。
トレントP 2018

actualDataをstd :: array <type、size>ポインターにキャストし、ptrを逆参照することを再解釈することで、同様のことが実現できます。アサートで。次のようなもの:gist.github.com/daantimmer/…–
Daan Timmer

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 2017

9

まったく同じ質問があったので、2つの汎用コンテナーを比較するマクロをいくつか作成しました。それは持っている任意のコンテナに拡張可能だ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 )

これがうまくいくことを願っています(そして、質問が送信されてから2か月後に実際にこの回答を確認してください)。


それは素晴らしいアプローチです!たぶんあなたはこれをグーグルに提供して彼らがそれをフレームワークに追加することができますか?
Tobias Furuholm

2
彼らは(code.google.com/p/googletest/issues/detail?id=231)、マクロの追加を推奨しておらず、この機能はGoogleMockフレームワークである程度利用可能であると述べました。
セスジョンソン

5

私はグーグルテストで配列を比較することで同様の問題に遭遇しました。

基本void*およびchar*(低レベルのコードテスト用)との比較が必要だったので、グーグルモック(私もプロジェクトで使用しています)またはセスの素晴らしいマクロが特定の状況で役立つことはありません。私は次のマクロを書きました:

#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を使用することをお勧めします。それもうまくいきませんか?
トビアスフルホルム

私が答えを投稿した理由の1つは、誰かがより良い代替案を提案してくれることを望んでいたからです。あなたがやったようです、トビアス:)
nietaki

EXPECT_STREQゼロ要素を含む任意の配列では機能しません。私はまだ@nietakiの解決策に投票します。
Mohammad Dashti 2018

4

以下は、2つの浮動小数点配列[のフラグメント]を比較するために私が書いたアサーションです。

/* 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 TestingFramework内での使用法は次のとおりです。

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]);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.