python接口自動化測試 - mock模塊基本使用介紹


mock簡介

 

mock作用

解決依賴問題,達到解耦作用

當我們測試某個目標接口(模塊)時,該接口依賴其他接口,當被依賴的接口未開發完成時,可以用mock模擬被依賴接口,完成目標接口的測試

 

模擬復雜業務的接口

當我們測試某個目標接口(模塊),該接口依賴一個非常復雜的接口時,可以用mock來模擬這個復雜的業務接口;也解決接口依賴一樣的原理

 

單元測試

如果某個接口(模塊)未開發完成時,又需要編寫測試用例,則可以通過mock模擬該接口(模塊)進行測試

 

前后端聯調

前端開發的頁面需要根據后端返回的不同狀態碼展示不同的頁面,當后端接口未開發完成時,也可通過mock來模擬后端接口返回自己想要的數據

 

mock類解讀

class Mock(spec=None,side_effect=None,return_value=DEFFAULT,name=None) 

  • secp:定義mock對象的屬性值,可以是列表,字符串,甚至一個對象或者實例 
  • side_effect:可以用來拋出異常或者動態改變返回值,它必須是一個iterator(列表),它會覆蓋return_value
  • return_value:定義mock方法的返回值,它可以是一個值,可以是一個對象(如果存在side_effect參數那這個就沒有用,也就是不能同時用)
  • name:作為mock對象的一個標識,在print時可以看到

 

mock實際使用

一個未開發完成的功能如何測試?

 1 def add(self, a, b):
 2     """兩個數相加"""
 3     pass
 4 
 5 
 6 class TestSub(unittest.TestCase):
 7     """測試兩個數相加用例"""
 8 
 9     def test_sub(self):
10         # 創建一個mock對象 return_value代表mock一個數據
11         mock_add = mock.Mock(return_value=15)
12         # 將mock對象賦予給被測函數
13         add = mock_add
14         # 調用被測函數
15         result = add(5, 5)
16         # 斷言實際結果和預期結果
17         self.assertEqual(result, 15)

 

一個完成開發的功能如何測試?

class SubClass(object):
    def add(self, a, b):
        """兩個數相加"""
        return a + b


class TestSub(unittest.TestCase):
    """測試兩個數相加用例"""


    def test_add2(self):
        # 初始化被測函數類實例
        sub = SubClass()
        # 創建一個mock對象 return_value代表mock一個數據
        # 傳遞side_effect關鍵字參數, 會覆蓋return_value參數值, 使用真實的add方法測試
        sub.add = Mock(return_value=15, side_effect=sub.add)
        # 調用被測函數
        result = sub.add(5, 5)
        # 斷言實際結果和預期結果
        self.assertEqual(result, 10)

 

 

side_effect:這里給的參數值是sub.add相當於add方法的地址,當我們調用add方法時就會調用真實的add方法

簡單理解成:傳遞了side_effect參數且值為被測函數地址時,mock不會起作用;兩者不可共存

另外,side_effect接受的是一個可迭代序列,當傳遞多個值時,每次調用mock時會返回不同的值;如下

 1 mock_obj = mock.Mock(side_effect= [1,2,3])
 2 print(mock_obj())
 3 print(mock_obj())
 4 print(mock_obj())
 5 print(mock_obj())
 6 
 7 # 輸出
 8 Traceback (most recent call last):
 9 1
10   File "D:/MyThreading/mymock.py", line 37, in <module>
11 2
12     print(mock_obj())
13 3
14   File "C:\Python36\lib\unittest\mock.py", line 939, in __call__
15     return _mock_self._mock_call(*args, **kwargs)
16   File "C:\Python36\lib\unittest\mock.py", line 998, in _mock_call
17     result = next(effect)
18 StopIteration

 

