Как проверить EXE с помощью Google Test?

У меня есть проект C++ в Visual Studio, и я добавил другой проект исключительно для тестирования. Оба этих проекта являются EXEs (консольные приложения). Итак,как мне использовать первый проект внутри второго?

просто чтобы уточнить, вопрос здесь был бы несколько самоочевидным, если бы первый проект был библиотекой, которую можно было бы просто включить во второй проект, но, будучи EXE, именно в этом заключается проблема.

6 ответов


в ваших комментариях, у вас есть консольное приложение на C++ (MyApp) для которого вы разработали некоторые классы приложений, которые вы хотите тестировать с помощью googletest в Visual Studio. Как?

как вы говорите, если вы хотите юнит-тест a библиотека способ сделать это было бы очевидный. Вы:

  • 1) создайте проект для создания приложения модульного тестирования (UnitTest).
  • 2) Настройка каталогов include-search чтобы компилятор мог найти заголовки библиотеки.
  • 3) настройте каталоги поиска библиотеки, чтобы компоновщик мог найти саму библиотеку.
  • 4) Добавьте библиотеку к входам компоновщика.
  • 5) Сделать UnitTest проект зависит от проекта библиотеки, так что building UnitTest обеспечивает MyApp вверх-к-дата.
  • 6) код UnitTest приложение для документов googletest.

но так как классы вы хотите юнит-тест специфичен для MyApp, у вас нет никаких библиотека.

строевой сержант отвечает на это:у вас нет библиотеки, содержащей классы, которые вы хотите юнит-тестировать? Так сделай один!

таким образом, вы используете 3 проекта: -

  • MyAppLib, создание библиотеки, которая содержит все функции, которые вы хотите модульного тестирования.
  • MyApp, генерируя тот же исполняемый файл, что и в настоящее время, но связывая MyAppLib
  • UnitTest, генерируя исполняемый файл, который unit-tests MyAppLib, также связывая MyAppLib

однако, если вам не нравится ответ сержанта-инструктора, вы можете обойти его.

С обычной точки зрения системы сборки (той, которая предназначена для Visual Studio), важный вывод MyApp проект является build-target-the .exe. The .obj генерируемые файлы являются лишь промежуточными побочными продуктами. VS не предлагает вам никакой поддержки для рассматривая эти побочные продукты как автоматические входы компоновщика зависимого проекта, и если зависимый проект также был .exe того же рода - как это ваш случай - тогда такая автоматическая связь будет невозможна в любом случае, потому что основная точка входа будет умножена.

но с точки зрения модульного тестирования это наоборот. The .exe не представляет никакого интереса, в то время как (некоторые).obj файлы полностью или частично содержат реализаций классов хотите модульный тест. В случае учебника, где class foo определена в foo.h и реализовала в foo.cpp объект необходим в связи UnitTest.

для простоты предположим, что MyApp использует только один класс, специфичный для приложения foo, определено в foo.h и реализовала в foo.cpp. Тогда у вас есть два варианта построения UnitTest.

  • A) Вы можете добавить foo.cpp к исходным файлам UnitTest. Не скопировать это конечно. Просто добавить существующий элемент из исходной папки MyApp. Тогда все кончено, но это ... конечно, имеет обратную сторону, что foo.cpp подвергается неблагоприятные изменения в the .

  • b) вы можете лечить foo.obj как статическая библиотека требуется для связи UnitTest и выполните шаги 1) - 6) выше. Это означает, в частности, на Шаге 3), что {Debug|Release} сборка UnitTest настроен с каталогами библиотеки-поиска, которые включают \path\to\MyApp\{Debug|Release} (в относительной или абсолютной форме).

на самом деле, для варианта b), очень вероятно, что более одного С MyApp что вам придется связать в UnitTest, и вполне вероятно, что их число будет расти с течением времени. Поддержание правильной связи


зависит. Google Test-это (в первую очередь) платформа модульного тестирования (упрощение, тестирование классов). Вы можете абсолютно использовать is для других типов тестов, но у него нет "встроенной" функциональности для других типов тестирования, вам придется написать ее самостоятельно.

Если вы пытаетесь протестировать исполняемый файл, вы можете запустить процесс. Я предлагаю использовать Boost.Процесс, если вы используете многоплатформенную систему или уже имеете зависимость boost. Еще посмотри здесь: запустить exe / процесс с stdin stdout и stderr?

" тесты", которые вы пишете, будут вызывать исполняемый файл и могут вводить stdin или stdout соответственно.

например:

std::string path_to_exectuable = "thepath";
TEST(FooTester,CheckHelpScriptReturns0)
{
 using bp =::boost::process; 
 std::vector<std::string> args; args.push_back("--help");
 bp::context ctx; 
 ctx.stdout_behavior = bp::capture_stream(); 

 bp::child c = bp::launch(exec, args, ctx); 
 bp::status s = c.wait(); 
 ASSERT_TRUE(s.exited())<<"process didn't exit!";
 ASSERT_EQ(s.exit_status(),0)<<"Help didn't return 0";
}

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

