移动端运行JS脚本调试方案-单元测试

前言

前段时间写了一篇关于移动端运行JS脚本的文章记录一次在移动端运行JS脚本的试验, 里面提到关于调试的部分:搭建一个Vue项目用于脚本的调试。但经过一段时间的实践发现,该方案弊端较多

  1. 模块之间较难做整合
  2. 调试是通过eval注入的脚本打包产物,虽说也可在浏览器控制台调试,但不够直接。(其实是移动端写多了不太习惯在浏览器调试。。。)
  3. Vue毕竟与视图有关联,每次新增脚本都需要编写额外的Vue部分代码,增加了成本

说白了就是懒。。。所以针对调试这件事,笔者重新思考了一下。JS脚本的验证主要分为两个部分:逻辑正确环境适配。环境的话,只要JS引擎的适配性强,一般不会有大问题。毕竟最终还会使用Babel进行编译,这也是借鉴前端开发的场景得出的结论。所以大部分问题会出现在逻辑上,再结合上面提到的问题,最后笔者打算通过Jest做一个由Typescript编写的单元测试

Jest单元测试

流程

image.png 这里将之前的浏览器层替换成了Jest单元测试。由于是模拟层,所以关于脚本中需要原生注入的对象都会在单元测试中进行模拟。

Jest搭建

这里笔者采用的是Jest + Babel + Typescript的结构。Babel负责Typescript的编译,以及JS版本的转换问题。

npm install jest @types/jest babel-jest --save-dev

npx jest --init

初始化后,会生成一个jest.config.js,用于Jest的配置,这里没有特殊的配置所以没有修改。编译过程中会自动读取babel.config.js,如果测试与实际打包的Babel配置有区别则需要特别区分。更多的信息可以查看Jest文档

简单的测试代码

Jest环境就绪后,就需要一个.(spec|test).ts的文件作为单元测试的case文件。以下是以上篇文章提到的Demo代码为基础编写的单元测试。这里主要分为两端的测试,Android、iOS。

describe('Test', () => {
    beforeEach(() => {
        jest.resetModules()
    });

    test('Android', () => {
        process.env.OS = 'Android'

        // 模拟原生对象注入
        const dbObj = require('./exports/db').default
        dbObj.loadDB('./test/sqlite/test.db', 'database')

        const deviceInfoObj = require('./exports/deviceInfo').default
        deviceInfoObj.loadDeviceInfo('Android')

        // 注入脚本
        require('../src/Test')
        
        // 脚本内容执行
        const inferInterface = global['test']
            
        inferInterface.testFetchOne()

        dbObj.closeDB('database')
    })

    test('iOS', () => {
        process.env.OS = 'iOS'
        
        // 模拟原生对象注入
        const dbObj = require('./exports/db').default
        dbObj.loadDB('./test/sqlite/test.db', 'database')

        const deviceInfoObj = require('./exports/deviceInfo').default
        deviceInfoObj.loadDeviceInfo('iOS')
        
        // 注入脚本
        require('../src/Test')

        // 脚本内容执行
        const inferInterface = global['test']
            
        inferInterface.testFetchOne()

        dbObj.closeDB('database')
    })

    afterEach(() => {
        delete process.env.OS
    })
})
复制代码

test函数可以理解为每个测试case,这里分为Android、iOS。具体的流程就和移动端运行时大同小异了:

  1. 原生对象注入(这里是创建一个JS对象添加到global进行模拟)。
  2. 注入脚本(依赖脚本代码)。
  3. 脚本内容执行。

ps:这里没有用太多Jest的api,具体细节可查看Jest官方文档

运行效果:

在控制台运行后,可查看每个case的运行状况,如果是出错也会有对应的堆栈

image.png

image.png

结合VSCode

还可以结合VSCode进行断点调试

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "launch",
            "name": "Jest",
            "program": "${workspaceFolder}/module-script/node_modules/.bin/jest",
            "args": [
                
            ],
            "cwd": "${workspaceRoot}/module-script", 
            "outputCapture": "std",
        }
    ]
}
复制代码

创建一个launch.json执行jest命令,接下来就能愉快的断点调试脚本了。

最后

以上就是关于脚本的单元测试内容。采用这种方式可以很好的解决随脚本复杂度提高带来的调试成本,也是比较符合移动端开发习惯的

最后再贴一下Demo地址:xcyoung/mobile-js-engine-exsample (github.com)

猜你喜欢

转载自juejin.im/post/7095661839442247717