Python中的單元測試模塊Unittest快速入門 unittest單元測試框架總結 Python單元測試unittest Python3 unittest斷言詳解 Python3 unittest

前言html

爲何須要單元測試?python

若是沒有單元測試,咱們會遇到這種狀況:已有的健康運行的代碼在通過改動以後,咱們沒法得知改動以後是否引入了Bug。若是有單元測試的話,只要單元測試所有經過,咱們就能夠保證沒有Bug被引入。所以,單元測試是保證軟件工程質量的一個很重要的方面。web

Python中的單元測試shell

Python最強大的地方在於,開發效率高,而且有豐富的Package,避免重複造輪子。那麼Python中的Unittest模塊有很豐富的功能提供給咱們調用:完整的測試框架,豐富的拓展,好比咱們能夠設置測試以前的一些初始化工做,好比連接數據庫等,規劃測試集中有哪些測試用例須要跳過,以及跳過的緣由。數據庫

Unittest中幾個類(Class)的基本概念框架

TestCase 是咱們要寫的具體的測試用例
TestSuite 多個測試用例集合在一塊兒,中文翻譯過來叫測試套件,其實就是測試集。
TestLoader是用來加載TestCase到TestSuite中的(更通俗一點,就是用來把符合咱們定義的條件的測試用例組合起來,成爲一個測試集),通常會以參數的形式傳進去一些條件,好比收集某個目錄下全部的test case組成新的測試集。
TestRunner是來執行測試用例的,測試的結果會保存到TestResult實例中,包括運行了多少測試用例,成功了多少,失敗了多少等信息函數

一個簡單的測試例子post

 

>>> class MyTest(unittest.TestCase):
        #Run before whole testcase set execution, decorator classmethod is essential
    @classmethod
    def setUpClass(self):
        print("UnitTest Begin...")
        #Run after whole testcase set execution, decorator classmethod is essential
    @classmethod
    def tearDownClass(self):
        print("UnitTest End...")
        #Run before each test case execution 
    def setUp(self):
        print("Begin...")
        #Run after each test case execution
    def tearDown(self):
        print("End...")
    def test_1(self):
        self.assertEqual(1,1)
    def test_2(self):
        self.assertEqual(1,2)

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

UnitTest Begin...
Begin...
End...
.Begin...
End...
FUnitTest End...

