用Jest模拟可观察到的-rxjs

时间:2018-12-07 10:53:57

标签: unit-testing mocking rxjs jestjs

我有一个要测试的来自其他Observable的简单Observable管道。

const loginState$ = messageBusObservables.loginState$.pipe(
    startWith({ isLoggedIn: false })
    pluck('isLoggedIn'),
    distinctUntilChanged()
  )

messageBusObservables是可观察对象。其中loginState $是可观察的。

在测试中,我认为我可以轻松地像这样模拟'./messageBus'模块:(该模块的导入方式无关紧要,但首选导入)

import { of } from 'rxjs'
import './messageBus'
jest.mock('./messageBus', () => ({
  loginState$: of({ isLoggedIn: true }),
}))

但是,Jest抛出了错误:

  

babel-plugin-jest-hoist:jest.mock()的模块工厂不允许引用任何范围外的变量。       无效的变量访问:of

我尝试过将其放入jest.fn()中,我尝试将of({ isLoggedIn: true })提取到变量中。但是我总是从玩笑中得到同样的错误。

那么我该如何使用Jest模拟输入到Observable的内容呢?我将使用.merge,.zip等其他可观察对象遇到相同的问题。

它必须是真实的可观察物,是我其他可观察物的输入。我只想使用of()之类的值来模拟值,而不是模拟带有方法的对象,该方法使用.pipe方法等返回对象。(我不想模拟可观察)。我想通过在单元测试中设置的值将其传递给真实的可观察对象。

我还需要这些模拟是动态的。因此,来自1断言的模拟可能不同于下一个断言中的模拟。 (用beforeEach之类的东西清除它们)

编辑:

我还尝试使用babel-plugin-rewire来模拟此模块,在我模拟它的* .test.js文件中,它工作正常。但是在实际文件中,无论我将导出设置为使用rewire进行什么操作,它始终都将作为原始的Observable导入。

2 个答案:

答案 0 :(得分:2)

您已经关闭。

您正在尝试通过passing a module factory as the second parameter to jest.mock模拟该模块。这种方法的主要限制是模块工厂必须完全独立,并且“不允许引用任何范围外的变量”。

从模块工厂中的of引用rxjs(您已经发现)打破了该约束,并导致了您看到的错误。

幸运的是,还有其他模拟模块的方法。

从您的代码中可以看出,最简单的方法似乎是创建messageBus模块的Manual Mock


在与__mocks__相同的目录中创建一个messageBus.js文件夹,并在messageBus.js文件夹中创建模拟对象(也称为__mocks__)。

__mocks__/messageBus.js看起来像这样:

import { of } from 'rxjs'

export default {
  loginState$: of({ isLoggedIn: true })
}

然后通过致电tell Jest you want to use the manual mock within your test

jest.mock('messageBus');

位于测试文件的顶部。

That call is hoisted by Jest,并确保在测试过程中导入messageBus的所有代码都将获得模拟模块。

答案 1 :(得分:1)

收到此消息的原因:

  

babel-plugin-jest-hoist:jest.mock()的模块工厂不允许引用任何范围外的变量。无效的变量访问:of

是因为jest自动将调用提升到jest.mock,以便它们在导入之前发生。

您有两种方法可以避免这种默认行为,简单的方法是使用未悬挂的jest.doMock:

jest.doMock('./messageBus', () => ({
  loginState$: of({ isLoggedIn: true }),
}))

或者,您可以在传递给jest.mock的模拟工厂中引用的所有变量前面加上“ mock”:

const mockMessageBus = {
  loginState$: of({ isLoggedIn: true }),
}
jest.doMock('./messageBus', () => mockMessageBus)

(请注意,当调用jest.mock时,您有责任确保工厂函数中引用的所有模拟变量都在范围内)