unittest的參數化
- 2019 年 12 月 9 日
- 筆記
之前寫了很多關於unittest單元測試框架的文章,本小節主要介紹它在參數化方面的應用,首先需要安裝第三方的庫parameterized,安裝的命令為:pip install parameterized。安裝成功後。這裡主要結合具體的案例來說明它的應用和實現的具體細節 ,編寫一個兩個數相加的函數,然後針對該函數來設計具體的測試點,實現的代碼如下:
#!/usr/bin/env python #author:wuya from parameterized import parameterized,param import unittest def add(a,b): return a+b class AddTest(unittest.TestCase): @parameterized.expand([ param(1,1,2), param(1.0,1.0,2.0), param('hi',' wuya','hi wuya') ]) def test_add_cases(self,first,second,result): self.assertEqual(add(first,second),result) if __name__ == '__main__': unittest.main(verbosity=2)
執行如上的代碼後,顯示三個測試點都測試通過,parameterized的設計思想有點和ddt相似,至少在參數化方面可以說是思想是一致的。在執行具體的測試點時候,它是對列表裏面的參數進行進行循環然後依次賦值,也就是說,當循環到第一個元組的參數的時候,first其實是1,second是1,result是2,依次循環,這樣就可以使用parameterized,來達到一個測試點的代碼完成N個測試點的場景的測試。當然上面的不是很完善的。具體對代碼打斷點,來看賦值的具體過程,如下圖所示:

在如上的信息中,可以看到具體循環賦值的過程。當然上面的函數還是不夠完善,至少沒有加異常的處理,那麼需要添加異常,完善後的代碼為:
#!/usr/bin/env python #author:wuya from parameterized import parameterized,param import unittest def add(a,b): try: return a + b except Exception as e: return e.args[0] class AddTest(unittest.TestCase): @parameterized.expand([ param(1,1,2), param(1.0,1.0,2.0), param('hi',' wuya','hi wuya') ]) def test_add_cases(self,first,second,result): self.assertEqual(add(first,second),result) if __name__ == '__main__': unittest.main(verbosity=2)
再次執行代碼,依然執行通過。但是我們很清晰的看到,增加異常後,在測試的場景裏面並沒有考慮到異常情況的測試,比如int與str相加會怎麼樣,這樣的測試點沒加,也就意味着add()函數裏面的異常部分並沒有被覆蓋到,具體我們結合coverage來看下,coverage執行的過程具體是執行要測試的代碼,然後是分析,最後是報告,執行的命令分別是:coverage run coverage report coverage html,如下圖顯示命令執行的執行細節:

打開對應的html報告後,可以看到異常的代碼並沒有被覆蓋到,如下圖所示

那麼就需要再次完善測試點,增加對異常的測試點的考慮,完善後的代碼為:
#!/usr/bin/env python #author:wuya from parameterized import parameterized,param import unittest def add(a,b): try: return a + b except Exception as e: return e.args[0] class AddTest(unittest.TestCase): @parameterized.expand([ param(1, 1, 2), param(1.0, 1.0, 2.0), param(1, 1.0, 2.0), param(1, 0, 1), param('', '', ''), param('hi ', 'wuya', 'hi wuya'), param(0, '', "unsupported operand type(s) for +: 'int' and 'str'"), param(1, 'hi', "unsupported operand type(s) for +: 'int' and 'str'"), param(1.0, 'wuya', "unsupported operand type(s) for +: 'float' and 'str'"), ]) def test_add_cases(self,first,second,result): self.assertEqual(add(first,second),result) if __name__ == '__main__': unittest.main(verbosity=2)
見如上的代碼,這樣結合coverage以及parameterized的工具,就能夠使用很簡單的代碼對一個函數的代碼都能夠覆蓋到,並且使用一個測試方法就能夠測試很多的測試場景。
感謝您的閱讀和關注,後續文章會持續更新。如您感興趣,也可購買本人的書籍和實戰視頻,謝謝!