python接口自动化接口依赖_Python接口自动化之mock模块简单使用
mock簡介
mock原是python的第三方庫,python 2可以直接安裝mock模塊,但在python 3.3以后mock模塊已經整合到了unittest測試框架中,不需要再單獨安裝。
Mock這個詞在英語中有模擬的這個意思,因此我們可以猜測出這個庫的主要功能是模擬一些東西。準確的說,Mock是Python中一個用于支持單元測試的庫,它的主要功能是使用mock對象替代掉指定的Python對象,以達到模擬對象的行為。簡單的說,mock庫用于如下的場景:假設你開發的一個api在工作的時候需要調用發送請求給特定的服務器來得到一個JSON返回值,然后根據這個返回值來做處理。如果要為該API寫一個單元測試,該如何做?
一個簡單的辦法是搭建一個測試的服務器,在單元測試的時候,讓該API和這個測試服務器交互。但是這種做法有兩個問題:
1、測試服務器可能很不好搭建,或者搭建效率很低。
2、你搭建的測試服務器可能無法返回所有可能的值,或者需要大量的工作才能達到這個目的。
那么如何在沒有測試服務器的情況下進行上面這種情況的單元測試呢?Mock模塊就是答案。因為mock模塊可以替換Python對象,返回值能夠由我們的mock對象來決定,而不需要服務器的參與。
mock作用:
1. 解決依賴問題:當我們測試一個接口或者功能模塊的時候,如果這個接口或者功能模塊依賴其他接口或其他模塊,那么如果所依賴的接口或功能模塊未開發完畢,那么我們就可以使用mock模擬被依賴接口,完成目標接口的測試
2. 單元測試:如果某個功能未開發完成,我們又要進行測試用例的代碼編寫,我們也可以先模擬這個功能進行測試
3. 模擬復雜業務的接口:實際工作中如果我們在測試一個接口功能時,如果這個接口依賴一個非常復雜的接口業務,那么我們完全可以使用mock來模擬這個復雜的業務接口,其實這個和解決接口依賴是一樣的原理
4.前后端聯調:如果你是一個前端頁面開發,現在需要開發一個功能:根據后臺返回的狀態展示不同的頁面,那么你就需要調用后臺的接口,但是后臺接口還未開發完成,是不是你就停止這部分工作呢?答案是否定的,你完全可以借助mock來模擬后臺這個接口返回你想要的數據
Mock的安裝和導入
1、在Python 3.3以前的版本中,需要另外安裝mock模塊,可以使用pip命令來安裝:pip install mock
然后在代碼中就可以直接import進來:import mock
2、從Python 3.3開始,mock模塊已經被合并到標準庫中,被命名為unittest.mock,可以直接import進來使用:from unittest import mock
Mock對象
Mock對象是mock模塊中最重要的概念。Mock對象就是mock模塊中的一個類的實例,這個類的實例可以用來替換其他的Python對象,來達到模擬的效果。Mock類的定義如下:classMock(spec=None, side_effect=None, return_value=DEFAULT, wraps=None, name=None, spec_set=None, **kwargs)
Mock對象的一般用法是這樣的:
1、找到你要替換的對象,這個對象可以是一個類,或者是一個函數,或者是一個類實例。
2、然后實例化Mock類得到一個mock對象,并且設置這個mock對象的行為,比如被調用的時候返回什么值,被訪問成員的時候返回什么值等。
3、使用這個mock對象替換掉我們想替換的對象,也就是步驟1中確定的對象。
4、之后就可以開始寫測試代碼,這個時候我們可以保證我們替換掉的對象在測試用例執行的過程中行為和我們預設的一樣。
mock實例及基本用法
一個未開發完成的功能如何測試?假如們現在有一個實現兩個數相加的功能需要編寫測試用例,但是由于開發進度緩慢,只搭兩個簡單的框架,并沒有內部實現。import unittest
from unittest import mock
class SubClass(object):
def add(self, a, b):
"""兩個數相加"""
pass
class TestSub(unittest.TestCase):
"""測試兩個數相加用例"""
def test_sub(self):
sub = SubClass()? # 初始化被測函數類實例
sub.add = mock.Mock(return_value=10)? # mock add方法 返回10
result = sub.add(5, 5)? # 調用被測函數
self.assertEqual(result, 10)? # 斷言實際結果和預期結果
if __name__ == '__main__':
unittest.main()
測試結果:----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Process finished with exit code
測試結果顯示,測試用例執行通過了。
實際上mock模擬add方法的原理是 使用相同的對象方法接收mock的對象(使用sub.add接收),那么當mock對象被調用時(sub.add())就會返回return_value參數對應的數據
稍微高級的用法
1、class Mock的參數
上面講的是mock對象最基本的用法。下面來看看mock對象的稍微高級點的用法
先來看看Mock這個類的參數,在上面看到的類定義中,我們知道它有好幾個參數,這里介紹最主要的幾個:
name: 這個是用來命名一個mock對象,只是起到標識作用,當你print一個mock對象的時候,可以看到它的name。
return_value: 這個我們剛才使用過了,這個字段可以指定一個值(或者對象),當mock對象被調用時,如果side_effect函數返回的是DEFAULT,則對mock對象的調用會返回return_value指定的值。
side_effect: 這個參數指向一個可調用對象,一般就是函數。當mock對象被調用時,如果該函數返回值不是DEFAULT時,那么以該函數的返回值作為mock對象調用的返回值。
上面的例子,我們把用例的代碼修改一句如下:class TestSub(unittest.TestCase):
"""測試兩個數相加"""
def test_sub(self):
sub = SubClass()? # 初始化被測函數類實例
sub.add = mock.Mock(return_value=10, side_effect=sub.add)? # 傳遞side_effect關鍵字參數, 會覆蓋return_value參數值, 使用真實的add方法測試
result = sub.add(5, 11)? # 真正的調用被測函數
self.assertEqual(result, 16)? # 斷言實際結果和預期結果
代碼中我們給Mock方法添加了另一個關鍵字參數side_effect = sub.add, 這個參數和return_value 正好相反,當傳遞這個參數的時候return_value 參數就會失效
而side_effect生效,這里我給的參數值是sub.add 相當于add方法的地址,那么當調用add方法時就會真實的使用add方法,也就達到了我們測試實際的add 方法。
你也可以理解為當傳遞了side_effect參數且值為被測方法地址時,mock就不會起作用
side_effect接收的是一個可迭代序列,當傳遞多個值時,那么每次調用mock時會返回不同的值mock_obj = mock.Mock(side_effect= [1,2,3])
print(mock_obj())
print(mock_obj())
print(mock_obj())
print(mock_obj())
輸出
Traceback (most recent call last):
1
File "D:/MyThreading/mymock.py", line 37, in
2
print(mock_obj())
3
File "C:\Python36\lib\unittest\mock.py", line 939, in __call__
return _mock_self._mock_call(*args, **kwargs)
File "C:\Python36\lib\unittest\mock.py", line 998, in _mock_call
result = next(effect)
StopIteration
Process finished with exit code 1
當所有值被取完后就會報錯(這個地方有點類似生成器的原理)
2、mock對象的自動創建
當訪問一個mock對象中不存在的屬性時,mock會自動建立一個子mock對象,并且把正在訪問的屬性指向它,這個功能對于實現多級屬性的mock很方便。
client= mock.Mock()client.v2_client.get.return_value ='200'
這個時候,你就得到了一個mock過的client實例,調用該實例的v2_client.get()方法會得到的返回值是"200"。
從上面的例子中還可以看到,指定mock對象的return_value還可以使用屬性賦值的方法。
存在依賴關系的功能如何測試?
假設有這樣一個場景:我們要測試一個支付接口但是這個支付接口又依賴一個第三方支付接口,那么第三方支付接口我們暫時沒有權限使用,那么我們該如何測試我們自己這個接口呢?
看下面的實例,假設第三方接口和我們自己的支付接口如下:import requests
class PayApi(object):
@staticmethod
def auth(card, amount):
"""
第三方支付接口
:param card: 卡號
:param amount: 支付金額
:return:
"""
pay_url = "http://www.zhifubao.com"? # 第三方支付接口地址
data = {"card": card, "amount": amount}
response = requests.post(pay_url, data=data)? # 請求第三方支付接口
return response? # 返回狀態碼
def pay(self, user_id, card, amount):
"""
我們自己的支付接口
:param user_id: 用戶id
:param card: 卡號
:param amount: 支付金額
:return:
"""
# 調用第三方支付接口
response = self.auth(card, amount)
try:
if response['status_code'] == '200':
print('用戶{}支付金額{}成功'.format(user_id, amount))
return '支付成功'
elif response['status_code'] == '500':
print('用戶{}支付失敗, 金額不變'.format(user_id))
return '支付失敗'
else:
return '未知錯誤'
except Exception:
return "Error, 服務器異常!"
if __name__ == '__main__':
pass
很明顯第三方支付接口是無法訪問的,因為接口的地址是我DIY的,為了模擬實際中我們無法使用的第三方支付接口。編寫測試用例如下:import unittest
from unittest import mock
from payment.PayMent import PayApi
class TestPayApi(unittest.TestCase):
def test_success(self):
pay = PayApi()
pay.auth = mock.Mock(return_value={'status_code':'200'})
status = pay.pay('1000', '12345', '10000')
self.assertEqual(status, '支付成功')
def test_fail(self):
pay = PayApi()
pay.auth = mock.Mock(return_value={'status_code':'500'})
status = pay.pay('1000', '12345', '10000')
self.assertEqual(status, '支付失敗')
def test_error(self):
pay = PayApi()
pay.auth = mock.Mock(return_value={'status_code':'300'})
status = pay.pay('1000', '12345', '10000')
self.assertEqual(status, '未知錯誤')
def test_exception(self):
pay = PayApi()
pay.auth = mock.Mock(return_value='200')
status = pay.pay('1000', '12345', '10000')
self.assertEqual(status, 'Error, 服務器異常!')
if __name__ == '__main__':
unittest.main()
測試輸出結果:....用戶1000支付失敗, 金額不變
用戶1000支付金額10000成功
----------------------------------------------------------------------
Ran 4 tests in 0.001s
OK
Process finished with exit code 0
從執行結果可以看出,即使第三方支付接口無法使用,但是我們自己的支付接口仍然測試通過了。也許有人會問,第三方支付都不能用,我們的測試結果是否是有效的呢?通常我們在測試一個模塊的時候,我們是可以認為其他模塊的功能是正常的,只針對目標模塊進行測試是沒有任何問題的,所以說測試結果也是正確的。
總結
以上是生活随笔為你收集整理的python接口自动化接口依赖_Python接口自动化之mock模块简单使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python 数组赋值_LeetCode
- 下一篇: python 没找到库_这十个Pytho