使用mock模拟解决测试中依赖问题

应用场景

我们开发应用也好、服务也好,常常需要依赖后端或者服务的接口或第三方接口,有时是没做好但需要返回数据进行前端调试,有时第三方接口是不方便总调用,但我们还希望知道我们确实调用了。

1、开发移动应用 App,可能后端接口还在开发中,这时 App 的开发因为无法调用后端,很不方便。
2、程序会依赖第三方的接口,例如微信支付,在本地开发时不能直接调用。

相关技术:

  • Stub 就是一个纯粹的模拟服务,用于替代真实的服务,收到请求返回指定结果,不会记录任何信息。
  • Mock 则更进一步,还会记录调用行为,可以根据行为来验证系统的正确性(断言)。
  • 这是源于单元测试,目前应用范围单元,集成,接口,功能(前后端,服务间,与第三方间,子功能间)测试中
    解决方案:
    1、使用代理工具fiddler/charles实现mock服务器
    2、使用mock解决(python)

mock的介绍:

  • unittest.mock是一个用于在Python中进行测试的库。它允许您使用模拟对象替换受测试系统的部分,检查调用并对如何使用它们进行断言。

  • unittest.mock提供了一个核心Mock类,还有MagicMock。

  • 执行操作后,您可以断言使用哪些方法/属性以及调用它们的参数。

  • 您还可以指定返回值并以正常方式设置所需属性。

  • mock的patch()装饰器,用于处理测试范围内的修补模块和类级属性。

  • [https://docs.python.org/3/library/unittest.mock.html]

实现例子:

设置返回值和属性
mock object对象的返回值

mock = Mock()
mock.return_value = 3
mock()

methods 具体方法返回值

mock.something.return_value = 3
mock.something()

attribute setting 属性的设置

mock.x =5
mock.x

通过构造方法-传参的方式

mock = Mock(return_value=3)
mock()

多次不同返回值,及顺序

Mock.side_effect=(200,404,302,500)

mock_calls是跟踪是否被调用
assert_called_with()是断言是否调用的这个参数
assert_called_once_with()是断言是否只调用一次
对已有的类实例使用patch临时改变返回值
dnd.py

from random import randint


def attack_damage(modifier):
    roll = randint(1, 8)
    return modifier + roll

test_dnd.py

from dnd import attack_damage
from unittest import mock
import pytest


@mock.patch("dnd.randint", return_value=5, autospec=True)
def test_attack_damage(mock_randint):
    assert attack_damage(1) == 6
    print(mock_randint.mock_calls)
    mock_randint.assert_called_with(1,8)


if __name__ == '__main__':
    pytest.main(['-s', '-v', 'test_dnd.py'])

实际应用:

单元测试中的应用
shot_tweeter.py

def tweet(api, message):
    if len(message) > 40:
        message = message.strip(",.!?")
    if len(message) > 40:
        message = message.replace('and','&')
    status = api.PostUpdate(message)
    return status

test_shot_tweeter.py

import unittest
from unittest.mock import Mock
import shot_tweeter


class TestTweet(unittest.TestCase):
    def test_example(self):
        mock_twitter = Mock()
        shot_tweeter.tweet(mock_twitter, "message and")
        mock_twitter.mock_calls
        mock_twitter.PostUpdate.assert_called_with("message &")

    def test_example2(self):
        mock_twitter = Mock()
        shot_tweeter.tweet(mock_twitter, "message")
        mock_twitter.mock_calls
        mock_twitter.PostUpdate.assert_called_with("message")


if __name__ == '__main__':
    unittest.main()

接口测试mock实例
users.py

import requests

BASE_URL = "http://reqres.in"


class Users:
    def list_users(self):
        resp = requests.get(BASE_URL+'/api/users?page=2')
        return resp

test_users.py

from users import Users
import unittest
from unittest.mock import patch


class TestUsers(unittest.TestCase):
    @patch('users.Users.list_users')
    def test_user_set(self, mock_list_users):
        mock_list_users.return_value.status_code = 200
        mock_list_users.return_value.json.return_value = {"data":[
            {"id":4,
             "email":"eve.holt@reqres.in",
             "first_name":"Eve1",
             "last_name":"Holt",
             "avatar":"https://s3.amazonaws.com/uifaces/faces/twitter/marcoramires/128.jpg"
             }]}
        u = Users()
        resp = u.list_users()
        assert resp.status_code == 200
        self.assertEqual(resp.json()['data'][0]['first_name'],'Eve')


if __name__ == '__main__':
    unittest.main()

mock扩展应用-性能测试解决方案之一

进行子服务的压力测试方案
1、直接使用线上的后端服务进行压测:优点是近线上状态,代价极小;缺点是线上子服务的稳定性,数据统计,引入脏数据等;
2、部署完整的后端测试环境:优点是与线上隔离;测试结果基本与线上环境一致,测试结果相对准确;缺点是部署成本极高;要保证子服务性能的会造成资源浪费。
3、部署部分子服务:优点是与线上隔离;部署成本相对较小;缺点是测试结果有出入,后端性能可能是瓶颈。
4、使用测试平台mock后端接口数据:优点与线上隔离;缺点是mock平台一般性能较弱,测试结果有出入;mock平台的逻辑规则会有一定的学习成本。(可以通过django写的mock服务)
5、使用nginx cache mock子服务返回内容:优点是与线上隔离;子服务返回内容与线上一致;可保证后端性能不是瓶颈;缺点是必须使用固定的一组请求(请求数量在几万的量级没问题)
6、影表

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,635评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,543评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,083评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,640评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,640评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,262评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,833评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,736评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,280评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,369评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,503评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,185评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,870评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,340评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,460评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,909评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,512评论 2 359

推荐阅读更多精彩内容