小程序单元测试
发布于 7 年前 作者 zhengguorong 4216 次浏览 来自 分享

小程序的测试和web应用测试区别不大,可以利用jest进行测试,但是由于jest只提供了nodejs和浏览器执行环境,因此小程序的api我们需要mock,下面讲解小程序测试的一些mock技巧。

mock小程序API

我们测试小程序时,经常会调用微信api,例如wx.showLoading方法,但是因为我们的执行环境未定义该方法,会出现调用错误。

我们可以通过jest提供的global设置全局变量,可以在测试文件中单独编写,或者在package.json的jest块设置setupFiles属性,让jest自动加载。

 "jest": {
 "setupFiles": ["./__tests__/wx.js"]
 },

./tests/wx.js文件内容如下,表示将小程序的api方法定义为mock方法。

global.wx = {
 showLoading: jest.fn(),
 hideLoading: jest.fn(),
 showModal: jest.fn(),
 request: jest.fn(),
 getStorageSync: jest.fn(),
 showShareMenu: jest.fn(),
};

测试小程序页面

// 空白的小程序页面代码
Page({
 onLoad () {
 // your code
 }
})

一个空白的小程序页面,代码会被Page方法包裹,同时Page初始化后,会执行onLoad、onReady等生命周期方法,而且当前对象还能调用setData方法对页面data数据进行修改。

我们需要mock Page方法的实现,代码如下。

export const noop = () => {};
export const isFn = fn => typeof fn === 'function';
let wId = 0;
global.Page = ({ data, ...rest }) => {
 const page = {
 data,
 setData: jest.fn(function (newData, cb) {
 this.data = {
 ...this.data,
 ...newData,
 };
 cb && cb();
 }),
 onLoad: noop,
 onReady: noop,
 onUnLoad: noop,
 __wxWebviewId__: wId++,
 ...rest,
 };
 global.wxPageInstance = page;
 return page;
};

举个例子

假设我们的小程序页面是一个电影列表展示,业务代码如下。

const filmServer = require('../../server/film.js');
Page({
 data: {
 comingFilms: [],
 },
 onLoad() {
 this.getComingFilm();
 },
 // 获取即将上映电影列表
 getComingFilm() {
 return filmServer.getComingSoon(1, 5).then((data) => {
 data.films.forEach((film) => {
 const displayDate = `${new Date(film.premiereAt).getMonth() + 1}月${new Date(film.premiereAt).getDate()}日`;
 film.displayDate = displayDate;
 });
 this.setData({ comingFilms: data.films });
 });
 },
});

我们的编写两个测试用例保证代码的正确运行。 1、保证onLoad时执行getComingFilm方法。 2、保证getComingFilm后日期数据进行格式化。

import '../../pages/film'; // 加载需要测试的页面
// 获取当前初始化的page对象,后续可用来调用setData等方法,类似小程序页面里的this。
const page = global.wxPageInstance;
// mock网络请求
jest.mock('../../server/film.js');
describe('电影首页', () => {
 describe('onLoad', () => {
 beforeAll(() => {
 // spyOn后可使方法具有mock属性,同时不影响方法调用。
 jest.spyOn(page, 'getComingFilm');
 // 执行页面onLoad生命周期。
 page.onLoad();
 });
 it('should getComingFilm', () => {
 // 断言onLoad后,是否执行了getComingFilm方法。因为我们前面已经将getComingFilm进行spyOn了,所以可以执行toBeCalled判断,否则会出错。
 expect(page.getComingFilm).toBeCalled();
 });
 });
 describe('getComingFilm', () => {
 it('should format premiereAt as MM月DD日 ', () => page.getComingFilm().then(() => {
 // 断言获取数据后,原始数据增加displayDate属性,格式化为MM月DD日
 expect(page.data.comingFilms[0].displayDate).toEqual('9月12日');
 }));
 });
});

🌟🌟由于测试代码比较长,上面只截取了部分,完整代码可以访问github获取

回到顶部

AltStyle によって変換されたページ (->オリジナル) /