17

I have a unit test that I need to run for 200 possible combinations of data. (The production implementation has the data to be tested in configuration files. I know how to mock these values). I prefer nit writing separate test case for each combination and to use some way of looping through the data. Is there some such direct way using Google test for C++?

Mehdi Charife
  • 722
  • 1
  • 7
  • 22
Karthick S
  • 3,204
  • 6
  • 36
  • 52
  • Why don't you use an array of structs to hold your test data, and loop though each entry? You could have just one test case that tests all combinations. – Emile Cormier Nov 03 '12 at 20:13
  • Hi Emile, thanks for the suggestion. When I tried it, if one combination fails, it stops the test case from proceeding further and does not report the success rate properly. At the end of the day, these are different test cases for me. – Karthick S Nov 04 '12 at 04:06

2 Answers2

29

You can make use of gtest's Value-parameterized tests for this.

Using this in conjunction with the Combine(g1, g2, ..., gN) generator sounds like your best bet.

The following example populates 2 vectors, one of ints and the other of strings, then with just a single test fixture, creates tests for every combination of available values in the 2 vectors:

#include <iostream>
#include <string>
#include <tuple>
#include <vector>
#include "gtest/gtest.h"

std::vector<int> ints;
std::vector<std::string> strings;

class CombinationsTest :
    public ::testing::TestWithParam<std::tuple<int, std::string>> {};

TEST_P(CombinationsTest, Basic) {
  std::cout << "int: "        << std::get<0>(GetParam())
            << "  string: \"" << std::get<1>(GetParam())
            << "\"\n";
}

INSTANTIATE_TEST_CASE_P(AllCombinations,
                        CombinationsTest,
                        ::testing::Combine(::testing::ValuesIn(ints),
                                           ::testing::ValuesIn(strings)));

int main(int argc, char **argv) {
  for (int i = 0; i < 10; ++i) {
    ints.push_back(i * 100);
    strings.push_back(std::string("String ") + static_cast<char>(i + 65));
  }
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
hojin
  • 1,221
  • 14
  • 16
Fraser
  • 74,704
  • 20
  • 238
  • 215
  • 4
    "INSTANTIATE_TEST_CASE_P is deprecated, please use " "INSTANTIATE_TEST_SUITE_P" https://github.com/google/googletest/blob/f16d43cd38e9f2e41357dba8445f9d3a32d4e83d/googletest/include/gtest/internal/gtest-internal.h#L1295 – hojin May 28 '21 at 07:33
4

Use an array of structs (called, say, Combination) to hold your test data, and loop though each entry in a single test. Check each combination using EXPECT_EQ instead of ASSERT_EQ so that the test isn't aborted and you can continue checking other combinations.

Overload operator<< for a Combination so that you can output it to an ostream:

ostream& operator<<(ostream& os, const Combination& combo)
{
    os << "(" << combo.field1 << ", " << combo.field2 << ")";
    return os;
}

Overload operator== for a Combination so that you can easily compare two combinations for equality:

bool operator==(const Combination& c1, const Combination& c2)
{
    return (c1.field1 == c2.field1) && (c1.field2 == c2.field2);
}

And the unit test could look something like this:

TEST(myTestCase, myTestName)
{
    int failureCount = 0;
    for (each index i in expectedComboTable)
    {
        Combination expected = expectedComboTable[i];
        Combination actual = generateCombination(i);
        EXPECT_EQ(expected, actual);
        failureCount += (expected == actual) ? 0 : 1;
    }
    ASSERT_EQ(0, failureCount) << "some combinations failed";
}
Emile Cormier
  • 28,391
  • 15
  • 94
  • 122
  • Hi Emile, though this sounds easy, I am getting the count of test cases executed as 1 even for 100s of combinations in expectedComboTable. Due to this, I would need to redo the reporting dashboard et al to give the exact count of combinations that failed for cases which have combinations. Too much of a headache. So, I will not be able to use it. Thanks for the idea. – Karthick S Nov 09 '12 at 04:38