国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
CppUnit快速使用指南
CppUnit快速使用指南作者:李群    文章來源:developerWorks 中國網(wǎng)站    點(diǎn)擊數(shù):    更新時(shí)間:2006-2-7    

0. 背景

CppUnit 是個(gè)基于 LGPL 的開源項(xiàng)目,最初版本移植自 JUnit,是一個(gè)非常優(yōu)秀的開源測試框架。CppUnit 和 JUnit一樣主要思想來源于極限編程(XProgramming)。主要功能就是對(duì)單元測試進(jìn)行管理,并可進(jìn)行自動(dòng)化測試。這樣描述可能沒有讓您體會(huì)到測試框架的強(qiáng)大威力,那您在開發(fā)過程中遇到下列問題嗎?如果答案是肯定的,就應(yīng)該學(xué)習(xí)使用這種技術(shù):

  • 測試代碼沒有很好地維護(hù)而廢棄,再次需要測試時(shí)還需要重寫;
  • 投入太多的精力,找 bug,而新的代碼仍然會(huì)出現(xiàn)類似 bug;
  • 寫完代碼,心里沒底,是否有大量 bug 等待自己;
  • 新修改的代碼不知道是否影響其他部分代碼;
  • 由于牽扯太多,導(dǎo)致不敢進(jìn)行修改代碼;
    ...

這些問題下文都會(huì)涉及。這個(gè)功能強(qiáng)大的測試框架在國內(nèi)的 C++語言開發(fā)人員中使用的不是很多。本文從開發(fā)人員的角度,介紹這個(gè)框架,希望能夠使開發(fā)人員用最少的代價(jià)盡快掌握這種技術(shù)。下面從基本原理,CppUnit原理,手動(dòng)使用步驟,通常使用步驟,其他實(shí)際問題等方面進(jìn)行討論。以下討論基于 CppUnit1.8.0。

1. 基本原理

對(duì)于上面的問題僅僅說明 CppUnit 的使用是沒有效果的,下面先從測試的目的,測試原則等方面簡要說明,然后介紹 CppUnit 的具體使用。

首先要明確我們寫測試代碼的目的,就是驗(yàn)證代碼的正確性或者調(diào)試 bug。這樣寫測試代碼時(shí)就有了針對(duì)性,對(duì)那些容易出錯(cuò)的,易變的編寫測試代碼;而不用對(duì)每個(gè)細(xì)節(jié),每個(gè)功能編寫測試代碼,當(dāng)然除非有過量精力或者可靠性要求。

編碼和測試的關(guān)系是密不可分的,推薦的開發(fā)過程并不要等編寫完所有或者很多的代碼后再進(jìn)行測試,而是在完成一部分代碼,比如一個(gè)函數(shù),之后立刻編寫測試代碼進(jìn)行驗(yàn)證。然后再寫一些代碼,再寫測試。每次測試對(duì)所有以前的測試都進(jìn)行一遍。這樣做的優(yōu)點(diǎn)就是,寫完代碼,也基本測試完一遍,心里對(duì)代碼有信心。而且在寫新代碼時(shí)不斷地測試?yán)洗a,對(duì)其他部分代碼的影響能夠迅速發(fā)現(xiàn)、定位。不斷編碼測試的過程也就是對(duì)測試代碼維護(hù)的過程,以便測試代碼一直是有效的。有了各個(gè)部分測試代碼的保證,有了自動(dòng)測試的機(jī)制,更改以前的代碼沒有什么顧慮了。在極限編程(一種軟件開發(fā)思想)中,甚至強(qiáng)調(diào)先寫測試代碼,然后編寫符合測試代碼的代碼,進(jìn)而完成整個(gè)軟件。

根據(jù)上面說的目的、思想,下面總結(jié)一下平時(shí)開發(fā)過程中單元測試的原則:

  • 先寫測試代碼,然后編寫符合測試的代碼。至少做到完成部分代碼后,完成對(duì)應(yīng)的測試代碼;
  • 測試代碼不需要覆蓋所有的細(xì)節(jié),但應(yīng)該對(duì)所有主要的功能和可能出錯(cuò)的地方有相應(yīng)的測試用例;
  • 發(fā)現(xiàn) bug,首先編寫對(duì)應(yīng)的測試用例,然后進(jìn)行調(diào)試;
  • 不斷總結(jié)出現(xiàn) bug 的原因,對(duì)其他代碼編寫相應(yīng)測試用例;
  • 每次編寫完成代碼,運(yùn)行所有以前的測試用例,驗(yàn)證對(duì)以前代碼影響,把這種影響盡早消除;
  • 不斷維護(hù)測試代碼,保證代碼變動(dòng)后通過所有測試;

