学习笔记——测试进阶之路 工作笔记:基于微信 minium 框架的小程序自动化初步实践(2)

Lynn
Lynn
Lynn
订阅者
215
文章
0
粉丝
测试交流1 183字数 177阅读0分35秒阅读模式

下载项目源代码

申请 GitLab 项目代码管理权限,下载小程序源代码

学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(2)-图片1

学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(2)-图片1

学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(2)-图片1

下载并安装编译软件 HBuilderX

  • 下载 HBuilderX
    地址:https://dcloud.io/hbuilderx.html

  • 安装 HBuilderX

    学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(2)-图片2

  • 切换到小程序目录下,首先执行 npm install

    学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(2)-图片3

  • 打开 HBuilderX,配置微信开发者工具项目路径

    学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(2)-图片4

编译并发布小程序

因为公司的小程序是通过 Vue.js 进行编写,发布项目需要先通过 HBuilderX 工具进行编译。

学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(2)-图片5

学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(2)-图片5

学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(2)-图片5

学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(2)-图片5

学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(2)-图片5

执行测试脚本

学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(2)-图片6

输出测试报告

用例执行成功

学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(2)-图片7

用例执行失败

学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(2)-图片8

学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(2)-图片8

用例执行异常

学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(2)-图片9

学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(2)-图片9

参考资料

https://git.weixin.qq.com/groups/minitest

