mirror of
https://github.com/boostorg/test.git
synced 2026-01-26 19:12:10 +00:00
Components examples and test page introduced and incorporated Several spelling errors fixed [SVN r17359]
219 lines
13 KiB
HTML
219 lines
13 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
|
|
|
<HTML>
|
|
|
|
<HEAD>
|
|
<TITLE>Getting started</TITLE>
|
|
|
|
<LINK rel="stylesheet" type="text/css" href="style/btl-white.css" media="screen">
|
|
<LINK rel="stylesheet" type="text/css" href="style/btl-print.css" media="print">
|
|
|
|
<META http-equiv="Content-Language" content="en-us">
|
|
<META http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
</HEAD>
|
|
|
|
<BODY>
|
|
<DIV class="centered">
|
|
<TABLE class="body-table" cellspacing="3" >
|
|
<TR>
|
|
<TD id="body">
|
|
|
|
<A name='TOP'><IMG src='../../../c++boost.gif' width='277' height='86' alt="Boost logo"></A>
|
|
|
|
<H1>Getting started to use unit test framework</H1>
|
|
|
|
<P class="1-line-indented">Today is a momentous day. Today I am going to start a new life. I am going to stop
|
|
eating a greasy food, start attending a fitness club and ... since today I am going to test programs
|
|
I am writing. I can start after the last line of a program is completed or, even
|
|
better idea, I can write tests while I am coding. And maybe next time I will
|
|
write tests before the coding during the design stage. I have read a lot of literature
|
|
on how to write the tests, I have the unit test framework in hand and an idea of new
|
|
class. So let's get started.</P>
|
|
<P class="1-line-indented">Let say I want to encapsulate an unchangeable C character buffer with a length
|
|
into the simple class <B>const_string</B>. Rationale: a string class that does not
|
|
allocate a memory and provide a convenient read-only access to the preallocated
|
|
character buffer. I will probably want <B>const_string</B> to have an interface similar to
|
|
the class std::string. What will I do first? In my
|
|
new life I will start with writing a test module for future class <B>const_string</B>. It will look
|
|
like this:</P>
|
|
<P>const_string_test.cpp:</P>
|
|
<PRE class="code">#<SPAN class="reserv-word">include</SPAN> <boost/test/unit_test.hpp>
|
|
<SPAN class="reserv-word">using namespace</SPAN> boost::unit_test_framework;
|
|
|
|
test_suite*
|
|
init_unit_test_suite( <SPAN class="cpp-type">int</SPAN> argc, <SPAN class="cpp-type">char</SPAN>* argv[] )
|
|
{
|
|
test_suite* test= BOOST_TEST_SUITE( <SPAN class="literal">"const_string test"</SPAN> );
|
|
|
|
<SPAN class="reserv-word">return</SPAN> test;
|
|
}
|
|
|
|
<SPAN class="comment">// EOF</SPAN></PRE>
|
|
|
|
<P class="1-line-indented">Now I can compile it and link with the unit test framework. Done! I have a
|
|
working test program. It is empty, so when I
|
|
run the program it produces following output:</P>
|
|
<P class="test-output">*** No errors detected</P>
|
|
<P class="1-line-indented">Well, now it could be a good time to start a work on <B>const_string</B>.
|
|
First thing I imagine would be good to have is a constructors and trivial access
|
|
methods. So my class initial version looks like this:</P>
|
|
<P>const_string.hpp</P>
|
|
<PRE class="code"><SPAN class="reserv-word">class</SPAN> const_string {
|
|
<SPAN class="reserv-word">public</SPAN>:
|
|
// Constructors
|
|
const_string();
|
|
const_string( <SPAN class="cpp-type">std::string</SPAN> <SPAN class="reserv-word">const</SPAN>& s )
|
|
const_string( <SPAN class="cpp-type">char</SPAN> <SPAN class="reserv-word">const</SPAN>* s );
|
|
const_string( <SPAN class="cpp-type">char</SPAN> <SPAN class="reserv-word">const</SPAN>* s, <SPAN class="cpp-type">size_t</SPAN> length );
|
|
const_string( <SPAN class="cpp-type">char</SPAN> <SPAN class="reserv-word">const</SPAN>* begin, <SPAN class="cpp-type">char</SPAN> <SPAN class="reserv-word">const</SPAN>* end );
|
|
|
|
// Access methods
|
|
<SPAN class="cpp-type">char</SPAN> <SPAN class="reserv-word">const</SPAN>* data() <SPAN class="reserv-word">const</SPAN>;
|
|
<SPAN class="cpp-type">size_t</SPAN> length() <SPAN class="reserv-word">const</SPAN>;
|
|
<SPAN class="cpp-type">bool</SPAN> is_empty() <SPAN class="reserv-word">const</SPAN>;
|
|
|
|
...
|
|
};</PRE>
|
|
<P class="1-line-indented">Now I am able to write a first test case - constructors testing - and add it
|
|
to a test suite. My test program became to look like this:</P>
|
|
<P>const_string_test.cpp:</P>
|
|
<PRE class="code">#include <boost/test/unit_test.hpp>
|
|
<SPAN class="reserv-word">using namespace</SPAN> boost::unit_test_framework;
|
|
|
|
<SPAN class="cpp-type">void</SPAN> constructors_test() {
|
|
const_string cs0( <SPAN class="literal">""</SPAN> ); <SPAN class="comment">// 1 //</SPAN>
|
|
BOOST_CHECK_EQUAL( cs0.length(), (<SPAN class="cpp-type">size_t</SPAN>)<SPAN class="literal">0</SPAN> );
|
|
BOOST_CHECK( cs0.is_empty() );
|
|
|
|
const_string cs01( NULL ); <SPAN class="comment">// 2 //</SPAN>
|
|
BOOST_CHECK_EQUAL( cs01.length(), (<SPAN class="cpp-type">size_t</SPAN>)<SPAN class="literal">0</SPAN> );
|
|
BOOST_CHECK( cs01.is_empty() );
|
|
|
|
const_string cs1( <SPAN class="literal">"test_string"</SPAN> ); <SPAN class="comment">// 3 //</SPAN>
|
|
BOOST_CHECK_EQUAL( std::strcmp( cs1.data(), <SPAN class="literal">"test_string"</SPAN> ), <SPAN class="literal">0</SPAN> );
|
|
BOOST_CHECK_EQUAL( cs1.length(), std::strlen("test_string") );
|
|
|
|
<SPAN class="cpp-type">std::string</SPAN> s( <SPAN class="literal">"test_string"</SPAN> ); <SPAN class="comment">// 4 //</SPAN>
|
|
const_string cs2( s );
|
|
BOOST_CHECK_EQUAL( std::strcmp( cs2.data(), <SPAN class="literal">"test_string"</SPAN> ), <SPAN class="literal">0</SPAN> );
|
|
|
|
const_string cs3( cs1 ); <SPAN class="comment">// 5 //</SPAN>
|
|
BOOST_CHECK_EQUAL( std::strcmp( cs1.data(), <SPAN class="literal">"test_string"</SPAN> ), <SPAN class="literal">0</SPAN> );
|
|
|
|
const_string cs4( <SPAN class="literal">"test_string"</SPAN>, <SPAN class="literal">4</SPAN> ); <SPAN class="comment">// 6 //</SPAN>
|
|
BOOST_CHECK_EQUAL( std::strncmp( cs4.data(), <SPAN class="literal">"test"</SPAN>, cs4.length() ), <SPAN class="literal">0</SPAN> );
|
|
|
|
const_string cs5( s.data(), s.data() + s.length() ); <SPAN class="comment">// 7 //</SPAN>
|
|
BOOST_CHECK_EQUAL( std::strncmp( cs5.data(), <SPAN class="literal">"test_string"</SPAN>, cs5.length() ), <SPAN class="literal">0</SPAN> );
|
|
|
|
const_string cs_array[] = { <SPAN class="literal">"str1"</SPAN>, <SPAN class="literal">"str2"</SPAN> }; <SPAN class="comment">// 8 //</SPAN>
|
|
BOOST_CHECK_EQUAL( cs_array[<SPAN class="literal">0</SPAN>], <SPAN class="literal">"str1"</SPAN> );
|
|
BOOST_CHECK_EQUAL( cs_array[<SPAN class="literal">1</SPAN>], <SPAN class="literal">"str2"</SPAN> );
|
|
}
|
|
|
|
test_suite*
|
|
init_unit_test_suite( <SPAN class="cpp-type">int</SPAN> argc, <SPAN class="cpp-type">char</SPAN>* argv[] )
|
|
{
|
|
test_suite* test= BOOST_TEST_SUITE( <SPAN class="literal">"const_string test"</SPAN> );
|
|
|
|
test->add( BOOST_TEST_CASE( &constructors_test ) );
|
|
|
|
<SPAN class="reserv-word">return</SPAN> test;
|
|
}
|
|
|
|
<SPAN class="comment">// EOF</SPAN></PRE>
|
|
|
|
<P class="1-line-indented">The constructors_test test case is intended to check a simple feature of the class const_string:
|
|
an ability to construct itself properly based on different arguments. To test this
|
|
feature I am using such characteristics of constructed object as a data it
|
|
contains and a length. The specification of the class const_string does not contain any
|
|
expected failures, so, though the constructor can fail if I would pass a pointer to
|
|
an invalid memory, error check control is not performed (can't require what was not
|
|
promised :-)). But for any valid input it should work. So I am trying to check
|
|
a construction for an empty string (1), a NULL string (2) a regular C string(3),
|
|
an STL string(4), a copy construction(5) and so on . Well, after fixing all the errors in
|
|
the implementation (do you write programs without errors from scratch?) I am able to pass
|
|
this test case and the unit test framework gives me the following report:</P>
|
|
|
|
<P class="test-output">Running 1 test case...<BR>
|
|
*** No errors detected</P>
|
|
|
|
<P class="1-line-indented">Encouraged I am moving on and adding more access methods:</P>
|
|
<P>const_string.hpp</P>
|
|
<PRE class="code"><SPAN class="reserv-word">class</SPAN> const_string {
|
|
<SPAN class="reserv-word">public</SPAN>:
|
|
<SPAN class="cpp-type">char</SPAN> <SPAN class="reserv-word">operator</SPAN>[]( <SPAN class="cpp-type">size_t</SPAN> index ) <SPAN class="reserv-word">const</SPAN>;
|
|
<SPAN class="cpp-type">char</SPAN> at( <SPAN class="cpp-type">size_t</SPAN> index ) <SPAN class="reserv-word">const</SPAN>;
|
|
...
|
|
};
|
|
</PRE>
|
|
<P class="1-line-indented">I added the new feature - I need a new test case to check it. As a
|
|
result my test suite became to look like this:</P>
|
|
<P>const_string_test.cpp:</P>
|
|
<PRE class="code">#<SPAN class="reserv-word">include</SPAN> <boost/test/unit_test.hpp>
|
|
<SPAN class="reserv-word">using namespace</SPAN> boost::unit_test_framework;
|
|
|
|
<SPAN class="cpp-type">void</SPAN> constructors_test() {
|
|
...
|
|
}
|
|
|
|
<SPAN class="cpp-type">void</SPAN> data_access_test() {
|
|
const_string cs1( <SPAN class="literal">"test_string"</SPAN> ); <SPAN class="comment">// 1 //</SPAN>
|
|
BOOST_CHECK_EQUAL( cs1[(<SPAN class="cpp-type">size_t</SPAN>)<SPAN class="literal">0</SPAN>], <SPAN class="literal">'t'</SPAN> );
|
|
BOOST_CHECK_EQUAL( cs1[(<SPAN class="cpp-type">size_t</SPAN>)<SPAN class="literal">4</SPAN>], <SPAN class="literal">'_'</SPAN> );
|
|
BOOST_CHECK_EQUAL( cs1[cs1.length()-<SPAN class="literal">1</SPAN>], <SPAN class="literal">'g'</SPAN> );
|
|
|
|
BOOST_CHECK_EQUAL( cs1[(<SPAN class="cpp-type">size_t</SPAN>)<SPAN class="literal">0</SPAN>], cs1.at( <SPAN class="literal">0</SPAN> ) ); <SPAN class="comment">// 2 //</SPAN>
|
|
BOOST_CHECK_EQUAL( cs1[(<SPAN class="cpp-type">size_t</SPAN>)<SPAN class="literal">2</SPAN>], cs1.at( <SPAN class="literal">5</SPAN> ) );
|
|
BOOST_CHECK_EQUAL( cs1.at( cs1.length() - <SPAN class="literal">1</SPAN> ), <SPAN class="literal">'g'</SPAN> );
|
|
|
|
BOOST_CHECK_THROW( cs1.at( cs1.length() ), std::out_of_range ); <SPAN class="comment">// 3 //</SPAN>
|
|
}
|
|
|
|
test_suite*
|
|
init_unit_test_suite( <SPAN class="cpp-type">int</SPAN> argc, <SPAN class="cpp-type">char</SPAN>* argv[] )
|
|
{
|
|
test_suite* test= BOOST_TEST_SUITE( <SPAN class="literal">"const_string test"</SPAN> );
|
|
test->add( BOOST_TEST_CASE( &constructors_test ) );
|
|
test->add( BOOST_TEST_CASE( &data_access_test ) );
|
|
|
|
<SPAN class="reserv-word">return</SPAN> test;
|
|
}
|
|
|
|
<SPAN class="comment">// EOF</SPAN>
|
|
</PRE>
|
|
|
|
<P class="1-line-indented">In the data_access_test test case I am trying to check the class const_string character access
|
|
correctness. While tests (1) checks valid access using const_string::operator[] and test (2)
|
|
checks valid access using method const_string::at(), there is one more thing to test. The
|
|
specification of the method const_string::at() contains validation for the out of bound access. That
|
|
was test (3) is intended to do: check that the validation is working. A testing of
|
|
a validation and error handling code is an important part of a unit testing and should
|
|
not be left for a production stage. The data_access_test test case passed and I am ready for the next
|
|
step.</P>
|
|
<P class="1-line-indented">Continuing my effort I am able to complete class const_string (see <A href="getting_started/const_string.hpp">Listing
|
|
1</A>) and testing module for it (see <A href="getting_started/const_string_test.cpp">Listing
|
|
2</A>) that is checking all features that are presented in the class const_string
|
|
specification.</P>
|
|
<P class="1-line-indented">Your testing habits could be a little different. You could start with a class/library development and then at some point start writing test cases on
|
|
feature basis. Or you can, given a detailed specification for the future product,
|
|
including expected interfaces, immediately start with writing all test cases (or
|
|
it could be a different person, while you working on implementation at the same
|
|
time). In any case you should not have any problems to use facilities provided
|
|
by the unit test framework and, let me hope, be able to write a stable,
|
|
bulletproof code. And what is even more important is your confidence in an
|
|
ability to make a changes of any complexity without involving a lengthy regression
|
|
testing of your whole product. Your test module and the unit test framework will
|
|
stay behind your back to help you with any occasional errors.</P>
|
|
<DIV class="footer">
|
|
<P>© <A href='mailto:rogeeff@emailaccount.com'>Gennadiy Rozental</A>
|
|
2001-2002
|
|
</P>
|
|
<P>Revised: 12 February, 2003</P>
|
|
</DIV></TD>
|
|
</TR>
|
|
</TABLE>
|
|
</DIV>
|
|
</BODY>
|
|
|