存在依賴關系的功能如何測試?

 1 # 支付類
 2 class Payment:
 3 
 4     def requestOutofSystem(self, card_num, amount):
 5         '''
 6         請求第三方外部支付接口,並返回響應碼
 7         :param card_num: 卡號
 8         :param amount: 支付金額
 9         :return: 返回狀態碼,200 代表支付成功,500 代表支付異常失敗
10         '''
11         # 第三方支付接口請求地址(故意寫錯)
12         url = "http://third.payment.pay/"
13         # 請求參數
14         data = {"card_num": card_num, "amount": amount}
15         response = requests.post(url, data=data)
16         # 返回狀態碼
17         return response.status_code
18 
19     def doPay(self, user_id, card_num, amount):
20         '''
21         支付
22         :param userId: 用戶ID
23         :param card_num: 卡號
24         :param amount: 支付金額
25         :return:
26         '''
27         try:
28             # 調用第三方支付接口請求進行真實扣款
29             resp = self.requestOutofSystem(card_num, amount)
30             print('調用第三方支付接口返回結果:', resp)
31         except TimeoutError:
32             # 如果超時就重新調用一次
33             print('重試一次')
34             resp = self.requestOutofSystem(card_num, amount)
35 
36         if resp == 200:
37             # 返回第三方支付成功,則進行系統里面的扣款並記錄支付記錄等操作
38             print("{0}支付{1}成功!!!進行扣款並記錄支付記錄".format(user_id, amount))
39             return 'success'
40 
41         elif resp == 500:
42             # 返回第三方支付失敗,則不進行扣款
43             print("{0}支付{1}失敗!!不進行扣款!!!".format(user_id, amount))
44             return 'fail'
45 
46 # 單元測試類
47 class payTest(unittest.TestCase):
48 
49     def test_pay_success(self):
50         pay = Payment()
51         # 模擬第三方支付接口返回200
52         pay.requestOutofSystem = mock.Mock(return_value=200)
53         resp = pay.doPay(user_id=1, card_num='12345678', amount=100)
54         self.assertEqual('success', resp)
55 
56     def test_pay_fail(self):
57         pay = Payment()
58         # 模擬第三方支付接口返回500
59         pay.requestOutofSystem = mock.Mock(return_value=500)
60         resp = pay.doPay(user_id=1, card_num='12345678', amount=100)
61         self.assertEqual('fail', resp)
62 
63     def test_pay_time_success(self):
64         pay = Payment()
65         # 模擬第三方支付接口首次支付超時,重試第二次成功
66         pay.requestOutofSystem = mock.Mock(side_effect=[TimeoutError, 200])
67         resp = pay.doPay(user_id=1, card_num='12345678', amount=100)
68         self.assertEqual('success', resp)
69 
70     def test_pay_time_fail(self):
71         pay = Payment()
72         # 模擬第三方支付接口首次支付超時,重試第二次失敗
73         pay.requestOutofSystem = mock.Mock(side_effect=[TimeoutError, 500])
74         resp = pay.doPay(user_id=1, card_num='12345678', amount=100)
75         self.assertEqual('fail', resp)

也許有小伙伴會問,第三方支付都不能用,我們的測試結果是否是有效的呢?

通常在測試一個模塊的時候,是可以認為其他模塊的功能是正常的,只針對目標模塊進行測試是沒有任何問題的,所以說測試結果也是正確的

 

mock裝飾器

一共兩種格式

  1.  @patch('module名字.方法名') 
  2.  @patch.object(類名, '方法名') 
 1 # 裝飾類演示
 2 from mock import Mock, patch
 3 
 4 
 5 # 單獨的相乘函數
 6 def multiple(a, b):
 7     return a * b
 8 
 9 
10 # 單獨的捕獲Exception函數
11 def is_error():
12     try:
13         os.mkdir("11")
14         return False
15     except Exception as e:
16         return True
17 
18 
19 # 計算類,包含add方法
20 class calculator(object):
21     def add(self, a, b):
22         return a + b
23 
24 
25 # 裝飾類演示 - 單元測試類
26 class TestProducer(unittest.TestCase):
27 
28     # case執行前
29     def setUp(self):
30         self.calculator = calculator()
31 
32     # mock一個函數,注意也要指定module
33     @patch('mock_learn.multiple')
34     def test_multiple(self, mock_multiple):
35         mock_multiple.return_value = 3
36         self.assertEqual(multiple(8, 14), 3)
37 
38     # mock一個類對象的方法
39     @patch.object(calculator, 'add')
40     def test_add(self, mock_add):
41         mock_add.return_value = 3
42         self.assertEqual(self.calculator.add(8, 14), 3)
43 
44     # mock調用方法返回多個不同的值
45     @patch.object(calculator, 'add')
46     def test_effect(self, mock_add):
47         mock_add.side_effect = [1, 2, 3]
48         self.assertEqual(self.calculator.add(8, 14), 1)
49         self.assertEqual(self.calculator.add(8, 14), 2)
50         self.assertEqual(self.calculator.add(8, 14), 3)
51 
52     # mock的函數拋出Exception
53     @patch('os.mkdir')
54     def test_exception(self, mkdir):
55         mkdir.side_effect = Exception
56         self.assertEqual(is_error(), True)
57 
58     # mock多個函數,注意函數調用順序
59     @patch.object(calculator, 'add')
60     @patch('mock_learn.multiple')
61     def test_more(self, mock_multiple, mock_add):
62         mock_add.return_value = 1
63         mock_multiple.return_value = 4
64         self.assertEqual(self.calculator.add(3, 3), 1)
65         self.assertEqual(multiple(3, 3), 4)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM