Mock
本文举例讲解unittest中的mock
from unittest import mock
from pprint import pprint
pprint([i for i in dir(mock.Mock) if not ((i.startswith("_") or i.startswith("__")))])
- 从上面代码种可以得到Mock类有哪些方法
- 在日常工作中只需要掌握
return_value
和side_effect
两个参数
在日常工作中,往往需要对第三方接口,或者开发还未开发的接口,或者有些需要扣费的接口,不让我们调的接口等等。
在接口测试当中,我们又需要调这些接口怎么办?
unittest当中的Mock由此而生为我们解决这等问题。不让调的接口我们用假数据进行Mock掉。只要值符合接口文档即可。
- 新建一个unittest_mock文件夹
- 在此目录创建一个 payment.py 和 test_pay.py
- 模拟用户支付接口调用第三方支付宝接口
第三方支付宝接口,我们往往不能掉,因为需要花钱啊,你难道花钱去测试?
payment.py
import requests
class Payment:
"""
定义第三方支付类
"""
def auth(self, card_num, amount):
"""
请求第三方外部支付接口的方法, 返回响应状态码
:param card_num: 卡号
:param amount: 金额
:return: 返回状态码, 200 代表支付成功, 500 代表支付异常, 失败
"""
url = "http://第三方支付url.payment"
data = {"card_num": card_num, "amount": amount} # 请求参数
self.res = requests.post(url, data=data)
return self.res.status_code # 返回的状态码
def pay(self, user_id, card_num, amount):
"""
支付方法
:param user_id: 用户ID
:param card_num: 卡号
:param amount: 支付金额
:return:
"""
try:
status_code = self.auth(card_num, amount)
except TimeoutError:
status_code = self.auth(card_num, amount) # 如果支付超时, 再请求一次
if status_code == 200:
print("[{}]支付[{}]成功!!! 进行扣款并登记支付记录".format(user_id, amount))
return "success"
elif status_code == 500:
print("[{}]支付[{}]失败!!! 不进行扣款".format(user_id, amount))
return "Fail"
- 从上面可以看出 auth是第三方接口,我们如何mock掉,怎么测试呢?
test_pay.py
import unittest
from unittest import mock
from unittest_mock.payment import Payment
class PaymentTest(unittest.TestCase):
"""
测试支付接口
"""
def setUp(self):
self.payment = Payment()
def test_1_success(self):
"""
测试支付成功
:return:
"""
self.payment.auth = mock.Mock(return_value=200)
res = self.payment.pay(user_id=1001, card_num=12345678, amount=5000000)
self.assertEqual('success', res)
def test_2_fail(self):
"""
测试支付失败
:return:
"""
self.payment.auth = mock.Mock(return_value=500)
res = self.payment.pay(user_id=1001, card_num=12345678, amount=5000000)
self.assertEqual('Fail', res)
def test_3_retry_success(self):
"""
测试调用第三方接口超时之后, 再次支付成功
:return:
"""
self.payment.auth = mock.Mock(side_effect=[TimeoutError, 200])
res = self.payment.pay(user_id=1001, card_num=12345678, amount=5000000)
self.assertEqual('success', res)
def test_4_retry_fail(self):
"""
测试调用第三方接口超时之后, 再次支付失败
:return:
"""
# side_effect 第一次会得到列表第一个值抛出TimeoutError的异常,抛出异常payment.py里会再次调用第
# 三方支付接口auth,接着将列表第2个值 500返回给auth,pay函数里面代码判断 500 为失败 Fail.
# side_effect 参数可以等于另外一个函数 函数的返回值,作为Mock函数的返回值,例子这里就不举了。
self.payment.auth = mock.Mock(side_effect=[TimeoutError, 500])
res = self.payment.pay(user_id=1001, card_num=12345678, amount=5000000)
self.assertEqual('Fail', res)
if __name__ == '__main__':
unittest.main()
-
我们需要测的场景,一般有支付成功, 支付失败。支付超时,回调之后支付成功。支付超时,回调支付失败。其他网络异常支付成功未扣款这里暂时不讨论。先弄懂mock怎么去干这些事的。
-
self.payment.auth = mock.Mock(return_value=200)
return_value的值直接作为要mock掉的函数auth的返回值,之后无论在哪里调用,返回值都是200 -
side_effect=[TimeoutError, 200]
分两次给mock掉的函数auth传值,第一次传一个异常TimeoutError,第一次传 200给auth,请看pay函数的代码,超时会再掉一次。
当然side_effect也可以给函数名foo,要Mock的函数的返回值其实就是调用foo的函数值。 -
最后跑一下单元测试 看看结果
image.png
网友评论