某物业项目测试方案

背景介绍

项目:XXX物业服务项目

项目介绍:致力于打造数字物业和智慧物业,科技赋能物业日常管理工作,XXX物业服务平台作为支撑各智慧园区的基础信息平台,用于广泛连接各种硬件设备、应用系统、第三方物联网平台,为上层业务应用提供统一、规范的设备数据。

业务介绍

产品主要分为两个部分:

用户使用智慧园区app提供的各功能服务。主要功能为用户通过app使用各种物业服务,例如二位码通行、停车包月、场地预定等功能。

物业人员使用物业服务平台管理智慧园区,主要用途为园区管理、用户管理、智能设备管理、运营管理等。

架构介绍

image

测试方案

测试痛点1解决方案

痛点:

目前公司的自动化只有接口自动化,没有ui自动化和app自动化,每次新功能测试时还要手工回归很多场景,耗费了很多人力和时间。

解决方案:

根据在学院所学的ui自动化和app自动化的知识体系,搭建基于python的ui自动化测试框架和app自动化测试框架,筛选ui和app需要实现自动化测试的场景和用例,逐步完善ui和app自动化测试。项目框架目录如下:

image

image

技术总结:

使用python+pytest+selenium/appium+allure的技术架构,采用pageobject设计思想分别封装业务功能模块和非业务功能模块,依托了pytest的用例分发和执行优势,并且实现了参数化和数据驱动,输出详细的用例运行日志并能输出用例执行报表。

测试痛点2解决方案

痛点:

目前公司的接口自动化测试用例迁移到了开源平台metersphere上去了,冒烟测试和回归测试都需要到此平台上操作,尤其是每个迭代的冒烟测试,需要给研发人员提供账号让研发去平台上实施和确认冒烟的流程,十分繁杂,时间久了执行效果很差。

解决方案:

每个研发人员都有Jenkins账号,考虑通过将metersphere平台上的测试任务集成到Jenkins上,通过Jenkins工程触发测试任务执行,简化操作流程,降低研发人员学习成本和操作成本,提高整个团队的工作效率。

技术总结与介绍:

方案一:自由风格job

1、在metersphere中创建测试计划

在测试计划中创建项目对应的测试计划,并将接口自动化用例关联到测试计划中。

2、在个人信息中获取api key和secret key
image

image

3、插件下载及安装

要想实现在 Jenkins 中完成 MeterSphere 自动化接口测试,需要在 Jenkins 上安装 MeterSphere 提供的 Jenkins 插件。

插件下载地址: Releases · metersphere/jenkins-plugin · GitHub

下载对应版本的 hpi 包,在 Jenkins 的插件管理页面,上传并安装下载好的 hpi 插件包

注意:上传插件包后需要重启Jenkins才能安装成功

4、Jenkins 构建任务

插件安装后,在指定的 Jenkins 构建任务中,添加「MeterSphere」类型的构建步骤
image

通过配置 MeterSphere 认证信息,并指定需要触发执行的接口测试、性能测试或测试计划。
image

方案二:流水线pipeline

前三个步骤与方案一一样,仅步骤四Jenkins任务类型不同。

Metersphere 提供的pipeline script模板:

pipeline {
    agent any //任意选择
    // agent { label 'local-host'}   //指定agent
    stages {
        stage('Build') {
            steps{
                echo "building"
            }
        }
        stage('Deploy') {
            steps{
                echo "deploying"
            }
        }
        stage('Test') {
            steps{
                 script {
                    meterSphere msEndpoint:'http://XXXX',
                    msAccessKey:'XXXXXX',
                    msSecretKey:'XXXXXX',
                    workspaceId:'XXXXXX',
                    projectId:'XXXXXX',
                    method:'testPlan',
                    testPlanId:'XXXXXX',
                    mode:'parallel',
                    resourcePoolId:'',
                    result:'metersphere'
                }
            }  
        }
    }
}

其中MeterSphere插件共提供了以下参数供用户进行配置:

