❤️【CSDN首发】5W字minium微信小程序自动化测试框架项目手册❤️

大家好,我是小码哥,今天整理了一份minium微信小程序自动化测试框架手册,希望能对你有帮助!

目录

简介

特性

暂不支持

快速开始

运行环境

必要的知识

安装

开始使用

更多能力

常见问题排查

测试进阶

framework

一个简单例子

目录结构

编写第一个case

编写配置文件

运行case

查看结果

Class minium.MiniTest

命令行工具

minitest 命令

测试计划

目录结构

编写测试计划

运行测试计划

测试结果

测试报告

真机测试

Android

IOS

安装 libmobiledevice

配置 WebDriverAgent

配置测试 config.json

项目配置

Android的device_desire配置项

IOS的device_desire配置项

IDE的mock_native_modal配置项

mock_request配置项

例子

元素定位

简单选择器

多账号



简介

minium 是为小程序专门开发的自动化框架, 提供了 Python 版本。使用 minium 可以进行小程序 UI 自动化测试, 但是 minium 的功能不止于仅仅是 UI 自动化, 甚至可以使用 minium 来进行函数的 mock, 可以直接跳转到小程序某个页面并设置页面数据, 做针对性的全面测试, 这些都得益于我们开放了部分小程序 API 的能力。除此之外,小程序有部分组件使用了系统原生的组件,对于这部分的组件,我们也基于 uiautomator 和 wda 做了补充。

目前小程序的体量越来越大,相关的框架和组件库越来越多,对于测试能力要求也越来越高。业内同行基于Chrome DevTools Protocol开发了很多小程序相关的测试工具,这些工具都有以下缺点:

  1. 只能在Android端上运行。小程序实际是一个跨平台的产品(IDE,Android和IOS),测试的平台覆盖不足。
  2. 兼容性问题。小程序底层运行的内核多样化(x5,原生webview内核等等),对应的调试端口不一定能够打开。
  3. 只能做UI相关的测试。小程序架构上分为渲染层和逻辑层,这些框架对于逻辑层上面的测试限制较大。

而 minium 除了以上缺点都没有之外,还支持以下更多特性:

特性

  • 支持一套脚本,iOS & Android & 模拟器,三端运行
  • 提供丰富的页面跳转方式,看不到也能去得到
  • 可以获取和设置小程序页面数据,让测试不止点点点
  • 可以直接触发小程序元素绑定事件
  • 支持往 AppSerive 注入代码片段执行
  • 可以调用部分 wx 对象上的接口
  • 支持 Mock wx 对象上的接口
  • 支持 Hook wx 对象上的接口
  • 通过 suite 方式管理用例,config 管理运行设备
  • ...

暂不支持

  • H5页面的调试
  • 插件内wx接口调用

快速开始

运行环境

  • Python 3.8及以上
  • 微信开发者工具 最新版本,并打开安全模式: 设置 -> 安全设置 -> 服务端口: 打开
  • 微信 >= 7.0.7 (确认微信公共库版本 >= 2.7.3即可)

必要的知识

本框架与开发者工具有强关联,如果你之前对开发者工具没有基本的了解,可以点击下面的链接了解一些必要的知识:

  • Python3 官网文档 简单教程
  • 开发者工具
    • 开发者工具的界面
    • 真机调试
    • 命令行调用

安装

下载minium安装包,然后执行:

pip3 install minium-latest.zipCopy to clipboardErrorCopied

亦或者下载解压之后执行:

python3 setup.py installCopy to clipboardErrorCopied

安装完成后,可执行以下命令查看版本:

minitest -vCopy to clipboardErrorCopied

开始使用

以下是参考代码,输出system_info

import minium
mini = minium.Minium({
    "project_path": "path/to/project",  # 小程序项目目录地址
    "dev_tool_path": "path/to/cli"      # 开发者工具cli地址,如果没有修改过默认安装路径可不填此项
})
print(mini.get_system_info())Copy to clipboardErrorCopied

更多能力

以上是minium接口的基本用法,minium还集成了测试框架,给你提供更多的测试能力。详情见测试进阶

常见问题排查

  1. cli环境问题,一般报错如下:

MiniConfigError: dev_tool_path: /Applications/wechatwebdevtools.app/Contents/MacOS/cli not exists

