Mock技术的使用

Mock是什么

  • 在软件测试过程中,对一些不容易构造、获取的对象,用一个虚拟的对象来替代它,以达到相同的效果,这个虚拟的对象就是Mock。
  • 在前后端分离项目中,当后端工程师还没有完成接口开发的时候,前端开发工程师利用Mock技术,自己用mock技术先调用一个虚拟的接口,模拟接口返回的数据,来完成前端页面的开发。
  • 接口测试和前端开发有一个共同点,就是都需要用到后端工程师提供的接口。所以,当我们做接口测试的时候,如果后端某些接口还不成熟、所依赖的接口不稳定或者所依赖的接口为第三方接口、构造依赖的接口数据太复杂等问题时,我们可以用mock的方式先虚拟这些接口返回来代替,提高工作效率。

 

Mock的介绍

  • 实现mock的技术很多,这些技术中,可以分为两类,mock数据和mock服务
    • mock数据:即mock一个对象,写入一些预期的值,通过它进行自己想要的测试。常见有:EasyMock、Mockito、WireMock、JMockit,主要适用单元测试。
    • mock服务:即mock一个sever,构造一个依赖的服务并给予他预期的服务返回值,适用范围广,更加适合集成测试,如:moco框架。
  • Moco是类似一个Mock的工具框架,一个简单搭建模拟服务器的程序库/工具,下载就是一个JAR包,有如下特点
    • 只需要简单的配置request、response等即可满足要求
    • 支持http、https、socket协议,可以说是非常的灵活性
    • 支持在request中设置Headers,Cookies,StatusCode等
    • 对GET、POST、PUT、DELETE等请求方式都支持
    • 无需环境配置,有Java环境即可
    • 修改配置后,立刻生效。只需要维护接口,也就是契约即可
    • 支持多种数据格式,如JSON、Text、XML、File等
    • 可与其他工具集成,如Junit、Maven等,

 

 Mock环境的搭建步骤

[
  {
    "description": "demo",
    "request": {
      "uri": "/demo1"
    },
    "response": {
      "text": "Hello,demo1"
    }
  }
]
  • 接着,在有Java环境的机器上通过指定json文件启动mock服务,启动命令:java -jar moco-runner-1.1.0-standalone.jar http -p 8888 -c test.json
  • 最后,请求接口查看返回数据,访问地址:http://ip:8888/demo1

 

Mock模拟不同的请求接口

1、约定GET请求方式接口并指定参数

[
  {
    "description": "GET请求,并定义了请求参数,使用queries",
    "request": {
      "uri": "/request-get",
      "method": "GET",
      "queries": {
        "key1": "abc",
        "key2": "123"
      }
    },
    "response": {
      "headers": {
        "Content-Type": "text/plain;charset=utf-8"
      },
      "text": "Hello,这是第一个mock的Get请求接口!!!"
    }
  }
]
def mock_get() -> None:
    """
    description: mock模拟get请求,需要使用已经定义的请求参数
    :return: None
    """
    # 构建请求url,请求参数
    url = f"{MOCK_HOST}/request-get"
    param = {
        "key1": "abc",
        "key2": "123"
    }
    response = requests.get(url=url, params=param)
    print(response.text)

输出结果:Hello,这是第一个mock的Get请求接口!!!

2、约定POST请求方式接口并指定参数(表单格式:forms)

[
    {
        "description": "POST请求,并定义请求参数form格式,使用forms",
        "request": {
          "uri": "/request-post",
          "method": "POST",
          "forms": {
            "key1": "ABC"
          }
        },
        "response": {
          "headers": {
            "Content-Type": "text/plain;charset=utf-8"
          },
          "text": "Hello,这是第一个mock的Post请求接口!!!"
        }
    }
]
def mock_post_forms() -> None:
    """
    description: mock模拟post请求,使用自定义请求参数(表单格式)
    :return: None
    """
    # 构建请求url,请求参数
    url = f"{MOCK_HOST}/request-post"
    forms = {
        "key1": "ABC"
    }
    response = requests.post(url=url, data=forms)
    print(response.text)

输出结果:Hello,这是第一个mock的Post请求接口!!!

3、约定POST请求方式接口并指定参数(JSON格式:json)

