2
0
mirror of https://github.com/boostorg/test.git synced 2026-01-26 19:12:10 +00:00
Files
test/doc/getting_started.htm
Gennadiy Rozental a10d70cb3c Documentation default pallete changed to white
Components examples and test page introduced and incorporated
Several spelling errors fixed


[SVN r17359]
2003-02-13 08:49:38 +00:00

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> &lt;boost/test/unit_test.hpp&gt;
<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>&amp; 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 &lt;boost/test/unit_test.hpp&gt;
<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">&quot;&quot;</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">&quot;test_string&quot;</SPAN> ); <SPAN class="comment">// 3 //</SPAN>
BOOST_CHECK_EQUAL( std::strcmp( cs1.data(), <SPAN class="literal">&quot;test_string&quot;</SPAN> ), <SPAN class="literal">0</SPAN> );
BOOST_CHECK_EQUAL( cs1.length(), std::strlen(&quot;test_string&quot;) );
<SPAN class="cpp-type">std::string</SPAN> s( <SPAN class="literal">&quot;test_string&quot;</SPAN> ); <SPAN class="comment">// 4 //</SPAN>
const_string cs2( s );
BOOST_CHECK_EQUAL( std::strcmp( cs2.data(), <SPAN class="literal">&quot;test_string&quot;</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">&quot;test_string&quot;</SPAN> ), <SPAN class="literal">0</SPAN> );
const_string cs4( <SPAN class="literal">&quot;test_string&quot;</SPAN>, <SPAN class="literal">4</SPAN> ); <SPAN class="comment">// 6 //</SPAN>
BOOST_CHECK_EQUAL( std::strncmp( cs4.data(), <SPAN class="literal">&quot;test&quot;</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">&quot;test_string&quot;</SPAN>, cs5.length() ), <SPAN class="literal">0</SPAN> );
const_string cs_array[] = { <SPAN class="literal">&quot;str1&quot;</SPAN>, <SPAN class="literal">&quot;str2&quot;</SPAN> }; <SPAN class="comment">// 8 //</SPAN>
BOOST_CHECK_EQUAL( cs_array[<SPAN class="literal">0</SPAN>], <SPAN class="literal">&quot;str1&quot;</SPAN> );
BOOST_CHECK_EQUAL( cs_array[<SPAN class="literal">1</SPAN>], <SPAN class="literal">&quot;str2&quot;</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">&quot;const_string test&quot;</SPAN> );
test-&gt;add( BOOST_TEST_CASE( &amp;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> &lt;boost/test/unit_test.hpp&gt;
<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">&quot;test_string&quot;</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">&quot;const_string test&quot;</SPAN> );
test-&gt;add( BOOST_TEST_CASE( &amp;constructors_test ) );
test-&gt;add( BOOST_TEST_CASE( &amp;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>&copy <A href='mailto:rogeeff@emailaccount.com'>Gennadiy Rozental</A>
2001-2002
</P>
<P>Revised: 12 February, 2003</P>
</DIV></TD>
</TR>
</TABLE>
</DIV>
</BODY>