msEndpoint:MeterSphere服务地址(例如:https://demo.metersphere.com);
msAccessKey:MeterSphere上某个用户的API Access Key;
msSecretKey:上述Access Key对应的Secret Key;
workspaceId:需要触发执行的测试所在的工作空间id;
projectId:需要触发执行的测试所在的项目id;
method:触发执行的任务类型(testplan:执行整个测试计划,single:执行指定的某个测试任务);
testPlanId:测试计划id,method参数值为testplan时有效;
testCaseId:场景id/接口用例id/性能测试id,method参数值为single时有效;
mode:执行方式(serial:串行执行,parallel:并行执行);
resourcePoolId:执行测试使用的测试资源池id。
image

其中,workspaceId、projectId和testPlanId需要到metersphere平台测试计划页,利用F12查看页面请求参数获得。
image

方案效果:

方案一效果:

job执行成功,并且有链接跳转到metersphere报告页面,可行性验证成功。

image

方案二效果:

流水线job执行成功,并且有链接跳转到metersphere报告页面,可行性验证成功。

image

image

测试报告:

image

测试痛点3解决方案

痛点:

据项目数据统计,线上很多导致服务不可用的生产事故可能都因调用第三方接口返回异常、阻塞所致的。在测试过程中,我们无法控制第三方系统的接口返回情况,测试往往只会验证正常测试场景,异常场景很少涉及。还有有一些场景很难通过正常的测试流程测试,或者直接测试的成本很高,例如重复支付、支付失败或者支付巨大金额等等。

解决方案:

将一些较难构造的数据或者第三方相关接口返回的数据使用mock服务替代。在测试过程中,可以更多的模拟数据异常场景和第三方接口异常场景,将异常风险情况在测试环境提前验证。

技术总结与介绍:

经过调研发现mitmproxy工具比较合适用来做mock测试,不同于fiddler、Charles等工具,mitmproxy不仅可以截获请求实现rewrite、maplocal等常规操作,还可以通过载入自定义python脚本实现修改http链接、修改请求和响应内容等行为,写好的脚本可以沉淀下来方便其他人和团队使用,测试场景更加丰富且效率更高。而且,mitmproxy库是由python开发的,也方便了以后二次开发的需求。

一、安装mitmproxy

注意:要求python必须是3.6以上的版本
安装命令:pip install mitmproxy
安装之后需要配置环境变量:安装成功的提示中会给出需要配置的目录,将其配置到path环境变量中重启cmd即可。
可以使用mitmdump --version命令验证是否安装成功。

二、mitmproxy工具介绍

mitmproxy工具其实是由三个工具组成的:
mitmproxy ->命令行工具(Windows不支持)
mitmweb ->web界面工具
mitmdump ->可以加载Python脚本

mitmweb提供界面操作,跟charles类似但不如charles强大,这里主要是使用mitmdump工具。命令行中直接执行mitmdump命令,默认监听的是8080端口,也可以加-p参数指定其他端口,使用-s参数可以指定运行的脚本。
image

三、安装证书
电脑或者移动端设置代理为本机ip+8080,浏览器中输入mitm.it,选择相应端的证书下载安装即可。
image

四、脚本语法规则
根据官方提供的事件模板,定制化修改相应的请求和响应内容,以下方法名称是固定的不能随意更改。
官方部分常用模板:

"""HTTP-specific events."""
import mitmproxy.http
class Events:
    def http_connect(self, flow: mitmproxy.http.HTTPFlow):
        """
            An HTTP CONNECT request was received. Setting a non 2xx response on
            the flow will return the response to the client abort the
            connection. CONNECT requests and responses do not generate the usual
            HTTP handler events. CONNECT requests are only valid in regular and
            upstream proxy modes.
        """
    def requestheaders(self, flow: mitmproxy.http.HTTPFlow):
        """
            HTTP request headers were successfully read. At this point, the body
            is empty.
        """
    def request(self, flow: mitmproxy.http.HTTPFlow):
        """
            The full HTTP request has been read.
        """
    def responseheaders(self, flow: mitmproxy.http.HTTPFlow):
        """
            HTTP response headers were successfully read. At this point, the body
            is empty.
        """
    def response(self, flow: mitmproxy.http.HTTPFlow):
        """
            The full HTTP response has been read.
        """
    def error(self, flow: mitmproxy.http.HTTPFlow):
        """
            An HTTP error has occurred, e.g. invalid server responses, or
            interrupted connections. This is distinct from a valid server HTTP
            error response, which is simply a response with an HTTP error code.
        """

根据官方插件开发的教程得出以下结论:

名称 命名要求 类型 用途
类名 任意命名 class 插件实例
addons 必须为addons list 记录多个插件(任务列表)

示例:
新建addons.py文件并写入以下内容:

import mitmproxy.http
from mitmproxy import ctx

class Counter:
    def request(self, flow: mitmproxy.http.HTTPFlow):
        ctx.log.info('白色标准输出:{}'.format(flow.request.url))
        ctx.log.warn('黄色警告输出:{}'.format(flow.request.url))
        ctx.log.error('红色异常输出:{}'.format(flow.request.url))

    def response(self, flow: mitmproxy.http.HTTPFlow):
        print(flow.response.status_code)#获取网页状态码
        
addons = [
    Counter()
]

随后在终端输入mitmdump -s addons.py -p 8888启动插件

新建http_demo.py文件并写入以下内容:

import requests
headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36'
}
proxies = {
    'http':'127.0.0.1:8080',
    'https':'127.0.0.1:8080',
}
url = 'https://www.baidu.com'
html = requests.get(url,headers=headers,proxies = proxies,verify=False)
print(html.status_code)

