2012-12-07 9 views
5

Napisałem własną warstwę dostępu do silnika gry. Istnieje GameLoop, która nazywa się każdą ramką, która pozwala mi przetwarzać mój własny kod. Mogę robić określone rzeczy i sprawdzać, czy takie rzeczy się zdarzały. W bardzo prosty sposób może to wyglądać tak:Jak przetestować kod asynchroniczny

void cycle() 
{ 
    //set a specific value 
    Engine::setText("Hello World"); 

    //read the value 
    std::string text = Engine::getText(); 
} 

chcę sprawdzić, czy mój Engine -warstwa pracuje przez pisanie testów automatycznych. Mam doświadczenie w korzystaniu z Boost Unittest Framework do prostych testów porównawczych, takich jak ten.

Problem polega na tym, że niektóre rzeczy, które chcę wykonać, są przetwarzane po zakończeniu połączenia pod numerem cycle(). Dlatego wywołanie Engine::getText() bezpośrednio po Engine::setText(...) zwróci pusty ciąg znaków. Jeśli miałbym poczekać do następnego połączenia cycle(), zwrócona zostanie prawidłowa wartość.

Zastanawiam się teraz, w jaki sposób powinienem napisać moje testy, jeśli nie można ich przetworzyć w tym samym cyklu. Czy są jakieś najlepsze praktyki? Czy możliwe jest zastosowanie podejścia "tradycyjnego testowania" podanego przez Boost Unittest Framework w takim środowisku? Czy są możliwe inne ramy ukierunkowane na tak specjalistyczny przypadek?

Używam C++ do wszystkiego tutaj, ale mogę sobie wyobrazić, że istnieją odpowiedzi niezwiązane z językiem programowania.

UPDATE: Nie jest możliwe, aby uzyskać dostęp do Engine poza cycle()

+0

O ile silnik nie może zasygnalizować użytkownikowi, że jest przetwarzany, nie widzę, żeby to działało. Bardzo ciekawi jednak odpowiedzi innych ludzi. –

Odpowiedz

-1

Istnieją dwie opcje ze sobą:

Jeśli biblioteka że masz mogą być używane synchronicznie lub za pomocą C++ 11 futures jak placówki (co może wskazywać na readyness rezultatu), a następnie w przypadku testowego można zrobić coś jak poniżej

void testcycle() 
{ 
    //set a specific value 
    Engine::setText("Hello World"); 
    while (!Engine::isResultReady()); 
    //read the value 
    assert(Engine::getText() == "WHATEVERVALUEYOUEXPECT"); 
} 

Jeśli nie masz powyżej najlepiej można mam limit czasu (nie jest dobrym rozwiązaniem, ponieważ choć można mieć fałszywe awarie):

void testcycle() 
{ 
    //set a specific value 
    Engine::setText("Hello World"); 
    while (Engine::getText() != "WHATEVERVALUEYOUEXPECT") { 
     wait(1 millisec); 
     if (total_wait_time > 1 sec) // you can put whatever max time 
       assert(0); 
    } 

} 
+0

Pierwsza odpowiedź nie jest możliwa, ponieważ silnik nie ma "isResultReady()", druga odpowiedź jest zła z punktu widzenia projektu: wprowadzenie limitów czasu i snu w tego rodzaju testach to zła rzecz, ponieważ zapominasz, że czas potrzebny do snu może być różny na każdej maszynie. Twój Core i7 może potrzebować tylko 1 sekundę, ale niektóre starsze Pentium może potrzebować 2. W obu przypadkach testament powinien przejść, ale - jeśli śpisz jest używany - w drugim przypadku nie powiedzie się. –

+1

GameEngine przetwarza 'Engine :: setText (..)' po wywołaniu 'cycle()', więc dodanie timeout byłoby takie samo jak gdybyś nazwał 'Engine :: getText()' bezpośrednio po, to po prostu zajmuje więcej czas. Mogę uzyskać poprawne wyniki po przetworzeniu 'setText' w GameEngine, co oznacza, że ​​w następnym' cycle() ' – MOnsDaR

+0

@DanielKamilKozar - powinieneś dokładnie przeczytać moje komentarze .." (to nie jest dobra opcja ale ponieważ możesz mieć fałszywe niepowodzenia) " – RamneekHanda

0

W przykładzie powyżej, std::string text = Engine::getText(); jest kod chcesz zapamiętać z jednego cyklu, ale wykonać w następnym. Możesz go zapisać do późniejszego wykonania. Na przykład - używając C++ 11 można użyć lambda do zawinięcia testu do prostej funkcji określonej inline.