有上面的理論做指導(dǎo),測試行為就可以有規(guī)可循。那么 CppUnit 如何實(shí)現(xiàn)這種測試框架,幫助我們管理測試代碼,完成自動(dòng)測試的?下面就看看 CppUnit 的原理。

2. CppUnit 的原理

在 CppUnit 中,一個(gè)或一組測試用例的測試對(duì)象被稱為 Fixture(設(shè)施,下文為方便理解盡量使用英文名稱)。Fixture 就是被測試的目標(biāo),可能是一個(gè)對(duì)象或者一組相關(guān)的對(duì)象,甚至一個(gè)函數(shù)。

有了被測試的 fixture,就可以對(duì)這個(gè) fixture 的某個(gè)功能、某個(gè)可能出錯(cuò)的流程編寫測試代碼,這樣對(duì)某個(gè)方面完整的測試被稱為TestCase(測試用例)。通常寫一個(gè) TestCase 的步驟包括:

  1. 對(duì) fixture 進(jìn)行初始化,及其他初始化操作,比如:生成一組被測試的對(duì)象,初始化值;
  2. 按照要測試的某個(gè)功能或者某個(gè)流程對(duì) fixture 進(jìn)行操作;
  3. 驗(yàn)證結(jié)果是否正確;
  4. 對(duì) fixture 的及其他的資源釋放等清理工作。

對(duì) fixture 的多個(gè)測試用例,通常(1)(4)部分代碼都是相似的,CppUnit 在很多地方引入了 setUp 和tearDown 虛函數(shù)??梢栽?setUp 函數(shù)里完成(1)初始化代碼,而在 tearDown函數(shù)中完成(4)代碼。具體測試用例函數(shù)中只需要完成(2)(3)部分代碼即可,運(yùn)行時(shí) CppUnit 會(huì)自動(dòng)為每個(gè)測試用例函數(shù)運(yùn)行setUp,之后運(yùn)行 tearDown,這樣測試用例之間就沒有交叉影響。

