1. 程式人生 > >VS2015 c++程序單元測試初探——從0到1中所遇到的錯誤和歷程

VS2015 c++程序單元測試初探——從0到1中所遇到的錯誤和歷程

ima 資料 因此 開頭 完成 數字 style debug unit

實現過程

一開始對單元測試這個東西感覺很恐懼,在看過雪晴的博客後,覺得自己可以試試學學,找到了一篇博客,地址:

VS2015安裝與C++進行簡單單元測試

前面的建立和初始化都比較easy,但很快遇到了一個問題,例子中是對一個類的接口進行的測試,是否能對非類接口(如函數進行測試呢),問了雪晴後,發現應該是可以的,那麽就自己試一下吧。

準備試試測試void word_to_word(word_count* word, wprd_count* word1);代碼如下:

class word_count
{
    //單詞計數器類
public:
    //friend struct std::hash<word_count>;
public: //string* temp;//用來存真實的單詞 string* str;//單詞的名字 string* num;//數字後綴 int num_rear;//數字後綴的開始位 int str_count;//單詞個數 int flag;//判斷是否在高頻內 int size;//單詞 string* word;//單詞部分 word_count* next_ptr; word_count(); ~word_count(); }; void word_to_word(word_count* word, word_count* word1) {
//把所有的word的值賦給word1 *(word1->str) = *(word->str); *(word1->num) = *(word->num); word1->num_rear=word->num_rear; //數字後綴的開始位 word1->str_count = word->str_count; //單詞個數 word1->flag = word->flag; word1->size = word->size; *(word1->word) = *(word->word); word1
->next_ptr=word->next_ptr;

但是很快遇到了麻煩,這個函數是為了將對象word中的string和其他值(大多為int類型)都賦給word1類。(在這裏仔細想了想發現之所以寫這個函數完全是因為對OOP的理解不到家,明明就定義了一個對象,為什麽還要做這種復雜的內存轉儲操作呢……直接定義一個新的不就好了,指針不就是幹這個的嗎……這就等於在讀取單詞的過程中我自己瘋狂創建了無數個副本,而且他們全部能活到最後,為了驗證我的猜測,等一下我要去試一下改改代碼,看看是不是這樣)。

好吧回到原題,這中間有這樣的操作,但博客中只提到了int類型的比較,所以我現在還不確定該怎麽使用assert,那麽就來摸索一下。

之後我想,string類重載了操作符==,那會不會可以直接對內部的string進行Areequal操作呢,代碼如下:

技術分享圖片

接下來是鏈接到obj文件上,鏈接完成,但是程序報錯,錯誤如下:

Microsoft::VisualStudio::TestTools::UnitTesting::Assert::AreEqual”: 15 個重載中沒有一個可以轉換所有參數類型

查看到代碼,發現是areEqual無法判別string類是否相等,繼續查閱資料,發現StringAssert類,但是經過閱讀發現,StringAssert類大多是對子串和包含/開頭結尾來判斷的,沒有找到合適的方法,於是回頭找AreEqual的重載類型,發現,合適的重載參數應該為:

技術分享圖片

技術分享圖片

由於本例中都是大寫字母,所以就用true即可

但是他繼續報錯,說明還不對,之後我又發現了string^類型的字串,據說是托管類型的,是什麽意思呢 感覺要崩。關於這個托管類型的意義,我感覺有必要專門花時間去學習了了解了。。。不知道看到的老師和同學有沒有能教教我的。

最後我放棄了采用Assert,決定#include <assert.h>,然後用assert(word1==word2)的方式來判斷。

最終代碼如下:

void TestMethod1()
        {
            word_count* h1=new word_count();
            word_count* h2=new word_count();
            h1->flag = 12;
            
            *(h1->str) = "strtest123";
            *(h1->num) = "123";
            *(h1->word) = "strtest";
            h1->num_rear = 7;
            h1->size = 10;
            h1->str_count = 1;
            h1->next_ptr = NULL;
            word_to_word(h1, h2);
            Assert::AreEqual(h2->flag,h1->flag);
            Assert::AreEqual(h2->num_rear, h1->num_rear);

            assert(*(h1->word)== *(h2->word));
            assert(*(h1->str)== *(h2->str));
            assert(*(h1->num)== *(h2->num));
            assert(*(h1->word) == *(h2->word));
            Assert::AreEqual(h2->str_count, h1->str_count);
            Assert::AreEqual(h2->size, h1->size);
            /*    Assert::AreEqual(*(h1->str), *(h2->str)); 
            Assert::AreEqual(*(h1->num), *(h2->num)); */
            //Assert::AreEqual(*(h1->word), *(h2->word));
            
            //        
            // TODO:  在此處添加測試邏輯
            //
        };

然後我開始進行鏈接,具體操作子啊教程中有。但是我沒想到的是,由於我的工程是含有預編譯頭的,所以一開始我只link了../ConsoleApplication4/Debug/word_count.obj,不知道要鏈接../ ConsoleApplication4/Debug/stdafx.obj,因此一直報如下錯誤:

技術分享圖片

先預告一下,事實證明,接下來一個小時更加痛苦的經歷都是由於我對warning沒有重視,以為問題不大,所以一直崩盤。。。。

這裏我們首先要解決error。 關於這個未連接預編譯對象,一開始查到的是說要我重新編譯原工程,然而這個辦法並沒有任何卵用。之後我又去問了雪晴,雪晴說她當時是把所有目錄下的*.obj都給加入了附加依賴項,所以我也決定用*.obj來代替word_count.h,(之後我也查到了,其實是加入stdafx.h應該就沒問題了)。

做完這一步 error沒有了,測試程序編譯通過但是錯誤接踵而至,測試程序產生了異常。不過令人欣喜的是,至少測試程序開始運行了,對吧。

接著來處理異常,如下:

技術分享圖片

上網查看了debug_heap.cpp,發現並不能解決問題,接著又查詢了_CrtisValidHeapPointer(block),發現可能是內存泄漏等等的錯誤,這不禁讓我懷疑起自己寫的測試程序,於是在測試代碼的短短幾行裏胡亂改動。。。然而在半個小時的徒勞無功下,我最後決定從warning入手。

我首先重新搜索了忽略/EDITANDCONTINUE,但是沒有找到端倪。後來在無意中,我看到有篇博客中專門提到需要忽略下面的warning中的兩個lib,MSVCRT和UCRTb,然而我在生成測試時,發現IDE似乎在哪裏說過了忽略這兩個庫,這導致我以為這個問題系統已經自動解決(畢竟報的是warning),於是我又浪費了15分鐘在懷疑自己和程序上,最後我特意把這兩句話上網百度後,發現一篇博客裏講述的一個莫名其妙(因為我不懂)的方法,就是右鍵TestProject1à屬性àC/C++à生成代碼à運行庫 中改為另一個(MDàMT),見圖:

技術分享圖片

技術分享圖片

於是我就嘗試了一下,但是失敗了,於是我把四個選項都嘗試了一遍,終於在MDd的狀態下,測試繼續進行了!而且,總算是顯示了測試資源管理器,裏面發現測試成功了!下面上一個測試失敗的樣例和成功的樣例(上為失敗,下為成功),可以看到失敗的原因是因為assert()被設置成了!=,但實際上應該是等於。

技術分享圖片

技術分享圖片

至此,這說明我的第一次單元測試的嘗試已經完成了!雖然測試的是一個無關痛癢的功能,但是至少完成了從0到1的轉變,令人激動!

感想

事實證明,第一次用一樣東西最痛苦的就是報錯了你都不知道他是為啥,在哪查,連他到底在幹什麽都不知道,所以從0到1真的需要最大的精力和耐心。

首先,我一直在懷疑測試代碼有問題,甚至到最後都在懷疑是不是我的鏈接過程還是有問題,但是這些懷疑沒有來源,所以不可靠。但我卻沒有關註warning,對warning的查詢雖然不是沒有。但是就是草草看了一眼就斷定不是(應該給自己一巴掌),以後真的一定要有清理warning的習慣啊!

下面附上一些有用的資料:

VS2015 使用微軟自帶的單元測試框架測試本地C++代碼的註意事項

如果測試類使用了預編譯頭文件的話,要在工程設置中添加stdafx.obj

測試STL容器時,會彈出異常錯誤對話框.解決辦法是忽略MSVCRT.lib 和UCRT.lib

Assert類:

單元測試中Assert類,單元測試Assert類

斷言(ASSERT)的用法

Assert.AreEqual方法:

https://msdn.microsoft.com/zh-cn/library/microsoft.visualstudio.testtools.unittesting.assert.areequal(VS.80).aspx

StringAssert方法:

https://msdn.microsoft.com/zh-cn/library/microsoft.visualstudio.testtools.unittesting.stringassert.aspx

其他教程:

Visaul Studio2015安裝以及c++單元測試使用方法

帶你玩轉Visual Studio——單元測試

一個關於單元測試未解決的問題:

C++單元測試一:並非看上去那麽簡單——幾個很實際的問題

VS2015 c++程序單元測試初探——從0到1中所遇到的錯誤和歷程