美文网首页
Mock:unittest

Mock:unittest

作者: 阿登20 | 来源:发表于2021-04-19 00:45 被阅读0次

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_valueside_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

相关文章

网友评论

      本文标题:Mock:unittest

      本文链接:https://www.haomeiwen.com/subject/ufmblltx.html