mirror of
https://github.com/boostorg/test.git
synced 2026-01-24 06:22:12 +00:00
210 lines
13 KiB
HTML
210 lines
13 KiB
HTML
<HTML>
|
|
<HEAD>
|
|
<TITLE>Getting started to use Unit Test Framework</TITLE>
|
|
<LINK rel="stylesheet" type="text/css" href="../../../style/btl.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="header"> <A href="../../../index.html">Boost.Test</A> > <A href="../../index.html">Components</A>
|
|
> <A href="../index.html">Unit Test Framework</A> > <SPAN class="current_article">Getting started</SPAN> </DIV>
|
|
<DIV class="body"> <IMG src="../../btl1.gif" width="252" height="43" alt="Boost Test logo">
|
|
<H1 class="subtitle">Getting started to use the Unit Test Framework</H1>
|
|
<P class="first-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="first-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;
|
|
|
|
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="first-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="first-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="first-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;
|
|
|
|
<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="first-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="first-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="first-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;
|
|
|
|
<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="first-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="first-line-indented">Continuing my effort I am able to complete class
|
|
const_string (see <A href="const_string.hpp">Listing 1</A>) and
|
|
testing module for it (see <A href="const_string_test.cpp">Listing
|
|
2</A>) that is checking all features that are presented in the class const_string
|
|
specification.</P>
|
|
<P class="first-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>
|
|
<DIV class="footer">
|
|
<DIV class="footer-body">
|
|
<P> © <A name="Copyright">Copyright</A> <A href="mailto:boost-test%20at%20emailaccount%20dot%20com%20%28please%20unobscure%29">Gennadiy Rozental</A> 2001-2006. <BR>
|
|
Distributed under the Boost Software License, Version 1.0.
|
|
(See accompanying file <A href="../../../../../../LICENSE_1_0.txt">LICENSE_1_0.txt</A> or copy at
|
|
<A href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</A>)</P>
|
|
<P>Revised: <!-- #BeginDate format:Sw1 -->6 January, 2004<!-- #EndDate --> </P>
|
|
</DIV>
|
|
</DIV>
|
|
</BODY>
|
|
</HTML>
|