2008-09-23 68 views
6

今天有很多人將單元測試作爲發展的麪包和黃油銷售。這甚至可能適用於強大的面向算法的例程。然而,你將如何單元測試,例如,內存分配器(think malloc()/ realloc()/ free())。生成滿足指定接口的工作(但絕對無用)內存分配器並不困難。但是,如何爲單元測試功能提供合適的上下文,這是絕對需要的,但不是合同的一部分:合併空閒塊,在下一次分配時重用空閒塊,向系統返回多餘的空閒內存,斷言分配策略(例如首先適合)真的被尊重,等等。你會如何單元測試一個內存分配器?

我的經驗是,斷言,即使複雜和耗時(如遍歷整個自由列表來檢查不變量),工作少得多,比單元測試更可靠尤其是,編碼複雜的時間相關算法時。

有什麼想法?

回答

10

高度可測試代碼的結構不同於其他代碼。

你描述你想要的分配做幾個任務:

  • 凝聚空閒塊
  • 旁邊 分配
  • 返回多餘的空閒內存的 系統
  • 斷言重用的空閒塊分配政策 (例如第一次適用)確實受到尊重

儘管您可能會將您的分配代碼編寫爲非常耦合,就像在一個函數體內執行其中的幾項操作一樣,您也可以將每個任務分解爲可測試塊的代碼。這幾乎是你可能習慣的反轉。我發現可測試代碼往往非常透明,並且從更小的部分構建。

接下來,我想說的是,在任何種類的自動化測試比沒有自動化測試更好。我絕對會更專注於確保你的測試能夠做一些有用的事情,而不是擔心你是否正確地使用了模擬器,是否確保它被正確隔離,以及它是否是真正的單元測試。這些都是令人欽佩的目標,希望能使99%的測試更好。另一方面,請使用常識和最佳工程判斷來完成工作。

沒有代碼示例我不認爲我可以更具體。

1

這兩件事都有它們的位置。使用單元測試檢查接口的行爲是否符合預期,並使用斷言來檢查合同是否受到尊重。

9

如果在那裏有任何邏輯,它可以進行單元測試。
如果您的邏輯涉及決策並調用操作系統/硬件/系統API,假設/模擬出與設備相關的調用,並對您的邏輯進行單元測試,以驗證在給定的前置條件下是否做出正確決策。在單元測試中遵循Arrange-Act-Assert三元組。
斷言不能替代自動化單元測試。他們不會告訴你哪個方案失敗,他們在開發過程中不提供反饋,他們不能用來證明代碼在其他方面符合所有規範。

非模糊更新: 我不知道確切的方法調用..我想我會「推出自己的」 比方說,你的代碼審視了當前的條件下,作出決定,並向電話OS根據需要。比方說,你的OS電話是(可能有更多):

void* AllocateMemory(int size); 
bool FreeMemory(void* handle); 
int MemoryAvailable(); 

首先把它變成一個接口,I_OS_MemoryFacade。創建此接口的實現,以實際調用OS。現在讓你的代碼使用這個接口 - 你現在已經從設備/操作系統中解耦了你的代碼/邏輯。接下來在你的單元測試中,你使用一個模擬框架(它的目的是給你一個指定接口的模擬實現,然後你可以告訴模擬框架期望這些調用,這些參數並返回這個時候在測試結束時,您可以要求模擬框架驗證是否滿足所有期望(例如,在此測試中,應以10,30,50作爲參數,隨後3次FreeMemory調用將AllocateMemory調用三次。檢查MemoryAvailable是否返回初始值。)
因爲你的代碼依賴於一個接口,所以它不知道真正的實現和你用於測試的虛擬/模擬實現之間的區別 Google out'mock frameworks'欲瞭解更多信息,請點擊這裏

+0

您能否介紹一下如何編寫單元測試的更多細節。你提倡他們很多,但我讀了這個問題,然後回答了你的答案,我仍然不明白你提出的是什麼。 – 2008-09-23 07:08:50

0

我個人認爲大部分的單元測試都是像別人的願望而不是我的。我認爲任何單元測試都應該像正常程序一樣書寫,除了測試庫/算法或代碼的任何部分之外,它不會做任何事情。

我的單元測試通常不使用像CUnitCppUnit和類似軟件的工具。 我創建了自己的測試。例如,不久以前,我需要在通常情況下測試一個容器的新實現來處理內存泄漏。單元測試對於提供一個很好的測試是沒有幫助的。相反,我創建了自己的分配器,並且在一定(可調整)的分配數量之後,它無法分配內存,以查看在這種情況下我的應用程序是否有內存泄漏(並且它有:))。

這怎麼能通過單元測試?更多的努力使你的代碼適合單元測試「模式」。

所以我強烈建議不要每次都使用單元測試,因爲它是「新潮」的,但只有當它們很容易與你喜歡測試的代碼集成在一起時。

1

您可能還想要包含性能測試,壓力測試等。它們不會是單元測試,因爲它會測試整個事情,但它們在內存分配器的情況下非常有價值。

單元測試不排除這些類型的測試。最好是有他們兩個。

1

我也認爲單元測試被高估了。他們有用,但真正提高項目質量的是審查它。另一方面,我真的很喜歡斷言,但它們並不取代單元測試。

我不是在談論同行評審,而是簡單地重讀你寫的內容,可能在用調試器遍歷它並檢查每條線做它應該做什麼的時候,將會增加軟件的質量。

我會推薦「高級」單元測試,測試一個功能塊而不是一個微小的方法調用。後者傾向於使任何代碼更改非常痛苦和昂貴。

0

單元測試不僅僅是爲了確保你的代碼的工作。這也是一個非常好的設計方法。爲了使測試有用,如前所述,代碼需要儘可能地分離,比如在需要的地方使用接口。

我並不總是先寫測試,但很多時候如果我在開始使用某些東西時遇到困難,我會寫一個簡單的測試,試驗設計並從那裏開始。另外,良好的單元測試可以作爲很好的文檔。在工作中,當我需要了解如何使用特定的類或類似的東西時,我會查看它的單元測試。

只記得單元測試是不是集成測試。單元測試確實有其侷限性,但總的來說,我認爲這是一個非常好的工具,可以知道如何正確使用。

0

因此,當您嘗試測試時,遇到一個問題,您的分配器被測試框架使用,這可能會導致分配器狀態出現問題。考慮爲分配器功能添加前綴(請參閱dlmalloc)。你寫

prefix_malloc(); 
prefix_free(); 

然後

#ifndef USE_PREFIX 
#define prefix_malloc malloc 
#define prefix_free free 
#endif 

現在,設置你的編譯系統編譯版採用-DUSE_PREFIX圖書館。編寫你的單元測試來調用prefix_malloc和prefix_free。這使您可以將分配器的狀態與系統分配器的狀態分開。

如果您使用sbrk並且系統分配器使用sbrk,那麼如果任何一個allocator假定它完全控制了斷點,則可能會有一段糟糕的時間。在這種情況下,你想鏈接另一個分配器,你可以配置它只使用mmap,因此你的分配器可以有斷點。