软件测试接口测试之业务功能测试

 
    • loneyao
      loneyao 9

      继续学习参考资料中的项目不是公开的,看不到诶你需要打开这个链接:https://git.weixin.qq.com/minitest/minitest-demo执行测试脚本这块写了什么? # !/usr/bin/python
      # -*- coding: utf-8 -*-

      “””
      @File : run.py
      @Create Time: 2022-06-01 17:21
      @Description:
      “””

      import os

      # 运行执行testcase文件中的指定用例
      cmd_testcase = “minitest -m testcase.xxxxxx_test -c ./config/config_emulator.json -g”

      # 按照suite配置执行用例
      cmd_suite = “minitest -s ./config/suite_caselist.json -c ./config/config_emulator.json -g”

      os.system(cmd_suite)

      mark 一下 等最近有时间也弄一下这个

    匿名

    发表评论

    匿名网友
    确定

    拖动滑块以完成验证

    学习笔记——测试进阶之路 工作笔记:基于微信 minium 框架的小程序自动化初步实践(1)

    校服杀人魔
    校服杀人魔
    校服杀人魔
    订阅者
    269
    文章
    0
    粉丝
    测试交流1 299字数 1329阅读4分25秒阅读模式

    minium 框架

    框架优点
    • 微信小程序官方推出的小程序自动化框架,是为小程序专门开发的自动化框架, 提供了 Python 和 JavaScript 版本。
    • 支持一套脚本,iOS & Android & 模拟器,三端运行
    • 提供丰富的页面跳转方式,看不到也能去得到
    • 可以获取和设置小程序页面数据,让测试不止点点点
    • 支持往 AppSerive 注入代码片段
    • 可以使用 minium 来进行函数的 mock, 可以直接跳转到小程序某个页面并设置页面数据, 做针对性的全面测试
    框架缺点
    • 暂不支持 H5 页面的调试;
    • 暂不支持插件内 wx 接口调用;
    技术选型
    • minium 支持 Python 和 JavaScript 版本,而且有专门的团队定期维护,遇到问题可以在微信开发者社区进行提问,因此选择了 minium。

    minium 框架介绍

    • minium 提供一个基于 unittest 封装好的测试框架,利用这个简单的框架对小程序测试可以起到事半功倍的效果。
    • 测试基类 Minitest 会根据测试配置进行测试,minitest 向上继承了 unittest.TestCase,并做了以下改动:
    • 加载读取测试配置
    • 在合适的时机初始化 minium.Minium、minium.App 和 minium.Native
    • 根据配置打开 IDE,拉起小程序项目和或自动打开真机调试
    • 拦截 assert 调用,记录检验结果
    • 记录运行时数据和截图,用于测试报告生成
    • 使用 MiniTest 可以大大降低小程序测试成本。

    Properties

    名称类型默认值说明
    • appminium.AppNoneApp 实例,可直接调用 minium.App 中的方法
    • miniminium.MiniumNoneMinium 实例,可直接调用 minium.Minium 中的方法
    • nativeminium.NativeNoneNative 实例,可直接调用 minium.Native 中的方法

    环境搭建

    搭建 Minium Doc(微信官方人员确认,无需进行本地搭建,本地搭建的都是错的,而且还是旧的文档)

    无需构建,直接访问官方文档(https://minitest.weixin.qq.com/#/)

    安装软件
    • 下载并安装 python 3.8+,地址:https://www.python.org/downloads/release/python-390/
    • 下载并安装 Node.js,地址:http://nodejs.cn/download/(可选项,仅限于我司小程序产品
    • 下载并安装微信开发者工具,地址:https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html
    安装 minium
    • 下载 https://minitest.weixin.qq.com/minium/Python/dist/minium-latest.zip,然后执行
    • 第一步:解压,解压路径自己记住(我这里解压到 C:\minium-1.2.6)
      学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(1)-图片1
    • 第二步:切换到文件目录下
    • 第三步:执行即可(如下图)
      学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(1)-图片1
    • 第四步:测试
      学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(1)-图片1
    特别说明
    • 如果新手通过本地解压再执行,遇到以下问题

      学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(1)-图片1

    • 请直接使用以下命令,即可一次性成功安装

      pip3 install https://minitest.weixin.qq.com/minium/Python/dist/minium-latest.zip
      

      学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(1)-图片2

      学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(1)-图片2

    配置微信开发者工具
    • 安装微信开发者工具(我本机使用的版本是 1.06.2205312),并打开安全模式: 设置 -> 安全设置 -> 服务端口: 打开

      学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(1)-图片3

    • 在工具栏菜单中点击设置,选择项目设置,切换到 “本地设置”,将调试基础库选择大于 2.7.3 的库;

      学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(1)-图片4

    • 开启微信工具安全设置中的 CLI/HTTP (提供了命令行和 HTTP 两种调用方式) 调用功能。

    • 开启被测试项目的自动化端口号

    "path/to/cli" auto --project "path/to/project" --auto-port 9420
    

    路径说明

    • path/to/project: 指代填写存放小程序源码的目录地址,文件夹中需要包含有 project.config.json 文件
      学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(1)-图片5
    • path/to/cli: 指代开发者工具 cli 命令路径
      学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(1)-图片5
    • 与下图一致证明开启成功
    "C:/Program Files (x86)/Tencent/微信web开发者工具/cli" auto --project "C:/WeChatProjects/miniprogram-1" --auto-port 9420
    

    学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(1)-图片5

    配置信息

    代码结构目录

    学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(1)-图片6

    模拟器 Config.json
    {
    "project_path": "C:\\WeChatProjects\\miniprogram-1",
    "dev_tool_path": "C:\\Program Files (x86)\\Tencent\\微信web开发者工具\\cli.bat",
    "debug_mode": "debug",
    "test_port": 9420,
    "platform": "ide",
    "app": "wx",
    "assert_capture": true,
    "request_timeout":60,
    "remote_connect_timeout": 300,
    "auto_relaunch": true
    }
    
    真机 Config.json
    {
    "project_path": "C:\\WeChatProjects\\xxx_chinamobile-pmc_migration2\\unpackage\\dist\\build\\mp-weixin",
    "dev_tool_path": "C:\\Program Files (x86)\\Tencent\\微信web开发者工具\\cli.bat",
    "debug_mode": "debug",
    "test_port": 9420,
    "platform": "Android",
    "app": "wx",
    "enable_app_log": true,
    "device_desire": {
    "serial": "d310bf55"
    },
    "assert_capture": true,
    "request_timeout":60,
    "remote_connect_timeout": 300,
    "auto_relaunch": true
    }
    
    Suite.json
    {
    "pkg_list": [
    {
    "case_list": [
    "test_*"
    ],
    "pkg": "testcase.*_test"
    }
    ]
    }
    

    测试用例

    first_test.py
    # !/usr/bin/python
    # -*- coding: utf-8 -*-
    
    """
    @File    : first_test.py
    @Create Time: 2022-06-01 16:17
    @Description:
    """
    import minium
    class FirstTest(minium.MiniTest):
    def test_get_system_info(self):
    sys_info = self.mini.get_system_info()
    print("FirstTest: ", sys_info)
    self.assertIn("SDKVersion", sys_info)
    if __name__ == "__main__":
    import unittest
    loaded_suite = unittest.TestLoader().loadTestsFromTestCase(FirstTest)
    result = unittest.TextTestRunner().run(loaded_suite)
    print(result)
    

    主程序入口

    run.py
    # !/usr/bin/python
    # -*- coding: utf-8 -*-
    """
    @File    : run.py
    @Create Time: 2022-06-01 17:21
    @Description:
    """
    import os
    # 运行执行class文件中的指定用例
    cmd0 = "minitest -m testcase.first_test --case test_get_system_info -c config.json -g"
    # 运行执行testcase文件中的指定用例
    cmd1 = "minitest -m testcase.first_test -c config.json -g"
    # 按照suite配置执行用例
    cmd2 = "minitest -s suite.json -c config.json -g"
    os.system(cmd0)
    

    执行用例

    学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(1)-图片7

    测试报告

    测试结果存储在 outputs 下,运行命令

    python -m http.server 12345 -d outputs
    

    然后在浏览器上访问 http://localhost:12345 即可查看报告

    学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(1)-图片8

    参考资料

    https://blog.csdn.net/jiangjunsss/article/details/120228371
    https://blog.csdn.net/baguenaudier/article/details/124478687
    https://blog.csdn.net/weixin_49546967/article/details/119858529
    https://minitest.weixin.qq.com/#/minium/Python/readme
    https://developers.weixin.qq.com/community/develop/article/doc/0000cae3a58748ed7f2c8975351413

    软件功能测试文档模板

     
      • loneyao
        loneyao 9

        总结的很好,谢谢分享。看到大佬已经写了 4 篇了,我还没搞过小程序的测试,准备照着你的实践下,多谢分享更新文档中的操作说明
        如果新手遇到以下问题

        注意,不要采用本地解压再执行的方法,请直接使用 pip3 install https://minitest.weixin.qq.com/minium/Python/dist/minium-latest.zip
        即可一次性成功安装

      匿名

      发表评论

      匿名网友
      确定

      拖动滑块以完成验证

      学习笔记——测试进阶之路 工作笔记:基于微信 minium 框架的小程序自动化初步实践(5)

      优雅先森。
      优雅先森。
      优雅先森。
      订阅者
      254
      文章
      0
      粉丝
      测试交流评论162字数 2484阅读8分16秒阅读模式

      等待内容更新。。。。。。。。。。。。。。。

      学习过程中的经验总结

      遇到的技术问题及解决过程(长期更新)

      • get_element 方法
      • inner_wxml

      测试用例 DEMO

      # !/usr/bin/python
      # -*- coding: utf-8 -*-
      
      """
      @Author  : Charles
      @Contact : MyProject@MyProject.com
      @File    : MyProject_test.py
      @Create Time: 2022-06-30 09:26
      @Description: XXXXXXXXXXXX
      """
      import unittest
      import time
      import minium
      from common import db_func
      from common.db_func import get_current_time
      from common.message import send_failmessage
      execid = int(time.time())
      print("execid: ", execid)
      @minium.ddt_class
      class MyProject(minium.MiniTest):
      """
      MyProjectMyProjectMyProjectMyProjectMyProjectMyProject
      """
      case_name = "MyProject"
      case_field = "MyProject"
      project_name = "MyProject"
      show_livedata_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(0))
      show_offline_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(0))
      @minium.ddt_case("43338957","43338966", "43338976", "43338978", "44280929", "43338962", "43338960", "43338961",
      "43338954", "43338956", "43338958", "43338955", "43338959", "43338950", "43338952", "43338951",
      "43338953", "43338963", "43338965", "43338967", "43338964", "43338968", "43338969", "43338970",
      "43338971", "43338972", "43338973", "43338974", "43338975", "43338977", "43338979", "44280927",
      "44280930", "44280921", "44280922", "44280917", "44280918", "44280920", "44280923", "44280924",
      "44280925", "44280926")
      def test_device_livedata(self, args):
      """
      MyProjectMyProjectMyProjectMyProjectMyProject
      """
      self.page.wait_for(2)
      # 用例开始时间
              case_starttime = get_current_time()
      try:
      if self.page.get_element("/page/view/equip//view/view[3]/view[1]/view[2]/view[2]",
      text_contains="MyProject",
      max_timeout=5).inner_text == "MyProject":
      self.page.wait_for(2)
      except:
      if self.page.get_element("/page/view/equip//view/view[3]/view[2]",
      text_contains="MyProject",
      max_timeout=5).inner_text == "MyProject":
      self.page.wait_for(2)
      # 点击设备搜索框
              try:
      elem = self.page.get_element("input[name='input'][placeholder='MyProject']",
      inner_text="MyProject",
      text_contains="MyProject",
      value="MyProject",
      max_timeout=5)
      except:
      elem = self.page.get_element("/page/view/equip//view/view[1]/view/view[2]/input", max_timeout=5)
      elem.click()
      self.page.wait_for(2)
      # 设备搜索框中输入设备号
              device_number = args
      try:
      elem = self.page.get_element("input[name='input'][placeholder='MyProject']", max_timeout=5)
      except:
      elem = self.page.get_element("/page/view/view/view[1]/view/view[2]/input", max_timeout=5)
      elem.trigger("input", {"value": device_number})
      self.page.wait_for(2)
      # 点击搜索图标进行搜索
              elem = self.page.get_element("/page/view/view/view[1]/view/view[1]/image", max_timeout=5)
      elem.click()
      self.page.wait_for(2)
      # 点击设备,跳转到设备详情页
              try:
      elem = self.page.get_element("text.text-black", max_timeout=5)
      except:
      elem = self.page.get_element("/page/view/view/view[2]/view/scroll-view/view",
      inner_text="MyProject",
      text_contains="MyProject",
      value="MyProject",
      max_timeout=5)
      elem.click()
      # 获取当前楼层数据
              trigger_data_time = get_current_time()
      print("获取当前楼层数据 trigger_data_time:  ", trigger_data_time)
      try:
      # 判断状态是否为--
                  start_time = time.time()
      floor_number = '--'
      while self.page.element_is_exists("/page/view/view[2]/view[2]/view/view[1]/view/view[2]/text"):
      print("While True: 继续执行下面的代码")
      if floor_number == '--':
      end_time = time.time()
      duration = end_time - start_time
      print("数据加载时间: ", duration)
      print("-------------------判断加载时间是否大于60秒-----------------")
      if duraion > 60:
      # 超过60秒默认数据加载失败,获取当前设备掉线时间
                              MyProject.show_offline_time = get_current_time()
      MyProject.show_livedata_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(0))
      print("超过60秒默认数据加载失败,数据加载失败的时间: ", MyProject.show_offline_time,
      "实时数据设为默认时间", MyProject.show_livedata_time)
      break
      floor_marking = self.page.get_element(
      "/page/view/view[2]/view[2]/view/view[1]/view/view[2]/text",
      max_timeout=5).inner_text
      floor_number = floor_marking.strip()
      print("循环语句下,当前楼层数为:", floor_number)
      if floor_number != "--" and floor_number != "----" and floor_number != "设备DTU掉线" and floor_number != "设备CPU掉线":
      MyProject.show_livedata_time = get_current_time()
      MyProject.show_offline_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(0))
      print("循环语句下,实时数据成功展示时间: ", MyProject.show_livedata_time,
      "设备掉线时间设为默认值", MyProject.show_offline_time)
      break
      elif floor_number == "----":
      floor_marking = self.page.get_element(
      "/page/view/view[2]/view[2]/view/view[1]/view/view[2]/text",
      max_timeout=5).inner_text
      floor_number = floor_marking.strip()
      print("发现xpath路径,再次进行取值,当前楼层数为:", floor_number)
      MyProject.show_livedata_time = get_current_time()
      MyProject.show_offline_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(0))
      print("循环语句下,实时数据成功展示时间: ", MyProject.show_livedata_time,
      "设备掉线时间设为默认值", MyProject.show_offline_time)
      break
      else:
      print("设备实时数据,存在异常。")
      continue
      except:
      # 进入设备掉线的页面
                  print("等待状态已改变,进入设备掉线的页面。。。。。。。。。。")
      floor = self.page.get_element("/page/view/view[2]/view[2]/view/view[1]/text",
      text_contains="掉线",
      max_timeout=5)
      floor_marking = floor.inner_text
      floor_number = floor_marking.strip()
      print("当前楼层数为: ", floor_number)
      MyProject.show_offline_time = get_current_time()
      MyProject.show_livedata_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(0))
      print("进入设备掉线的页面,设备掉线的时间: ", MyProject.show_offline_time,
      "设备掉线,实时数据设为默认时间", MyProject.show_livedata_time)
      # 楼层数据校验
              if floor_number != "" and floor_number != "--" and floor_number != "设备XXX掉线" and floor_number != "设备YYY掉线":
      floor_int_value = ["-", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
      floor_str_value = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
      "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
      if 1 < len(floor_number) < 7:
      if floor_number[0] in floor_int_value and floor_number[1] in floor_int_value:
      # 如果楼层数为正负数开头的,且第二位是数字,说明数据显示正常,进行类型转换
                          self.assertTrue(floor_number, "当前楼层显示正常,楼层为: {}".format(int(floor_number)))
      assert_status = "pass"
      elif floor_number[0] in floor_str_value and floor_number[1] in floor_int_value:
      # 如果楼层数第一位是字母,第二位是数字,说明数据依然是显示正常,不需要进行类型转换
                          self.assertTrue(floor_number, "当前楼层显示正常,楼层为: {}".format(floor_number))
      assert_status = "pass"
      else:
      # 电梯数据存在异常,直接推送报警
                          send_failmessage(self.case_name, device_number, self.project_name, self.case_field,
      floor_number)
      assert_status = "fail"
      case_endtime = get_current_time()
      # 写入数据库
                          db = db_func.connect_db()
      sql = "insert INTO device (execid, device_number, project_name, case_field, case_content, triggertime, " 
      "showtime, offlinetime, starttime, endtime, status) " 
      "VALUES ('{}','{}','{}','{}','{}','{}','{}','{}','{}','{}','{}');".format 
      (execid, device_number, self.project_name, self.case_field, floor_number,
      trigger_data_time,
      MyProject.show_livedata_time, MyProject.show_offline_time, case_starttime, case_endtime,
      assert_status)
      db_func.db_insert(db, sql)
      self.assertFalse(floor_number, "楼层信息显示异常,楼层为:{}".format(floor_number))
      elif len(floor_number) == 1:
      if floor_number[0] in floor_int_value:
      # 如果楼层数为单个数字,说明数据显示正常,进行类型转换
                          self.assertTrue(floor_number, "当前楼层显示正常,楼层为: {}".format(int(floor_number)))
      assert_status = "pass"
      elif floor_number[0] in floor_str_value:
      # 如果楼层数为单个字母,说明数据显示正常,进行类型转换
                          self.assertTrue(floor_number, "当前楼层显示正常,楼层为: {}".format(floor_number))
      assert_status = "pass"
      else:
      # 如果楼层数不是单个数字或者单个字母,说明数据显示异常,直接推送报警
                          send_failmessage(self.case_name, device_number, self.project_name, self.case_field,
      floor_number)
      assert_status = "fail"
      case_endtime = get_current_time()
      # 写入数据库
                          db = db_func.connect_db()
      sql = "insert INTO device (execid, device_number, project_name, case_field, case_content, triggertime, " 
      "showtime, offlinetime, starttime, endtime, status) " 
      "VALUES ('{}','{}','{}','{}','{}','{}','{}','{}','{}','{}','{}');".format 
      (execid, device_number, self.project_name, self.case_field, floor_number,
      trigger_data_time,
      MyProject.show_livedata_time, MyProject.show_offline_time, case_starttime, case_endtime,
      assert_status)
      db_func.db_insert(db, sql)
      self.assertFalse(floor_number, "楼层信息显示异常,楼层为:{}".format(floor_number))
      else:
      # 如果获取到的数据长度不是1,2,7,说明是其他内容,直接推送报警
                      send_failmessage(self.case_name, device_number, self.project_name, self.case_field,
      floor_number)
      assert_status = "fail"
      case_endtime = get_current_time()
      # 写入数据库
                      db = db_func.connect_db()
      sql = "insert INTO device (execid, device_number, project_name, case_field, case_content, triggertime, " 
      "showtime, offlinetime, starttime, endtime, status) " 
      "VALUES ('{}','{}','{}','{}','{}','{}','{}','{}','{}','{}','{}');".format 
      (execid, device_number, self.project_name, self.case_field, floor_number, trigger_data_time,
      MyProject.show_livedata_time, MyProject.show_offline_time, case_starttime, case_endtime,
      assert_status)
      db_func.db_insert(db, sql)
      self.assertFalse(floor_number, "楼层信息显示异常,楼层为:{}".format(floor_number))
      elif floor_number == "设备XXX掉线":
      # 设备掉线,直接推送报警
                  send_failmessage(self.case_name, device_number, self.project_name, self.case_field, floor_number)
      assert_status = "fail"
      case_endtime = get_current_time()
      # 写入数据库
                  db = db_func.connect_db()
      sql = "insert INTO device (execid, device_number, project_name, case_field, case_content, triggertime, " 
      "showtime, offlinetime, starttime, endtime, status) " 
      "VALUES ('{}','{}','{}','{}','{}','{}','{}','{}','{}','{}','{}');".format 
      (execid, device_number, self.project_name, self.case_field, floor_number, trigger_data_time,
      MyProject.show_livedata_time, MyProject.show_offline_time, case_starttime, case_endtime,
      assert_status)
      db_func.db_insert(db, sql)
      self.assertFalse(floor_number, "楼层信息显示异常,楼层为:{}".format(floor_number))
      elif floor_number == "设备YYY掉线":
      # 设备掉线,直接推送报警
                  send_failmessage(self.case_name, device_number, self.project_name, self.case_field, floor_number)
      assert_status = "fail"
      case_endtime = get_current_time()
      # 写入数据库
                  db = db_func.connect_db()
      sql = "insert INTO device (execid, device_number, project_name, case_field, case_content, triggertime, " 
      "showtime, offlinetime, starttime, endtime, status) " 
      "VALUES ('{}','{}','{}','{}','{}','{}','{}','{}','{}','{}','{}');".format 
      (execid, device_number, self.project_name, self.case_field, floor_number, trigger_data_time,
      MyProject.show_livedata_time, MyProject.show_offline_time, case_starttime, case_endtime,
      assert_status)
      db_func.db_insert(db, sql)
      self.assertFalse(floor_number, "楼层信息显示异常,楼层为:{}".format(floor_number))
      elif floor_number == "--" or floor_number == "----":
      # 实时数据没有加载出来,推送报警
                  send_failmessage(self.case_name, device_number, self.project_name, self.case_field, floor_number)
      assert_status = "fail"
      case_endtime = get_current_time()
      # 写入数据库
                  db = db_func.connect_db()
      sql = "insert INTO device (execid, device_number, project_name, case_field, case_content, triggertime, " 
      "showtime, offlinetime, starttime, endtime, status) " 
      "VALUES ('{}','{}','{}','{}','{}','{}','{}','{}','{}','{}','{}');".format 
      (execid, device_number, self.project_name, self.case_field, floor_number, trigger_data_time,
      MyProject.show_livedata_time, MyProject.show_offline_time, case_starttime, case_endtime,
      assert_status)
      db_func.db_insert(db, sql)
      self.assertFalse(floor_number, "楼层信息未成功显示,楼层为:{}".format(floor_number))
      else:
      # 楼层信息显示为其他字符,说明电梯存在异常,直接推送报警
                  send_failmessage(self.case_name, device_number, self.project_name, self.case_field, floor_number)
      assert_status = "fail"
      case_endtime = get_current_time()
      # 写入数据库
                  db = db_func.connect_db()
      sql = "insert INTO device (execid, device_number, project_name, case_field, case_content, triggertime, " 
      "showtime, offlinetime, starttime, endtime, status) " 
      "VALUES ('{}','{}','{}','{}','{}','{}','{}','{}','{}','{}','{}');".format 
      (execid, device_number, self.project_name, self.case_field, floor_number, trigger_data_time,
      MyProject.show_livedata_time, MyProject.show_offline_time, case_starttime, case_endtime,
      assert_status)
      db_func.db_insert(db, sql)
      self.assertFalse(floor_number, "楼层信息显示异常,楼层为:{}".format(floor_number))
      # 返回上一级:搜索结果页
              self.page.wait_for(2)
      self.app.navigate_back()
      self.page.wait_for(2)
      # 返回上一级:小程序首页
              self.app.navigate_back()
      self.page.wait_for(2)
      # 测试用例结束时间
              case_endtime = get_current_time()
      self.page.wait_for(2)
      # 数据写入数据库
              db = db_func.connect_db()
      sql = "insert INTO device (execid, device_number, project_name, case_field, case_content, triggertime, " 
      "showtime, offlinetime, starttime, endtime, status) " 
      "VALUES ('{}','{}','{}','{}','{}','{}','{}','{}','{}','{}','{}');".format 
      (execid, device_number, self.project_name, self.case_field, floor_number, trigger_data_time,
      MyProject.show_livedata_time, MyProject.show_offline_time, case_starttime, case_endtime,
      assert_status)
      db_func.db_insert(db, sql)
      if __name__ == "__main__":
      loaded_suite = unittest.TestLoader().loadTestsFromTestCase(KoneView)
      result = unittest.TextTestRunner().run(loaded_suite)
      

       
      匿名

      发表评论

      匿名网友
      确定

      拖动滑块以完成验证

      学习笔记——测试进阶之路 工作笔记:基于微信 minium 框架的小程序自动化初步实践(4)

      Prince0813
      Prince0813
      Prince0813
      订阅者
      270
      文章
      0
      粉丝
      测试交流评论145字数 2731阅读9分6秒阅读模式

      创建数据库和数据表

      数据库:XXXXX

      学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(4)-图片1

      数据表:device

      学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(4)-图片2

      存储数据信息

      学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(4)-图片3

      SQL 语句如下
      CREATE TABLE `device` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `execid` int(11) NOT NULL,
      `device_number` int(11) DEFAULT NULL,
      `project_name` varchar(255) DEFAULT NULL,
      `case_field` varchar(255) DEFAULT NULL,
      `case_content` varchar(255) DEFAULT NULL,
      `triggertime` datetime DEFAULT NULL,
      `showtime` datetime DEFAULT NULL,
      `offlinetime` datetime DEFAULT NULL,
      `starttime` datetime DEFAULT NULL,
      `endtime` datetime DEFAULT NULL,
      `status` varchar(255) DEFAULT NULL,
      PRIMARY KEY (`id`)
      ) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=gb18030;
      

      创建 Flask 服务

      新建 db_func.py
      # !/usr/bin/python
      # -*- coding: utf-8 -*-
      
      """
      @Author  : Charles
      @File    : db_func.py
      @Create Time: 2022-06-21 09:18
      @Description:
      """
      import time
      import pymysql
      def connect_db():
      url = "127.0.0.1"
      name = "root"
      pwd = "123456"
      dataBase = "XXXXX"
      return pymysql.connect(host=url, port=3306, user=name, passwd=pwd, db=dataBase)
      def query_database(db, sql):
      cursor = db.cursor()
      try:
      if isinstance(sql, str):
      cursor.execute(sql)
      result = list(cursor.fetchall())
      else:
      result = []
      for sq in sql:
      cursor.execute(sq)
      result.append(list(cursor.fetchall()))
      except Exception as err:
      result = ''.join(('An db query exception happened: ', str(err)))
      # db.close()  # 关闭数据库连接
          return result
      def update_db(db, sql):
      cursor = db.cursor()
      try:
      if isinstance(sql, str):
      cursor.execute(sql)
      db.commit()
      else:
      print('sql 不是一个合格的字符串:{}'.format(sql))
      except Exception as err:
      result = ''.join(('An db update exception happened: ', str(err)))
      db.rollback()
      print(result)
      # 数据库数据插入更新
      def db_insert(db, sql):
      cursor = db.cursor()
      i = 0
      try:
      cursor.execute(sql)
      db.commit()
      result = 'db insert success'
      except Exception as err:
      db.rollback()
      result = 'An db insert exception happened: ' + str(err) + '    ' + str(i)
      db.close()  # 关闭数据库连接
          return result
      def close_db(db):
      try:
      db.close()
      except Exception as err:
      result = ''.join(('An db closed exception happened: ', str(err)))
      def get_current_time():
      return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
      
      新建 project_index.py
      # !/usr/bin/python
      # -*- coding: utf-8 -*-
      
      """
      @Author  : Charles
      @File    : project_index.py
      @Create Time: 2022-06-21 09:53
      @Description:
      """
      import datetime
      import time
      from flask import *
      from common import db_func
      app = Flask(__name__)
      @app.route('/')
      def display():
      """
      最新一轮回归测试的整体页面展示
      :return:
      """
      db = db_func.connect_db()
      # 如果实时数据正常显示,就把设备掉线时间默认设置为"1970-01-01 08:00:00" ,实时数据加载时长=数据显示时间-设备被触发时间
          # 如果设备显示掉线页面,就把实时数据时间默认设置为"1970-01-01 08:00:00" ,实时数据加载时长=设备掉线时间-设备被触发时间
          sql_all = 'SELECT device_number, project_name, case_field, case_content, ' 
      '(CASE WHEN offlinetime ="1970-01-01 08:00:00" THEN TIMESTAMPDIFF(SECOND,triggertime,showtime) ' 
      'WHEN showtime ="1970-01-01 08:00:00" THEN TIMESTAMPDIFF(SECOND,triggertime,offlinetime) else 0 ' 
      'END) as duration, triggertime, showtime, offlinetime, starttime, endtime, status FROM device ' 
      'where execid in (select max(execid) from device) ;'
      # 如果实时数据正常显示,就把设备掉线时间默认设置为"1970-01-01 08:00:00" ,实时数据加载时长=数据显示时间-设备被触发时间
          # 如果设备显示掉线页面,就把实时数据时间默认设置为"1970-01-01 08:00:00" ,实时数据加载时长=设备掉线时间-设备被触发时间
          sql_fail = 'SELECT device_number, project_name, case_field, case_content, ' 
      '(CASE WHEN offlinetime ="1970-01-01 08:00:00" THEN TIMESTAMPDIFF(SECOND,triggertime,showtime) ' 
      'WHEN showtime ="1970-01-01 08:00:00" THEN TIMESTAMPDIFF(SECOND,triggertime,offlinetime) else 0 ' 
      'END) as duration, starttime, endtime, status FROM device ' 
      'where status="fail" and execid in (select max(execid) from device) ;'
      pass_total_duration = 'SELECT CAST(SUM(TIMESTAMPDIFF(SECOND,triggertime,showtime)) AS CHAR) AS duration FROM device ' 
      'WHERE case_field="当前楼层" AND STATUS="pass" AND TIMESTAMPDIFF(SECOND,triggertime,showtime) <= "10" ' 
      'AND execid IN (SELECT MAX(execid) FROM device) '
      fail_total_duration = 'SELECT CAST(SUM(TIMESTAMPDIFF(SECOND,triggertime,offlinetime)) AS CHAR) AS duration FROM device ' 
      'WHERE case_field="当前楼层" AND STATUS="fail" AND TIMESTAMPDIFF(SECOND,triggertime,offlinetime) > "10" ' 
      'AND execid IN (SELECT MAX(execid) FROM device) '
      device_total_number = 'SELECT COUNT(*) FROM device WHERE case_field="当前楼层" AND execid IN (SELECT MAX(execid) FROM device) '
      device_pass_number = 'SELECT COUNT(*) FROM device WHERE case_field="当前楼层" AND STATUS="pass" AND execid IN (SELECT MAX(execid) FROM device) '
      device_fail_number = 'SELECT COUNT(*) FROM device WHERE case_field="当前楼层" AND STATUS="fail" AND execid IN (SELECT MAX(execid) FROM device) '
      db_res_all = db_func.query_database(db, sql_all)
      de_res_fail = db_func.query_database(db, sql_fail)
      db_pass_total_duration = db_func.query_database(db, pass_total_duration)
      db_device_total_number = db_func.query_database(db, device_total_number)
      db_device_pass_number = db_func.query_database(db, device_pass_number)
      db_device_fail_number = db_func.query_database(db, device_fail_number)
      # Average Loading Time
          average_loading_time = "%.2f" % (int(db_pass_total_duration[0][0])/int(db_device_total_number[0][0]))
      print("average_loading_time: ", average_loading_time)
      # Percentage of Loading Time Less Than 10s
          percentage_less_than_10s = "{:.2%}".format(int(db_device_pass_number[0][0])/int(db_device_total_number[0][0]))
      print("percentage_less_than_10s: ", percentage_less_than_10s)
      # Percentage of Loading Time Over 10s
          percentage_over_10s = "{:.2%}".format(int(db_device_fail_number[0][0])/int(db_device_total_number[0][0]))
      print("percentage_over_10s: ", percentage_over_10s)
      db_res = [db_res_all, de_res_fail, average_loading_time, percentage_less_than_10s, percentage_over_10s]
      if db_res:
      return render_template("/koneview_page.html", content=db_res)
      else:
      pass
      if __name__ == "__main__":
      app.run(host='xx.xx.xx.xx', port=5500, debug=True)
      

      创建 HMTL 网页

      新建 project_page.html
      <!DOCTYPE html>
      <html lang="en">
      <head>
      <meta charset="UTF-8">
      <title>MyProject Monitor Platform</title>
      <link rel="icon" href="https://www.myproject.cn/zh/Images/myproject-logo-76x52_tcm156-8930.png">
      <script src="static/lib/jquery-1.11.1.min.js" type="text/javascript"></script>
      <div class="navi-brand">
      <a class="logo" onclick="zhugeTrack('顶栏按钮点击',{'按钮名称':'LOGO'" href="https://www.myproject.com/en/" target="_blank"> <img src="/static/images/myprojectLOGO.png" style="text-align: left; width: 265px; height: 50px; position: absolute; left: 62px; top: 30px; margin-left: -60px;margin-top: -20px;"></a>
      </div>
      <style type="text/css">
      .bg{
      background-image: url("https://qiuniu.playezu.com/wp-content/uploads/2022/07/v2-052324a9dae7a6feb2e5ddf6f68ad8c6_720w.jpg");
      background-repeat: repeat;
      }
      em{
      color: red;
      font-style: normal;
      }
      table{
      border-spacing: 0;
      width: 100%;
      border: 1px solid black;
      }
      thead th {
      border: 1px solid black;
      /*text-align: center;*/
      width: auto;
      color: blueviolet;
      }
      th{
      border: 1px solid black;
      text-align: left;
      width: auto;
      background-color: #69ABD6;
      }
      td{
      border: 1px solid black;
      text-align: left;
      }
      </style>
      </head>
      <body class="bg">
      <table style="margin-bottom: -1px" class="left"  id="table_top_header">
      <h1 align="center" style="color:#0071B9 ; font-size:30px">MyProject Monitor Platform</h1>
      <h3 align="left" style="color:#0071B9 ; font-size:20px">Basic Information</h3>
      <tr>
      <th>Owner</th>
      <th>Project Name</th>
      <th>Running Environment</th>
      <th>Running System</th>
      <th>Running Equipment</th>
      <th>Testing Phase</th>
      <th>Monitor Frequency</th>
      <th>Test Report</th>
      </tr>
      <tr>
      <td>Charles</td>
      <td>MyProject</td>
      <td>Production</td>
      <td>Windows 10 64bit</td>
      <td>Wechat DevTools</td>
      <td>Regression Test</td>
      <td>One day/time</td>
      <td><a style="background: #eee4a6" href="http://ip:port/" target="_blank">Minium</a></td>
      </tr>
      </table>
      <table style="margin-bottom: -1px" class="left"  id="table_analysis">
      <tbody>
      <h3 align="left" style="color:#0071B9 ; font-size:20px">LiveData Analysis</h3>
      <tr>
      <th>Average Loading Time(sec)</th>
      <th>Percentage of Loading Time Less Than 10s</th>
      <th>Percentage of Loading Time Over 10s</th>
      </tr>
      <div >
      <div id="ChangelistTable0">
      <tr>
      <td  class="text-center" >
      <div>
      {% if content[2] %}
      <span style="background: #e8e272"> <a>{{content[2]}}</a> </span>
      {% else %}
      {% endif  %}
      </div>
      </td>
      <td  class="text-center" >
      <div>
      {% if content[3] %}
      <span style="background: #7ad9f4"> <a>{{content[3]}}</a> </span>
      {% else %}
      {% endif  %}
      </div>
      </td>
      <td  class="text-center" >
      <div>
      {% if content[4] %}
      <span style="background: #e999d4"> <a>{{content[4]}}</a> </span>
      {% else %}
      {% endif  %}
      </div>
      </td>
      </tr>
      </div>
      </div>
      </tbody>
      </table>
      <table style="margin-bottom: -1px" class="left"  id="table_header">
      <tbody>
      <h3 align="left" style="color:#0071B9 ; font-size:20px">TestCase Failed</h3>
      <tr>
      <th>No</th>
      <th>Device Number</th>
      <th>Project Name</th>
      <th>Monitor Field</th>
      <th>Live Data</th>
      <th>Duration(s)</th>
      <th>Latest Case Executed Time</th>
      <th>Latest Case Ended Time</th>
      <th>Latest Case Result</th>
      </tr>
      <div >
      <div id="ChangelistTable1">
      {% for i in range(content[1]| length) %}
      <tr>
      <td>
      {{ i+1 }}
      </td>
      <td  class="text-center" >
      <div>
      {% if content[1][i][0] %}
      {{ content[1][i][0]| safe }}
      {% else %}
      {% endif  %}
      </div>
      </td>
      <td>
      <div>
      {% if content[1][i][1] %}
      {{ content[1][i][1]| safe }}
      {% else %}
      {% endif  %}
      </div>
      </td>
      <td  class="text-center" >
      <div>
      {% if content[1][i][2] %}
      {{ content[1][i][2]| safe }}
      {% else %}
      {% endif  %}
      </div>
      </td>
      <td  class="text-center" >
      <div>
      {% if content[1][i][3] %}
      {{ content[1][i][3]| safe }}
      {% else %}
      {% endif  %}
      </div>
      </td>
      <td  class="text-center" >
      <div>
      {% if content[1][i][4] %}
      {% if content[1][i][4]<=10 %}
      <span style="background: lightseagreen"> <a>{{content[1][i][4]}}</a> </span>
      {% else %}
      <span style="background: lightcoral"> <a>{{content[1][i][4]}}</a></span>
      {% endif  %}
      {% else %}
      {% endif  %}
      </div>
      </td>
      <td  class="text-center" >
      <div>
      {% if content[1][i][5] %}
      {{ content[1][i][5]| safe }}
      {% else %}
      {% endif  %}
      </div>
      </td>
      <td  class="text-center" >
      <div>
      {% if content[1][i][6] %}
      {{ content[1][i][6]| safe }}
      {% else %}
      {% endif  %}
      </div>
      </td>
      <td  class="text-center" >
      <div>
      {% if content[1][i][7] %}
      {% if content[1][i][7]=='pass' %}
      <span style="background: mediumseagreen"> <a>PASS</a> </span>
      <!--                                    <span> <a href={{content[0][i][6]}} target="_blank">Pass</a> </span>-->
      {% elif content[1][i][7]=='fail' %}
      <span style="background: orangered"> <a>FAIL</a> </span>
      <!--        <span> <a href={{content[0][i][6]}} target="_blank">Fail</a> </span>-->
      {% else %}
      <span style="background: sandybrown"> <a>Scheduled</a> </span>
      {% endif  %}
      {% else %}
      {% endif  %}
      </div>
      </td>
      </tr>
      {% endfor %}
      </div>
      </div>
      </tbody>
      </table>
      <table style="margin-bottom: -1px" class="left"  id="table_list">
      <tbody>
      <h3 align="left" style="color:#0071B9 ; font-size:20px">TestCase Description</h3>
      <tr>
      <th>No</th>
      <th>Device Number</th>
      <th>Project Name</th>
      <th>Monitor Field</th>
      <th>Live Data</th>
      <th>Duration(s)</th>
      <th>Latest Triggered Time</th>
      <th>Latest Showed Time</th>
      <th>Latest Dropped Time</th>
      <th>Latest Case Executed Time</th>
      <th>Latest Case Ended Time</th>
      <th>Latest Case Result</th>
      </tr>
      <div >
      <div id="ChangelistTable">
      {% for i in range(content[0]| length) %}
      <tr>
      <td>
      {{ i+1 }}
      </td>
      <td  class="text-center" >
      <div>{{ content[0][i][0]| safe }}</div>
      </td>
      <td>
      <div>{{ content[0][i][1]| safe }}</div>
      </td>
      <td  class="text-center" >
      <div>{{ content[0][i][2]| safe }}</div>
      </td>
      <td  class="text-center" >
      <div>
      {% if content[0][i][3] %}
      {{ content[0][i][3]| safe }}
      {% else %}
      {% endif  %}
      </div>
      </td>
      <td  class="text-center" >
      <div>
      {% if content[0][i][4] %}
      {% if content[0][i][4]<=10 %}
      <span style="background: lightseagreen"> <a>{{content[0][i][4]}}</a> </span>
      {% else %}
      <span style="background: lightcoral"> <a>{{content[0][i][4]}}</a></span>
      {% endif  %}
      {% else %}
      {% endif  %}
      </div>
      </td>
      <td  class="text-center" >
      <div>
      {% if content[0][i][5] %}
      {{ content[0][i][5]| safe }}
      {% else %}
      {% endif  %}
      </div>
      </td>
      <td  class="text-center" >
      <div>
      {% if content[0][i][6] %}
      {{ content[0][i][6]| safe }}
      {% else %}
      {% endif  %}
      </div>
      </td>
      <td  class="text-center" >
      <div>
      {% if content[0][i][7] %}
      {{ content[0][i][7]| safe }}
      {% else %}
      {% endif  %}
      </div>
      </td>
      <td  class="text-center" >
      <div>
      {% if content[0][i][8] %}
      {{ content[0][i][8]| safe }}
      {% else %}
      {% endif  %}
      </div>
      </td>
      <td  class="text-center" >
      <div>
      {% if content[0][i][9] %}
      {{ content[0][i][9]| safe }}
      {% else %}
      {% endif  %}
      </div>
      </td>
      <td  class="text-center" >
      <div>
      {% if content[0][i][10] %}
      {% if content[0][i][10]=='pass' %}
      <span style="background: mediumseagreen"> <a>PASS</a> </span>
      <!--                                    <span> <a href={{content[0][i][6]}} target="_blank">Pass</a> </span>-->
      {% elif content[0][i][10]=='fail' %}
      <span style="background: orangered"> <a>FAIL</a> </span>
      <!--        <span> <a href={{content[0][i][6]}} target="_blank">Fail</a> </span>-->
      {% else %}
      <span style="background: sandybrown"> <a>Scheduled</a> </span>
      {% endif  %}
      {% else %}
      {% endif  %}
      </div>
      </td>
      </tr>
      {% endfor %}
      </div>
      </div>
      </tbody>
      </table>
      </body>
      </html>
      

      在线查看报告

      打开http://IP:PORT/,在线查看网页报告

      学习笔记——测试进阶之路
工作笔记:基于微信 minium 框架的小程序自动化初步实践(4)-图片4

       
      匿名

      发表评论

      匿名网友
      确定

      拖动滑块以完成验证