解决方法:

  • 请参考开发者工具的命令行工具排查环境问题。
  • 在minium配置文件中配置dev_tool_path路径或实例化的时候加上dev_tool_path选项。参考测试配置或例子

检查方法:

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

看到类似下图的log并能正确打开开发者工具即可。 cli/http

  1. 登录开发者工具的帐号没有该项目的开发者权限,一般报错如下: MiniLaunchError: Open project in automation mode fail! Please ensure you have permission of project and have not environ error

解决方法:

  • 请找相关项目成员添加
  1. 调试基础库(公共库)版本过低,一般报错如下: receive from remote timeout, id: 99eb239c-a2a3-4a12-80da-6fd0312e768f

解决方法:

使用MiniTest可以大大降低小程序测试成本。如何快速使用测试框架进行测试,可参考例子

  • 开发者工具->详情->本地设置选择最新版本的调试基础库(公共库)
  • 测试进阶

  • framework

    minium提供一个基于unittest封装好的测试框架,利用这个简单的框架对小程序测试可以起到事半功倍的效果。

    测试基类Minitest会根据测试配置进行测试,minitest向上继承了unittest.TestCase,并做了以下改动:

  • 加载读取测试配置
  • 在合适的时机初始化minium.Minium、minium.App和minium.Native
  • 根据配置打开IDE,拉起小程序项目和或自动打开真机调试
  • 拦截assert调用,记录检验结果
  • 记录运行时数据和截图,用于测试报告生成

一个简单例子

目录结构

.
├── test
│   └── __init__.py
│   └── first_test.py
└── config.jsonCopy to clipboardErrorCopied

编写第一个case

编辑case文件first_test.py

#!/usr/bin/env python3
import minium
class FirstTest(minium.MiniTest):
    def test_get_system_info(self):
        sys_info = self.mini.get_system_info()
        self.assertIn("SDKVersion", sys_info)Copy to clipboardErrorCopied

编写配置文件

编辑配置文件config.json

{
  "project_path": "/Users/yopofeng/workspace/miniprograms/devtools-test/demo",
  "debug_mode": "info"
}Copy to clipboardErrorCopied

更多配置信息请参考测试配置

运行case

minitest -m test.first_test -c config.json -gCopy to clipboardErrorCopied

test.first_test是python包名,不要跟path搞混

更多命令行参数请参考命令行工具

运行结果如下:

查看结果

测试结果存储在outputs下,运行命令python3 -m http.server 12345 -d outputs然后在浏览器上访问http://localhost:12345即可查看报告,如图: ❤️【CSDN首发】5W字minium微信小程序自动化测试框架项目手册❤️_第1张图片

Class minium.MiniTest

MiniTest是minium中继承自unittest.TestCase的测试基类

Properties:

名称 类型 默认值 说明
mini minium.Minium None Minium实例,可直接调用minium.Minium中的方法
app minium.App None App实例,可直接调用minium.App中的方法
native minium.Native None Native实例,可直接调用minium.Native中的方法

代码示例:

#!/usr/bin/env python3
import minium
class FirstTest(minium.MiniTest):
    def test_get_system_info(self):
        sys_info = self.mini.get_system_info()
        self.assertIn("SDKVersion", sys_info)Copy to clipboardErrorCopied

运行

参考例子

命令行工具

测试用例的执行可以用执行unittest的方式,也可以用我们提供的脚本minitest来加载用例,相关的参数说明如下:

minitest 命令

  • -h, --help: 使用帮助。

  • -v, --version: 查看 minium 的版本。

  • -p PATH/--path PATH: 用例所在的文件夹,默认当前路径。

  • -m MODULE_PATH, --module MODULE_PATH: 用例的包名或者文件名

  • --case CASE_NAMEtest_开头的用例名

  • -s SUITE, --suite SUITE:测试计划文件,文件的格式如下:

    {
      "pkg_list": [
        {
          "case_list": [
            "test_*"
          ],
          "pkg": "test.*_test"
        }
      ]
    }Copy to clipboardErrorCopied

    suite.json的pkg_list字段说明要执行用例的内容和顺序,pkg_list是一个数组,每个数组元素是一个匹配规则,会根据pkg去匹配包名,找到测试类,然后再根据case_list里面的规则去查找测试类的测试用例。可以根据需要编写匹配的粒度。注意匹配规则不是正则表达式,而是通配符。

    测试文件可以指定特定的用例,规定执行顺序

  • -c CONFIG, --config CONFIG:配置文件名,配置项目参考配置文件

  • -g, --generate: 生成网页测试报告

  • --module_search_path [SYS_PATH_LIST [SYS_PATH_LIST ...]]: 添加 module 的搜索路径

  • -a, --accounts: 查看开发者工具当前登录的多账号, 需要通过 9420 端口,以自动化模式打开开发者工具

  • --mode RUN_MODE: 选择以parallel(并行)或者fork(复刻)的方式运行用例

