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

Both sides previous revision Previous revision
Next revision
Previous revision
boosttest [2008/04/16 01:51]
twroniak
boosttest [2008/04/16 23:00] (aktualna)
twroniak
Linia 1: Linia 1:
 +The acceptance test makes the customer satisfied that the\\
 +software provides the business value that makes them willing\\
 +to pay for it. The unit test makes the programmer satisfied\\
 +that the software does what the programmer thinks it does.\\
 +
 ===== Opis biblioteki ===== ===== 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 ====
 +
 +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> <code cpp>
Linia 34: Linia 40:
   
  int foo(3);  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 );  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( foo ) == 9 );
  BOOST_CHECK( square_err( foo ) == 9 );  BOOST_CHECK( square_err( foo ) == 9 );
Linia 50: Linia 62:
  if(cube( foo ) != 4 )  if(cube( foo ) != 4 )
  throw "​cube(3) != 4";​ //​recznie wykryty blad, zglaszany poprzez wyjatek  throw "​cube(3) != 4";​ //​recznie wykryty blad, zglaszany poprzez wyjatek
- //ktory nie ma okazji byc zlapany+ //ktory nie ma okazji byc zlapany
  
  if(cube( foo ) != 8 )  if(cube( foo ) != 8 )
- BOOST_FAIL("​cube(3) != 8"​);​ //​rowniez zglasza wyjatek+ BOOST_FAIL("​cube(3) != 8"​);//​rowniez zglasza wyjatek
  
- BOOST_REQUIRE( foo == 4 ); //blad w BOOST_REQUIRE powoduje przerwanie testow+ BOOST_REQUIRE( foo == 4 ); //blad w BOOST_REQUIRE powoduje przerwanie testow
  
  std::cout << "Ten kod nigdy nie zostanie osiagniety\n";​  std::cout << "Ten kod nigdy nie zostanie osiagniety\n";​
Linia 66: Linia 78:
 ==== Program execution monitor ==== ==== 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 ====
  
 +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 ====
 +
 +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.1208303464.txt.gz · ostatnio zmienione: 2008/04/16 01:51 przez twroniak