﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-只有有耐心圆满完成简单工作的人，才能够轻而易举地完成困难的事。-随笔分类-E文全翻</title><link>http://www.cppblog.com/leetaolion/category/4352.html</link><description>Only those who have the patience to do simple things perfectly ever acquire the skill to do difficult things easily. </description><language>zh-cn</language><lastBuildDate>Mon, 19 May 2008 12:20:56 GMT</lastBuildDate><pubDate>Mon, 19 May 2008 12:20:56 GMT</pubDate><ttl>60</ttl><item><title>我是笨人——读Rob Pike的《Notes on C Programming 》（附全文链接）</title><link>http://www.cppblog.com/leetaolion/archive/2008/02/29/43429.html</link><dc:creator>创建更好的解决方案</dc:creator><author>创建更好的解决方案</author><pubDate>Fri, 29 Feb 2008 00:39:00 GMT</pubDate><guid>http://www.cppblog.com/leetaolion/archive/2008/02/29/43429.html</guid><wfw:comment>http://www.cppblog.com/leetaolion/comments/43429.html</wfw:comment><comments>http://www.cppblog.com/leetaolion/archive/2008/02/29/43429.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/leetaolion/comments/commentRss/43429.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/leetaolion/services/trackbacks/43429.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Ken Thompson —— Unix 最初版本的设计者和实现者，禅宗偈语般地对 Pike 的原则4 作了强调：拿不准就穷举 <br>花哨的算法比简单算法更容易出 bug 、更难实现。尽量使用简单的算法配合简单的数据结构。<br>只要掌握了数据结构中的四大法宝，就可以包打天下，他们是：array 、linked list 、hash table、binary tree 。这四大法宝可不是各自为战的，灵活结合才能游刃有余。比如，一个用hash table组织的symbol table，其中是一个个由字符型array构成的linked list。&nbsp;&nbsp;<a href='http://www.cppblog.com/leetaolion/archive/2008/02/29/43429.html'>阅读全文</a><img src ="http://www.cppblog.com/leetaolion/aggbug/43429.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/leetaolion/" target="_blank">创建更好的解决方案</a> 2008-02-29 08:39 <a href="http://www.cppblog.com/leetaolion/archive/2008/02/29/43429.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Unit testing with CPPUnit </title><link>http://www.cppblog.com/leetaolion/archive/2007/05/26/24883.html</link><dc:creator>创建更好的解决方案</dc:creator><author>创建更好的解决方案</author><pubDate>Sat, 26 May 2007 03:05:00 GMT</pubDate><guid>http://www.cppblog.com/leetaolion/archive/2007/05/26/24883.html</guid><wfw:comment>http://www.cppblog.com/leetaolion/comments/24883.html</wfw:comment><comments>http://www.cppblog.com/leetaolion/archive/2007/05/26/24883.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/leetaolion/comments/commentRss/24883.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/leetaolion/services/trackbacks/24883.html</trackback:ping><description><![CDATA[<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td class=HeaderLogo><a href="http://www.codeproject.com/"><img height=90 alt=Home src="http://www.codeproject.com/images/standard/codeproject225x90.gif" border=0></a></td>
            <td bgColor=#ff9900>&nbsp;</td>
        </tr>
        <tr>
            <td colSpan=2>
            <table class=ArticleHeader cellSpacing=0 cellPadding=3 width="100%">
                <tbody>
                    <tr vAlign=top>
                        <td class=smallText style="PADDING-RIGHT: 10px"><a href="http://www.codeproject.com/?cat=1">All Topics</a>, <a href="http://www.codeproject.com/?cat=2">MFC / C++</a> &gt;&gt; <a href="http://www.codeproject.com/library/">Libraries &amp; Projects</a> &gt;&gt; <a href="http://www.codeproject.com/library/#General">General</a><br><a href="http://www.codeproject.com/library/Using_CPPUnit.asp">http://www.codeproject.com/library/Using_CPPUnit.asp</a><br><br>
                        <div style="FONT-WEIGHT: bold; FONT-SIZE: 16pt">Unit testing with CPPUnit</div>
                        <strong>By <a href="http://www.codeproject.com/script/Articles/list_articles.asp?userid=53625">JM Navarro</a></strong>. <br><br>
                        <div style="FONT-SIZE: 12px">CPPUnit is a unit testing framework for C++, with which you can improve your systems' quality.</div>
                        </td>
                        <td class=smallText style="WIDTH: 200px">C++ (VC7.1, VC7, VC6)<br>Windows (WinXP, Win2K, Win2003, Win95, Win98, WinME)<br>MFC, Win32, VS (VS6)<br>Dev<br><span style="PADDING-RIGHT: 2ex">Posted</span>: <strong>15 Dec 2003</strong><br><span style="PADDING-RIGHT: 3ex">Views</span>: <strong>99,370</strong> </td>
                    </tr>
                    </td>
                </tr>
                </td>
            </tr>
        </tbody>
    </table>
    <table cellSpacing=0 cellPadding=0 border=0>
        <tbody>
            <tr vAlign=top>
                <td width="100%">
                <table width="100%">
                    <tbody>
                        <tr vAlign=top>
                            <td class=SmallText noWrap></td>
                            <td noWrap align=right><a name=__top></a>
                            <table>
                                <tbody>
                                    <tr>
                                        <td class=smallText align=right>32 votes for this article.</td>
                                        <td>
                                        <table cellSpacing=0 cellPadding=0 border=2>
                                            <tbody>
                                                <tr>
                                                    <td><img height=5 src="http://www.codeproject.com/script/images/red.gif" width=20 border=0></td>
                                                    <td><img height=5 src="http://www.codeproject.com/script/images/red.gif" width=20 border=0></td>
                                                    <td><img height=5 src="http://www.codeproject.com/script/images/red.gif" width=20 border=0></td>
                                                    <td><img height=5 src="http://www.codeproject.com/script/images/red.gif" width=20 border=0></td>
                                                    <td><img height=5 src="http://www.codeproject.com/script/images/red.gif" width=14 border=0><img height=5 src="http://www.codeproject.com/script/images/white.gif" width=6 border=0></td>
                                                </tr>
                                            </tbody>
                                        </table>
                                        </td>
                                    </tr>
                                    <tr>
                                        <td class=smallText align=right colSpan=2><a title="Calculated as rating x Log10(# votes)" href="http://www.codeproject.com/script/articles/top_articles.asp?st=2">Popularity: 7.09</a>. Rating: <strong>4.71</strong> out of 5.</td>
                                    </tr>
                                </tbody>
                            </table>
                            </td>
                        </tr>
                    </tbody>
                </table>
                </td>
            </tr>
            <tr>
                <td class=ArticlePane><span id=intelliTXT>
                <div id=contentdiv><!-- Article Starts -->
                <ul class=download>
                    <li><a href="http://www.codeproject.com/library/Using_CPPUnit/my_tests.zip">Download demo project - 7.88 Kb</a> </li>
                </ul>
                <p><img height=375 src="http://www.codeproject.com/library/Using_CPPUnit/testrunner.jpg" width=591></p>
                <h2>Introduction</h2>
                <p>Within a Quality Assurance process, we have mainly two kinds of tests:</p>
                <ul>
                    <li>Unit tests (or acceptance tests): a set of verifications we can make to each <em>logic unit</em> in our system. With each test, we're checking its behavior, without keeping in mind all collaborations with other units.
                    <li>System tests (or integration tests): every test allows you to check system's behavior, emphasizing unit collaborations. </li>
                </ul>
                <p>We're going to speak about "unit testing" and how we can apply it in our C/C++ project, through CPPUnit unit testing framework.</p>
                <p>I'm going to consider, you know what unit testing is, and why it is very important in software development process. If you want to read more about unit testing basis, you can check <a href="http://www.junit.org/" target=_blank>JUnit web site</a>.</p>
                <h2>Unit tests design</h2>
                <p>Think about a typical scenario in a development team: a programmer is testing his or her code using the debugger. With this tool, you can check each variable value in every program at any time. Running step by step, you can verify if a variable has the expected value. This is powerful, but pretty slow and might have plenty of errors. A few programmers can keep their mind in a deep, hard and long debugging process and, after one or two hours, the programmer's brain is near break down. All these repetitive and hard verifications can be done automatically, with a few programming instructions and proper tools.</p>
                <p>These tools I'm going to speak about are called "unit testing frameworks", with them you can write small modules which help you to test modules (classes, functions or libraries) of your applications.</p>
                <p>Let's see this example: we're programming a small program module, whose main responsibility is to just add two numbers. As we're coding in plain C, this module is represented by a C function:</p>
                <pre>BOOL addition(<span class=cpp-keyword>int</span> a, <span class=cpp-keyword>int</span> b)
                {
                <span class=cpp-keyword>return</span> (a + b);
                }</pre>
                <p>Our testing unit should be coded with another module, that is: another C function. This function checks all possible addition cases, and returns <code>TRUE</code> or <code>FALSE</code>, denoting if the module does or doesn't pass the test:</p>
                <pre>BOOL additionTest()
                {
                <span class=cpp-keyword>if</span> ( addition(<span class=cpp-literal>1</span>, <span class=cpp-literal>2</span>) != <span class=cpp-literal>3</span> )
                <span class=cpp-keyword>return</span> (FALSE);
                <span class=cpp-keyword>if</span> ( addition(<span class=cpp-literal>0</span>, <span class=cpp-literal>0</span>) != <span class=cpp-literal>0</span> )
                <span class=cpp-keyword>return</span> (FALSE);
                <span class=cpp-keyword>if</span> ( addition(<span class=cpp-literal>10</span>, <span class=cpp-literal>0</span>) != <span class=cpp-literal>10</span> )
                <span class=cpp-keyword>return</span> (FALSE);
                <span class=cpp-keyword>if</span> ( addition(-<span class=cpp-literal>8</span>, <span class=cpp-literal>0</span>) != -<span class=cpp-literal>8</span> )
                <span class=cpp-keyword>return</span> (FALSE);
                <span class=cpp-keyword>if</span> ( addition(<span class=cpp-literal>5</span>, -<span class=cpp-literal>5</span>) != <span class=cpp-literal>0</span> )
                <span class=cpp-keyword>return</span> (FALSE);
                <span class=cpp-keyword>if</span> ( addition(-<span class=cpp-literal>5</span>, <span class=cpp-literal>2</span>) != -<span class=cpp-literal>3</span> )
                <span class=cpp-keyword>return</span> (FALSE);
                <span class=cpp-keyword>if</span> ( addition(-<span class=cpp-literal>4</span>, -<span class=cpp-literal>1</span>) != -<span class=cpp-literal>5</span> )
                <span class=cpp-keyword>return</span> (FALSE);
                <span class=cpp-keyword>return</span> (TRUE);
                }</pre>
                <p>As we can see, we've tested all possible addition cases:</p>
                <ul>
                    <li>Positive + Positive
                    <li>Zero + Zero
                    <li>Positive + Zero
                    <li>Negative + Zero
                    <li>Positive + Negative
                    <li>Negative + Positive
                    <li>Negative + Negative </li>
                </ul>
                <p>Each test compares the addition result with expected value, and it returns <code>FALSE</code> if result is a value which is different than expected one. If execution path reaches last line, we consider that all tests have been passed correctly, and it returns <code>TRUE</code>.</p>
                <p>This small module (or function) is called <strong>Test Case</strong>, and it shows a set of checks we do over a single unit. Every verification must be related with a single unit scenario. In this case, we check how "addition operation" behaves about operand's sign. We can write other Test Cases, for checking others scenarios. For example, we can code another Test Case in order to check our module behavior with typical addition properties:</p>
                <pre><span class=cpp-keyword>int</span> additionPropertiesTest()
                {
                <span class=cpp-comment>// conmutative: a + b = b + a</span>
                <span class=cpp-keyword>if</span> ( addition(<span class=cpp-literal>1</span>, <span class=cpp-literal>2</span>) != addition(<span class=cpp-literal>2</span>, <span class=cpp-literal>1</span>) )
                <span class=cpp-keyword>return</span> (FALSE);
                <span class=cpp-comment>// asociative: a + (b + c) = (a + b) + c</span>
                <span class=cpp-keyword>if</span> ( addition(<span class=cpp-literal>1</span>, addition(<span class=cpp-literal>2</span>, <span class=cpp-literal>3</span>)) != addition(addition(<span class=cpp-literal>1</span>, <span class=cpp-literal>2</span>), <span class=cpp-literal>3</span>) )
                <span class=cpp-keyword>return</span> (FALSE);
                <span class=cpp-comment>// neutral element: a + NEUTRAL = a</span>
                <span class=cpp-keyword>if</span> ( addition(<span class=cpp-literal>10</span>, <span class=cpp-literal>0</span>) != <span class=cpp-literal>10</span> )
                <span class=cpp-keyword>return</span> (FALSE);
                <span class=cpp-comment>// inverse element: a + INVERSE = NEUTRAL</span>
                <span class=cpp-keyword>if</span> ( addition(<span class=cpp-literal>10</span>, -<span class=cpp-literal>10</span>) != <span class=cpp-literal>0</span> )
                <span class=cpp-keyword>return</span> (FALSE);
                <span class=cpp-keyword>return</span> (TRUE);
                }</pre>
                <p>In this example, we've checked some mathematical addition properties. These two Test Cases, build a <strong>Test Suite</strong>, that is: a collection of Test Cases which test the same unit.</p>
                <p>All those Test Cases and Test Suites must be developed while we're coding the units, and every time the unit changes, corresponding unit test should reflect changes, modifying a Test Case or adding new one.</p>
                <p>For instance, if we improve our "addition" module in order to add decimal numbers, we have to change our tests, adding for example a new <code>addDecimalNumbersTest</code> Test Case.</p>
                <p><a href="http://www.extremeprogramming.org/" target=_blank>Extreme programming</a> recommends you that you code all these unit tests <strong>before</strong> you code the target unit. Main reason is very simple: when you're involved in a development process, you're in a permanent research stage, in which you're thinking about how a unit should behave, what public interface you should publish, what parameters you should pass in methods, and other concrete aspects about external access, internal behavior... Coding "unit tests" before its development, you're getting this set of knowledge, and, when you code the main unit, you'll be able to develop faster and better than the other way.</p>
                <p>Each time a team wishes to deploy a new release, they should perform a complete unit tests battery. <strong>All</strong> units must pass their unit (or acceptance) tests, and in this case, we can release a successful new version. If at least one unit doesn't pass all its tests, then we've found a bug. In that case, we must code another test, even add a new Test Case if its necessary, checking all conditions to reproduce this bug. When our new coded test can reproduce the bug properly, we can fix it, and perform the test again. If unit passes the test, we consider bug is resolved and we can release our new bug-free version.</p>
                <p>Adding new tests cases for each bug found is very important, because that bug can reappear, and we need a test that detects that bug when it comes back again. In this way, our testing battery is growing bigger and bigger, and all possible errors, and all historic bugs, are covered.</p>
                <h2>Testing tools</h2>
                <p>Once upon a time, two guys called Kent Beck &amp; Eric Gamma, wrote a set of Java classes in order to make unit testing as automatic as they can. They called them <a href="http://www.junit.org/" target=_blank>JUnit</a> and it became a great hit in unit testing world. Other developers ported their code to other languages, building a big collection of products, called xUnit frameworks. Among them, we can find one for C/C++ (CUnit and CPPUnit), Delphi (DUnit), Visual Basic (VBUnit), NUnit (.NET platform), and many others.</p>
                <p>All these frameworks apply similar rules, and probably you can use one if you've used another one, with few language-dependency exceptions.</p>
                <p>Now, we're going to explain how you can use <a href="http://cppunit.sourceforge.net/" target=_blank>CPPUnit</a> in order to write you own unit tests and improve your units' quality.</p>
                <p>CPPUnit uses object oriented programming, so we're going to work with concepts like inheritance, encapsulation and polymorphism. Also, CPPUnit uses C++'s SEH (Structured Exception Handling), so you should understand concepts like "exception" and instructions and structures like <code><span class=cpp-keyword>throw</span></code>, <code><span class=cpp-keyword>try</span></code>, <code><span class=cpp-keyword>finally</span></code>, <code><span class=cpp-keyword>catch</span></code> and so on.</p>
                <h2>CPPUnit</h2>
                <p>Each Test Case should be coded inside a class derived from <code>TestCase</code>. This class brings us all basic functionality to run a test, register it inside a Test Suite, and so on.</p>
                <p>For instance, we've wrote a small module which stores some data in disk. This module (coded as a class called <code>DiskData</code>) has mainly two responsibilities: load and store data inside a file. Let's take a look:</p>
                <pre><span class=cpp-keyword>typedef</span> <span class=cpp-keyword>struct</span> _DATA
                {
                <span class=cpp-keyword>int</span>  number;
                <span class=cpp-keyword>char</span> string[<span class=cpp-literal>256</span>];
                } DATA, *LPDATA;
                <span class=cpp-keyword>class</span> DiskData
                {
                <span class=cpp-keyword>public</span>:
                DiskData();
                ~DiskData();
                LPDATA getData();
                <span class=cpp-keyword>void</span> setData(LPDATA value);
                <span class=cpp-keyword>bool</span> load(<span class=cpp-keyword>char</span> *filename);
                <span class=cpp-keyword>bool</span> store(<span class=cpp-keyword>char</span> *filename);
                <span class=cpp-keyword>private</span>:
                DATA m_data;
                };</pre>
                <p>For now, it isn't important how these methods are coded, because most important thing is that we must be sure this class is doing all the things it must do, that is: load and store data correctly into a file.</p>
                <p>In order to do this verification, we're going to create a new Test Suite with two test cases: one for load data and another for store data.</p>
                <h2>Using CPPUnit</h2>
                <p>You can get latest CPPUnit version <a href="http://cppunit.sourceforge.net/" target=_blank>here</a>, where you can find all libraries, documentation, examples and other interesting stuff. (I've downloaded 1.8.0 and it works fine)</p>
                <p>In Win32 world, you can use CPPUnit under Visual C++ (6 and later), but as CPPUnit uses ANSI C++, there are few ports to other environments like C++Builder.</p>
                <p>All steps and information about building libraries can be found in <em>INSTALL-WIN32.txt</em> file, inside CPPUnit distribution. Once all binaries are built, you can write your own Test Suites.</p>
                <p>In order to write your own unit test applications, under Visual C++, you must follow these steps:</p>
                <ul>
                    <li>Create a new Dialog based MFC application (or doc-view one)
                    <li>Enable RTTI: Project Settings - C++ - C++ Language
                    <li>Add <em>CPPUnit\include</em> folder to include directories: Tools - Options - Directories - Include.
                    <li>Link your application with <em>cppunitd.lib</em> (for static link) or <em>cppunitd_dll.lib</em> (for dynamic link), and <em>testrunnerd.lib</em>. If you're compiling under "Release" configuration, you should link with same libraries, bout without "d" suffix.
                    <li>Copy <em>testrunnerd.dll</em> in your executable folder, or any other folder in your path, and <em>cppunitd_dll.dll</em> if you linked dynamically (or <em>testrunner.dll</em> and <em>cppunit_dll.dll</em> if you're under <em>Release</em>) </li>
                </ul>
                <p>Once your project is ready, we can code our first unit test class.</p>
                <p>We're going to test our <code>DiskData</code> class, which mainly performs two operations: load and store data into a disk file. Our test case should test this two operations, with two Test Cases: one for load and the other for store the data.</p>
                <p>Let's take a look at the unit test class definition:</p>
                <pre><span class=cpp-preprocessor>#if !defined(DISKDATA_TESTCASE_H_INCLUDED)</span>
                <span class=cpp-preprocessor>#define DISKDATA_TESTCASE_H_INCLUDED</span>
                <span class=cpp-preprocessor>#if _MSC_VER &gt; 1000</span>
                <span class=cpp-preprocessor>#pragma once</span>
                <span class=cpp-preprocessor>#endif // _MSC_VER &gt; 1000</span>
                <span class=cpp-preprocessor>#include &lt;cppunit/TestCase.h&gt;</span>
                <span class=cpp-preprocessor>#include &lt;cppunit/extensions/HelperMacros.h&gt;</span>
                <span class=cpp-preprocessor>#include "DiskData.h"</span>
                <span class=cpp-keyword>class</span> DiskDataTestCase : <span class=cpp-keyword>public</span> CppUnit::TestCase
                {
                CPPUNIT_TEST_SUITE(DiskDataTestCase);
                CPPUNIT_TEST(loadTest);
                CPPUNIT_TEST(storeTest);
                CPPUNIT_TEST_SUITE_END();
                <span class=cpp-keyword>public</span>:
                <span class=cpp-keyword>void</span> setUp();
                <span class=cpp-keyword>void</span> tearDown();
                <span class=cpp-keyword>protected</span>:
                <span class=cpp-keyword>void</span> loadTest();
                <span class=cpp-keyword>void</span> storeTest();
                <span class=cpp-keyword>private</span>:
                DiskData *fixture;
                };
                <span class=cpp-preprocessor>#endif</span></pre>
                <p>First of all, we must include <em>TestCase.h</em> and <em>HelperMacros.h</em>. First one, lets us derive our new class from <code>TestCase</code> base class. Second one, helps us with some macros to define unit tests faster, like <code>CPPUNIT_TEST_SUITE</code> (for starting Test suite definition), <code>CPPUNIT_TEST</code> (for defining a test case) or <code>CPPUNIT_TEST_SUITE_END</code> (for ending our test suite definition).</p>
                <p>Our class (called <code>DiskDataTestCase</code>) overrides two methods called <code>setUp()</code> and <code>tearDown()</code>. These methods are called automatically, and are executed when each Test Case starts and ends, respectively.</p>
                <p>Protected methods implement our test logic, one for each Test Case. Few lines below, we're going to explain how you can code you test logic.</p>
                <p>And finally, we define an attribute called <code>fixture</code>. This pointer will hold target object of our tests. We should create this object inside <code>setUp()</code> method, which is called before each Test Case. Then, Test Case code will be executed using our <code>fixture</code> object, and finally we destroy this object inside <code>tearDown</code>, after each Test Case execution. In this way, we get a new fresh object each time we execute a test case.</p>
                <p>Our test sequence should be something like this:</p>
                <ul>
                    <li>Start test application
                    <li>Click "Run" button
                    <li>Call <code>setUp()</code> method: create our <code>fixture</code> object
                    <li>Call first test case method
                    <li>Call <code>tearDown()</code> method: free <code>fixture</code> object
                    <li>Call <code>setUp()</code> method: create our <code>fixture</code> object
                    <li>Call second test case method
                    <li>Call <code>tearDown()</code> method: free the <code>fixture</code> object
                    <li>... </li>
                </ul>
                <p>Our test sequence should be something like this:</p>
                <pre><span class=cpp-preprocessor>#include "DiskDataTestCase.h"</span>
                CPPUNIT_TEST_SUITE_REGISTRATION(DiskDataTestCase);
                <span class=cpp-keyword>void</span> DiskDataTestCase::setUp()
                {
                fixture = <span class=cpp-keyword>new</span> DiskData();
                }
                <span class=cpp-keyword>void</span> DiskDataTestCase::tearDown()
                {
                <span class=cpp-keyword>delete</span> fixture;
                fixture = NULL;
                }
                <span class=cpp-keyword>void</span> DiskDataTestCase::loadTest()
                {
                <span class=cpp-comment>// our load test logic</span>
                }
                <span class=cpp-keyword>void</span> DiskDataTestCase::storeTest()
                {
                <span class=cpp-comment>// our store test logic</span>
                }
                </pre>
                <p>Implementation is very simple for now: <code>setUp</code> and <code>tearDown</code> methods, create and free <code>fixture</code> object respectively. Next you can see test case methods, which we're going to explain.</p>
                <h2>Test case programming</h2>
                <p>Once we know what aspects we should test, we must be able to program it. We can perform all operations we need: use base library calls, 3rd party library calls, Win32 API calls, or simply use internal attributes with C/C++ operators and instructions.</p>
                <p>Sometimes, we'll need external helps like an auxiliary file or database table which stores correct data. In our test case, we should compare internal data with external file data to check they're the same.</p>
                <p>Each time we find an error (for instance, if we detect internal data isn't the same as external correct data), we should raise a concrete exception. You can do this with <code>CPPUNIT_FAIL(message)</code> helper macro which raises an exception showing message parameter.</p>
                <p>There is another way to check a condition and raise an exception if it's false, all in a single step. The way to do this is through <strong>assertions</strong>. Assertions are macros that let us check a condition, and they raise proper exception if condition is false, with other options.<br>There're some assertion macros:</p>
                <ul>
                    <li><code>CPPUNIT_ASSERT(condition)</code>: checks condition and throws an exception if it's false.
                    <li><code>CPPUNIT_ASSERT_MESSAGE(message, condition)</code>: checks condition and throws an exception and showing specified message if it is false.
                    <li><code>CPPUNIT_ASSERT_EQUAL(expected,current)</code>: checks if <code>expected</code> is the same as <code>current</code>, and raises exception showing expected and current values.
                    <li><code>CPPUNIT_ASSERT_EQUAL_MESSAGE(message,expected,current)</code>: checks if <code>expected</code> is the same as actual, and raises exception showing expected and current values, and specified message.
                    <li><code>CPPUNIT_ASSERT_DOUBLES_EQUAL(expected,current,delta)</code>: checks if <code>expected</code> and <code>current</code> difference is smaller than <code>delta</code>. If it fails, expected and current values are shown. </li>
                </ul>
                <p>Following with our example, we should code our <code>loadTest</code> method. We're going to follow next algorithm: we need an auxiliary file which stores one correct <code>DATA</code> structure. The way of creating this auxiliary file isn't important, but it is very important this file must be correctly created and <code>DATA</code> structure must be correctly stored. In order to check our <code>load</code> method behavior, we're going to call it with our auxiliary file, and then check if loaded data is, the same we know is stored in our file. We can code like this:</p>
                <pre><span class=cpp-comment>//</span>
                <span class=cpp-comment>// These are correct values stored in auxiliar file</span>
                <span class=cpp-comment>//</span>
                <span class=cpp-preprocessor>#define AUX_FILENAME    "ok_data.dat"</span>
                <span class=cpp-preprocessor>#define FILE_NUMBER    19</span>
                <span class=cpp-preprocessor>#define FILE_STRING    "this is correct text stored in auxiliar file"</span>
                <span class=cpp-keyword>void</span> DiskDataTestCase::loadTest()
                {
                <span class=cpp-comment>// convert from relative to absolute path</span>
                TCHAR    absoluteFilename[MAX_PATH];
                DWORD    size = MAX_PATH;
                strcpy(absoluteFilename, AUX_FILENAME);
                CPPUNIT_ASSERT( RelativeToAbsolutePath(absoluteFilename, &amp;size) );
                <span class=cpp-comment>// executes action</span>
                CPPUNIT_ASSERT( fixture-&gt;load(absoluteFilename) );
                <span class=cpp-comment>// ...and check results with assertions</span>
                LPDATA    loadedData = fixture-&gt;getData();
                CPPUNIT_ASSERT(loadedData != NULL);
                CPPUNIT_ASSERT_EQUAL(FILE_NUMBER, loadedData-&gt;number);
                CPPUNIT_ASSERT( <span class=cpp-literal>0</span> == strcmp(FILE_STRING,
                fixture-&gt;getData()-&gt;string) );
                }</pre>
                <p>With a single test case, we're testing four possible errors:</p>
                <ul>
                    <li><code>load</code> method's return value
                    <li><code>getData</code> method's return value
                    <li><code>number</code> structure member's value
                    <li><code>string</code> structure member's value </li>
                </ul>
                <p>In our second test case, we'll follow a similar scheme, but things are getting little harder. We're going to fill our fixture data with known data, store it in another temporal disk file, and then open both files (new one and auxiliary one), read them and compare contents. Both files should be identical because <code>store</code> method must generate same file structure.</p>
                <pre><span class=cpp-keyword>void</span> DiskDataTestCase::storeTest()
                {
                DATA    d;
                DWORD      tmpSize, auxSize;
                BYTE     *tmpBuff, *auxBuff;
                TCHAR    absoluteFilename[MAX_PATH];
                DWORD    size = MAX_PATH;
                <span class=cpp-comment>// configures structure with known data</span>
                d.number = FILE_NUMBER;
                strcpy(d.string, FILE_STRING);
                <span class=cpp-comment>// convert from relative to absolute path</span>
                strcpy(absoluteFilename, AUX_FILENAME);
                CPPUNIT_ASSERT( RelativeToAbsolutePath(absoluteFilename, &amp;size) );
                <span class=cpp-comment>// executes action</span>
                fixture-&gt;setData(&amp;d);
                CPPUNIT_ASSERT( fixture-&gt;store(<span class=cpp-string>"data.tmp"</span>) );
                <span class=cpp-comment>// Read both files contents and check results </span>
                <span class=cpp-comment>// ReadAllFileInMemory is an auxiliar function which allocates a buffer</span>
                <span class=cpp-comment>// and save all file content inside it. Caller should release the buffer.</span>
                tmpSize = ReadAllFileInMemory(<span class=cpp-string>"data.tmp"</span>, tmpBuff);
                auxSize = ReadAllFileInMemory(absoluteFilename, auxBuff);
                <span class=cpp-comment>// files must exist</span>
                CPPUNIT_ASSERT_MESSAGE(<span class=cpp-string>"New file doesn't exists?"</span>, tmpSize &gt; <span class=cpp-literal>0</span>);
                CPPUNIT_ASSERT_MESSAGE(<span class=cpp-string>"Aux file doesn't exists?"</span>, auxSize &gt; <span class=cpp-literal>0</span>);
                <span class=cpp-comment>// sizes must be valid</span>
                CPPUNIT_ASSERT(tmpSize != <span class=cpp-literal>0xFFFFFFFF</span>);
                CPPUNIT_ASSERT(auxSize != <span class=cpp-literal>0xFFFFFFFF</span>);
                <span class=cpp-comment>// buffers must be valid</span>
                CPPUNIT_ASSERT(tmpBuff != NULL);
                CPPUNIT_ASSERT(auxBuff != NULL);
                <span class=cpp-comment>// both file's sizes must be the same as DATA's size</span>
                CPPUNIT_ASSERT_EQUAL((DWORD) <span class=cpp-keyword>sizeof</span>(DATA), tmpSize);
                CPPUNIT_ASSERT_EQUAL(auxSize, tmpSize);
                <span class=cpp-comment>// both files content must be the same</span>
                CPPUNIT_ASSERT( <span class=cpp-literal>0</span> == memcmp(tmpBuff, auxBuff, <span class=cpp-keyword>sizeof</span>(DATA)) );
                <span class=cpp-keyword>delete</span> [] tmpBuff;
                <span class=cpp-keyword>delete</span> [] auxBuff;
                ::DeleteFile(<span class=cpp-string>"data.tmp"</span>);
                }</pre>
                <p>As we can see, we've configured a <code>DATA</code> structure with know data, and stored it using our fixture object. Then, we read resulting file (<em>data.tmp</em>) and compare it with our pattern file. We made all kind of verifications, like buffers and files sizes or buffers' contents. If both buffers are identical, then our <code>store</code> method works fine.</p>
                <h2>Launching user interface</h2>
                <p>And finally, we're going to see how we can show a MFC based user interface dialog, compiled inside <em>TestRunner.dll</em> library.</p>
                <p>We should open our application class implementation file (<em>ProjectNameApp.cpp</em>) and add these lines to our <code>InitInstance</code> method:</p>
                <pre><span class=cpp-preprocessor>#include &lt;cppunit/ui/mfc/TestRunner.h&gt;</span>
                <span class=cpp-preprocessor>#include &lt;cppunit/extensions/TestFactoryRegistry.h&gt;</span>
                BOOL CMy_TestsApp::InitInstance()
                {
                ....
                <span class=cpp-comment>// declare a test runner, fill it with our registered tests and run them</span>
                CppUnit::MfcUi::TestRunner runner;
                runner.addTest( CppUnit::TestFactoryRegistry::getRegistry().makeTest() );
                runner.run();
                <span class=cpp-keyword>return</span> TRUE;
                }</pre>
                <p>This is simpler isn't it? Just define a "runner" instance, and add all registered tests. Tests are registered through <code>CPPUNIT_TEST_SUITE_REGISTRATION</code> macro call inside our CPP file. Once tests are registered and added to runner, we can show the dialogs with <code>run</code> method.</p>
                <p>Now, we're ready to run our test cases. Just compile your new project and run it from Visual Studio. You'll see MFC based dialog as above. Just click on browse and you'll see this dialog:</p>
                <p align=center><img height=237 src="http://www.codeproject.com/library/Using_CPPUnit/browse.jpg" width=395></p>
                <p>Just select one test (green node), or select parent blue node to run all registered tests.</p>
                <h2>History</h2>
                <p>2003 December: Initial version</p>
                <!-- Article Ends --></div>
                </span><SCRIPT src="http://www.codeproject.com/script/togglePre.js" 
            type=text/javascript></SCRIPT>
                <h2>About JM Navarro</h2>
                <div style="OVERFLOW: hidden">
                <table border=0>
                    <tbody>
                        <tr vAlign=top>
                            <td class=smallText noWrap><img src="http://www.codeproject.com/script/profile/images/{C2C068F5-D165-4CD1-BEDB-A4F68E988077}.jpg"><br></td>
                            <td class=smallText>JM is a Spanish System Developer, spending his time writing mobile phones games with J2ME. <br>He also wrote data-mining aplications with Win32, Visual C++, C++Builder, XML and others.<br>You can see his personal website (spanish) at <a href="http://www.lawebdejm.com/">http://www.lawebdejm.com/</a> where he talk about Win32 internals, C/C++, Delphi, eXtreme Programming, UML and others technologies.
                            <p class=smallText>Click <a href="http://www.codeproject.com/script/profile/whos_who.asp?vt=arts&amp;id=53625">here</a> to view JM Navarro's online profile.</p>
                            </td>
                        </tr>
                    </tbody>
                </table>
                </div>
                <br>
                <table cellPadding=0 width="100%" bgColor=#ff9900>
                    <tbody>
                        <tr>
                            <td><img height=60 src="http://www.codeproject.com/images/bannerlogo.gif" width=468 border=0></td>
                        </tr>
                    </tbody>
                </table>
                <h2>Discussions and Feedback</h2>
                <blockquote><img src="http://www.codeproject.com/script/images/news_unselected.gif"> <strong>28 comments</strong> have been posted for this article. Visit <strong><a href="http://www.codeproject.com/library/Using_CPPUnit.asp">http://www.codeproject.com/library/Using_CPPUnit.asp</a></strong> to post and view comments on this article.</blockquote>
                <table cellSpacing=5 width="100%">
                    <tbody>
                        <tr vAlign=top>
                            <td class=smallText>Updated: 15 Dec 2003 </td>
                            <td class=SmallText align=right>Article content copyright JM Navarro, 2003<br>everything else Copyright ?<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#119;&#101;&#98;&#109;&#97;&#115;&#116;&#101;&#114;&#64;&#99;&#111;&#100;&#101;&#112;&#114;&#111;&#106;&#101;&#99;&#116;&#46;&#99;&#111;&#109;">CodeProject</a>, 1999-2007</a>. </td>
                        </tr>
                    </tbody>
                </table>
                </td>
            </tr>
        </tbody>
    </table>
    <SCRIPT 
      src="http://codeproject.us.intellitxt.com/intellitxt/front.asp?ipid=5102" 
      type=text/javascript></SCRIPT></td>
</tr>
</tbody>
</table>
<img src ="http://www.cppblog.com/leetaolion/aggbug/24883.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/leetaolion/" target="_blank">创建更好的解决方案</a> 2007-05-26 11:05 <a href="http://www.cppblog.com/leetaolion/archive/2007/05/26/24883.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>