模拟 es6 模块返回工厂函数(moment.js)

Posted

技术标签:

【中文标题】模拟 es6 模块返回工厂函数(moment.js)【英文标题】:Mocking es6 module returning factory function (moment.js) 【发布时间】:2018-11-30 01:13:36 【问题描述】:

警告:我是 Jest 的新手,所以请忍耐。

我正在尝试使用名为 DateFilter 的 Jest 测试 Vue2.js 过滤器。此过滤器只是将日期格式应用于传递给它的日期。

日期过滤器.js

import Vue from 'vue';
import moment from 'moment';

const dateFormatter = (dateValue, dateFormat) => 
    return moment(dateValue).format(dateFormat);
;

Vue.filter('date', dateFormatter);

export default dateFormatter;

所以,我在这里看到三个有效的单元测试

    DateFilter 模块应该导出一个函数

    日期过滤器应使用传递的日期值初始化时刻

    日期过滤器应该在传递了 dateFormat 的那一刻调用 format 方法

DateFilter.test.js

import moment from 'moment';
import DateFilter from './DateFilter';

describe('DateFilter', () => 
    it('should exist', () => 
        expect(DateFilter).toBeDefined();
        expect(typeof DateFilter).toBe('function');
    );

    it('should moment.format with the dateValue and dateFormat passed.', () => 
        // Here I get lost in how to spyOn moment function and the .format function
        const mockDateFormat = `dateFormat-$Math.random()`;
        const mockDate = `mockDate-$Math.random()`;
        jest.mock('moment', () => 
            return  format: jest.fn() 
        );
        // expect moment to have been called with mockDate
        // expect moment(mockDate) to have been called with mockDateFormat
    );
);

【问题讨论】:

【参考方案1】:

不确定你想测试多少细节,但我猜这个秘密是对 momentjs 的一个很好的模拟。由于您只想测试您的 dateFormatter,您可以执行以下操作:

首先我们将 mock 设置为 momentjs:

jest.mock('moment', () => 
    const momentMock =  format: jest.fn() 

    return jest.fn(() => momentMock);
);

如果您尝试将对象传递给jest.fn 而不是声明 const,您可能会收到未调用该函数的错误,那是因为我们将在每次调用 moment 时生成不同的 mock,而不是使用相同的 mock对于所有moment 调用。

这是一个非常简单的,你可以做一个更详细的时刻模拟,但我认为不值得付出努力,因为你的功能很简单。

然后,我认为您已经分离了单元测试,您可以将它们放在一个中,但有时单独断言函数链会更好。

it('calls moment with the dateValue passed.', () => 
    const mockDateFormat = `dateFormat-$Math.random()`;
    const mockDate = `mockDate-$Math.random()`;

    dateFormatter(mockDate, mockDateFormat);

    expect(moment).toHaveBeenCalledWith(mockDate)
);
it('calls format with the dateFormat passed.', () => 
    const mockDateFormat = `dateFormat-$Math.random()`;
    const mockDate = `mockDate-$Math.random()`;

    dateFormatter(mockDate, mockDateFormat);

    expect(moment(mockDate).format).toHaveBeenCalledWith(mockDateFormat)
);

免责声明:在第二个测试中,您是否期望 moment(), moment(mockDate) or moment('Whatever') 并不重要,因为您总是模拟相同的东西,您将收到相同的 format 模拟返回。

如果你想要更复杂的东西,你需要创建一个fixture,将momentjs被调用的日期映射到一个包含模拟函数的新对象。但我相信这更麻烦,实际上你最好只测试那个时刻已经被调用并且格式已经被调用。否则,您将在很大程度上测试 3rd 方库的工作方式。

希望这能给你一些指导

【讨论】:

以上是关于模拟 es6 模块返回工厂函数(moment.js)的主要内容,如果未能解决你的问题,请参考以下文章

在开玩笑的模拟模块工厂中模拟一个承诺

TypeScript + moment.js:错误 TS2307:找不到模块'moment'

jest.mock():如何使用工厂参数模拟 ES6 类默认导入

如何使用 Moment.js 返回当前时间戳?

无法使用 moment.js 返回 UTC 日期时间

在 React Native 中使用 moment.js 無法載入語系檔案