lyrebird 安装及简介
lyrebird 抓包、lyrebird mock功能
lyrebird 插件:lyrebird-android、lyrebird-ios、lyrebird-api-coverage、lyrebird-tracking

lyrebird简介

Lyrebird是美团-点评开源的功能强大的测试工具,是一个基于 mitmproxy(在之前的文章介绍过) 拦截及模拟 HTTP/HTTPS 网络请求的主要面向移动端的插件式测试平台,主要功能如下:

  • 移动端HTTP/HTTPS网络抓包
  • 提供 UI 操作,也可以通过 API 控制所有功能
  • Mock 功能及管理
  • 插件功能:通过插件扩展能力,实现埋点自动测试、API 覆盖率统计、移动设备及 APP 控制和信息记录、自定义检查脚本等一系列功能

lyrebird相关项目地址

lyrebird安装及其插件安装

  • lyrebird安装:pip install lyrebird (python>=3.6)
  • lyrebird安装:pip install lyrebird-android(lyrebird-ios、lyrebird-api-coverage、lyrebird-tracking插件安装方式相同,根据项目需要安装即可)
    • lyrebird-android:用于从Android设备获取信息
    • lyrebird-ios:从 iOS 设备获取信息
    • lyrebird-api-coverage:为客户端提供API维度测试覆盖评估方法
    • lyrebird-tracking:移动端应用提供服务请求的数据分析及验证的功能

lyrebird功能介绍

准备工作

  • 手机电脑局域网内,设置手机网络代理为电脑ip及端口为4272(默认端口)
  • 手机浏览器访问http://mitm.it(某些手机自带浏览器不能下载的,换个第三方浏览器试试),并选择对应操作系统安装证书

基本命令

  • lyrebird
    以缺省参数启动 lyrebird
  • lyrebird -v
    以输出详细日志模式启动 lyrebird
  • lyrebird -b
    启动 lyrebird 不默认打开浏览器
  • lyrebird --mock 9090 --proxy 4272 --data . --config your/config/file
    指定参数启动 lyrebird
    • --mock 默认9090 , mock服务及前端端口
    • --proxy 默认4272, 代理服务端口
    • --data 默认./data, mock数据根目录
    • --config 默认~/.lyrebird/conf.json, lyrebird启动配置

移动端HTTP/HTTPS网络抓包

  • 手机设置wifi代理并安装证书即可能正常抓到http/https包了
  • 界面比较简洁清新
  • 抓包功能类似于mitmweb

Mock功能及管理

  1. datemanager - add group
  2. inspector - 选中某一需要mock的请求 - Activated Mock Group中选择刚才创建的group - 保存
  3. 切换到datemanager - 发现改请求已经被添加到了group中
  4. 修改对应的responsedate(即需要mock的数据)
  5. 再次发起相同的请求,则该请求的结果则被mock了(如上图被标记)

lyrebird插件

  • lyrebird-android,lyrebird-ios个人感觉没啥用,一个设备相关信息与操作相关的界面
  • lyrebird-api-coverage:为客户端提供API维度测试覆盖评估方法,可结合自动遍历使用,达到activity 覆盖率和api 覆盖率的统计,多维度分析自动遍历的效果
  • lyrebird-tracking:移动端应用提供服务请求的数据分析及验证的功能。主要用于客户端发送数据的校验,项目中举例的是客户端发送的埋点数据的校验。当前工作中对单一发送数据校验的场景较少,也可用类似httprunner直接对接口请求和响应进行校验

LyrebirdMockServer源码

from flask import Flask, redirect, url_for
from . import context
from .blueprints.apis import api
from .blueprints.ui import ui
from .blueprints.core import core
from flask_socketio import SocketIO
from ..version import VERSION
from lyrebird.base_server import ThreadServer
from lyrebird import application
from lyrebird import log


"""
Mock server

Lyrebird main server
Default port : 9090

* HTTP mock
* HTTP record
* Lyrebird UI
* Lyrebird API
* Lyrebird plugin management
"""

_logger = log.get_logger()


class LyrebirdMockServer(ThreadServer):
    """
    模拟接口服务
    使用flask在默认的9090端口启动,模拟线上接口,同时支持通过api动态修改接口数据。

    """

    def __init__(self):
        super().__init__()

        self.conf = application.config
        # TODO rm conf rom mock context
        context.application.conf = application.config

        self.debug = False
        self.port = 9090
        self._working_thread = None
        self.app = Flask('MOCK')

        self.app.env = 'development'

        # async_mode = threading / eventlet / gevent / gevent_uwsgi
        self.socket_io = SocketIO(self.app, async_mode='threading', logger=False, cors_allowed_origins='*')

        # 存储socket-io
        context.application.socket_io = self.socket_io
        application._socketio = self.socket_io

        # 生成过滤器实例
        if self.conf:
            self.port = self.conf.get('mock.port')
        else:
            _logger.error('Can not start mock server without config file')
            raise SyntaxError('Can not start mock server without config file.'
                              ' Default config file path = api-mock/conf.json')

        # Register blueprints
        self.app.register_blueprint(api)
        self.app.register_blueprint(core)
        self.app.register_blueprint(ui)

        @self.app.route('/')
        def index():
            """
            设置默认页面为UI首页
            """
            return redirect(url_for('ui.index')+f'?v={VERSION}')

    def run(self):
        server_ip = application.config.get('ip')
        _logger.warning(f'start on http://{server_ip}:{self.port}')
        self.socket_io.run(self.app, host='0.0.0.0', port=self.port, debug=self.debug, use_reloader=False)

    def stop(self):
        """
        停止服务

        """
        super().stop()
        try:
            self.socket_io.stop()
        except Exception:
            pass
        _logger.warning('MockServer shutdown')