TDD簡單的說只有三步
1. 寫好程式的介面,只要能夠通過編譯即可
2. 增加測試
3. 執行測試,如果有失敗的測試的話就修改程式,然後回到步驟2
我要寫的程式是輸入一個多邊形的頂點,檢查是否為近似四邊形。
這個問題可以很簡單,我們只需要檢查多邊形的頂點數目,
如果是四個點的話就是四邊形。
當然我希望這個程式的能力不只如此,不然就沒有練習的效果啦。
其實這個問題是從實際的問題演變過來的,實際上是應用在擴增實境中,
我們從攝影機抓取影像,然後找出影像中的正方形,做為一個參考點。
一個平片上的正方形從不同角度去看,會變成一個任意的四邊形,
我們從影像分割出許多多邊形,然後判斷像不像四邊形。然而由於影像處理必定會有誤差,
所以一個四邊形可能有一些凸出的部分,而會變成五角形或六角形。我們的程式須要能處理這種情況。
這也是採用TDD的理由,我們可以一步一步改進我們的程式。
開始囉
首先定義函數IsQuadrilateral,輸入為一個多邊形,輸出真假值。由於現在還沒有測試,
不假思索就可以得到一個最簡單的實作方法,一律傳回假就好。
def IsQuadrilateral(polygon): return False
接著是增加測試,利用Python的unittest模組,我們將測試程式包在TestSequenceFunctions物件中。
import unittest import numpy class TestSequenceFunctions(unittest.TestCase): def setUp(self): self.triangle = numpy.array( [ (0,1,0),(0,0,1) ] ) self.square = numpy.array( [ (0,1,1,0),(0,0,1,1) ] ) def testIsQuadrilateral(self): self.assertEqual(IsQuadrilateral(self.triangle), False) self.assertEqual(IsQuadrilateral(self.square), True) if __name__ == '__main__': unittest.main()
setUp函數是用來建立測試用的資料,這邊我們建立了兩個二維陣列來表示三角形和正方形的頂點。
numpy是常用的數學函式庫,程式中的 [ (0,1,0),(0,0,1) ] 表示一個二維陣列,第一列是三個頂點的x座標 0,1,0,
第二列三個頂點的y座標 (0,0,1)。square物件存放的是正方形,有四個頂點。
完成以後就是執行測試。結果在第二個測試失敗了,所以我們要回頭修改程式。第二版的程式如下:檢查傳入的多邊形是否含有四個頂點,
有的話就為真,否則為假。
def IsQuadrilateral(polygon): x,y = polygon if len(x) != 4 or len(x)!=len(y): return False return True
現在回頭再跑測試,就可以過關啦。當然我們不能停在這裡,要繼續加測試才行。
五角形1:
self.pentagon1 = numpy.array( [ (0,1,1,0,-1),(0,0,1,1,0.5) ] )
五角形2:
self.pentagon2 = numpy.array( [ (0,1,1,0,-0.01),(0,0,1,1,0.5) ] )
五角形3:
self.pentagon3 = numpy.array( [ (0,1,1,0,-0.21),(0,0,1,1,0.5) ] )
此處我們用了三個五角形,長相如下:
其中第二個五角形其實是四角形,只是左邊有一點小突出而已,我們的新測試如下:
def testIsQuadrilateral(self): self.assertEqual(IsQuadrilateral(self.triangle), False) self.assertEqual(IsQuadrilateral(self.square), True) self.assertEqual(IsQuadrilateral(self.pentagon1), False) self.assertEqual(IsQuadrilateral(self.pentagon2), True) self.assertEqual(IsQuadrilateral(self.pentagon3), False)
修改演算法,四邊形是兩個三角形所組成,所以我們先嘗試找到四邊形的兩個頂點。這裡我用了一個經驗法則,先任意選取polygon上的一個點p0,然後選取離p0最遠的點p1,接著選取離p1最遠的點p2,如此一來p1和p2就是近似四邊形上的兩個點。p1p2的連線把polygon分成兩半,我們接下來只需要判斷這兩半是否為三角形即可。請見下面的圖。
為了要找到離p0最遠的點,我需要再寫一個函數FindFarthestPoint,同時需要新的測試來驗證這新的函數。
今天就先寫到這裡吧。來回顧一下到目前為止我們的程式看起來如何:
import unittest import numpy # 主函數 def IsQuadrilateral(polygon): x,y = polygon if len(x) != 4 or len(x)!=len(y): return False return True # 測試程式 class TestSequenceFunctions(unittest.TestCase): # 此函數在 testIsQuadrilateral 被執行前會被呼叫,以建立測試所需的物件 # 想一想為何需要一個獨立的 setUp 函數呢? def setUp(self): self.triangle = numpy.array( [ (0,10,0),(0,0,10) ] ) self.square = numpy.array( [ (0,1,1,0),(0,0,1,1) ] ) self.pentagon1 = numpy.array( [ (0,1,1,0,-1),(0,0,1,1,0.5) ] ) self.pentagon2 = numpy.array( [ (0,1,1,0,-0.01),(0,0,1,1,0.5) ] ) # 這個測試會失敗 self.pentagon3 = numpy.array( [ (0,1,1,0,-0.21),(0,0,1,1,0.5) ] ) def testIsQuadrilateral(self): self.assertEqual(IsQuadrilateral(self.triangle), False) self.assertEqual(IsQuadrilateral(self.square), True) self.assertEqual(IsQuadrilateral(self.pentagon1), False) self.assertEqual(IsQuadrilateral(self.pentagon2), True) self.assertEqual(IsQuadrilateral(self.pentagon3), False) if __name__ == '__main__': unittest.main() # 會呼叫TestSequenceFunctions裡所有的測試函數
No comments:
Post a Comment