介绍测试驱动的一个提纲

类别:软件工程 点击:0 评论:0 推荐:

About Test Driven Development

I-Overview
===========


1.What is Test Driven Development(TDD)
 Test-driven Development (TDD) is the craft of producing automated tests for production
 code, and using that process to drive design and programming. For every tiny bit of
 functionality in the production code, you first develop a test that specifies and
 validates what the code will do. You then produce exactly as much code as will enable
 that test to pass. Then you refactor (simplify and clarify) both the production code
 and the test code.--From www.agilealliance.org

2.Several kind of tests.
 (1).Unit Test. A tool of developers.Small scope,one class usually.
 (2).Acceptance Test. Also called as Functional Test.Perform by customer.
 
 Which one we should concentrate on?Both,They affect in different scene.
 
3.What is the benefit
 A list of ways that test-first programming can affect design:
 
 (1).Re-use is good. Test first code is born with two clients, not one. This makes
     adding a third client twice as easy.
 (2).Refactoring test-first code results in equally tested code, permitting more
     aggressive refactorings. Cruft is not allowed, and code is generally in better
     shape to accept more refactorings.
 (3).When paying attention during all of the little steps, you may discover
     patterns in your code.
 (4).Test code is easy to write. It's usually a couple calls to the server object,
     then a list of assertions. Writing the easy code first makes writing the hard code easy.
 (5).DesignPatterns may be incremented in, not added all of a bunch up front.
 (6).Test-first code is written Interface first. You think of the simplest
     interface that can show function.
 (7).Code tends to be less coupled. Effective unit tests only test one thing. To do
     this you have to move the irrelevant portions out of the way (e.g., MockObjects).
     This forces out what might be a poor design choice.
 (8).UnitTests stand as canonical & tested documentation for objects' usage. Developers
     read them, and do what they do in production code to the same objects. This keeps
     projects annealed and on track.
 (9).When the developer has to write tests for what he is going to do, he is far less
     likely to add extraneous capabilities. This really puts a damper on developer
     driven scope creep.
 (10).Test First Design forces you to really think about what you are going to do.
     It gets you away from "It seemed like a good idea at the time" programming.  

4.Rhythm of TDD
 (1).Write a unit test that the system currently doesn’t pass.
 (2).Quickly write the code to pass that test.
 (3).Refactor the code to remove any duplication or other design nasties
 (4).Move on to the next unit test

5.Detailed Step
 (1).Think about what you want to do. (**Critical**)
 (2).Think about how to test it. (**Critical**)
 (3).Write a small test. Think about the desired API.
 (4).Write just enough code to fail the test.
 (5).Run and watch the test fail. (The test-runner, if you're using something like
     JUnit, shows the "Red Bar"). Now you know that your test is going to be executed.
 (6).Write just enough code to pass the test (and pass all your previous tests).
 (7).Run and watch all of the tests pass. (The test-runner, if you're using JUnit, etc.,
     shows the "Green Bar"). If it doesn't pass, you did something wrong, fix it now
     since it's got to be something you just wrote.
 (8).If you have any duplicate logic, or inexpressive code, refactor to remove
     duplication and increase expressiveness -- this includes reducing coupling and
     increasing cohesion.
 (9).Run the tests again, you should still have the Green Bar. If you get the Red Bar,
     then you made a mistake in your refactoring. Fix it now and re-run.
 (10).Repeat the steps above until you can't find any more tests that drive writing new code.

II-Getting Started
==================


1.Preparation
 (1).Choose right Unittest Framework(UF).The UF is some develop tools with which one can
     easily create tests,orginaze them and view the fedback.
 (2).Setting up UF.Using UF to perform test.
 (3).CppUnit is a C++ unit testing framework. It started its life as a port of JUnit to
     C++ by Michael Feathers.
