Narzędzia użytkownika

Narzędzia witryny


boosttest

To jest stara wersja strony!


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

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().

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

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.

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

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.

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

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.

//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;
 
/*******************************************************************************
// funkcja main nie jest dostarczana przez programiste, robi to za niego unit
// test framework. Programista musi zdefiniowac funkcje o naglowku
// boost::unit_test::test_suite* init_unit_test_suite ( int argc, char* argv[] )
// (argc i argv sa parametrami wywolania, nie mozna ich pominac przy deklaracj,
// mozna je zignorowac piszac init_unit_test_suite ( int, char* [] ) ).
// Zadaniem tej funkcji jest inicjalizacja drzewa testowego, wartoscia zwracana
// powinien byc master test suite, czyli zbior wszystkich przypadkow tesotwych.
// w przypadku zwrocenia wartosci NULL testy nie beda wykonane, a program
// zakonczy sie zwroceniem boost::exit_test_failure
*******************************************************************************/
 
/******************************************************************************
 * 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;
}

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.1208379264.txt.gz · ostatnio zmienione: 2008/04/16 22:54 przez twroniak