Blame doc/Money.dox

Packit 8c9aa0
/*! \page money_example Money, a step by step example
Packit 8c9aa0
Packit 8c9aa0
\section Table of contents
Packit 8c9aa0
Packit 8c9aa0
  - \ref sec_setting_vc
Packit 8c9aa0
  - \ref sec_setting_unix
Packit 8c9aa0
  - \ref sec_running_test
Packit 8c9aa0
  - \ref sec_adding_testfixture
Packit 8c9aa0
  - \ref sec_first_tests
Packit 8c9aa0
  - \ref sec_more_tests
Packit 8c9aa0
  - \ref sec_credits
Packit 8c9aa0
Packit 8c9aa0
  The example explored in this article can be found in \c examples/Money/.
Packit 8c9aa0
Packit 8c9aa0
Packit 8c9aa0
Packit 8c9aa0
\section sec_setting_vc Setting up your project (VC++)
Packit 8c9aa0
Packit 8c9aa0
\subsection sec_install Compiling and installing CppUnit libaries
Packit 8c9aa0
Packit 8c9aa0
In the following document, $CPPUNIT is the directory where you unpacked %CppUnit:
Packit 8c9aa0
$CPPUNIT/:
Packit 8c9aa0
	include/
Packit 8c9aa0
	lib/
Packit 8c9aa0
	src/
Packit 8c9aa0
		cppunit/
Packit 8c9aa0
Packit 8c9aa0
First, you need to compile %CppUnit libraries:
Packit 8c9aa0
- Open the $CPPUNIT/src/CppUnitLibraries.dsw workspace in VC++.
Packit 8c9aa0
- In the 'Build' menu, select 'Batch Build...'
Packit 8c9aa0
- In the batch build dialog, select all projects and press the build button.
Packit 8c9aa0
- The resulting libraries can be found in the $CPPUNIT/lib/ directory.
Packit 8c9aa0
Packit 8c9aa0
Once it is done, you need to tell VC++ where are the includes and libraries
Packit 8c9aa0
to use them in other projects. Open the 'Tools/Options...' dialog, and in the
Packit 8c9aa0
'Directories' tab, select 'include files' in the combo. Add a new entry that
Packit 8c9aa0
points to $CPPUNIT/include/. Change to 'libraries files' in the combo and 
Packit 8c9aa0
add a new entry for $CPPUNIT/lib/. Repeat the process with 'source files' 
Packit 8c9aa0
and add $CPPUNIT/src/cppunit/.
Packit 8c9aa0
Packit 8c9aa0
\subsection sec_getting_started Getting started
Packit 8c9aa0
Packit 8c9aa0
Creates a new console application ('a simple application' template will do).
Packit 8c9aa0
Let's link %CppUnit library to our project. In the project settings:
Packit 8c9aa0
- In tab 'C++', combo 'Code generation', set the combo to 'Multithreaded DLL'
Packit 8c9aa0
for the release configuration, and 'Debug Multithreaded DLL' for the debug
Packit 8c9aa0
configure,
Packit 8c9aa0
- In tab 'C++', combo 'C++ langage', for All Configurations, check 
Packit 8c9aa0
'enable Run-Time Type Information (RTTI)',
Packit 8c9aa0
- In tab 'Link', in the 'Object/library modules' field, add cppunitd.lib for
Packit 8c9aa0
the debug configuration, and cppunit.lib for the release configuration.
Packit 8c9aa0
Packit 8c9aa0
We're done !
Packit 8c9aa0
Packit 8c9aa0
Packit 8c9aa0
  
Packit 8c9aa0
    
Packit 8c9aa0
      
Packit 8c9aa0
        
Packit 8c9aa0
          
Packit 8c9aa0
\section sec_setting_unix Setting up your project (Unix)
Packit 8c9aa0
We'll use \c autoconf and \c automake to make it simple to 
Packit 8c9aa0
create our build environment. Create a directory somewhere to 
Packit 8c9aa0
hold the code we're going to build. Create \c configure.in and 
Packit 8c9aa0
\c Makefile.am in that directory to get started.
Packit 8c9aa0
Packit 8c9aa0
<tt>configure.in</tt>
Packit 8c9aa0
\verbatim
Packit 8c9aa0
dnl Process this file with autoconf to produce a configure script.
Packit 8c9aa0
AC_INIT(Makefile.am)
Packit 8c9aa0
AM_INIT_AUTOMAKE(money,0.1)
Packit 8c9aa0
AM_PATH_CPPUNIT(1.9.6)
Packit 8c9aa0
AC_PROG_CXX
Packit 8c9aa0
AC_PROG_CC
Packit 8c9aa0
AC_PROG_INSTALL
Packit 8c9aa0
AC_OUTPUT(Makefile)\endverbatim
Packit 8c9aa0
Packit 8c9aa0
<tt>Makefile.am</tt>
Packit 8c9aa0
\verbatim
Packit 8c9aa0
# Rules for the test code (use `make check` to execute)
Packit 8c9aa0
TESTS = MoneyApp
Packit 8c9aa0
check_PROGRAMS = $(TESTS)
Packit 8c9aa0
MoneyApp_SOURCES = Money.h MoneyTest.h MoneyTest.cpp MoneyApp.cpp
Packit 8c9aa0
MoneyApp_CXXFLAGS = $(CPPUNIT_CFLAGS)
Packit 8c9aa0
MoneyApp_LDFLAGS = $(CPPUNIT_LIBS) -ldl\endverbatim
Packit 8c9aa0
Packit 8c9aa0
Packit 8c9aa0
  
Packit 8c9aa0
    
Packit 8c9aa0
      
Packit 8c9aa0
        
Packit 8c9aa0
          
Packit 8c9aa0
            
Packit 8c9aa0
\section sec_running_test Running our tests
Packit 8c9aa0
Packit 8c9aa0
We have a main that doesn't do anything. Let's start by adding the mechanics
Packit 8c9aa0
to run our tests (remember, test before you code ;-) ). For this example, 
Packit 8c9aa0
we will use a TextTestRunner with the CompilerOutputter for post-build 
Packit 8c9aa0
testing:
Packit 8c9aa0
Packit 8c9aa0
<tt>MoneyApp.cpp</tt>
Packit 8c9aa0
\code
Packit 8c9aa0
#include "stdafx.h"
Packit 8c9aa0
#include <cppunit/CompilerOutputter.h>
Packit 8c9aa0
#include <cppunit/extensions/TestFactoryRegistry.h>
Packit 8c9aa0
#include <cppunit/ui/text/TestRunner.h>
Packit 8c9aa0
Packit 8c9aa0
Packit 8c9aa0
int main(int argc, char* argv[])
Packit 8c9aa0
{
Packit 8c9aa0
  // Get the top level suite from the registry
Packit 8c9aa0
  CppUnit::Test *suite = CppUnit::TestFactoryRegistry::getRegistry().makeTest();
Packit 8c9aa0
Packit 8c9aa0
  // Adds the test to the list of test to run
Packit 8c9aa0
  CppUnit::TextUi::TestRunner runner;
Packit 8c9aa0
  runner.addTest( suite );
Packit 8c9aa0
Packit 8c9aa0
  // Change the default outputter to a compiler error format outputter
Packit 8c9aa0
  runner.setOutputter( new CppUnit::CompilerOutputter( &runner.result(),
Packit 8c9aa0
                                                       std::cerr ) );
Packit 8c9aa0
  // Run the tests.
Packit 8c9aa0
  bool wasSucessful = runner.run();
Packit 8c9aa0
Packit 8c9aa0
  // Return error code 1 if the one of test failed.
Packit 8c9aa0
  return wasSucessful ? 0 : 1;
Packit 8c9aa0
}\endcode
Packit 8c9aa0
Packit 8c9aa0
  VC++: Compile and run (Ctrl+F5).
Packit 8c9aa0
Packit 8c9aa0
  Unix: First build. Since we don't have all the file yet, let's create them
Packit 8c9aa0
  and build our application for the first time:
Packit 8c9aa0
\verbatim
Packit 8c9aa0
touch Money.h MoneyTest.h MoneyTest.cpp
Packit 8c9aa0
aclocal -I /usr/local/share/aclocal
Packit 8c9aa0
autoconf
Packit 8c9aa0
automake -a
Packit 8c9aa0
touch NEWS README AUTHORS ChangeLog # To make automake happy
Packit 8c9aa0
./configure
Packit 8c9aa0
make check\endverbatim
Packit 8c9aa0
Packit 8c9aa0
  Our application will report that everything
Packit 8c9aa0
is fine and no test were run. So let's add some tests...
Packit 8c9aa0
Packit 8c9aa0
Packit 8c9aa0
Packit 8c9aa0
\subsection sec_post_build Setting up automated post-build testing (VC++)
Packit 8c9aa0
Packit 8c9aa0
What does post-build testing means? It means that each time you compile,
Packit 8c9aa0
the test are automatically run when the build finish. This is very
Packit 8c9aa0
useful, if you compile often you can know that you just 'broke' something,
Packit 8c9aa0
or that everything is still working fine.
Packit 8c9aa0
Packit 8c9aa0
Let's adds that to our project, In the project settings, in the 
Packit 8c9aa0
'post-build step' tab:
Packit 8c9aa0
- Select 'All configurations' (upper left combo)
Packit 8c9aa0
- In the 'Post-build description', enter 'Unit testing...'
Packit 8c9aa0
- In 'post-build command(s)', add a new line: <tt>\$(TargetPath)</tt>
Packit 8c9aa0
Packit 8c9aa0
<tt>\$(TargetPath)</tt> expands into the name of your application:
Packit 8c9aa0
Debug\\MoneyApp.exe in debug configuration and Release\\MoneyApp.exe in release
Packit 8c9aa0
configuration.
Packit 8c9aa0
Packit 8c9aa0
What we are doing is say to VC++ to run our application for each build. 
Packit 8c9aa0
Notices the last line of \c main(), it returns a different error code, 
Packit 8c9aa0
depending on weither or not a test failed. If the code returned by
Packit 8c9aa0
an application is not 0 in post-build step, it tell VC++ that the build
Packit 8c9aa0
step failed.
Packit 8c9aa0
Packit 8c9aa0
Compile. Notice that the application's output is now in the build window.
Packit 8c9aa0
How convenient!
Packit 8c9aa0
Packit 8c9aa0
  (Unix: tips to integrate make check into various IDE?)
Packit 8c9aa0
Packit 8c9aa0
Packit 8c9aa0
  
Packit 8c9aa0
    
Packit 8c9aa0
      
Packit 8c9aa0
        
Packit 8c9aa0
          
Packit 8c9aa0
\section sec_adding_testfixture Adding the TestFixture
Packit 8c9aa0
Packit 8c9aa0
For this example, we are going to write a simple money class. Money
Packit 8c9aa0
has an amount and a currency. Let's begin by creating a fixture where
Packit 8c9aa0
we can put our tests, and add single test to test Money constructor:
Packit 8c9aa0
Packit 8c9aa0
<tt>MoneyTest.h:</tt>
Packit 8c9aa0
\code
Packit 8c9aa0
#ifndef MONEYTEST_H
Packit 8c9aa0
#define MONEYTEST_H
Packit 8c9aa0
Packit 8c9aa0
#include <cppunit/extensions/HelperMacros.h>
Packit 8c9aa0
Packit 8c9aa0
class MoneyTest : public CppUnit::TestFixture
Packit 8c9aa0
{
Packit 8c9aa0
  CPPUNIT_TEST_SUITE( MoneyTest );
Packit 8c9aa0
  CPPUNIT_TEST( testConstructor );
Packit 8c9aa0
  CPPUNIT_TEST_SUITE_END();
Packit 8c9aa0
Packit 8c9aa0
public:
Packit 8c9aa0
  void setUp();
Packit 8c9aa0
  void tearDown();
Packit 8c9aa0
Packit 8c9aa0
  void testConstructor();
Packit 8c9aa0
};
Packit 8c9aa0
Packit 8c9aa0
#endif  // MONEYTEST_H\endcode
Packit 8c9aa0
Packit 8c9aa0
- CPPUNIT_TEST_SUITE declares that our Fixture's test suite.
Packit 8c9aa0
- CPPUNIT_TEST adds a test to our test suite. The test is implemented 
Packit 8c9aa0
by a method named testConstructor().
Packit 8c9aa0
- setUp() and tearDown() are use to setUp/tearDown some fixtures. We are
Packit 8c9aa0
not using any for now.
Packit 8c9aa0
Packit 8c9aa0
<tt>MoneyTest.cpp</tt>
Packit 8c9aa0
\code
Packit 8c9aa0
#include "stdafx.h"
Packit 8c9aa0
#include "MoneyTest.h"
Packit 8c9aa0
Packit 8c9aa0
// Registers the fixture into the 'registry'
Packit 8c9aa0
CPPUNIT_TEST_SUITE_REGISTRATION( MoneyTest );
Packit 8c9aa0
Packit 8c9aa0
Packit 8c9aa0
void 
Packit 8c9aa0
MoneyTest::setUp()
Packit 8c9aa0
{
Packit 8c9aa0
}
Packit 8c9aa0
Packit 8c9aa0
Packit 8c9aa0
void 
Packit 8c9aa0
MoneyTest::tearDown()
Packit 8c9aa0
{
Packit 8c9aa0
}
Packit 8c9aa0
Packit 8c9aa0
Packit 8c9aa0
void 
Packit 8c9aa0
MoneyTest::testConstructor()
Packit 8c9aa0
{
Packit 8c9aa0
  CPPUNIT_FAIL( "not implemented" );
Packit 8c9aa0
}
Packit 8c9aa0
\endcode
Packit 8c9aa0
Packit 8c9aa0
Compile. As expected, it reports that a test failed. Press the \c F4 key
Packit 8c9aa0
(Go to next Error). VC++ jump right to our failed assertion CPPUNIT_FAIL.
Packit 8c9aa0
We can not ask better in term of integration!
Packit 8c9aa0
\verbatim
Packit 8c9aa0
Compiling...
Packit 8c9aa0
MoneyTest.cpp
Packit 8c9aa0
Linking...
Packit 8c9aa0
Unit testing...
Packit 8c9aa0
.F
Packit 8c9aa0
G:\prg\vc\Lib\cppunit\examples\money\MoneyTest.cpp(26):Assertion
Packit 8c9aa0
Test name: MoneyTest.testConstructor
Packit 8c9aa0
not implemented
Packit 8c9aa0
Failures !!!
Packit 8c9aa0
Run: 1   Failure total: 1   Failures: 1   Errors: 0
Packit 8c9aa0
Error executing d:\winnt\system32\cmd.exe.
Packit 8c9aa0
Packit 8c9aa0
moneyappd.exe - 1 error(s), 0 warning(s)
Packit 8c9aa0
\endverbatim
Packit 8c9aa0
Packit 8c9aa0
Well, we have everything set up, let's start doing some real testing.
Packit 8c9aa0
Packit 8c9aa0
Packit 8c9aa0
  
Packit 8c9aa0
    
Packit 8c9aa0
      
Packit 8c9aa0
Packit 8c9aa0
  
Packit 8c9aa0
\section sec_first_tests Our first tests
Packit 8c9aa0
Packit 8c9aa0
Let's write our first real test. A test is usually decomposed in three parts:
Packit 8c9aa0
- setting up datas used by the test
Packit 8c9aa0
- doing some processing based on those datas
Packit 8c9aa0
- checking the result of the processing
Packit 8c9aa0
Packit 8c9aa0
\code
Packit 8c9aa0
void 
Packit 8c9aa0
MoneyTest::testConstructor()
Packit 8c9aa0
{
Packit 8c9aa0
  // Set up
Packit 8c9aa0
  const std::string currencyFF( "FF" );
Packit 8c9aa0
  const double longNumber = 12345678.90123;
Packit 8c9aa0
Packit 8c9aa0
  // Process
Packit 8c9aa0
  Money money( longNumber, currencyFF );
Packit 8c9aa0
Packit 8c9aa0
  // Check
Packit 8c9aa0
  CPPUNIT_ASSERT_EQUAL( longNumber, money.getAmount() );
Packit 8c9aa0
  CPPUNIT_ASSERT_EQUAL( currencyFF, money.getCurrency() );
Packit 8c9aa0
}\endcode
Packit 8c9aa0
Packit 8c9aa0
Well, we finally have a good start of what our Money class will
Packit 8c9aa0
look like. Let's start implementing...
Packit 8c9aa0
Packit 8c9aa0
<tt>Money.h</tt>
Packit 8c9aa0
\code
Packit 8c9aa0
#ifndef MONEY_H
Packit 8c9aa0
#define MONEY_H
Packit 8c9aa0
Packit 8c9aa0
#include <string>
Packit 8c9aa0
Packit 8c9aa0
class Money
Packit 8c9aa0
{
Packit 8c9aa0
public:
Packit 8c9aa0
  Money( double amount, std::string currency )
Packit 8c9aa0
    : m_amount( amount )
Packit 8c9aa0
    , m_currency( currency )
Packit 8c9aa0
  {
Packit 8c9aa0
  }
Packit 8c9aa0
Packit 8c9aa0
  double getAmount() const
Packit 8c9aa0
  {
Packit 8c9aa0
    return m_amount;
Packit 8c9aa0
  }
Packit 8c9aa0
Packit 8c9aa0
  std::string getCurrency() const
Packit 8c9aa0
  {
Packit 8c9aa0
    return m_currency;
Packit 8c9aa0
  }
Packit 8c9aa0
Packit 8c9aa0
private:
Packit 8c9aa0
  double m_amount;
Packit 8c9aa0
  std::string m_currency;
Packit 8c9aa0
};
Packit 8c9aa0
Packit 8c9aa0
#endif\endcode
Packit 8c9aa0
Packit 8c9aa0
Include <tt>Money.h</tt> in MoneyTest.cpp and compile.
Packit 8c9aa0
Packit 8c9aa0
Hum, an assertion failed! Press F4, and we jump to the assertion
Packit 8c9aa0
that checks the currency of the constructed money object. The report
Packit 8c9aa0
indicates that string is not equal to expected value. There is only
Packit 8c9aa0
two ways for this to happen: the member was badly initialized or we
Packit 8c9aa0
returned the wrong value. After a quick check, we find out it is the former.
Packit 8c9aa0
Let's fix that:
Packit 8c9aa0
Packit 8c9aa0
<tt>Money.h</tt>
Packit 8c9aa0
\code
Packit 8c9aa0
  Money( double amount, std::string currency )
Packit 8c9aa0
    : m_amount( amount )
Packit 8c9aa0
    , m_currency( currency )
Packit 8c9aa0
  {
Packit 8c9aa0
  }\endcode
Packit 8c9aa0
Packit 8c9aa0
Compile. Our test finally pass!
Packit 8c9aa0
Let's add some functionnality to our Money class.
Packit 8c9aa0
Packit 8c9aa0
Packit 8c9aa0
  
Packit 8c9aa0
    
Packit 8c9aa0
      
Packit 8c9aa0
        
Packit 8c9aa0
          
Packit 8c9aa0
            
Packit 8c9aa0
\section sec_more_tests Adding more tests
Packit 8c9aa0
Packit 8c9aa0
\subsection sec_equal Testing for equality
Packit 8c9aa0
Packit 8c9aa0
  We want to check if to Money object are equal. Let's start by adding
Packit 8c9aa0
a new test to the suite, then add our method:
Packit 8c9aa0
Packit 8c9aa0
<tt>MoneyTest.h</tt>
Packit 8c9aa0
\code
Packit 8c9aa0
  CPPUNIT_TEST_SUITE( MoneyTest );
Packit 8c9aa0
  CPPUNIT_TEST( testConstructor );
Packit 8c9aa0
  CPPUNIT_TEST( testEqual );
Packit 8c9aa0
  CPPUNIT_TEST_SUITE_END();
Packit 8c9aa0
public:
Packit 8c9aa0
  ...
Packit 8c9aa0
  void testEqual();
Packit 8c9aa0
\endcode
Packit 8c9aa0
Packit 8c9aa0
<tt>MoneyTest.cpp</tt>
Packit 8c9aa0
\code
Packit 8c9aa0
void
Packit 8c9aa0
MoneyTest::testEqual()
Packit 8c9aa0
{
Packit 8c9aa0
  // Set up
Packit 8c9aa0
  const Money money123FF( 123, "FF" );
Packit 8c9aa0
  const Money money123USD( 123, "USD" );
Packit 8c9aa0
  const Money money12FF( 12, "FF" );
Packit 8c9aa0
  const Money money12USD( 12, "USD" );
Packit 8c9aa0
Packit 8c9aa0
  // Process & Check
Packit 8c9aa0
  CPPUNIT_ASSERT( money123FF == money123FF );     // ==
Packit 8c9aa0
  CPPUNIT_ASSERT( money12FF != money123FF );      // != amount
Packit 8c9aa0
  CPPUNIT_ASSERT( money123USD != money123FF );    // != currency
Packit 8c9aa0
  CPPUNIT_ASSERT( money12USD != money123FF );     // != currency and != amount
Packit 8c9aa0
}\endcode
Packit 8c9aa0
Packit 8c9aa0
  Let's implements \c operator \c == and \c operator \c != in Money.h:
Packit 8c9aa0
Packit 8c9aa0
<tt>Money.h</tt>
Packit 8c9aa0
\code
Packit 8c9aa0
class Money
Packit 8c9aa0
{
Packit 8c9aa0
public:
Packit 8c9aa0
...
Packit 8c9aa0
  bool operator ==( const Money &other ) const
Packit 8c9aa0
  {
Packit 8c9aa0
    return m_amount == other.m_amount  &&  
Packit 8c9aa0
           m_currency == other.m_currency;
Packit 8c9aa0
  }
Packit 8c9aa0
Packit 8c9aa0
  bool operator !=( const Money &other ) const
Packit 8c9aa0
  {
Packit 8c9aa0
    return (*this == other);
Packit 8c9aa0
  }
Packit 8c9aa0
};
Packit 8c9aa0
\endcode
Packit 8c9aa0
Packit 8c9aa0
  Compile, run... Ooops... Press F4, it seems we're having trouble 
Packit 8c9aa0
with \c operator \c !=. Let's fix that:
Packit 8c9aa0
\code
Packit 8c9aa0
  bool operator !=( const Money &other ) const
Packit 8c9aa0
  {
Packit 8c9aa0
    return !(*this == other);
Packit 8c9aa0
  }\endcode
Packit 8c9aa0
Packit 8c9aa0
Compile, run. Finally got it working!
Packit 8c9aa0
Packit 8c9aa0
Packit 8c9aa0
Packit 8c9aa0
\subsection sec_opadd Adding moneys
Packit 8c9aa0
Packit 8c9aa0
  Let's add our test 'testAdd' to MoneyTest. You know the routine...
Packit 8c9aa0
Packit 8c9aa0
<tt>MoneyTest.cpp</tt>
Packit 8c9aa0
\code
Packit 8c9aa0
void 
Packit 8c9aa0
MoneyTest::testAdd()
Packit 8c9aa0
{
Packit 8c9aa0
  // Set up
Packit 8c9aa0
  const Money money12FF( 12, "FF" );
Packit 8c9aa0
  const Money expectedMoney( 135, "FF" );
Packit 8c9aa0
Packit 8c9aa0
  // Process
Packit 8c9aa0
  Money money( 123, "FF" );
Packit 8c9aa0
  money += money12FF;
Packit 8c9aa0
Packit 8c9aa0
  // Check
Packit 8c9aa0
  CPPUNIT_ASSERT( expectedMoney == money );           // add works
Packit 8c9aa0
  CPPUNIT_ASSERT( &money == &(money += money12FF) );  // add returns ref. on 'this'.
Packit 8c9aa0
}\endcode
Packit 8c9aa0
Packit 8c9aa0
  While writing that test case, you ask yourself, what is the result of
Packit 8c9aa0
adding money of currencies. Obviously this is an error and it should be
Packit 8c9aa0
reported, say let throw an exception, say \c IncompatibleMoneyError, 
Packit 8c9aa0
when the currencies are not equal. We will write another test case
Packit 8c9aa0
for this later. For now let get our testAdd() case working:
Packit 8c9aa0
Packit 8c9aa0
<tt>Money.h</tt>
Packit 8c9aa0
\code
Packit 8c9aa0
class Money
Packit 8c9aa0
{
Packit 8c9aa0
public:
Packit 8c9aa0
...
Packit 8c9aa0
  Money &operator +=( const Money &other )
Packit 8c9aa0
  {
Packit 8c9aa0
    m_amount += other.m_amount;
Packit 8c9aa0
    return *this;
Packit 8c9aa0
  }
Packit 8c9aa0
}; \endcode
Packit 8c9aa0
Packit 8c9aa0
Compile, run. Miracle, everything is fine! Just to be sure the test is indeed
Packit 8c9aa0
working, in the above code, change \c m_amount \c += to \c -=. Build and 
Packit 8c9aa0
check that it fails (always be suspicious of test that work the first 
Packit 8c9aa0
time: you may have forgotten to add it to the suite for example)! 
Packit 8c9aa0
Change the code back so that all the tests are working.
Packit 8c9aa0
  
Packit 8c9aa0
  Let's the incompatible money test case before we forget about it...
Packit 8c9aa0
That test case expect an \c IncompatibleMoneyError exception to be thrown. 
Packit 8c9aa0
%CppUnit can test that for us, you need to specify that the test case
Packit 8c9aa0
expect an exception when you add it to the suite:
Packit 8c9aa0
  
Packit 8c9aa0
<tt>MoneyTest.h</tt>
Packit 8c9aa0
\code
Packit 8c9aa0
class MoneyTest : public CppUnit::TestFixture
Packit 8c9aa0
{
Packit 8c9aa0
  CPPUNIT_TEST_SUITE( MoneyTest );
Packit 8c9aa0
  CPPUNIT_TEST( testConstructor );
Packit 8c9aa0
  CPPUNIT_TEST( testEqual );
Packit 8c9aa0
  CPPUNIT_TEST( testAdd );
Packit 8c9aa0
  CPPUNIT_TEST_EXCEPTION( testAddThrow, IncompatibleMoneyError );
Packit 8c9aa0
  CPPUNIT_TEST_SUITE_END();
Packit 8c9aa0
public:
Packit 8c9aa0
  ...
Packit 8c9aa0
  void testAddThrow();
Packit 8c9aa0
};\endcode
Packit 8c9aa0
Packit 8c9aa0
By convention, you end the name of such tests with \c 'Throw', that way, you
Packit 8c9aa0
know that the test expect an exception to be thrown. Let's write our test case:
Packit 8c9aa0
Packit 8c9aa0
<tt>MoneyTest.cpp</tt>
Packit 8c9aa0
\code
Packit 8c9aa0
void 
Packit 8c9aa0
MoneyTest::testAddThrow()
Packit 8c9aa0
{
Packit 8c9aa0
  // Set up
Packit 8c9aa0
  const Money money123FF( 123, "FF" );
Packit 8c9aa0
Packit 8c9aa0
  // Process
Packit 8c9aa0
  Money money( 123, "USD" );
Packit 8c9aa0
  money += money123FF;        // should throw an exception
Packit 8c9aa0
}
Packit 8c9aa0
\endcode
Packit 8c9aa0
Packit 8c9aa0
  Compile... Ooops, forgot to declare the exception class. Let's do that:
Packit 8c9aa0
Packit 8c9aa0
<tt>Money.h</tt>
Packit 8c9aa0
\code
Packit 8c9aa0
#include <string>
Packit 8c9aa0
#include <stdexcept>
Packit 8c9aa0
Packit 8c9aa0
class IncompatibleMoneyError : public std::runtime_error
Packit 8c9aa0
{
Packit 8c9aa0
public:
Packit 8c9aa0
  IncompatibleMoneyError() : runtime_error( "Incompatible moneys" )
Packit 8c9aa0
  {
Packit 8c9aa0
  }
Packit 8c9aa0
};
Packit 8c9aa0
\endcode
Packit 8c9aa0
Packit 8c9aa0
  Compile. As expected testAddThrow() fail... Let's fix that:
Packit 8c9aa0
  
Packit 8c9aa0
<tt>Money.h</tt>
Packit 8c9aa0
\code
Packit 8c9aa0
  Money &operator +=( const Money &other )
Packit 8c9aa0
  {
Packit 8c9aa0
    if ( m_currency != other.m_currency )
Packit 8c9aa0
      throw IncompatibleMoneyError();
Packit 8c9aa0
Packit 8c9aa0
    m_amount += other.m_amount;
Packit 8c9aa0
    return *this;
Packit 8c9aa0
  }\endcode
Packit 8c9aa0
Packit 8c9aa0
  Compile. Our test finaly passes!
Packit 8c9aa0
Packit 8c9aa0
  TODO:
Packit 8c9aa0
- How to use CPPUNIT_ASSERT_EQUALS with Money
Packit 8c9aa0
- Copy constructor/Assignment operator
Packit 8c9aa0
- Introducing fixtures
Packit 8c9aa0
- ?
Packit 8c9aa0
Packit 8c9aa0
Packit 8c9aa0
  
Packit 8c9aa0
    
Packit 8c9aa0
      
Packit 8c9aa0
        
Packit 8c9aa0
\section sec_credits Credits
Packit 8c9aa0
This article was written by Baptiste Lepilleur. Unix configuration & set up 
Packit 8c9aa0
by Phil Verghese. Inspired from many others (JUnit, Phil's cookbook...), 
Packit 8c9aa0
and all the newbies around that keep asking me for the 
Packit 8c9aa0
'Hello world' example ;-)
Packit 8c9aa0
Packit 8c9aa0
Packit 8c9aa0
Packit 8c9aa0
*/