2.Action(Example using CPPUnit--an UF for cpp)

 (1).Write a unit test that the system currently doesn’t pass.
 
     For example, to test the equality comparison for a MyComplex number class, write:
     class ComplexNumberTest : public CppUnit::TestCase {
     public:
       ComplexNumberTest( std::string name ) : CppUnit::TestCase( name ) {}
      
       void runTest() {
         CPPUNIT_ASSERT( MyComplex (10, 1) == MyComplex (10, 1) );
         CPPUNIT_ASSERT( !(MyComplex (1, 1) == MyComplex (2, 2)) );
       }
     };

 (2).Quickly write the code to pass that test.
 
     In order to pass the test quickly, we write a class named MyComplex.
    
     class MyComplex {};
     //If we compile now ,we get compile error.So keep fixing it.
     bool operator==( const MyComplex &a, const MyComplex &b)
     {
       return true;
     }
     //Now compile it again,Ok!Run it,we'll get some fail.
     //This is because the operator==() doesn't work properly.Keep fixing it.
    
     class MyComplex {
       friend bool operator ==(const MyComplex& a, const MyComplex& b);
       double real, imaginary;
     public:
       MyComplex( double r, double i = 0 )
         : real(r)
             , imaginary(i)
       {
       }
     };
    
     bool operator ==( const MyComplex &a, const MyComplex &b )
     {
       return a.real == b.real  &&  a.imaginary == b.imaginary;
     }
     //If we compile now and run our test it will pass.
    
    
 (3).Refactor the code to remove any duplication or other design nasties
     //Here I found the name "MyComplex" is not good,I Change them to "Complex"
     //using replace.
    
 (4).Move on to the next unit test
     //Now it worked ok.Move to other cases.Such as GetMod()...
 
 (5).Use containers to hold cases.
     There'll always be more than one test case.So we need to organize them
     into some friendly format.Here we have CppUnit::TestFixture to hold a
     lot of test cases.
    
     //Code begin...
     class ComplexNumberTest : public CppUnit::TestFixture  {
     private:
       Complex *m_10_1, *m_1_1, *m_11_2;
     public:
       void setUp()
       {
         m_10_1 = new Complex( 10, 1 );
         m_1_1 = new Complex( 1, 1 );
         m_11_2 = new Complex( 11, 2 ); 
       }
     
       void tearDown()
       {
         delete m_10_1;
         delete m_1_1;
         delete m_11_2;
       }
     
       void testEquality()
       {
         CPPUNIT_ASSERT( *m_10_1 == *m_10_1 );
         CPPUNIT_ASSERT( !(*m_10_1 == *m_11_2) );
       }
     
       void testAddition()
       {
         CPPUNIT_ASSERT( *m_10_1 + *m_1_1 == *m_11_2 );
       }
     };
     //Code end...
   
   Also there is often more than one test fixture,so we use CppUnit::TestSuite
   to orginaze more than one "Fixture".
   
   //Code begin...
   CppUnit::TestSuite suite;
     CppUnit::TestResult result;
     suite.addTest( new CppUnit::TestCaller<ComplexNumberTest>(
                            "testEquality",
                            &ComplexNumberTest::testEquality ) );
     suite.addTest( new CppUnit::TestCaller<ComplexNumberTest>(
                            "testAddition",
                            &ComplexNumberTest::testAddition ) );
     suite.run( &result );
     //Code end...

3.Deeper thinking

 (1).What can we do when the background is complicated?
    When we implement some components which relate to database or GUI,what can we do
    to test it? Mock Objects. What is mock objects? For example, when use a
    database for querying some data, what can we do if the database server is not
    ready yet? We can give a simple class which implement the functions just simple
    and quick, then we can test our function locally.Below is the Definition about
    Mock Object--from www.mockobjects.com
        A mock object is a "double agent" used to test the behaviour of other objects.
        First, a mock object acts as a faux implementation of an interface or class that
        mimics the external behaviour of a true implementation. Second, a mock object
        observes how other objects interact with its methods and compares actual
        behaviour with preset expectations. When a discrepancy occurs, a mock object
        can interrupt the test and report the anomaly. If the discrepancy cannot be noted
        during the test, a verification method called by the tester ensures that all
        expectations have been met or failures reported.
    
    What situation we should consider about using mock objects?
    * The real object has nondeterministic behavior (it produces
     unpredictable results; as in a stock-market quote
     feed.)
    * The real object is difcult to set up.
    * The real object has behavior that is hard to trigger (for
     example, a network error).
    * The real object is slow.
    * The real object has (or is) a user interface.
    * The test needs to ask the real object about how it was
     used (for example, a test might need to check to see that
     a callback function was actually called).
    * The real object does not yet exist (a common problem
     when interfacing with other teams or new hardware systems).
     
    The three key steps to using mock objects for testing are:
    1. Use an interface to describe the object
    2. Implement the interface for production code
    3. Implement the interface in a mock object for testing

 

 


III-Resources
=============


Wiki About TDD
 http://c2.com/cgi/wiki?TestDrivenDevelopment
Unittests in extremeprogramming.com
 http://www.extremeprogramming.org/rules/unittests.html
Unittest Patterns
 http://www.codeproject.com/script/admentor/include/ServeAdHTML.aspx?C=False&id=786

本文地址:http://com.8s8s.com/it/it33758.htm