测试计划

测试项目中一般包含大量的测试case,在不同的测试阶段可能需要选取不同的case运行,因此项目中需要配置不同的测试计划

以下是一个使用测试计划进行配置的例子

目录结构

.
├── test
│   └── __init__.py
│   └── first_test.py
│   └── second_test.py
└── config.json
└── suite.jsonCopy to clipboardErrorCopied

case配置编写可参考例子

编写测试计划

编辑suite文件suite.json

{
  "pkg_list": [
    {
      "case_list": [
        "test_*"
      ],
      "pkg": "test.*_test"
    }
  ]
}Copy to clipboardErrorCopied

suite.json的pkg_list字段说明要执行用例的内容和顺序,pkg_list是一个数组,每个数组元素是一个匹配规则,会根据pkg去匹配包名,找到测试类,然后再根据case_list里面的规则去查找测试类的测试用例。可以根据需要编写匹配的粒度。注意匹配规则不是正则表达式,而是通配符。

运行测试计划

minitest -s suite.json -c config.json -gCopy to clipboardErrorCopied

更多命令行参数请参考命令行工具

测试结果

每条用例的测试结果我们会存放到一个目录里面,里面包含:

  1. 包含用例执行信息的json文件
  2. 用例运行中的截图
  3. 用例运行中的日志
  4. 小程序运行中的日志

基于这些数据可以生成测试报告,也可以做一些存档的事情。

测试报告

根据用例的执行结果,我们基于Vue和element提供一个简洁的测试报告:例子。

报告生成有2种方式:

  1. 执行用例的时候加上-g参数
  2. 针对已经生成的用例结果目录
    minireport input_path output_pathCopy to clipboardErrorCopied
    output_path里面会生成有报告的入口。

生成报告之后,在对应的目录下面有index.html文件,但是我们不能直接用浏览器打开这个 文件,需要把这个目录放到一个静态服务器上。以下方式都是可行的:

  1. 本地执行python3 -m http.server 12345 -d /path/to/dir/of/report,然后浏览器输入:http://localhost:12345/

    PS: 其中/path/to/dir/of/report为上文的output_path

  2. 利用nginx的配置:

     server {
       listen 80;
       server_name  your.domain.com;
    
       location / {
         alias /path/to/dir/of/report;
         index index.html;
       }
     }

真机测试

minium通过配置文件来识别小程序运行的平台,如果需要测试手机上的小程序,那么需要把配置项platform改成Android或者iOS

小程序真机调试是基于小程序开发者工具的真机调试能力和appnium实现的。如果case使用了minium.Native的接口,则配置文件中必须配置device_desire配置项

Android

Android需要保证命令行能识别到手机设备

$ adb devices

List of devices attached
28fb61d0ef1c7ece    deviceCopy to clipboardErrorCopied

如果只有一台手机在线,那么只需要把platform配置成Android即可, 而如果多台设备连接到手机,配置文件需要制定设备的序列号,如:

{
  "debug_mode": "debug",
  "enable_app_log": false,
  "platform": "Android",
  "device_desire": {
    "serial": "28fb61d0ef1c7ece"
  }
}Copy to clipboardErrorCopied

在我们连接真机的时候,Android手机安装微信测试的apk,有些手机在安装过程中会弹框或者输入密码,所以第一次运行的时候可能需要人为的处理

IOS

安装 libmobiledevice

brew uninstall ideviceinstaller
brew uninstall libimobiledevice
brew install --HEAD libimobiledevice
brew link --overwrite libimobiledevice
brew install ideviceinstaller
brew link --overwrite ideviceinstallerCopy to clipboardErrorCopied

如果没有安装过直接 brew install ideviceinstaller 即可。

当然你也可以本地编译:

git clone https://github.com/libimobiledevice/libimobiledevice.git
cd libimobiledevice
./autogen.sh --disable-openssl
make
sudo make installCopy to clipboardErrorCopied