то, что я сделал, это создать пользовательскую конфигурацию, которую я назвал "тестирование". Вы создаете новую конфигурацию, открывая параметры проекта, выбрав " Configuration Manager..."и выбрав "новый..."в выборе конфигурации коробка.

при появлении запроса я решил скопировать настройки из конфигурации "Debug" по умолчанию, чтобы я мог использовать отладчик с моими тестами так же, как если бы я был в конфигурации "Debug".

в новой конфигурации тестирования я установил параметры компилятора и компоновщика для использования теста google, как обычно.

важным изменением свойств является то, что я определяю переменную препроцессора, которую я назвал "тестирование".

I переписал мой "главный.cpp", чтобы выглядеть примерно так:

...
// includes
// functions
// whatever
...

#ifdef TESTING
#include <gtest/gtest.h>
#endif

int main(int argc, char **argv) {
   #ifdef TESTING
   ::testing::InitGoogleTest(&argc, argv);
   int val = RUN_ALL_TESTS();
   getchar();  // not necessary, but keeps the console open
   return val;
   #endif    

   // rest of main() as normal...
}

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

теперь, когда все это настроено, я просто сделал новую исходную папку для своих тестов и создал ".cpp " файлы там. Чтобы избежать раздувания обычного исполняемого файла, я обертываю эти файлы с проверкой переменной тестирования, поэтому у меня есть что-то вроде это:

tests/Test.cpp:

#ifdef TESTING

#include <gtest/gtest.h>

#include "my_class_header.h"

TEST(TestMyClass, test_something) {
    // perform some test on class
} 

#endif

Я думаю, что эти файлы по-прежнему "попадают" компилятором в конфигурации отладки и выпуска, поэтому их тонна может замедлить сборку, но объекты отладки и выпуска не будут раздуваться с помощью тестового кода.

два выноса:

  • используя этот метод, код тестирования по-прежнему организован отдельно от кода приложения, но он по-прежнему находится в том же проекте Visual Studio, который может быть полезным, а может и нет. Лично мне нравится не управлять/беспокоиться о втором проекте.
  • как Майк Kinghan сказал, управление и связывание .obj файлы сами могут стать рутиной, но с помощью этого метода настройки Visual Studio по умолчанию управляют этим для вас.

один недостаток заключается в том, что фактически избыточные копии всех объектных файлов будут созданы в выходном каталоге "тестирование". С большей конфигурацией, конечно, должен быть способ "поделитесь" объектными файлами отладки, но у меня не было причин заходить так далеко.

Это очень простой метод, который может быть намного проще, чем рефакторинг приложения в отдельные библиотеки и основной. Я не любовь используя препроцессор wankery, но в этом случае это довольно просто, не слишком много кода раздувается и выполняет именно то, что ему нужно. Вы всегда можете запустить тесты другим способом, без использования препроцессора.


Если вы хотите протестировать консольное приложение, вы можете запустить тест, который открывает окно консоли и запускает exe-файл первого приложения. Затем в вашем googletest поймать стандартный вывод из exe вы только что побежали.

[для большего контроля над первым приложением вам может потребоваться отправить ему первые аргументы синтаксического анализа приложения, например, некоторые флаги, такие как-x или что вам нужно.]


Я подготовил РЕПО github, включая решение Visual Studio 2015, в parralel предложения Майка "drill-sergeant". Вы можете использовать его напрямую без каких-либо дополнительных условий или зависимости.

https://github.com/fuatcoskun/GoogleTestVS2015

надеюсь, это поможет...


Если вы не очень жестко относитесь к тестам в другом проекте, вы можете написать тесты в своем проекте приложения. Затем просто заставьте приложение выполнить тесты при получении определенных аргументов командной строки и выполните обычную логику приложения иначе, т. е.

int main(int argc, char* argv[])
{
    if (argc >= 2 && std::string(argv[1]) == "--tests")
    {
        ::testing::InitGoogleTest(&argc, argv);
        return RUN_ALL_TESTS();
    }
    else
    {
        // Application logic goes here
    }
}

TEST(ExampleTests, TestSQRTCalculation) // assuming all the right headers are included
{
    EXPECT_NEAR(2.0, std::sqrt(4.0), 0.000001);
}

это позволяет избежать создания ненужной библиотеки с единственной целью тестирования, хотя вы все еще можете сделать это, если это правильно по структуре. Недостатком является то, что тестовый код идет в исполняемый файл, который вы собираетесь выпускать. Если вы этого не хотите, я думаю, вам нужна дополнительная конфигурация, которая указывает директиву pre-processor для отключения тестов.

отладка тестов или их автоматический запуск в post build легко, просто указав "--tests " как debug args или в командной строке post build соответственно.