Narzędzia użytkownika

Narzędzia witryny


boosttest

Różnice

Różnice między wybraną wersją a wersją aktualną.

Odnośnik do tego porównania

Next revision
Previous revision
boosttest [2008/04/14 21:58]
twroniak utworzono
boosttest [2008/04/16 23:00] (aktualna)
twroniak
Linia 1: Linia 1:
-cdn.+The acceptance test makes the customer satisfied that the\\ 
 +software provides the business value that makes them willing\\ 
 +to pay for itThe unit test makes the programmer satisfied\\ 
 +that the software does what the programmer thinks it does.\\ 
 + 
 +===== Opis biblioteki ===== 
 + 
 +Biblioteka Boost.Test dostarcza programiście zestaw narzędzi do testowania tworzonego przez niego oprogramowania. Mechanizmy dostarczane przez bibliotekę umożliwiają tworzenie programów testujących,​ definiowanie przypadków testowych i grupowanie ich w zestawy testów oraz uruchamianie testów w monitorowanym środowisku. 
 + 
 +==== Minimal testing facility ==== 
 + 
 +Minimal testing facility, jak sama nazwa wskazuje, stanowi minimum mechanizmów umożliwiających testowanie oprogramowania. Pierwsza wersja Boost.Test zawierała jedynie prezentowaną w tym podrozdziale funkcjonalność. Minimal testing facility dostarcza własną funkcję main(), która uruchamia funkcję test_main(dostarczaną przez użytkownika) w monitorowanym środowisku. Biblioteka dba o to, aby wszystkie parametry uruchomienia programu zostały również przekazane do funkcji test_main().  
 + 
 +<code cpp> 
 +#include <​boost/​test/​minimal.hpp>​ 
 +#include <​iostream>​ 
 + 
 +int square_err( int arg ) 
 +
 + return arg*arg-1;​ //​blad gruby:) 
 +
 + 
 +int square( int arg ) 
 +
 + return arg*arg; 
 +
 + 
 +int cube( int arg ) 
 +
 + return arg*arg*arg;​ 
 +
 + 
 +int cube_err( int arg ) 
 +
 + return square_err( arg )*arg; 
 +
 + 
 +int test_main( int /*argc*/, char* /*argv*/[] ) //uwaga - zmieniona nazwa funkcji main 
 +
 +  
 + int foo(3); 
 +  
 + //w monitorowanym srodowisku uzyskujemy dostep do makr testujacych o wiele mowiacych nazwach 
 + //makro BOOST_REQUIRE przerywa testowanie w przypadku niespelnienia podanego mu warunku 
 + BOOST_REQUIRE( foo == 3 ); 
 + //za pomoca tego makra powinny byc wiec testowane warunki, ktorych spelnienie jest krytyczne dla 
 + //dalszego dzialania programu 
 + 
 + 
 + //​BOOST_CHECK wypisuje informacje o bledzie na standardowe wyjscie po zakonczeniu testow 
 + BOOST_CHECK( square( foo ) == 9 ); 
 + BOOST_CHECK( square_err( foo ) == 9 ); 
 + 
 + BOOST_CHECK( cube( foo ) == 27 ); 
 + BOOST_CHECK( cube_err( foo ) == 27 ); 
 + 
 + if( foo != 4 ) 
 + BOOST_ERROR( "foo != 4 !!!!!" ); 
 + 
 + //ponizsze 3 sprawdzenia przy bledzie spowoduja przerwanie dalszego testowania 
 + 
 + if(cube( foo ) != 4 ) 
 + throw "​cube(3) != 4";​ //​recznie wykryty blad, zglaszany poprzez wyjatek 
 + //​ktory nie ma okazji byc zlapany 
 + 
 + if(cube( foo ) != 8 ) 
 + BOOST_FAIL("​cube(3) != 8"​);//​rowniez zglasza wyjatek 
 + 
 + BOOST_REQUIRE( foo == 4 ); //blad w BOOST_REQUIRE powoduje przerwanie testow 
 + 
 + std::cout << "Ten kod nigdy nie zostanie osiagniety\n";​ 
 + 
 +    return 0; 
 +
 +</​code>​ 
 + 
 + 
 +==== Program execution monitor ==== 
 + 
 +Kolejnym udostępnianym przez bibliotekę mechanizmem jest Program execution monitor. Podobnie jak minimal testing facility tworzy on monitorowane środowisko uruchomieniowe,​ w którym uruchamiany jest program użytkownika. Po zakończeniu testów użytkownikowi przedstawiany jest raport z przeprowadzonych testów, zawierający informacje o testach, które się nie powiodły oraz o wyjątkach, które zostały zgłoszone, ale nie zostały obsłużone. 
 + 
 +<code cpp> 
 +#include <​boost/​test/​prg_exec_monitor.hpp>​ 
 + 
 +int square_err( int arg ) 
 +
 + return arg*arg-1;​ //​blad gruby:) 
 +
 + 
 +int square( int arg ) 
 +
 + return arg*arg; 
 +
 + 
 + 
 +int cpp_main( int, char* [] ) //​zmieniona nazwa !!!!!! 
 +
 + int foo(3); 
 + 
 + if( square( foo ) != 9 ) 
 + throw "​square() error";​ 
 + 
 + if( square_err( foo ) != 9) 
 + throw "​square_err() error";​ //​niezlapany wyjatek, spowoduje wypisanie na konsole 
 + //​komunikatu:​ exception: C string: square_err() error 
 + 
 + //aby uzyskac komunikat o bledzie nalezy wyrzucic jeden z nastepujacych typow: 
 + //ciag znakow w stylu C (NULL-terminated) 
 + //​instancje std::​string 
 + //​std::​exception lub dowolna klase pochodna 
 + 
 + return 1; 
 +
 +</​code>​ 
 + 
 +Program execution monitor posiada możliwość konfiguracji przez następujące zmienne środowiskowe:​ 
 +  * BOOST_TEST_CATCH_SYSTEM_ERRORS - pozwala wyłączyć przechwytywanie błędów systemowych,​ domyślnie ustawiona na "​yes"​ 
 +  * BOOST_PRG_MON_CONFIRM - domyślnie ustawiona na "​yes"​ powoduje wyświetlanie wiadomość potwierdzającą w przypadku pomyślnego zakończenia testów. 
 + 
 +==== Execution monitor ==== 
 + 
 +Execution monitor, czyli monitor wykonywania programu, jest jednym z niskopoziomowych elementów biblioteki Boost.Test, oraz stanowi bazę do implementacji pozostałych narzędzi przez nią oferowanych. Używany jako osobne narzędzie zapewnia monitorowane środowisko wykonywania programu oraz ujednoliconą obsługę błędów. Poniżej zaprezentowano jedną z ciekawszych jego cech, czyli rejestrowanie funkcji obsługujących własne wyjątki programisty. 
 + 
 +<code cpp> 
 +#include <​boost/​test/​prg_exec_monitor.hpp>​ 
 +#include <​boost/​test/​execution_monitor.hpp>​ 
 +#include <​boost/​test/​utils/​basic_cstring/​io.hpp>​ 
 + 
 +#include <​iostream>​ 
 + 
 +struct NotImplementedYetException 
 +{}; 
 + 
 +struct DivisionByZeroException 
 +{}; 
 + 
 +namespace 
 +
 + class TestClass 
 +
 + int arg; 
 + 
 + public: 
 + TestClass( int a ): arg(a){} 
 + 
 + int operator() () 
 +
 + if( arg > 10 ) 
 + throw NotImplementedYetException();​ 
 + 
 + if( arg == 0 ) 
 + throw DivisionByZeroException();​ 
 + 
 + return 10/arg; 
 +
 + }; 
 + 
 + void translate_NotImplementedYetException( NotImplementedYetException const& ex ) 
 +
 + std::​cout<<​ "tej funkcji jeszcze nie zaimplementowano\n";​ 
 +
 + 
 + void translate_DivisionByZeroException( DivisionByZeroException const& ex ) 
 +
 + std::​cout<<​ "​wymuszenie dzielenia przez zero\n";​ 
 +
 +} //​zakonczenie lokalnej przestrzeni nazw 
 + 
 +int cpp_main( int /*argc*/, char* /​*argv*/​[]) 
 +
 + ::​boost::​execution_monitor monitor; 
 + 
 + 
 + //​rejestrowanie funkcji tlumaczacych wyjatki 
 + //​pozwalaja one na bezpiecznie przechwytywanie wyjatkow przez mechanizmy biblioteki w przypadku 
 + //gdy uzytkownik nie dostarczy kodu wylapujacego te wyjatki 
 + //​zapobiega to normalnemu w takich wypadkach wyjsciu z programu oraz umozliwia 
 + //​przejrzenie listy zgloszonych w ten sposob wyjatkow po zakonczeniu testow 
 + monitor.register_exception_translator<​NotImplementedYetException>​( &​translate_NotImplementedYetException ); 
 + monitor.register_exception_translator<​DivisionByZeroException>​( &​translate_DivisionByZeroException ); 
 + 
 + try 
 +
 + monitor.execute( ::​boost::​unit_test::​callback0<​int>​( TestClass( 20 ) ) ); 
 + /* 
 + execution_monitor::​execute( unit_test::​callback0<​int>​ const& F, bool catch_system_errors,​ int timeout ) 
 + F - funkcja przyjmujaca zero argumentow,​ 
 + rzucany jest wyjatek boost::​execution_exception przy niezlapanym wyjatku, wystapieniu bledu systemowego 
 + (jesli catch_system_errors jest ustawiony na true) lub po okreslonym timeoucie 
 + */ 
 +
 +    catch ( boost::​execution_exception const& ex ) 
 +
 +        std::cout << "​Zlapano wyjatek: " << ex.what() << std::​endl;​ 
 +    } 
 + 
 + return 0; 
 +
 +</​code>​ 
 + 
 +====Unit test framework ==== 
 + 
 +Unit test framework jest narzędziem oferującym programiście prosty i przystępny sposób na testowanie jego programów. Jest moim zdaniem najprzydatniejszym elementem biblioteki. Umożliwia tworzenie przypadków testowych testujących zarówno niezwiązane funkcje, jak i metody klas. Przypadki testowe (test cases) można grupować w zestawy testowe (test suites) tak, aby np. testy metod jednej klasy były zgrupowane w jednym zestawie.\\ 
 +\\ 
 + 
 +Funkcja main nie jest dostarczana przez programistę,​ robi to za niego unit test framework. Programista musi zdefiniować funkcje o nagłówku boost::​unit_test::​test_suite* init_unit_test_suite ( int argc, char* argv[] ) 
 + (argc i argv są parametrami wywołania, nie można ich pominąć przy deklaracji, można je zignorować pisząc init_unit_test_suite ( int, char* [] ) ). Zadaniem tej funkcji jest inicjalizacja drzewa testowego, wartością zwracaną powinien być master test suite, czyli zbiór wszystkich przypadków testowych. 
 + 
 +<code cpp> 
 + 
 +//naglowek zawierajacy Unit Test Framework 
 +#include <​boost/​test/​unit_test.hpp>​ 
 +//naglowek zawierajacy BOOST_CHECK_CLOSE 
 +#include <​boost/​test/​floating_point_comparison.hpp>​ 
 +#include <​boost/​shared_ptr.hpp>​ 
 +using namespace boost::​unit_test;​ 
 + 
 +/​****************************************************************************** 
 + * wartosci zwracane przez Unit Test Framework po zakonczeniu testow: 
 + * boost::​exit_success - wszystkie testy zakonczone pomyslnie 
 + * boost::​exit_test_failure - wykryto niekytyczne bledy (nonfatal errors) lub 
 + * nie powiodla sie inicjalizacja unit test suite 
 + * boost::​exit_exception_failure - pojawily sie bledy krytyczne lub niezlapane  
 + * wyjatki 
 + ​******************************************************************************/​ 
 + 
 +// przypadki testowe mozna rejestrowac na kilka roznych sposobow,​najprostszym z  
 +// nich jest na pewno automatycznie rejestrowana funkcja niezwiazana z zadna klasa 
 +// rejestrujemy ja za pomoca jednego z magicznych makr boost.test 
 +// w nawiasie podawana jest nazwa przypadku testowego 
 +BOOST_AUTO_TEST_CASE( auto_test_case ) 
 +
 + /* makro to automatycznie tworzy obiekt function_test_case oraz umieszcza go w 
 +    ​globalnym zestawie testowym. Testowana funkcja jest wlasnie niniejsza funkcja:) 
 + */ 
 + 
 + // w ramach kazdego przypadku testowego mozemy sprawdzic dowolna ilosc warunkow 
 +    int i = 666; 
 + 
 + 
 + // zostanie wygenerowany komunikat 'error in "​auto_test_case":​ check i == 667 failed [666 != 667]'​ 
 +    BOOST_CHECK_EQUAL( i, 667 ); 
 + 
 + // tym razem wynik testu bedzie poprawny, nie zotanie wygenerowany zaden komunikat 
 +    BOOST_CHECK( i == 666 ); 
 +
 + 
 +// automatycznie rejestrowane przypadki testowe mozna grupowac w zetawy testowe 
 +BOOST_AUTO_TEST_SUITE( auto_test_suite ) 
 + 
 +// ten przypadek testowy bedzie nalezal do auto_test_suite,​ a nie do globalnego zestawu 
 +BOOST_AUTO_TEST_CASE( nonglobal_test ) 
 +
 + BOOST_CHECK_MESSAGE( 2+2 == 5, "ten komunikat bedzie wypisany zamiast zwyklego komunikatu o bledzie"​);​ 
 + 
 + double x = 1.000000, y = 1.000001; 
 + double epsilon = 1e-6; 
 + 
 + //​sprawdzenie,​ czy dwie liczby roznia sie od siebie o nie wiecej niz zadana wartosc 
 + BOOST_CHECK_CLOSE( x, y, epsilon ); 
 + 
 +
 + 
 +// automatyczne zestawy testowe mozna zagniezdzac 
 +BOOST_AUTO_TEST_SUITE( internal_test_suite ) 
 + 
 +BOOST_AUTO_TEST_CASE( internal_suite_test_case ) 
 +
 + 
 + BOOST_ERROR( "​internal_suite_test_case_error"​ ); 
 + 
 +
 + 
 +BOOST_AUTO_TEST_SUITE_END() //​zakonczenie internal_test_suite 
 + 
 +BOOST_AUTO_TEST_SUITE_END() //​zakonczenie auto_test_suite 
 + 
 +// mozemy definiowac niezwiazane funkcje testujace, ktore nastepnie beda dodane zamienione 
 +// na przypadki testowe w funkcji init_unit_test_suite 
 +void free_test_function() 
 +
 +    // wypisuje '​unknown location(0):​ fatal error in "​free_test_function":​ memory access violation 
 +    //          nazwapliku.cpp(numerLinii):​ last checkpoint'​ 
 +    int* p = (int*)0x01;​ 
 + BOOST_CHECKPOINT( "Za chwile wystapi naruszenie ochrony pamieci"​ ); 
 +    //​BOOST_CHECK( *p == 0 );​ //​wywolanie tej linijki spowoduje wystapienie fatalerror 
 + //​  ​ co z kolei spowoduje zakonczenie testow i wyjscie z programu 
 + 
 + BOOST_CHECK( 2 == 1 ); 
 +
 + 
 +class KlasaTestujaca 
 +
 + int i; 
 + public: 
 + explicit KlasaTestujaca(int i_): i(i_) {} 
 + 
 + void class_test_case() 
 +
 + BOOST_CHECK(2 == 1); 
 +
 +}; 
 +//​____________________________________________________________________________//​ 
 + 
 + 
 +test_suite* 
 +init_unit_test_suite( int, char* [] ) { 
 + 
 + framework::​master_test_suite().p_name.value = "​Przykladowe test_suite";​ 
 + 
 + //jesli nie korzystamy z globalnego zestawu testow, mozemy definiowac wlasne 
 + //za pomoca makra o nastepujacej skladni 
 + //​test_suite* test= BOOST_TEST_SUITE( "nazwa zestawu testow"​ ); 
 + //​wywolujac metode add(tak jak ponizej) mozemy dodawac przypadki testowe 
 + //oraz nowe zestawy testow, ukladajac je w drzewiasta strukture 
 + 
 + 
 +    framework::​master_test_suite().add( BOOST_TEST_CASE( &​free_test_function ), 3 ); 
 + boost::​shared_ptr<​KlasaTestujaca>​ instance( new KlasaTestujaca(0) ); 
 + framework::​master_test_suite().add( BOOST_CLASS_TEST_CASE( &​KlasaTestujaca::​class_test_case,​ instance ) ); 
 + 
 +    return 0; 
 +
 +</​code>​ 
 + 
 +Jak łatwo zauważyć biblioteka ta w znacznym stopniu polega na prostych makrach opakowujących szablony. Skutkuje to niestety znacznym wydłużeniem kompilacji, która na słabszych komputerach (takich jak np. komputer autora:) ) może trwać na prawdę długo. Elegancję tak frywolnego użycia tak dużej ilości makr pozostawiam do oceny czytelnikowi. 
boosttest.1208203100.txt.gz · ostatnio zmienione: 2008/04/14 21:58 przez twroniak