在终端输入python http_demo.py运行Python文件

实现效果如下,在请求时以不同的日志级别打印请求url
image

方案效果:

项目的实际测试需求是业主进出小区是需要刷二维码通行的,由于当前疫情管控需要以及智慧管理数字化的目标,现将通行二维码对接健康码状态,健康码绿码业主能正常获取通行二维码并通行,健康码黄码/红码业主不能获取通行二维码无法进出小区。

因为健康码状态是从房管局接口获取的返回值信息,正常情况下测试只有绿码场景能够覆盖,不好测试黄码和红码情况。通过编写mitmdump插件脚本,修改第三方接口返回的响应信息,模拟健康码黄码/红码以及返回结果为空的场景,测试通行码应用结果是否符合预期,应用返回结果截图如下。

其中发现问题,当房管局接口返回为空时,应用返回通行码不可用,而此时可能是房管局自身接口挂掉了,不一定是用户自身的健康码问题,这种情况下会导致很多业主的通行码都不可用开不了门,投诉到物业公司甚至引起纠纷。此问题已经反馈至产品经理,优化此场景的处理逻辑,给用户提供更好的使用体验,同时也避免了一次可能出现的生产事故。

image
image
image

遗留问题:

1、目前使用mitmproxy作为mock测试工具,虽然使用了插件脚本,但是每个场景编写为了一个独立的脚本,所以每个场景测试时都需要手动启动mitmdump+对应脚本进行,还没有达到完全自动化的方式,不知道是这种脚本编写方式不合理还是有其他方式能解决这种问题,希望能够解答一下。
2、后续要搭建一个团队级别的mock server有什么好的方案和建议吗?
3、如方案一所示,目前也在做公司的UI自动化和app自动化,UI自动化可以使用无头浏览器模式将用例放到服务器上跑,app自动化好像没有这种方式,只能放在本地电脑上跑,app自动化还有什么好的执行方案吗?
4、在做UI自动化的过程中发现,公司登录认证是使用token的方式,获取不到cookie信息,学院教的场景是使用cookie保持登录状态在这里不适用,想问一下对于这种token认证方式有什么方式更好呢?

2 Likes