單元測試框架 unittest 複習

測試:在規定的條件下對軟件進行操作,發現軟件存在的邏輯,功能,性能等問題
測試過程:單元測試–集成測試–系統測試–性能測試


單元測試:對軟件設計最小單元進行正確性檢測的測試,發現可能存在的問題。
單元測試的目的:就是發現模塊內部的邏輯,語法,算法等錯誤。
單元測試方式代碼級別測試模塊功能測試。
代碼級別測試:
接口測試:確保模塊接口實現正確,符合設計文檔規範或者約定。
數據結構測試:確保數據結構可用,數據庫、文件、自定義數據結構;
邊界測試:對於邊界值測試,看模塊會不會出現問題;

模塊功能測試:通過黑盒,對模塊測試。
其他單元測試項:性能,代碼規範


框架unittest介紹:三個步驟
找到測試類(testcase),加載測試方法(runtest),執行測試方法。

1、被測模塊model.py // 定義一個類,提供接口,實現兩數相加

'''
實現兩個數的加減
'''
class Calculator():
    def __init__(self,a,b):
        self.a = int(a)
        self.b = int(b)
    '''加法'''
    def add(self):
       return self.a + self.b
    '''減法'''
    def sub(self):
        return self.a - self.b
    '''乘法'''
    def mul(self):
        return self.a * self.b
    '''除法'''
    def div(self):
        return self.a / self.b

2、準備測試環境,編寫測試用例

import unittest
from module import Calculator
from HTMLTestRunner2 import HTMLTestRunner 
"""
1、我們添加了 setUp() 和 tearDown() 兩個方法(其實是重寫了TestCase的這兩個方法),
這兩個方法在每個測試方法執行前以及執行後執行一次,
setUp用來爲測試準備環境,tearDown用來清理環境,已備之後的測試
2、@unittest.skip  跳過某個case不執行

"""
class ModuleTest(unittest.TestCase):  //測試用例

    def setUp(self):  # 初始化,給被測模塊的類傳入參數
        self.cal = Calculator(8,4)

    def tearDown(self):
        pass
     // 調用方法,執行斷言判斷
    def test_add(self):
        result = self.cal.add()
        self.assertEqual(result,12)

    def test_sub(self):
        result = self.cal.sub()
        self.assertEqual(result, 4)

    def test_mul(self):
        result = self.cal.mul()
        self.assertEqual(result, 32)

    def test_div(self):
        result = self.cal.div()
        self.assertEqual(result, 2)

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


if __name__ == "__main__":  
    #完全可以使用“unittest.main()”替代(前提是:所有的測試模塊均以test開頭)
    suite = unittest.TestSuite()  #第二步,構造測試集,加載需要用到的測試用例
    suite.addTest(ModuleTest("test_add"))
    suite.addTest(ModuleTest("test_sub"))
    suite.addTest(ModuleTest("test_mul"))
    suite.addTest(ModuleTest("test_div"))
    #執行
    #runner = unittest.TextTestRunner()
    # runner.run(suite)
    with open('HTMLReport.html','w') as f:
       runner = HTMLTestRunner(stream=f, title='MathFunc Test Report',
                                description='generated by HTMLTestRunner.',
                                verbosity=2)
       runner.run(suite)  //第三步,調用執行

#若不保存測試輸出結果,執行如下命令
#result = unittest.TextTestRunner(verbosity = 2).run(suite)

3、自動構成測試集
suite = unittest.makeSuite(測試用例名稱,prefix = 'test') (加載test開頭的文件)

import pytest
import unittest
from module import Calculator
from HTMLTestRunner2 import HTMLTestRunner

class ModuleTest(unittest.TestCase):

    def setUp(self): 
        self.cal = Calculator(8,4)

    def tearDown(self):
        pass

    def test_add(self):
        result = self.cal.add()
        self.assertEqual(result,12)

    def test_sub(self):
        result = self.cal.sub()
        self.assertEqual(result, 4)

    def test_mul(self):
        result = self.cal.mul()
        self.assertEqual(result, 32)

    def test_div(self):
        result = self.cal.div()
        self.assertEqual(result, 2)

#如果在上面繼續添加測試用例,爲提高效率可以可以自動添加到測試集,如果不想把某些測試用例加載到測試集,**就不要用test開頭**

if __name__ == "__main__": 
    suite = unittest.makeSuite(ModuleTest,prefix='test')
    #suite.addTest(ModuleTest("get_number")) 同樣可以結合這個addtest使用
    print(suite.counTestCase())   #打印加載測試用例個數。
    runner = unittest.TextTestRunner()
    runner.run(suite) 