配置 WebDriverAgent

minium 不包含 WebDriverAgent(简称wda) 工程,请到appium/WebDriverAgent clone 最新版本,只需要简单配置两个选项即可

❤️【CSDN首发】5W字minium微信小程序自动化测试框架项目手册❤️_第2张图片❤️【CSDN首发】5W字minium微信小程序自动化测试框架项目手册❤️_第3张图片

配置完成之后,可以用⌘+u快捷键运行 unit test 测试 wda 是否正常运行

❤️【CSDN首发】5W字minium微信小程序自动化测试框架项目手册❤️_第4张图片

更加详细的配置说明请访问appium/WebDriverAgent/wiki

配置测试 config.json

在用例目录下面新增一个叫config.json的配置文件,格式如下

{
  "platform": "iOS",
  "device_desire":{
    "wda_project_path": "/Users/sherlock/github/appium/WebDriverAgent", //自定义 wda 的路径
    "device_info": {
          "udid": "aee531018e668ff1aadee0889f5ebe21a2292...", //手机的 udid 
          "model": "iPhone XR",
          "version": "12.2.5",
          "name": "sherlock's iPhone"
    }
  }
}Copy to clipboardErrorCopied

PS: JSON不支持注释,请把“//”以及后面的内容删掉

详细说明请看:测试配置

项目配置

为了保证同一套代码在IDE,Android,IOS上运行,环境组成比较复杂,所以测试用例的运行依赖于配置文件。相关配置项说明如下表:

配置项 类型 默认值 说明
platform String ide 小程序运行的平台,可选值为:ide, Android, IOS
project_path String 小程序代码的项目路径,如果配置了之后,那么需要同时配置dev_tool_path
dev_tool_path String 小程序IDE cli的路径
enable_app_log Boolean True 是否监听小程序代码返回的日志
enable_network_panel Boolean False 是否监听所有wx.request的请求和返回,日志生成到request.log
outputs String outputs 用例运行的结果存放目录
debug_mode String info 日志打印级别,可选:error, warn, info, debug
close_ide Boolean False 执行完一个 class 是否关闭 ide,ide 下运行不生效
full_reset Boolean False 执行完一个 class 是否关闭 ide 和 native driver
device_desire Object null 连接手机的参数,跟手机平台有关系
test_port int 9420 IDE监听的端口,默认为9420
assert_capture Boolean True 在assert的时候是否截图
auto_relaunch Boolean True 启动的时候relaunch到启动页面
use_push Boolean True 是否自动推送远程调试
remote_connect_timeout int 180 远程调试连接超时时间 s
request_timeout int 30 请求连接超时时间 s
account_info dict None 账号信息,多账号运行使用
mock_native_modal dict {} 仅在ide上生效, mock会引起授权弹窗的方法, 使有弹窗的情况下仍能在ide上运行,具体用法请参考IDE的mock_native_modal配置项
mock_request list [] mock网络请求, 具体用法参考mock_request配置项

其中 account_info 有如下两项,通过minitest -a 获取:

配置项 类型 默认值 说明
wx_nick_name String None 微信账号名称
open_id String None 微信账号的 open_id

其中,device_desire跟平台有关系,不同平台配置不一样。

Android的device_desire配置项

配置项 类型 默认值 说明
serial String null Android设备号, adb devices查看
uiautomator_version int 1 底层使用的Ui Automator版本, 可选: 12

IOS的device_desire配置项

device_desire:

配置项 类型 默认值 说明
wda_project_path String not null 自定义 wda 的路径
device_info Dict not null 真机信息

其中device_info:

配置项 类型 默认值 说明
udid String not null 手机的 uuid
model String null 机型
version String null 系统版本
name String null 设备名称

IDE的mock_native_modal配置项

mock_native_modal:

配置项 类型 默认值 说明
weRunData Dict None 参考wx.getWeRunData接口返回的结果信息
userInfo Dict None 参考wx.getUserInfo接口返回的结果信息
location Dict None 参考wx.getLocationwx.chooseAddress接口返回的结果信息
{
    "mock_native_modal": {
        "weRunData": {
            "encryptedData": "123",
            "iv": "456=="
        },
        "userInfo": {
            "nickName":"test test",
            "gender":1,
            "language":"zh_CN",
            "city":"",
            "province":"",
            "country":"St.Kitts and Nevis",
            "avatarUrl":"https://xxxx.qq.com"
        },
        "location": {
            "address": "广东省广州市",
            "latitude": 23.0999,
            "longitude": 113.3249,
            "name": "腾讯微信总部"
        }
    }
}Copy to clipboardErrorCopied

