1. 程式人生 > >單元測試框架之unittest(二)

單元測試框架之unittest(二)

一、摘要

本章筆者將詳細介紹組織測試程式碼的相關內容,所用的測試例子會是氣泡排序,筆者在從業這麼久之後回想很多面試都要問氣泡排序,雖然不知道為什麼要問這個,但還是希望大家掌握,它與自動化測試關係不大屬於python的基礎範疇

在上一篇內容中我們展示了一個小例子,在程式碼的前兩行是如下內容

import unittest
class TestStringMethods(unittest.TestCase): 

它的意義何在呢? import unittest 匯入unittest模組,使得我們可以使用它,class TestStringMethods(unittest.TestCase): 新建立的測試類繼承了unittest.TestCase,使得我們可以是使用TestCase裡的特性

那麼它有哪些主要特性呢?

 1、測試用例,當我們的測試類繼承了unittest.TestCase,若以“def test_xxx(self):”這樣的命名方式(test開頭)在測試類中定義函式時,它就會被unittest認為是一條測試方法;然而就像我們做手動測試用例的時候,總有一些原則在,那麼在寫自動化測試用例時有哪些主要的原則呢?

  • 每一個測試用例必須是完全獨立的,從而能夠單獨執行,也可以組團執行
  • 每一個測試用例必須有斷言,從而在測試失敗的情況下斷言異常和一條解釋性的語句(AssertionError)將會丟擲,此時unittest將會將這條用例標識為失敗,其他的異常型別將會被認為是錯誤(error)
  • 在設計測試用例時要儘可能考慮後續維護的問題,我們要儘可能的減少修改測試程式碼,從而能夠滿足快速的迭代測試

2、setUp():這個函式也繼承自unittest.TestCase,它的作用是用來完成每一個測試方法執行前的準備工作,如果setUp()方法執行的時候出現異常,那麼unittest框架認為測試出現了錯誤,測試方法是不會被執行的

3、tearDown(): 同樣繼承自unittest.TestCase,它的作用是每一個測試方法執行完後的清理工作,如果setUp()執行成功,那麼測試方法執行成功還是失敗,tearDown()方法都會被執行

4、setUpClass(): 同樣繼承自unittest.TestCase,它的作用是完成在所有測試方法執行前(包括setUp()),單元測試的前期準備工作,必須用@classmethod修飾,整個測試類只執行一次

5、tearDownClass(): 同樣繼承自unittest.TestCase,它的作用是完成在所有測試方法執行後(包括tearDown()),單元測試的清理工作,必須用@classmethod修飾,整個測試類只執行一次

6、還有一種特例,最簡單的測試用例只需要通過覆蓋runTest()方法來執行自定義的測試程式碼,我們稱之為靜態方法,測試方法名不能重複,也意味著測試類中只能有一個runTest()方法,很顯然這樣的方式會導致很多冗餘程式碼

7、使用了1到5測試特性構建測試用例的,我們稱之為動態方法

二、例項程式碼

下邊將用例項程式碼詳細展示如上概念,待測程式碼如下

class BubbleSort(object):
    def __init__(self, mylist):
        self.myList = mylist
        self.length = len(mylist)

    def ascending_order(self):
        for i in range(self.length-1):
            for j in range(self.length-1-i):
                if self.myList[j] > self.myList[j + 1]:
                    self.myList[j], self.myList[j+1] = self.myList[j+1], self.myList[j]
        return self.myList

    def descending_order(self):
        for i in range(self.length-1):
            for j in range(self.length-1-i):
                if self.myList[j] < self.myList[j + 1]:
                    self.myList[j], self.myList[j+1] = self.myList[j+1], self.myList[j]
        return self.myList

測試程式碼如下:

import unittest
from Util.BubbleSort import BubbleSort


class TestBubbleSort(unittest.TestCase):  
    @classmethod
    def setUpClass(cls):
        print("execute setUpClass\n")

    @classmethod
    def tearDownClass(cls):
        print("execute tearDownClass\n")

    def setUp(self):
        self.list1 = [2, 10, 25, 30, 45, 100, 325]
        self.list3 = [325, 10, 25, 45, 30, 100, 2]
        self.list4 = [11, 3, 41, 101, 327, 26, 46]
        self.list2 = [327, 101, 46, 41, 26, 11, 3]

    def tearDown(self):
        print("execute tearDown\n")

    def test_descending_order(self):
        bls = BubbleSort(self.list4)
        self.list5 = bls.descending_order()
        print(self.list5)
        self.assertEqual(self.list5, self.list2)

    def test_ascending_order(self):
        bls = BubbleSort(self.list3)
        self.list6 = bls.ascending_order()
        print(self.list6)
        self.assertEqual(self.list6, self.list1)


if __name__ == '__main__':
    unittest.main()

執行結果應該是

..
execute setUpClass
----------------------------------------------------------------------

Ran 2 tests in 0.001s

[2, 10, 25, 30, 45, 100, 325]
OK
execute tearDown

[327, 101, 46, 41, 26, 11, 3]
execute tearDown

execute tearDownClass


Process finished with exit code 0

三、程式碼解析

從測試用例的設計和執行結果結合看,意義印證了摘要當中提及的TestCase的特性