articles
articles copied to clipboard
单元测试系列 -- jest常用mock
进行单元测试时,我们希望得到的数据是稳定可控的,例如应用涉及调用网络接口数据,可以通过mock的方法控制数据的返回。
下面为获取电影列表数据的业务代码 页面在onLoad时执行getComingFilm方法,getComingFilm方法获取网络数据。
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后日期数据进行格式化。
使用spyOn保留方法原定义逻辑和增加mock方法
下面的单元测试用来保障onLoad时调用getComingFilm方法,但是你发现jest会提示getComingFilm为非mock对象,不能调用toBeCalled函数。
it('should getComingFilm', () => {
page.onLoad();
expect(page.getComingFilm).toBeCalled();
});
那我们把getComingFilm方法转换成mock对象
it('should getComingFilm', () => {
page.getComingFilm = jest.fn();
page.onLoad();
expect(page.getComingFilm).toBeCalled();
});
以上写法虽然能调用toBeCalled方法了,但原来的getComingFilm方法被覆盖,如果后续要用到该方法,将无法执行正确逻辑。 可以使用spyOn方法,既保留方法原先定义,又让方法具备mock方法。
it('should getComingFilm', () => {
jest.spyOn(page, 'getComingFilm');
page.onLoad();
expect(page.getComingFilm).toBeCalled();
});
mock网络请求
const filmServer = require('../../server/film.js');
getComingFilm() {
return filmServer.getComingSoon(1, 5).then((data) => {
});
});
上面的业务代码,通过filmServer进行网络请求,获取相应业务数据。 我们希望测试代码中使用mock数据,可以在server目录下创建__mocks__文件夹并创建film.js文件。
server/mocks/film.js 文件代码如下
const filmService = jest.mock('../film.js');
const comingSoonRes = { films: [{ id: 1, name: 'test', premiereAt: Date.now() }], page: { total: 10, current: 1 } };
filmService.getComingSoon = jest.fn(() => Promise.resolve(comingSoonRes));
module.exports = {
getComingSoon: filmService.getComingSoon,
comingSoonRes,
};
在你的测试文件加入mock声明,原网络请求接口就会被替换。
// 使用mock文件
jest.mock('../../server/film.js');
// getComingFilm将返回server/__mocks__/film.js中定义的数据
it('should format premiereAt as MM月DD日 ', () => page.getComingFilm().then(() => {
expect(page.data.comingFilms[0].displayDate).toEqual('9月12日');
}));
注意:premiereAt字段使用了Date.now() 创建时间戳,但是因为该方法会随着执行时间变化,需要控制该方法的返回值
通过global设置方法的固定返回。
global.Date.now = jest.fn(() => 1536708613825);