mock_request配置项

mock_request中每一项配置:

配置项 类型 默认值 说明
rule str|dict Not None 规则,如类型为str,则默认匹配url
success dict None 成功回调结果,与参数fail需二选一
fail str|dict None 失败回调结果,如类型为str,会自动填充成基础库返回格式,与参数success需二选一

以下例子运行效果同App.mock_request中的例子

{
    "mock_request": [
        {
            "rule": ".*/SendMsg\\?.*", 
            "success": {"data": "mock result1", "statusCode": 200}
        },
        {
            "rule": {"url": ".*/SendMsg$"}, 
            "success": {"data": "mock result2", "statusCode": 200}
        },
        {
            "rule": {"url": ".*/SendMsg.*", "data": {"content": "^\\d+$"}}, 
            "success": {"data": "mock result3", "statusCode": 200}
        },
        {
            "rule": {"url": ".*/SendMsg.*"}, 
            "fail": {"errMsg": "request:fail mock fail"}
        },
    ]
}Copy to clipboardErrorCopied

例子

{
    "debug_mode": "debug",
    "enable_app_log": true,
    "project_path": "/Users/sherlock/github/miniprogram-demo",
    "dev_tool_path": "/Applications/wechatwebdevtools.app/Contents/MacOS/cli",
    "platform": "ios",
    "close_ide": true,
    "test_port": 9420,
    "assert_capture": true,
    "use_push": true,
    "auto_relaunch": true,
    "remote_connect_timeout": 180,
    "device_desire": {
        "wda_project_path": "/Users/sherlock/.npm-global/lib/node_modules/appium/node_modules/appium-webdriveragent",
        "os_type": "ios",
        "device_info": {
            "udid": "aee531018e668ff1aadee0889f5ebe21axxxxxe8",
            "model": "iPhone XR",
            "version": "12.2.5",
            "name": "sherlock's iPhone"
        }
    }
}

元素定位

minium 通过 WXSS 选择器来定位元素的,目前小程序仅支持以下的选择器:

选择器 样例 样例描述
.class .intro 选择所有拥有 class="intro" 的组件
#id #firstname 选择拥有 id="firstname" 的组件
element view 选择所有 view 组件
element, element view, checkbox 选择所有文档的 view 组件和所有的 checkbox 组件
::after view::after 在 view 组件后边插入内容
::before view::before 在 view 组件前边插入内容

简单选择器

一个元素的选择器通常是以下格式组成的:

id 不能以数字开头,命名规范问题

tageName + #id + .className

这其实是三个选择器组合的结果,其中:

  • tagName :类型选择器,标签名称,view、checkbox 等等,选择所有指定类型的最简单方式。
  • id:ID 选择器,自定义给元素的唯一 ID,使用时前面跟着 # 号,这是选择单个元素的最有效的方式。
  • className:类选择器,由一个点.以及类后面的类名组成,存在多个类的时候可以以点为间隔一直拼接下去。

e.g:

Copy to clipboardErrorCopied

假如要查找像上面这一个元素的话,他的选择器会像是下面这样:

view#main.page-section.page-section-gapCopy to clipboardErrorCopied

另一种写法

view[id='main'][class='page-section page-section-gap']Copy to clipboardErrorCopied

所以,通常我们只需要关注一个元素的 id 和 class 即可。但是有时候有的情况是,有一堆没有 id ,相同 class 的同名标签,我们没办法通过 id 或者 class 来区分了,比如我们 demo 的 input 页面:


    
      可以自动聚焦的input
      
        
          
        ...
          
        ...
          
        ...
          
        ...
          
        ...
          
        ...
          
        ...
          
        ...
          
        ...
          
        ...Copy to clipboardErrorCopied

我们仔细观察,虽然所有的 input 都有着同样的 class,但其实他们并非都是一模一样的,在实际测试中,我们发现绝大部分的属性都可以用来寻找。

e.g:

Copy to clipboardErrorCopied

如上,我们可以通过 type 和 placeholder 两个属性去找到这个元素。

input[type='digit']Copy to clipboardErrorCopied

