使用Jest在Vue组件中模拟导入的模块

11

我处理Jest的文档时遇到了一些问题,因为我期望这段代码可以工作:

import Vue from 'vue';
import Router from '@/router/index';
import OrdersService from '@/services/orders.service';

jest.mock('@/services/orders.service');

describe('OrdersItem.vue', () => {
  beforeEach(() => {
    // mockClear does not exist
    OrdersService.mockClear();
  });

  it('should render expected list contents', () => {
    // Orders.mock is undefined 
    OrdersService.getAll.mockResolvedValue([ ... ]);
    // ...

但事实并非如此。它失败的情况就好像OrdersService从未被模拟一样。我也尝试了类似以下的操作:

jest.mock('@/services/orders.service', () => jest.fn());
jest.mock('@/services/orders.service', () => { getAll: jest.fn() });

第一种方法是用一个模拟函数替换整个服务(我想实现在文档中提到过的自动模拟功能,其中原始服务的所有方法都会自动替换为模拟函数)。 第二种方法与只使用模块路径的.mock调用方式失败了。

我在这里做错了什么,为什么会这样?

orders.service骨架:

import axios from 'axios';
import config from '../config/config.json';
import Order from '../models/order';

class OrdersService {
  constructor(httpClient) {
    this.httpClient = httpClient;
  }

  getAll() {
      // ...
  }
}
export default new OrdersService(axios);

1
你能展示一下 order.service 的框架吗? - Icepickle
我猜这里的问题是你返回了一个实例,而不是类本身。 - Icepickle
@Icepickle,你能解释一下吗? - guessimtoolate
5个回答

5

看起来在使用jest.mock#4262)时存在问题,涉及到模块解析器、别名、路径等使用@/somethingmoduleNameMapper

// you cannot use a module resolver (i.e. '@')
jest.mock('@/services/orders.service');

// you must use the full path to the file for the import and mock
import OrdersService from '../../src/services/orders.service';
jest.mock('../../src/services/orders.service');

请关注问题的更新,最后一次更新似乎是在9/28

其次,如果您解决了上述问题,您将会导出一个类实例而不是类本身,就像Jest示例中所做的那样。因此,您将无法访问OrdersService上的clearMock方法,但您可以在类实例上调用每个模拟方法的clearMock

// mockClear will be undefined
OrdersService.mockClear();

// mockClear is defined
OrdersService.getAll.mockClear();

如果您想将实例导出为原样,只需在beforeEach中使用jest.clearAllMocks清除所有模拟数据,或循环遍历所有方法并在每个方法上调用mockClear。否则,导出类本身将使您可以访问OrdersService.mockClear,该方法将......

清除构造函数和所有方法的所有实例和调用 (ref)

这似乎在模拟类被用于另一个要测试的类中时非常有用,就像在Jest示例中一样。 所有这些都已经使用Jest v23.6和vue-cli v3.0.4进行了测试和确认。

谢谢,伙计。我很感激你的研究。然而,在我的特定情况下,切换导入语句使用相对路径并没有解决我的问题。 最终,我使用手动模拟,创建__mocks__目录来模拟模块,并放弃了es6类,转而使用导出带有方法的对象字面量。我觉得这不是很优雅,但它似乎到目前为止可以工作。现在我遇到了其他问题,所以我的原始问题很可能也会随着jest(22.0.4)、vue-test-utils(1.0.0-beta.25,sic)、babel-jest(21.0.2)等更新而解决。 - guessimtoolate
没关系,很抱歉这在你的情况下没有起作用。是的,我通常只模拟我需要的部分,忽略其他部分。 - Nickofthyme

1

由于OrdersService是一个类的实例,它将返回一个对象,您需要手动模拟此对象公开的所有属性。

您可以尝试使用以下实现来模拟您的函数。参考文档

OrdersService.getAll = jest.fn(()=>{
// mock implementation here;
});

希望这有所帮助 :)

0

0
你可以尝试在beforeEach块中调用jest.resetModules(),这可能会导致使用模拟服务。

0
遇到这个问题时,尝试使用"mount"命令时遇到了一些问题,不想手动设置很多东西,最简单的方法是导入该模块。
import TestThisModule from 'testThisModule';

然后直接为我观察的方法编写一个spyon,通过访问模块的原型来编写测试。
const resetMethodSpy = jest.spyOn(TestThisModule.prototype, 'reset');
const { wrapper } = factory();
await (wrapper.vm as any).triggerMethod();
expect(resetMethodSpy).toHaveBeenCalled();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接