對(duì) fixture 的所有測試用例可以被封裝在一個(gè) CppUnit::TestFixture的子類(命名慣例是[ClassName]Test)中。然后定義這個(gè)fixture 的 setUp 和 tearDown函數(shù),為每個(gè)測試用例定義一個(gè)測試函數(shù)(命名慣例是 testXXX)。下面是個(gè)簡單的例子:

            class MathTest : public CppUnit::TestFixture {            protected:            int m_value1, m_value2;            public:            MathTest() {}            // 初始化函數(shù)            void setUp () {            m_value1 = 2;            m_value2 = 3;            }            // 測試加法的測試函數(shù)            void testAdd () {            // 步驟(2),對(duì) fixture 進(jìn)行操作            int result = m_value1 + m_value2;            // 步驟(3),驗(yàn)證結(jié)果是否爭取            CPPUNIT_ASSERT( result == 5 );            }            // 沒有什么清理工作沒有定義 tearDown.            }            

在測試函數(shù)中對(duì)執(zhí)行結(jié)果的驗(yàn)證成功或者失敗直接反應(yīng)這個(gè)測試用例的成功和失敗。CppUnit 提供了多種驗(yàn)證成功失敗的方式:

            CPPUNIT_ASSERT(condition)					// 確信condition為真            CPPUNIT_ASSERT_MESSAGE(message, condition)	// 當(dāng)condition為假時(shí)失敗, 并打印message            CPPUNIT_FAIL(message)						// 當(dāng)前測試失敗, 并打印message            CPPUNIT_ASSERT_EQUAL(expected, actual)		// 確信兩者相等            CPPUNIT_ASSERT_EQUAL_MESSAGE(message, expected, actual)	// 失敗的同時(shí)打印message            CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta)	// 當(dāng)expected和actual之間差大于delta時(shí)失敗            

要把對(duì) fixture 的一個(gè)測試函數(shù)轉(zhuǎn)變成一個(gè)測試用例,需要生成一個(gè) CppUnit::TestCaller對(duì)象。而最終運(yùn)行整個(gè)應(yīng)用程序的測試代碼的時(shí)候,可能需要同時(shí)運(yùn)行對(duì)一個(gè) fixture 的多個(gè)測試函數(shù),甚至多個(gè) fixture的測試用例。CppUnit 中把這種同時(shí)運(yùn)行的測試案例的集合稱為 TestSuite。而 TestRunner 則運(yùn)行測試用例或者TestSuite,具體管理所有測試用例的生命周期。目前提供了 3 類TestRunner,包括:

            CppUnit::TextUi::TestRunner 	// 文本方式的TestRunner            CppUnit::QtUi::TestRunner		// QT方式的TestRunner            CppUnit::MfcUi::TestRunner		// MFC方式的TestRunner            

下面是個(gè)文本方式 TestRunner 的例子:

            CppUnit::TextUi::TestRunner runner;            CppUnit::TestSuite *suite= new CppUnit::TestSuite();            // 添加一個(gè)測試用例            suite->addTest(new CppUnit::TestCaller<MathTest> (            "testAdd", testAdd));            // 指定運(yùn)行TestSuite            runner.addTest( suite );            // 開始運(yùn)行, 自動(dòng)顯示測試進(jìn)度和測試結(jié)果            runner.run( "", true );    // Run all tests and wait            

對(duì)測試結(jié)果的管理、顯示等功能涉及到另一類對(duì)象,主要用于內(nèi)部對(duì)測試結(jié)果、進(jìn)度的管理,以及進(jìn)度和結(jié)果的顯示。這里不做介紹。

下面我們整理一下思路,結(jié)合一個(gè)簡單的例子,把上面說的思路串在一起。

3. 手動(dòng)使用步驟

首先要明確測試的對(duì)象fixture,然后根據(jù)其功能、流程,以及以前的經(jīng)驗(yàn),確定測試用例。這個(gè)步驟非常重要,直接關(guān)系到測試的最終效果。當(dāng)然增加測試用例的過程是個(gè)階段性的工作,開始完成代碼后,先完成對(duì)功能的測試用例,保證其完成功能;然后對(duì)可能出錯(cuò)的部分,結(jié)合以前的經(jīng)驗(yàn)(比如邊界值測試、路徑覆蓋測試等)編寫測試用例;最后在發(fā)現(xiàn)相關(guān) bug 時(shí),根據(jù) bug 完成測試用例。

比如對(duì)整數(shù)加法進(jìn)行測試,首先定義一個(gè)新的 TestFixture子類,MathTest,編寫測試用例的測試代碼。后期需要添加新的測試用例時(shí)只需要添加新的測試函數(shù),根據(jù)需要修改 setUp 和tearDown 即可。如果需要對(duì)新的 fixture 進(jìn)行測試,定義新的 TestFixture子類即可。注:下面代碼僅用來表示原理,不能編譯。

            /// MathTest.h            // A TestFixture subclass.            // Announce: use as your owner risk.            // Author  : liqun (liqun@nsfocus.com)            // Data    : 2003-7-5            #include "cppunit/TestFixture.h"            class MathTest : public CppUnit::TestFixture {            protected:            int m_value1, m_value2;            public:            MathTest() {}            // 初始化函數(shù)            void setUp ();            // 清理函數(shù)            void tearDown();            // 測試加法的測試函數(shù)            void testAdd ();            // 可以添加新的測試函數(shù)            };            /// MathTest.cpp            // A TestFixture subclass.            // Announce: use as your owner risk.            // Author  : liqun (liqun@nsfocus.com)            // Data    : 2003-7-5            #include "MathTest.h"            #include "cppunit/TestAssert.h"            void MathTest::setUp()            {            m_value1 = 2;            m_value2 = 3;            }            void MathTest::tearDown()            {            }            void MathTest::testAdd()            {            int result = m_value1 + m_value2;            CPPUNIT_ASSERT( result == 5 );            }            

然后編寫 main 函數(shù),把需要測試的測試用例組織到 TestSuite 中,然后通過 TestRuner 運(yùn)行。這部分代碼后期添加新的測試用例時(shí)需要改動(dòng)的不多。只需要把新的測試用例添加到 TestSuite 中即可。

            /// main.cpp            // Main file for cppunit test.            // Announce: use as your owner risk.            // Author  : liqun (liqun@nsfocus.com)            // Data    : 2003-7-5            // Note	   : Cannot compile, only for study.            #include "MathTest.h"            #include "cppunit/ui/text/TestRunner.h"            #include "cppunit/TestCaller.h"            #include "cppunit/TestSuite.h"            int main()            {            CppUnit::TextUi::TestRunner runner;            CppUnit::TestSuite *suite= new CppUnit::TestSuite();            // 添加一個(gè)測試用例            suite->addTest(new CppUnit::TestCaller<MathTest> (            "testAdd", testAdd));            // 指定運(yùn)行TestSuite            runner.addTest( suite );            // 開始運(yùn)行, 自動(dòng)顯示測試進(jìn)度和測試結(jié)果            runner.run( "", true );    // Run all tests and wait            }            

4. 常用使用方式

按照上面的方式,如果要添加新的測試用例,需要把每個(gè)測試用例添加到 TestSuite 中,而且添加新的 TestFixture需要把所有頭文件添加到 main.cpp 中,比較麻煩。為此 CppUnit 提供了CppUnit::TestSuiteBuilder,CppUnit::TestFactoryRegistry 和一堆宏,用來方便地把TestFixture 和測試用例注冊到 TestSuite 中。下面就是通常的使用方式:

            /// MathTest.h            // A TestFixture subclass.            // Announce: use as your owner risk.            // Author  : liqun (liqun@nsfocus.com)            // Data    : 2003-7-5            #include "cppunit/extensions/HelperMacros.h"            class MathTest : public CppUnit::TestFixture {            // 聲明一個(gè)TestSuite            CPPUNIT_TEST_SUITE( MathTest );            // 添加測試用例到TestSuite, 定義新的測試用例需要在這兒聲明一下            CPPUNIT_TEST( testAdd );            // TestSuite聲明完成            CPPUNIT_TEST_SUITE_END();            // 其余不變            protected:            int m_value1, m_value2;            public:            MathTest() {}            // 初始化函數(shù)            void setUp ();            // 清理函數(shù)            void tearDown();            // 測試加法的測試函數(shù)            void testAdd ();            // 可以添加新的測試函數(shù)            };            /// MathTest.cpp            // A TestFixture subclass.            // Announce: use as your owner risk.            // Author  : liqun (liqun@nsfocus.com)            // Data    : 2003-7-5            #include "MathTest.h"            // 把這個(gè)TestSuite注冊到名字為"alltest"的TestSuite中, 如果沒有定義會(huì)自動(dòng)定義            // 也可以CPPUNIT_TEST_SUITE_REGISTRATION( MathTest );注冊到全局的一個(gè)未命名的TestSuite中.            CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( MathTest, "alltest" );            // 下面不變            void MathTest::setUp()            {            m_value1 = 2;            m_value2 = 3;            }            void MathTest::tearDown()            {            }            void MathTest::testAdd()            {            int result = m_value1 + m_value2;            CPPUNIT_ASSERT( result == 5 );            }            /// main.cpp            // Main file for cppunit test.            // Announce: use as your owner risk.            // Compile : g++ -lcppunit MathTest.cpp main.cpp            // Run     : ./a.out            // Test    : RedHat 8.0 CppUnit1.8.0            // Author  : liqun ( a litthle modification. liqun@nsfocus.com)            // Data    : 2003-7-5            // 不用再包含所有TestFixture子類的頭文件            #include <cppunit/extensions/TestFactoryRegistry.h>            #include <cppunit/ui/text/TestRunner.h>            // 如果不更改TestSuite, 本文件后期不需要更改.            int main()            {            CppUnit::TextUi::TestRunner runner;            // 從注冊的TestSuite中獲取特定的TestSuite, 沒有參數(shù)獲取未命名的TestSuite.            CppUnit::TestFactoryRegistry &registry = CppUnit::TestFactoryRegistry::getRegistry("alltest");            // 添加這個(gè)TestSuite到TestRunner中            runner.addTest( registry.makeTest() );            // 運(yùn)行測試            runner.run();            }            

這樣添加新的測試用例只需要在類定義的開始聲明一下即可。

5. 其他實(shí)際問題

通常包含測試用例代碼和被測試對(duì)象是在不同的項(xiàng)目中。應(yīng)該在另一個(gè)項(xiàng)目(最好在不同的目錄)中編寫 TestFixture,然后把被測試的對(duì)象包含在測試項(xiàng)目中。

對(duì)某個(gè)類或者某個(gè)函數(shù)進(jìn)行測試的時(shí)候,這個(gè) TestFixture 可能引用了別的類或者別的函數(shù),為了隔離其他部分代碼的影響,應(yīng)該在源文件中臨時(shí)定義一些樁程序,模擬這些類或者函數(shù)。這些代碼可以通過宏定義在測試項(xiàng)目中有效,而在被測試的項(xiàng)目中無效。

6. 參考資料

  • CppUnit 主頁
  • JUnitTest Infected: Programmers Love Writing Tests
  • CppUnit Cookbook
  • xprogramming 主頁
  • 測試框架
  • 本文代碼下載

    7. 關(guān)于作者

    李群,當(dāng)前關(guān)注于網(wǎng)絡(luò)安全產(chǎn)品的開發(fā)、研究;軟件開發(fā)過程等方面。您可以通過 liqun@nsfocus.com 和他聯(lián)系。

  • 本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)。
    打開APP,閱讀全文并永久保存 查看更多類似文章
    猜你喜歡
    類似文章
    CppUnit快速入門
    NUnit學(xué)習(xí)筆記之進(jìn)階篇
    python unittest 添加測試用例的幾種方法
    CPPUNIT基本原理
    學(xué)習(xí)JUnit
    netbeans 中使用Junit
    更多類似文章 >>
    生活服務(wù)
    分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
    綁定賬號(hào)成功
    后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
    如果VIP功能使用有故障,
    可點(diǎn)擊這里聯(lián)系客服!

    聯(lián)系客服