美文网首页
使用mock模拟解决测试中依赖问题

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

作者: 测试星云 | 来源:发表于2019-06-13 19:29 被阅读0次

    应用场景

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

    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、影表

    相关文章

      网友评论

          本文标题:使用mock模拟解决测试中依赖问题

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