Как использовать INSTANTIATE_TEST_CASE_P в заголовочном файле с несколькими тестовыми .cpps? - PullRequest
1 голос
/ 12 марта 2019

Скажем, у меня есть прибор GTest, определенный в заголовочном файле fixtures.h:

 class baseFixture : public ::testing::Test{
   // some shared functionality among tests
 }

, а также производное приспособление, которое допускает некоторую параметризацию:

class derivedFixture: public baseFixture, 
  public ::testing::WithParamInterface<std::tuple<bool, int>>{};

То, что яхотел бы использовать вместе с INSTANTIATE_TEST_CASE_P для параметризации большого набора тестов, которые распределены по N .cpp файлам.Я хотел бы написать в заголовке:

INSTANTIATE_TEST_CASE_P(derivedTests, derivedFixture, 
  ::testing::Combine(::testing::Bool(), ::testing::Values(1));

Чтобы запустить набор тестов для перекрестного произведения {true, false} и {1}.Когда я компилирую только один файл cpp, называю его N1.cpp и запускаю исполняемый файл, я получаю правильное поведение с моими TEST_P(derivedFixture* тестами - они запускаются дважды каждый.Однако, когда я собираю весь проект и выполняю свои тесты, каждый тест запускается 2 * N раз.Я использовал include guards в заголовочном файле, чтобы предотвратить двойной запуск макроса INSTANTIATE, и я уверен, что больше я его не вызывал.

1 Ответ

0 голосов
/ 14 марта 2019

То, что вы делаете, по сути это:

fixture.hpp (1)

#ifndef FIXTURE_HPP
#define FIXTURE_HPP

#include <gtest/gtest.h>

struct fixture: ::testing::TestWithParam<std::tuple<bool, int>>
{};

INSTANTIATE_TEST_CASE_P(instantiation_one, fixture,
  ::testing::Combine(::testing::Bool(), ::testing::Values(1)));

#endif

t1.cpp

#include "fixture.hpp"
#include <tuple>

TEST_P(fixture, test_a)
{
    auto const & param = GetParam();
    std::cout << "param 0 = " << std::get<0>(param) << std::endl;
    std::cout << "param 1 = " << std::get<1>(param) << std::endl;
    SUCCEED();
}

t2.cpp

#include "fixture.hpp"
#include <tuple>

TEST_P(fixture, test_b)
{
    auto const & param = GetParam();
    std::cout << "param 0 = " << std::get<0>(param) << std::endl;
    std::cout << "param 1 = " << std::get<1>(param) << std::endl;
    SUCCEED();
}

main.cpp (1)

#include <gtest/gtest.h>

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

Компилировать, связывать и запускать:

$ ./gtester
[==========] Running 8 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 8 tests from instantiation_one/fixture
[ RUN      ] instantiation_one/fixture.test_a/0
param 0 = 0
param 1 = 1
[       OK ] instantiation_one/fixture.test_a/0 (0 ms)
[ RUN      ] instantiation_one/fixture.test_a/1
param 0 = 1
param 1 = 1
[       OK ] instantiation_one/fixture.test_a/1 (0 ms)
[ RUN      ] instantiation_one/fixture.test_a/0
param 0 = 0
param 1 = 1
[       OK ] instantiation_one/fixture.test_a/0 (0 ms)
[ RUN      ] instantiation_one/fixture.test_a/1
param 0 = 1
param 1 = 1
[       OK ] instantiation_one/fixture.test_a/1 (0 ms)
[ RUN      ] instantiation_one/fixture.test_b/0
param 0 = 0
param 1 = 1
[       OK ] instantiation_one/fixture.test_b/0 (0 ms)
[ RUN      ] instantiation_one/fixture.test_b/1
param 0 = 1
param 1 = 1
[       OK ] instantiation_one/fixture.test_b/1 (0 ms)
[ RUN      ] instantiation_one/fixture.test_b/0
param 0 = 0
param 1 = 1
[       OK ] instantiation_one/fixture.test_b/0 (0 ms)
[ RUN      ] instantiation_one/fixture.test_b/1
param 0 = 1
param 1 = 1
[       OK ] instantiation_one/fixture.test_b/1 (0 ms)
[----------] 8 tests from instantiation_one/fixture (0 ms total)

[----------] Global test environment tear-down
[==========] 8 tests from 1 test case ran. (1 ms total)
[  PASSED  ] 8 tests.

Вы видите 8 тестов, когда ожидаете 4, каждый из которых instantiation_one/fixture.test_a/N выполняется дважды, для N в {0,1}.

Ошибка заключается в следующем: Мы делаем:

INSTANTIATE_TEST_CASE_P(instantiation_one, fixture,
  ::testing::Combine(::testing::Bool(), ::testing::Values(1)));

в fixture.hpp, что является #include -ом, и, следовательно, повторяется, в каждый единица перевода tN.cpp, вызывающая 2 параметризованных теста, которые зарегистрированы по этому коду для регистрации N раз во время выполнения и, следовательно, для запуска N раз.

Предполагается, что мы должны скомпилировать каждый экземпляр параметризованного значения. для данного набора значений просто один раз , так что делайте это только в одном исходном файле, например,

fixture.hpp (2)

#ifndef FIXTURE_HPP
#define FIXTURE_HPP

#include <gtest/gtest.h>

struct fixture: ::testing::TestWithParam<std::tuple<bool, int>>
{};


#endif

main.cpp (2)

#include <gtest/gtest.h>
#include "fixture.hpp"

INSTANTIATE_TEST_CASE_P(instantiation_one, fixture,
  ::testing::Combine(::testing::Bool(), ::testing::Values(1)));

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

Перекомпиляция, перекомпоновка и повторный запуск:

$ g++ -Wall -Wextra -c main.cpp t1.cpp t2.cpp
$ g++ -o gtester main.o t1.o t2.o -lgtest -pthread
$ ./gtester
[==========] Running 4 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 4 tests from instantiation_one/fixture
[ RUN      ] instantiation_one/fixture.test_a/0
param 0 = 0
param 1 = 1
[       OK ] instantiation_one/fixture.test_a/0 (0 ms)
[ RUN      ] instantiation_one/fixture.test_a/1
param 0 = 1
param 1 = 1
[       OK ] instantiation_one/fixture.test_a/1 (0 ms)
[ RUN      ] instantiation_one/fixture.test_b/0
param 0 = 0
param 1 = 1
[       OK ] instantiation_one/fixture.test_b/0 (1 ms)
[ RUN      ] instantiation_one/fixture.test_b/1
param 0 = 1
param 1 = 1
[       OK ] instantiation_one/fixture.test_b/1 (0 ms)
[----------] 4 tests from instantiation_one/fixture (1 ms total)

[----------] Global test environment tear-down
[==========] 4 tests from 1 test case ran. (1 ms total)
[  PASSED  ] 4 tests.
...