[
    {
        "description": "POST请求,并定义请求参数json格式,使用json",
        "request": {
          "uri": "/request-post-json",
          "method": "POST",
          "json": {
            "key1": "aaa"
          }
        },
        "response": {
          "headers": {
            "Content-Type": "application/json;charset=utf-8"
          },
          "status": 200,
          "json": {
            "key1": "aaa,post json!"
          }
        }
      }
]
def mock_post_json() -> None:
    """
    description: mock模拟post请求,使用自定义请求参数(json格式)
    :return: None
    """
    # 构建请求url,请求参数
    url = f"{MOCK_HOST}/request-post-json"
    json = {
        "key1": "aaa"
    }
    response = requests.post(url=url, json=json)
    response.encoding = 'unicode_escape'
    print(response.json())

输出结果:{'key1': 'aaa,post json!'}

4、约定重定向接口

[
    {
        "description": "模拟重定向接口",
        "request": {
          "method": "GET",
          "uri": "/redirect"
        },
        "redirectTo": "https://www.baidu.com/"
    }
]

访问地址:http://ip:8888/redirect,会重定向到“https://www.baidu.com”

5、约定URI的“uri-startsWith”开始匹配

[
    {
        "description": "约定uri-startsWith匹配",
        "request": {
            "uri": {
                "startsWith": "/sq"
            }
        },
        "response": {
            "text": "Hello,uri-startWith!!!"
        }
    }
]

访问地址:http://ip:8888/sqxxx,都可以访问该请求

6、约定URI的“uri-endWith”结束匹配

[
    {
        "description": "约定uri-endsWith匹配",
        "request": {
            "uri": {
                "endsWith": "sq"
            }
        },
        "response": {
            "text": "Hello,uri-endWith!!!"
        }
    }
]

访问地址:http://ip:8888/xxxsq,都可以访问该请求

7、约定URI的“uri-contain”包含匹配

[
    {
        "description": "约定uri-contain匹配",
        "request": {
            "uri": {
                "contain": "sq"
            }
        },
        "response": {
            "text": "Hello,uri-contain!!!"
        }
    }
]

访问地址:http://ip:8888/xxsqxxx,都可以访问该请求

8.约定URI的返回状态码

 [
    {
        "description": "约定响应状态码",
        "request": {
            "uri": "/return_code"
        },
        "response": {
            "status": 200
        }
    }
]

访问地址:http://ip:8888/return_code,接口返回相应的状态码

 

Python请求Mock模拟的接口示例

  • mock定义了请求的参数和返回值,如果请求的参不是预定的值,就无法请求成功
[
    {
        "description": "支付接口",
        "request": {
            "headers": {
                "Content-Type": "application/json"
            },
            "json": {
                "auth_code": "28763443825664394",
                "buyer_id": "2088202954065786",
                "out_trade_no": "20150320010101001",
                "seller_id": "2088102146225135",
                "subject": "Iphone6",
                "total_amount": "88.88"
            },
            "method": "POST",
            "uri": "/trade/purchase"
        },
        "response": {
            "headers": {
                "Content-Type": "application/json"
            },
            "json": {
                "code": "40004",
                "msg": "Business Failed",
                "out_trade_no": "6823789339978248",
                "sub_code": "ACQ.TRADE_HAS_SUCCESS",
                "sub_msg": "交易已被支付",
                "trade_no": "2013112011001004330000121536"
            }
        }
    }
]
def mock_post_pay() -> None:
    """
    description: mock模拟支付接口
    :return: None
    """
    # 构建请求url,请求参数
    url = f"{MOCK_HOST}/trade/purchase"
    json = {
        "out_trade_no": "20150320010101001",
        "auth_code": "28763443825664394",
        "buyer_id": "2088202954065786",
        "seller_id": "2088102146225135",
        "subject": "Iphone6",
        "total_amount": "88.88"
    }
    response = requests.post(url=url, json=json)
    print(response.json())

输出结果:

{
  "code": "40004",
  "msg": "Business Failed",
  "out_trade_no": "6823789339978248",
  "sub_code": "ACQ.TRADE_HAS_SUCCESS",
  "sub_msg": "交易已被支付",
  "trade_no": "2013112011001004330000121536"
}

 

posted @ 2020-08-19 20:54  零下一度的微笑  阅读(491)  评论(0编辑  收藏  举报