或者

input[placeholder='带小数点的数字键盘']Copy to clipboardErrorCopied

亦或者,两者加起来

input[type='digit'][placeholder='带小数点的数字键盘']Copy to clipboardErrorCopied

所以,具体情况具体分析,在我测试的过程中发现,bindinput 这一类绑定方法是不能用作寻路依据的。

多账号

公共库 2.10.0 之后支持

  1. 使用多账号并行测试首先需要在开发者工具登录多个账号

❤️【CSDN首发】5W字minium微信小程序自动化测试框架项目手册❤️_第5张图片

  1. 获取登录账号的 open id

    2.1 先以自动化模式打开开发者工具,端口默认 9420

    2.2 minitest -a 获取 open id获取 open id

  2. 创建配置文件,形式如下,你需要将 open id 和 udid 替换成你自己的账号和设备,保存为 m_config.json

[{
    "debug_mode": "debug",
    "enable_app_log": true,
    "project_path": "/Users/sherlock/github/miniprogram-demo",
    "dev_tool_path": "/Applications/wechatwebdevtools.app/Contents/MacOS/cli",
    "platform": "ide",
    "app": "wx",
    "close_ide": false,
    "test_port": 9421,
    "assert_capture": true,
    "use_push": true,
    "auto_relaunch": true,
    "remote_connect_timeout": 10,
    "account_info": {
        "wx_nick_name": "locker",
        "open_id": "o6zAJs_pwr**********aROZDjiw"
    },
    "device_desire": {
        "wda_project_path": "/Users/sherlock/.npm-global/lib/node_modules/appium/node_modules/appium-webdriveragent",
        "os_type": "ios",
        "device_info": {
            "udid": "aee531018e668ff1aad*************2924e8",
            "model": "iPhone 6",
            "version": "12.2.5",
            "name": "sherlock's iPhone"
        }
    }
},
{
    "debug_mode": "debug",
    "enable_app_log": true,
    "project_path": "/Users/sherlock/github/miniprogram-demo",
    "dev_tool_path": "/Applications/wechatwebdevtools.app/Contents/MacOS/cli",
    "platform": "ide",
    "app": "wx",
    "close_ide": false,
    "test_port": 9422,
    "assert_capture": true,
    "use_push": true,
    "auto_relaunch": true,
    "remote_connect_timeout": 10,
    "account_info": {
        "wx_nick_name": "恒瑜_Sherlock",
        "open_id": "o6zAJsx7zt4***********Tz7Kx10A"
    },
    "device_desire": {
        "wda_project_path": "/Users/sherlock/.npm-global/lib/node_modules/appium/node_modules/appium-webdriveragent",
        "os_type": "ios",
        "device_info": {
            "udid": "aee531018e668ff1***********ebe21a22924e8",
            "model": "iPhone XR",
            "version": "12.2.5",
            "name": "sherlock's iPhone"
        }
    }
}]Copy to clipboardErrorCopied
  1. 启动测试
$ minitest -s suite.json -c m_config.json -gCopy to clipboardErrorCopied
  1. 静候

❤️【CSDN首发】5W字minium微信小程序自动化测试框架项目手册❤️_第6张图片

PS: 上图为了方便展示,platform 配置项都设置为 ide,真机运行只需将 platform 设置为 iOS 或者 Android,并填写好设备 udid 即可,跟之前单机真机运行的步骤一致

今天的文章就分享在这里了,关注我后续会继续更新优质的文章

最后感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走: 

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!

在我的QQ技术交流群里(技术交流和资源共享,广告勿扰)

可以自助拿走,群号:310357728群里的免费资料都是笔者十多年测试生涯的精华。还有同行大神一起交流技术哦

如果对你有一点点帮助,各位的「点赞」就是小编创作的最大动力,我们下篇文章见

好文推荐

在小公司“混”了2年,我只认真做了5件事,如今顺利拿到字节 Offe

去了字节跳动,才知道年薪 30w 的测试工程师有这么多?

北京35岁程序员失业,感叹:编程估计没戏了,想去卖点煎饼果子养家~ 

29岁转行软件测试靠谱吗?一个过来人的心路历程送给迷茫的你

同样是IT行业,测试和开发薪资真就差这么大吗? 

 

你可能感兴趣的:(程序人生,技术分享,小程序,微信,app,软件测试,测试工程师)