======================================================================
FAIL: test_2 (__main__.MyTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "<pyshell#41>", line 15, in test_2
AssertionError: 1 != 2

----------------------------------------------------------------------
Ran 2 tests in 0.097s

FAILED (failures=1)

 

在這個例子中,有幾個函數要注意:單元測試

setUp()和tearDown():每一個test case執行以前和執行以後要運行的操做:咱們能夠在這裏定義測試的準備工做,好比連接數據庫,web登陸等等。學習

用裝飾器classmethod裝飾的setUpClass()和tearDownClass(): 跑類中定義的全部test cases以前和以後,須要執行的操做。

test_1()和test_2(),具體的測試用例,必定要以test爲開頭,由於unittest框架中,定義爲,若是TestCase類中以test爲開頭的函數,將會做爲具體的testcase收錄進要執行的測試集裏。

self.assertEqual(),是TestCase類中的斷言函數,用來作判斷的,用以判斷該條測試用例是否經過。經過名字咱們能夠看出,這個函數的意思是判斷兩個值是否相等,若是相等,則用例經過,若是不等,則用例不經過。相似的,斷言函數還有不少:有一個msg參數,若是指定msg參數的值,則將該信息做爲失敗的錯誤信息返回

 

三種常見測試寫法

第一種: 搜索該模塊下全部以test開頭的測試用例方法,並自動執行它們

#執行測試用例方案一以下:
#unittest.main()方法會搜索該模塊下全部以test開頭的測試用例方法,並自動執行它們。

import unittest

#定義測試類,父類爲unittest.TestCase。
#可繼承unittest.TestCase的方法,如setUp和tearDown方法,不過此方法能夠在子類重寫,覆蓋父類方法。
#可繼承unittest.TestCase的各類斷言方法。
class Test(unittest.TestCase): 
    
    def setUp(self):
        self.number=raw_input('Enter a number:')
        self.number=int(self.number)

#定義測試用例,以「test_」開頭命名的方法
#可以使用unittest.TestCase類下面的各類斷言方法用於對測試結果的判斷
    def test_case1(self):
        print self.number
        self.assertEqual(self.number,10,msg='Your input is not 10')
        
    def test_case2(self):
        print self.number
        self.assertEqual(self.number,20,msg='Your input is not 20')

    @unittest.skip('暫時跳過用例3的測試')
    def test_case3(self):
        print self.number
        self.assertEqual(self.number,30,msg='Your input is not 30')


    def tearDown(self):
        print 'Test over'
        
#若是直接運行該文件(__name__值爲__main__),則執行如下語句,經常使用於測試腳本是否可以正常運行
if __name__=='__main__':
#執行順序是命名順序:先執行test_case1,再執行test_case2
    unittest.main()

第二種: 構造測試集,實例化test suite(即TestRunner類), 運行test suite中全部的測試用例。

'''
執行測試用例方案二以下:
先構造測試集
實例化測試套件
'''
    suite=unittest.TestSuite()
#將測試用例加載到測試套件中。
#執行順序是安裝加載順序:先執行test_case2,再執行test_case1
    suite.addTest(Test('test_case2'))
    suite.addTest(Test('test_case1'))
#執行測試用例
#實例化TextTestRunner類
    runner=unittest.TextTestRunner()
#使用run()方法運行測試套件(即運行測試套件中的全部用例)
    runner.run(suite)
    

第三種:經過收集指定目錄下的目標測試用例,構造測試集再執行

#構造測試集(簡化了方案二中先要建立測試套件而後再依次加載測試用例)
#執行順序同方案一:執行順序是命名順序:先執行test_case1,再執行test_case2
    test_dir = './'
    discover = unittest.defaultTestLoader.discover(test_dir, pattern='test_*.py')
#執行測試用例
#實例化TextTestRunner類
    runner=unittest.TextTestRunner()
#使用run()方法運行測試套件(即運行測試套件中的全部用例)
    runner.run(discover)   

 

如何生成HTML和XML格式的測試報告

上面咱們獲得的測試結果是文本格式的,可讀性很差,而且也沒法直接用來做後續的測試結果數據處理,好比測試結果的分類統計等等。

那麼有兩種方式可供咱們選擇:HTML和XML

HTML格式的報告,就是網頁格式,可讀性會比較好。XML格式的報告,則比較方便做後續的數據處理。

須要注意的是,咱們須要安裝額外的package,即HtmlTestRunner和xmlrunner。

在配置好Pip的前提下,能夠經過如下命令安裝:

pip install html-testrunner

pip instll xmlrunner

若是沒有配置好pip或者用pip安裝失敗,則須要用如下方式安裝(xmlrunner同理):

1. 下載HTMLTestRunner.py文件:地址 http://tungwaiyip.info/software/HTMLTestRunner.html
2. 將該文件保存在python安裝路徑下的lib文件夾中。在文件中能import HTMLTestRunner成功,即配置成功。
 
以生成HTML報告爲例:
#!/usr/bin/python3
# -*- coding: utf-8 -*-

import unittest
import HtmlTestRunner

class TestStringMethods(unittest.TestCase):
    def test_upper(self):
        self.assertEqual('foo'.upper(),'FOO')
    def test_isupper(self):
        self.assertFalse('Foo'.isupper())
    def test_split(self):
        s = 'hello world'
        self.assertEqual(s.split(),['hello','world'])
        with self.assertRaises(TypeError):
            s.split(2)

if __name__ == '__main__':
    suite = unittest.TestSuite()
    suite.addTest(TestStringMethods('test_upper'))
    suite.addTest(TestStringMethods('test_isupper'))
    suite.addTest(TestStringMethods('test_split'))
    runner = HtmlTestRunner.HTMLTestRunner(output='MyUnitTest')
    runner.run(suite)

最終咱們會獲得一個可讀性比較好的網頁報告。

XML報告:

 有時咱們須要獲得格式化數據的測試報告,此時XML格式就要比HTML格式好的多。

由於XML格式的test result容易被讀取和數據處理。

示例代碼以下:

#!/usr/bin/python3
# -*- coding: utf-8 -*-

import unittest
import xmlrunner

class TestStringMethods(unittest.TestCase):
    def test_upper(self):
        self.assertEqual('foo'.upper(),'FOO')
    def test_isupper(self):
        self.assertFalse('Foo'.isupper())
    def test_split(self):
        s = 'hello world'
        self.assertEqual(s.split(),['hello','world'])
        with self.assertRaises(TypeError):
            s.split(2)

if __name__ == '__main__':
    suite = unittest.TestSuite()
    suite.addTest(TestStringMethods('test_upper'))
    suite.addTest(TestStringMethods('test_isupper'))
    suite.addTest(TestStringMethods('test_split'))
    #fp = open('result.html','w')
    runner = xmlrunner.XMLTestRunner(output='MyUnitTest')
    #runner = HtmlTestRunner.HTMLTestRunner(stream=fp,output='MyUnitTest')
    runner.run(suite)

 

獲得的結果是這樣的:

<?xml version="1.0"?>

-<testsuite time="0.000" tests="3" name="TestStringMethods-20181115000346" failures="0" errors="0">

<testcase time="0.000" name="test_upper" classname="TestStringMethods"/>

<testcase time="0.000" name="test_isupper" classname="TestStringMethods"/>

<testcase time="0.000" name="test_split" classname="TestStringMethods"/>


-<system-out>

<![CDATA[]]>

</system-out>


-<system-err>

<![CDATA[]]>

</system-err>

</testsuite>

 

 

幾個利用unittest作測試的實際例子

百度搜索測試用例

from selenium import webdriver
import unittest, time

class BaiduTest(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Firefox()
        self.driver.implicitly_wait(30) #隱性等待時間爲30秒
        self.base_url = "https://www.baidu.com"
    
    def test_baidu(self):
        driver = self.driver
        driver.get(self.base_url + "/")
        driver.find_element_by_id("kw").clear()
        driver.find_element_by_id("kw").send_keys("unittest")
        driver.find_element_by_id("su").click()
        time.sleep(3)
        title=driver.title
        self.assertEqual(title, u"unittest_百度搜索") 

    def tearDown(self):
        self.driver.quit()

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

有道翻譯測試用例

from selenium import webdriver
import unittest, time

class YoudaoTest(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Firefox()
        self.driver.implicitly_wait(30) #隱性等待時間爲30秒
        self.base_url = "http://www.youdao.com"
    
    def test_youdao(self):
        driver = self.driver
        driver.get(self.base_url + "/")
        driver.find_element_by_id("translateContent").clear()
        driver.find_element_by_id("translateContent").send_keys(u"你好")
        driver.find_element_by_id("translateContent").submit()
        time.sleep(3)
        page_source=driver.page_source
        self.assertIn( "hello",page_source) 

    def tearDown(self):
        self.driver.quit()

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

web測試用例:經過測試套件TestSuite來組裝多個測試用例。

import unittest
from test_case import test_baidu
from test_case import test_youdao

#構造測試集
suite = unittest.TestSuite()
suite.addTest(test_baidu.BaiduTest('test_baidu'))
suite.addTest(test_youdao.YoudaoTest('test_youdao'))

if __name__=='__main__':
    #執行測試
    runner = unittest.TextTestRunner()
    runner.run(suite)

 

參考連接:

1. unittest單元測試框架總結

2. unittest — Unit testing framework https://docs.python.org/3/library/unittest.html

3. Python單元測試unittest

4. Python3 unittest斷言詳解

5. Python3 unittest單元測試

6. Python HTMLTestRunner 學習

相關文章
相關標籤/搜索