天天看點

《測試驅動的嵌入式C語言開發》——3.4節寫第一個測試

3.4 寫第一個測試

現在測試清單已經有了,我們可以開始了。很自然,第一個測試是去測試初始化是否正确。led在初始化後應當全部關閉。

首先我們要建立leddriver測試檔案。按照慣例,可以将它命名為leddrivertest.c。我通常把測試代碼放在一個與産品代碼不同的目錄裡。我會把這些代碼放在unity/leddriver目錄中,并調整makefile進而讓它能編譯和連結這個新的測試檔案。給測試起個合适的名字來反映我們要實作的目标,這個檔案看起來如下所示:

《測試驅動的嵌入式C語言開發》——3.4節寫第一個測試
《測試驅動的嵌入式C語言開發》——3.4節寫第一個測試

現在讓測試檢查一些有意義的東西。看一下測試清單,驅動程式的一個職責是在初始化時把所有的led都關閉。

如何進行檢查呢?自動化測試沒辦法檢視led,不是嗎?這需要有光感裝置或者光電裝置才行,不是嗎?的确,在軟硬體內建時我們要去看led,但是在單元測試時我們可以虛拟地來看它們。

在目标硬體上有一個特定的位址——一個i/o記憶體映射位址,真正地連接配接到電路上。寫到這個位址中的比特決定了是打開還是關閉特定的led。在調用leddriver_create()時驅動程式必須把一個16比特的0值寫進led的i/o位址中,以便把所有的led關閉。

這是一本關于tdd的書,是以另一個設計目标是leddriver必須獨立于硬體可測(也就是說在開發環境中可測)。如果在測試過程中驅動程式要向目标硬體的實體位址中寫入資料,這會是個問題:記憶體崩潰或記憶體通路失敗。讓我們來重定位這個位址,看看如何讓這段代碼在開發環境中可測。

為驅動程式僞造環境

如果這個位址是外界傳給驅動程式的,那麼在測試用例中就可以用有一系列虛拟led的位址來僞造成真正的實體位址。所謂虛拟led無非就是一個與led記憶體映射有着同樣比特位數的變量。測試用例可以設定、重置以及讀取代表這個虛拟led的變量。驅動程式不會知道它被捉弄了。它隻是按部就班地如同操作記憶體映射裝置一樣打開ram中的一個比特。

虛拟led工作起來沒有問題,但我們要檢查什麼值呢?設計說明和測試清單會指引我們要檢查什麼值。設定某一個led位為0會把這個led關閉,設定為1會把它打開。硬體啟動時每個led都處于打開狀态。按照設計說明,由軟體負責在初始化時把所有的led關閉。是以我們最好能保證虛拟led的每一位都被置為0。

為了測試led是否被正确初始化,我們要寫以下測試:

《測試驅動的嵌入式C語言開發》——3.4節寫第一個測試

這裡有個很微妙的地方。在test(leddriver, ledsoffaftercreate)中virtualleds先被置為0xffff,随後調用了leddriver_create(&virtualleds)。把virtualleds初始化成0xffff確定了測試可以把vitualleds碰巧為0和被正确地初始化為0區分開。

并且,請注意virtualleds的類型。這裡用一個16位無符号整數表示led,與led在i/o空間記憶體映射的寬度比對。測試和産品代碼須要至少在兩個機器上運作:開發系統和目标裝置。結果是,virtualleds的寬度必須明确指定。如你所知,int的大小在不同架構的機器上是不一樣的。使用可移植的整型,如stdint.h中的uint16_t,能讓我們強制把該整型的長度在任何機器上都指定為16位。

如我們期望的一樣,編譯會出錯:

《測試驅動的嵌入式C語言開發》——3.4節寫第一個測試
《測試驅動的嵌入式C語言開發》——3.4節寫第一個測試

依賴注入

把virtualleds傳給驅動程式的做法稱作“依賴注入”(dependency injection)。并不是讓驅動程式在編譯時知道并依賴于led的位址,而是我們在運作時将其注入。隻有目标系統的初始化函數在編譯時依賴led實體位址。

使用依賴注入的一個有意義的附帶好處是leddriver的可重用性更好了。可以将驅動程式放到庫中讓别的有着不同led位址的系統使用。這同時也是一個tdd自然地引導出靈活設計的例子。

不要讓編碼跑到測試前面

如果你在設想最終的代碼,這種不完整的實作可能會讓你很困惑。并沒有将ledsaddress儲存在任何地方,很明顯它必須儲存在某個地方。至少現在還不要儲存它,因為還沒有一個失敗的測試要求儲存它。這需要寫出一個測試,除非你把位址儲存下來,否則就會失敗。下一個測試會迫使驅動程式使用前面傳入的ledsaddress。

我知道忍住不去寫那些你已經知道會用到的代碼是很難的,但還是不要寫。讓編碼跟在測試之後,堅持這樣的原則就能産生被全面的測試用例徹底測試過的産品代碼。

bob martin編寫的“tdd三條原則”給我們提供了一個如何在寫測試代碼和産品代碼之間切換的指導。在有測試要求儲存位址之前就這樣做,這将違反bob的tdd三條原則。

繼續閱讀