測試用例的判斷:也可以集成這些判斷,進行擴展。
這裏寫圖片描述
這裏寫圖片描述

擴展 1、跳過某些接口,運行測試用例
————-重寫測試用例後,添加測試用例時,如何跳過某些用例,並給出出原因。
1、@unittest.skip('reason') 用例前加上裝飾器,表明直接跳過。

@unittest.skip('notest')
def test_add(self):
        result = self.cal.add()
        self.assertEqual(result,12)

擴展2、根據某些特定的條件跳過一些測試用例

  1. skipIf(conditon,reason) // conditon 條件爲真的話,就跳過並給出原因 reason
  2. skipUnless(condition,reason) //conditon 條件爲真,就不跳過。

在測試模塊中可以給出測試版本,選擇版本跳過(測試時用例是一樣編寫的,可以用版本號選擇跳過):

class Calculator():
   version = 1  //版本一
    def __init__(self,a,b):
        self.a = int(a)
        self.b = int(b)

    '''加法'''
    def add(self):
       return self.a + self.b
    '''減法'''
    def sub(self):
        return self.a - self.b
    '''乘法'''
    def mul(self):
        return self.a * self.b
    '''除法'''
    def div(self):
        return self.a / self.b

測試用編寫時,可以使用選擇跳過裝飾器

@unittest.skipIf(Calculator.version == 1 ,'no test')
def test_add(self):
        result = self.cal.add()
        self.assertEqual(result,12)

擴展 3、預期結果失敗 @exoextdFailure(func)
————-測試結果和預期結果不符合,不計入失敗統計,斷言的時有些結果不符合預期會發生執行錯誤,這個是否可以忽略不計入統計值

@unittest.expextdFailure
def test_add(self):
        result = self.cal.add()
        self.assertEqual(result,13)  //顯然這裏不等於13

這裏寫圖片描述

擴展 4、Mock模擬測試
單元測試基本測試流程圖:
這裏寫圖片描述
( 設計測試用例— > 去測試基本模塊裏面對象,函數 —> 用到測試資源—>網絡資源,第三方模塊支撐)

存在的問題:單元測試腳本可能依賴於服務器搭建,第三方模塊,以及測試結果難以知道,難以重複測試bug

解決 unittest.mock 模塊: Mock模塊像測試對象提供一套和測試資源完全相同的接口和方法,不關心具體實現,只關心具體結果。第三方模塊還沒有完成時,可以用mock 去模擬第三方模塊,給出接口值。
1、 mock.Mock : 構造器,可以模擬其他類,增加屬性

from unittest import mock
testmock = mock.Mock()  //創建一個mock實例
print(testmock)
print(dir(testmock))

1、1 mock提供的基本對象:

['assert_any_call', 'assert_called', 'assert_called_once', 
'assert_called_once_with', 'assert_called_with', 'assert_has_calls',
 'assert_not_called', 'attach_mock', 'call_args', 'call_args_list', 
'mock_add_spec', 'mock_calls', 'reset_mock', 'return_value', 
'side_effect']

2、創建mock類,構造其他屬性。
這裏寫圖片描述

from unittest import mock

attrs = ['connect','disconnect']  #增加兩個屬性
testmock = mock.Mock(name='TestMock',spec=attrs)  # 創建一個mock對象,對象名字,對象屬性

#testmock.connect.return_value = 200  #增加屬性返回值
testmock.disconnect.return_value = 200

testmock.connect.side_effect = [200,404,501]  #定義三個返回值,也可以定義一個返回函數,調用一次就返回一次。
for i in range(3):
    print(testmock.connect())

3、Mock斷言語句
這裏寫圖片描述

3、1 假設測試時用到的,第三方接口模塊
第三方模塊可能還沒有完成,輸入輸出都不夠完整,此時使用mock改寫無需關心第三方

"""
用 mock 模擬一個類,定義一個雲端客戶端,有四個基本的方法。
"""
from unittest import mock

class CouldClient(object):
    def connect(self):
        pass

    def disconnect(self):
        pass

    def upload(self):
        pass

    def download(self):
        pass

3、2 測試用例編寫

import unittest
from unittest import mock
from mock_class import CouldClient

class TestCould(unittest.TestCase):  
    def setUp(self):
        self.obj = mock.Mock(CouldClient)  #構造 mock 實例傳入改寫測試類
    def tearDown(self):
        self.obj = None

# 改寫並賦予測試類輸出值,斷言輸出是否正確。
    def test_connect(self):
        self.obj.connect.return_value = 200
        self.assertEqual(self.obj.connect(), 200)


if __name__ == '__main__':
    unittest.main()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章