mock簡(jiǎn)介
- py3已將mock集成到unittest庫(kù)中
- 為的就是更好的進(jìn)行單元測(cè)試
- 簡(jiǎn)單理解,模擬接口返回參數(shù)
- 通俗易懂,直接修改接口返回參數(shù)的值
- 官方文檔:unittest.mock --- 模擬對(duì)象庫(kù) — Python 3.11.3 文檔
mock作用
解決依賴問(wèn)題,達(dá)到解耦作用
當(dāng)我們測(cè)試某個(gè)目標(biāo)接口(模塊)時(shí),該接口依賴其他接口,當(dāng)被依賴的接口未開(kāi)發(fā)完成時(shí),可以用mock模擬被依賴接口,完成目標(biāo)接口的測(cè)試
模擬復(fù)雜業(yè)務(wù)的接口
當(dāng)我們測(cè)試某個(gè)目標(biāo)接口(模塊),該接口依賴一個(gè)非常復(fù)雜的接口時(shí),可以用mock來(lái)模擬這個(gè)復(fù)雜的業(yè)務(wù)接口;也解決接口依賴一樣的原理
單元測(cè)試
如果某個(gè)接口(模塊)未開(kāi)發(fā)完成時(shí),又需要編寫(xiě)測(cè)試用例,則可以通過(guò)mock模擬該接口(模塊)進(jìn)行測(cè)試
前后端聯(lián)調(diào)
前端開(kāi)發(fā)的頁(yè)面需要根據(jù)后端返回的不同狀態(tài)碼展示不同的頁(yè)面,當(dāng)后端接口未開(kāi)發(fā)完成時(shí),也可通過(guò)mock來(lái)模擬后端接口返回自己想要的數(shù)據(jù)
mock類(lèi)解讀
- class?Mock(spec=None,side_effect=None,return_value=DEFFAULT,name=None)?secp:定義mock對(duì)象的屬性值,可以是列表,字符串,甚至一個(gè)對(duì)象或者實(shí)例?
- side_effect:可以用來(lái)拋出異?;蛘邉?dòng)態(tài)改變返回值,它必須是一個(gè)iterator(列表),它會(huì)覆蓋return_value
- return_value:定義mock方法的返回值,它可以是一個(gè)值,可以是一個(gè)對(duì)象(如果存在side_effect參數(shù)那這個(gè)就沒(méi)有用,也就是不能同時(shí)用)
- name:作為mock對(duì)象的一個(gè)標(biāo)識(shí),在print時(shí)可以看到
mock實(shí)際使用
一個(gè)未開(kāi)發(fā)完成的功能如何測(cè)試?
1 def add(self, a, b):
2 """兩個(gè)數(shù)相加"""
3 pass
4
5
6 class TestSub(unittest.TestCase):
7 """測(cè)試兩個(gè)數(shù)相加用例"""
8
9 def test_sub(self):
10 # 創(chuàng)建一個(gè)mock對(duì)象 return_value代表mock一個(gè)數(shù)據(jù)
11 mock_add = mock.Mock(return_value=15)
12 # 將mock對(duì)象賦予給被測(cè)函數(shù)
13 add = mock_add
14 # 調(diào)用被測(cè)函數(shù)
15 result = add(5, 5)
16 # 斷言實(shí)際結(jié)果和預(yù)期結(jié)果
17 self.assertEqual(result, 15)
?一個(gè)完成開(kāi)發(fā)的功能如何測(cè)試?
class SubClass(object):
def add(self, a, b):
"""兩個(gè)數(shù)相加"""
return a + b
class TestSub(unittest.TestCase):
"""測(cè)試兩個(gè)數(shù)相加用例"""
def test_add2(self):
# 初始化被測(cè)函數(shù)類(lèi)實(shí)例
sub = SubClass()
# 創(chuàng)建一個(gè)mock對(duì)象 return_value代表mock一個(gè)數(shù)據(jù)
# 傳遞side_effect關(guān)鍵字參數(shù), 會(huì)覆蓋return_value參數(shù)值, 使用真實(shí)的add方法測(cè)試
sub.add = Mock(return_value=15, side_effect=sub.add)
# 調(diào)用被測(cè)函數(shù)
result = sub.add(5, 5)
# 斷言實(shí)際結(jié)果和預(yù)期結(jié)果
self.assertEqual(result, 10)
side_effect:這里給的參數(shù)值是sub.add相當(dāng)于add方法的地址,當(dāng)我們調(diào)用add方法時(shí)就會(huì)調(diào)用真實(shí)的add方法
簡(jiǎn)單理解成:傳遞了side_effect參數(shù)且值為被測(cè)函數(shù)地址時(shí),mock不會(huì)起作用;兩者不可共存
另外,side_effect接受的是一個(gè)可迭代序列,當(dāng)傳遞多個(gè)值時(shí),每次調(diào)用mock時(shí)會(huì)返回不同的值;如下
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
存在依賴關(guān)系的功能如何測(cè)試?
1 # 支付類(lèi)
2 class Payment:
3
4 def requestOutofSystem(self, card_num, amount):
5 '''
6 請(qǐng)求第三方外部支付接口,并返回響應(yīng)碼
7 :param card_num: 卡號(hào)
8 :param amount: 支付金額
9 :return: 返回狀態(tài)碼,200 代表支付成功,500 代表支付異常失敗
10 '''
11 # 第三方支付接口請(qǐng)求地址(故意寫(xiě)錯(cuò))
12 url = "http://third.payment.pay/"
13 # 請(qǐng)求參數(shù)
14 data = {"card_num": card_num, "amount": amount}
15 response = requests.post(url, data=data)
16 # 返回狀態(tài)碼
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: 卡號(hào)
24 :param amount: 支付金額
25 :return:
26 '''
27 try:
28 # 調(diào)用第三方支付接口請(qǐng)求進(jìn)行真實(shí)扣款
29 resp = self.requestOutofSystem(card_num, amount)
30 print('調(diào)用第三方支付接口返回結(jié)果:', resp)
31 except TimeoutError:
32 # 如果超時(shí)就重新調(diào)用一次
33 print('重試一次')
34 resp = self.requestOutofSystem(card_num, amount)
35
36 if resp == 200:
37 # 返回第三方支付成功,則進(jìn)行系統(tǒng)里面的扣款并記錄支付記錄等操作
38 print("{0}支付{1}成功!??!進(jìn)行扣款并記錄支付記錄".format(user_id, amount))
39 return 'success'
40
41 elif resp == 500:
42 # 返回第三方支付失敗,則不進(jìn)行扣款
43 print("{0}支付{1}失敗?。〔贿M(jìn)行扣款?。?!".format(user_id, amount))
44 return 'fail'
45
46 # 單元測(cè)試類(lèi)
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 # 模擬第三方支付接口首次支付超時(shí),重試第二次成功
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 # 模擬第三方支付接口首次支付超時(shí),重試第二次失敗
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)
也許有小伙伴會(huì)問(wèn),第三方支付都不能用,我們的測(cè)試結(jié)果是否是有效的呢?
通常在測(cè)試一個(gè)模塊的時(shí)候,是可以認(rèn)為其他模塊的功能是正常的,只針對(duì)目標(biāo)模塊進(jìn)行測(cè)試是沒(méi)有任何問(wèn)題的,所以說(shuō)測(cè)試結(jié)果也是正確的
mock裝飾器
一共兩種格式
?@patch('module名字.方法名')?
?@patch.object(類(lèi)名, '方法名')?
1 # 裝飾類(lèi)演示
2 from mock import Mock, patch
3
4
5 # 單獨(dú)的相乘函數(shù)
6 def multiple(a, b):
7 return a * b
8
9
10 # 單獨(dú)的捕獲Exception函數(shù)
11 def is_error():
12 try:
13 os.mkdir("11")
14 return False
15 except Exception as e:
16 return True
17
18
19 # 計(jì)算類(lèi),包含add方法
20 class calculator(object):
21 def add(self, a, b):
22 return a + b
23
24
25 # 裝飾類(lèi)演示 - 單元測(cè)試類(lèi)
26 class TestProducer(unittest.TestCase):
27
28 # case執(zhí)行前
29 def setUp(self):
30 self.calculator = calculator()
31
32 # mock一個(gè)函數(shù),注意也要指定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一個(gè)類(lèi)對(duì)象的方法
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調(diào)用方法返回多個(gè)不同的值
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的函數(shù)拋出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多個(gè)函數(shù),注意函數(shù)調(diào)用順序
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)
感謝每一個(gè)認(rèn)真閱讀我文章的人,禮尚往來(lái)總是要有的,雖然不是什么很值錢(qián)的東西,如果你用得到的話可以直接拿走:
這些資料,對(duì)于【軟件測(cè)試】的朋友來(lái)說(shuō)應(yīng)該是最全面最完整的備戰(zhàn)倉(cāng)庫(kù),這個(gè)倉(cāng)庫(kù)也陪伴上萬(wàn)個(gè)測(cè)試工程師們走過(guò)最艱難的路程,希望也能幫助到你!有需要的小伙伴可以點(diǎn)擊下方小卡片領(lǐng)取?文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-737414.html
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-737414.html
到了這里,關(guān)于自動(dòng)化測(cè)試mock模塊使用詳解介紹的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!