2014-04-15 14 views
8

Mam projekt C++ w Visual Studio i dodałem inny projekt wyłącznie do testowania. Oba te projekty to EXE (aplikacje konsolowe). Jak więc wykorzystać pierwszy projekt w drugim?Jak przetestować EXE za pomocą testu Google?

Po to, by wyjaśnić, pytanie tutaj byłoby nieco oczywiste, gdyby pierwszy projekt był biblioteką, którą można by po prostu włączyć do drugiego projektu, ale będąc EXE, to właśnie tam leży problem.

+3

wyniki testu to inny przykład, który zależy od tego, co chcesz przetestować, włączając pliki w projekcie testowym, lub po prostu oddziel dział w niezależnej bibliotece dll – ahmedsafan86

+0

Jeśli chcesz mieć plik exe dla aplikacji i inny dla testy jednostkowe, musisz pobrać kod, który chcesz przetestować i zbudować go w bibliotece. Gdy to zrobisz, możesz połączyć bibliotekę z obu exe. –

+0

Czy możesz wyjaśnić dalej: a) Stworzyłeś kilka klas/API specyficznych dla aplikacji dla aplikacji konsolowej, które chcesz testować jednostkowo za pomocą googletest. b) Chcesz przetestować zachowanie '.exe' przy użyciu googletest. Który? –

Odpowiedz

22

za komentarze, musisz aplikacji C++ konsoli (MyApp) dla których zostały opracowane pewne klasy specyficznych dla aplikacji, które chcesz jednostkę testu z googletest w Visual Studio. Jak

Jak można powiedzieć, jeśli chce się badania jednostkowych bibliotekę sposób to zrobić byłoby oczywiste byś:?.

  • 1) Utwórz projekt, aby utworzyć aplikację do testowania jednostkowego (UnitTest).
  • 2) Skonfiguruj katalogi include-search, aby kompilator mógł znaleźć nagłówki biblioteki.
  • 3) Skonfiguruj katalogi wyszukiwania biblioteki tak, aby linker mógł znaleźć samą bibliotekę.
  • 4) Dodaj samą bibliotekę do wejść linkera.
  • 5) Uczyń projekt UnitTest zależnym od projektu biblioteki, aby budynek UnitTest zapewniał aktualność .
  • 6) Koduj aplikację UnitTest dla każdego dokumentu Googletest.

Ale od klasy chcesz do jednostki testu są specyficzne dla MyApp, nie ma żadnego bibliotekę.

Odpowiedź drążka-sierżanta na to: Nie masz biblioteki zawierającej klasy, które chcesz przetestować? Więc zrób jeden!

ten sposób można skorzystać z 3 projektów: -

  • MyAppLib, tworząc bibliotekę, która zawiera wszystkie funkcje, które chcesz jednostkowej testu.
  • MyApp, generując takie same wykonywalny jak w chwili obecnej, ale łącząc MyAppLib
  • UnitTest, generując plik wykonywalny, który unit-testy MyAppLib, również łączenie MyAppLib

Jednak jeśli nie podoba ci się wiertła sierżant odpowiedź można obejść.

od zwykłego punktu build-system widzenia (jeden przeznaczony do Visual Studio), ważne wyjściowego projektu MyApp jest build-target - w .exe. Wygenerowane pliki .obj są tylko pośrednimi produktami ubocznymi. VS nie oferuje wsparcia dla za traktowanie tych produktów ubocznych jako automatycznych wejść łącznika do projektu zależnego, a jeśli projekt zależny był również .exe tego samego rodzaju - jak to jest w twoim przypadku - to takie automatyczne połączenie byłoby niemożliwe, ponieważ główny punkt wejścia zostałby zdefiniowany wielokrotnie.

Ale z punktu widzenia testów jednostkowych jest odwrotnie. Numer .exe nie jest interesujący, natomiast (niektóre) pliki .obj w całości lub w części zawierają implementacje klas, które chcesz przetestować w jednostce. W przypadku książki tekstowej, gdzie klasa foo jest zdefiniowana w foo.h i zaimplementowana w foo.cpp, plik obiektowy foo.obj jest potrzebny w połączeniu z UnitTest.

Dla uproszczenia przyjmijmy, że MyApp zatrudnia tylko jedno specyficzne dla aplikacji klasy foo, zdefiniowane w foo.h i realizowane w foo.cpp. Następnie masz dwie opcje budowania UnitTest.

  • a) można dodać foo.cpp do plików źródłowych UnitTest. Nie należy oczywiście kłaść kopii. Wystarczy Dodaj istniejący element z folderu źródłowego MyApp. To już koniec, ale ten kurs ma wadę, że foo.cpp jest narażony na niepożądaną edycję w ramach projektu w projekcie .

  • b) można traktować foo.obj niczym statycznej biblioteki wymaganych do powiązania UnitTest i wykonaj kroki 1) - 6) powyżej. Oznacza to w szczególności w kroku 3), że kompilacja {Debug | Release} UnitTest jest skonfigurowana z katalogami wyszukiwania biblioteki, które obejmują \path\to\MyApp\{Debug|Release} (w postaci względnej lub bezwzględnej).

W rzeczywistości, dla opcji b), jest bardzo prawdopodobne, więcej niż jednego pliku z MyApp.obj że trzeba będzie połączyć w UnitTest, a całkiem prawdopodobne, że ich liczba będzie rosła wraz z upływem czasu.Utrzymanie właściwego powiązania z UnitTest może stać się obowiązkiem i możesz dojść do wniosku, że sierżant miał rację.

+1

Dzięki, myślę, że ugryzę kulę i refaktor w LIB + EXE. –

+0

Bardzo dobra odpowiedź @Mike, rzeczywiście myślę, że 'foo.obj' jest trochę jak statyczna biblioteka, ponieważ biblioteka jest zbiorem obiektów (' .o', '.obj', itp.), Więc dodaje ją bezpośrednio będzie działać idealnie. – Patapoom

0

Jeśli chcesz przetestować aplikację konsoli, możesz uruchomić test otwierający okno konsoli i uruchamiający plik exe pierwszej aplikacji. Następnie w swoim googlorze złapać standardowe wyjście z exe, które właśnie uruchomiłeś.

[Aby uzyskać większą kontrolę nad pierwszą aplikacją, konieczne może być przesłanie do niej pierwszych argumentów analizy aplikacji, np. niektóre flagi jak -x lub czegokolwiek potrzebujesz.]

10

Zależy. Test Google jest (przede wszystkim) strukturą testów jednostkowych (upraszczające, testujące klasy). Możesz go bezwzględnie używać do innych typów testów, ale nie ma on wbudowanej funkcjonalności dla innych typów testów, musisz napisać to sam.

Jeśli próbujesz systemowo przetestować swój plik wykonywalny, możesz uruchomić proces. Proponuję użyć Boost.Process, jeśli korzystasz z systemu wieloplatformowego lub masz już zależność doładowania. Inaczej, spójrz tutaj: launch an exe/process with stdin stdout and stderr?

"Testy", które napiszesz, wywołają plik wykonywalny i mogą odpowiednio wprowadzić stdin lub stdout.

Na przykład:

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"; 
} 
+0

Czy masz pojęcie, dlaczego następujące czynności będą działać/jak zrobić następujące wokrking: 'EXPECT_EXIT (c.terminate(), :: testing :: ExitedWithCode (0)," "); '. W moim przypadku otrzymuję komunikat "Wynik: nie udało się umrzeć"?!? – HeinrichStack

0

Przygotowałem repozytorium github obejmujące rozwiązanie Visual Studio 2015 w parralelu sugestii Mike'a "sierżanta". Możesz go używać bezpośrednio, bez żadnych dodatkowych wymagań ani zależności.

https://github.com/fuatcoskun/GoogleTestVS2015

Mam nadzieję, że to pomaga ...

2

byłem w podobnej sytuacji i mam to skonfigurować w taki sposób, aby skutecznie zezwoli na osiągnięcie tego samego celu, jakim jest odpowiedzią Mike'a Kinghan w miarę kompilator ale chodzi o to inaczej niż z punktu widzenia użytkownika.

Co zrobiłem, to stworzyłem niestandardową konfigurację, którą nazwałem "Testowanie". Możesz utworzyć nową konfigurację, otwierając ustawienia projektu, wybierając "Configuration Manager ..." i wybierając "New ..." w polu wyboru konfiguracji.

Po wyświetleniu monitu wybrałem skopiowanie ustawień z domyślnej konfiguracji "Debugowanie", dzięki czemu mogę używać debuggera z moimi testami tak, jakbym był w konfiguracji "Debugowanie".

W nowej konfiguracji testowania ustawiam opcje kompilatora i łącznika, aby normalnie używać testu Google.

Ważną zmianą właściwości jest zdefiniowanie zmiennej preprocesora, którą nazwałem "TESTOWANIE".

przepisałem mój „main.cpp”, aby wyglądać tak:

... 
// 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... 
} 

Co próbuję wskazać jest to, że tylko zmienione kilka linii tuż gdzie main jest zdefiniowany, I don” t muszą wprowadzać zmiany brutto w całym pliku.

Teraz, gdy wszystko jest gotowe, po prostu utworzyłem nowy folder źródłowy dla moich testów i utworzyłem tam pliki ".cpp". Aby uniknąć wzdęcia normalny plik wykonywalny, ja owinąć te pliki z czekiem na zmiennej testowania, więc mam coś takiego:

tests/Test.cpp:

#ifdef TESTING 

#include <gtest/gtest.h> 

#include "my_class_header.h" 

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

#endif 

Myślę, że te pliki jeszcze dostać „hit” przez kompilator w konfiguracjach Debug and Release, więc posiadanie ich może spowolnić kompilację, ale obiekty Debug and Release nie zostaną nadpisane kodem testowym.

Dwa dania na wynos to:

  • Stosując tę ​​metodę, kod badania są nadal organizowane oddzielnie od kodu aplikacji, ale nadal mieszka w tym samym projekcie Visual Studio, które mogą lub nie mogą być korzystne. Osobiście nie chcę zarządzać/martwić się o drugi projekt.
  • Tak jak powiedział Mike Kinghan, samodzielne zarządzanie plikami .obj i łączenie się nimi może stać się obowiązkiem, ale za pomocą tej metody domyślne ustawienia Visual Studio zarządzają tym za Ciebie.

Jedną wadą jest to, że efektywnie redundantne kopie wszystkich plików obiektowych zostaną utworzone w katalogu wyjściowym "Testowanie".Przy większej konfiguracji, na pewno musi istnieć sposób na "udostępnianie" plików obiektów Debug, ale nie miałem powodu, aby posunąć się tak daleko.

Jest to bardzo prosta metoda, która może być znacznie łatwiejsza niż przekształcenie aplikacji w oddzielne biblioteki i główną. Ja nie miłość przy użyciu preprocessor wankery, ale w tym przypadku jest dość proste, nie za dużo kodu, i spełnia dokładnie to, czego potrzebuje. Zawsze można uruchomić testy w inny sposób, bez korzystania z preprocesora.

0

Jeśli nie masz zbyt dużej sztywności w testach w innym projekcie, możesz napisać testy w swoim projekcie aplikacji. Wtedy po prostu sprawiają, że aplikacja wykonać testy podczas odbierania niektórych argumentów wiersza poleceń i wykonywanie normalnej logiki aplikacji w przeciwnym razie, tj

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); 
} 

ten sposób unika się tworzenia niepotrzebnych biblioteki wyłącznie w celu testowania, choć nadal można to zrobić jeśli jest poprawna pod względem struktury. Minusem jest to, że kod testowy przechodzi do pliku wykonywalnego, który zamierzasz zwolnić. Jeśli tego nie chcesz, to myślę, że potrzebujesz dodatkowej konfiguracji, która określa dyrektywę pre-procesora, aby wyłączyć testy.

Debugowanie testów lub ich automatyczne uruchamianie po kompilacji postów jest łatwe, po prostu określając "--tests" jako argumenty debugowania lub odpowiednio na linii poleceń budowania postu.

Powiązane problemy