单元测试
优质
小牛编辑
133浏览
2023-12-01
Mpx 会生成源码与最终产物包的映射关系,结合微信小程序提供的 miniprogram-simulate 来进行单元测试的工作。
因为目前仅微信提供了仿真工具,暂时只支持微信小程序平台的单元测试。如果需要 E2E 测试,则和框架无关了,可参考微信的小程序自动化。
简单的断言
组件必须是被项目真实使用的,且经过一次构建才可被测试。构建时 MpxPlugin 的配置信息中要将 generateBuildMap 属性置为 true
来生成源码与最终代码的映射关系。
<template>
<view>{{ message }}</view>
</template>
<script>
import {createComponent} from '@mpxjs/core'
createComponent({
data: {
message: 'hello!'
},
attached () {
this.message = 'bye!'
}
})
</script>
然后通过辅助方法读取 dist/outputMap.json 以获取源码最终生成的组件dist的路径,再配合 miniprogram-simulate 进行测试。你可以使用许多常见的断言 (这里我们使用的是 Jest 风格的 expect 断言作为示例):
const simulate = require('miniprogram-simulate')
function resolveDist (dir) {
return path.join(__dirname, '../dist/wx', dir)
}
// 辅助方法,通过源码获取最终的dist路径,让simulate工具以正确load
function loadComponent (componentPathStr) {
const outputMap = require(resolveDist('../outputMap.json'))
const componentPath = resolve(componentPathStr)
const realComponentPath = resolveDist(outputMap[componentPath])
return simulate.load(realComponentPath, undefined, {rootPath: resolveDist('')})
}
// 这里是一些 Jasmine 2.0 的测试,你也可以使用你喜欢的任何断言库或测试工具。
describe('MyComponent', () => {
let id
beforeAll(() => {
id = loadComponent('src/components/hello-world.mpx')
})
// 检查 mount 中的组件实例
it('correctly sets the message when component attached', () => {
const comp = simulate.render(id)
const instance = comp.instance
// Mpx提供的数据响应是发生在组件挂载时的,未挂载前只能通过实例上的data访问数据
expect(instance.data.message).toBe('hello!')
const parent = document.createElement('parent-wrapper') // 创建容器节点
comp.attach(parent) // 将组件插入到容器节点中,会触发 attached 生命周期
// 挂载后则可以直接通过实例访问
expect(instance.message).toBe('bye!')
})
// 创建一个实例并检查渲染输出
it('renders the correct message', () => {
const comp = simulate.render(id)
const parent = document.createElement('parent-wrapper') // 创建容器节点
comp.attach(parent) // 挂载组件到容器节点
expect(comp.dom.innerHTML).toBe('<wx-view>bye!</wx-view>')
})
})
编写可被测试的组件
很多组件的渲染输出由它的 props 决定。事实上,如果一个组件的渲染输出完全取决于它的 props,那么它会让测试变得简单,就好像断言不同参数的纯函数的返回值。看下面这个例子:
<template>
<view>{{ msg }}</view>
</template>
<script>
import {createComponent} from '@mpxjs/core'
createComponent({
properties: { msg: String }
})
</script>
你可以在不同的 properties 中,通过 simulate.render 的第二个参数控制组件的输出:
const simulate = require('miniprogram-simulate')
// 省略辅助方法
describe('MyComponent', () => {
it('renders correctly with different props', () => {
const id = loadComponent('src/components/hello-world.mpx')
const comp1 = simulate.render(id, { msg: 'hello' })
const parent1 = document.createElement('parent-wrapper')
comp1.attach(parent1)
expect(comp1.dom.innerHTML).toBe('<wx-view>hello</wx-view>')
const comp2 = simulate.render(id, { msg: 'bye' })
const parent2 = document.createElement('parent-wrapper')
comp2.attach(parent2)
expect(comp2.dom.innerHTML).toBe('<wx-view>bye</wx-view>')
})
})
断言异步更新
小程序视图层的更新是异步的,一些依赖视图更新结果的断言必须 await simulate.sleep() 后进行:
const simulate = require('miniprogram-simulate')
// 省略辅助方法
it('updates the rendered message when vm.message updates', async () => {
const id = loadComponent('src/components/hello-world.mpx')
const comp = simulate.render(id)
const parent = document.createElement('parent-wrapper')
comp.attach(parent)
comp.instance.msg = 'foo'
await simulate.sleep(10)
expect(comp.dom.innerHTML).toBe('<wx-view>foo</wx-view>')
})
更深入的 Mpx 单元测试的内容将在以后持续更新……