为什么当我的JEST模拟游戏中的一个正常工作时,我的另一个模拟游戏无法正常工作?

时间:2019-10-14 16:48:51

标签: javascript unit-testing jestjs

我定义了2个JEST模拟。我遇到的问题。第一个模拟无效,而第二个模拟无效。

import Helper from '../../test-helper'

import Storage from '@/storage'
import GuestContext from '@/auth/guest-context'
import UserContext from '@/auth/user-context'

// import LocalStorageGateway from '@/storage/local/local-storage-gateway'
const mockContextUpsert = jest.fn()

jest.mock('@/storage/local/local-storage-gateway', () => {
    return jest.fn().mockImplementation((authContext) => {
        return {
            authContext,
            context: {
                upsert: mockContextUpsert
            }
        }
    })
})

// import RemoteStorageGateway from '@/storage/remote/remote-storage-gateway'
const mockFetch = jest.fn()

jest.mock('@/storage/remote/remote-storage-gateway', () => {
    return jest.fn().mockImplementation((authContext) => {
        return {
            authContext,
            fetch: mockFetch
        }
    })
})

我尝试过...

  • 注释第二个模拟定义
  • 切换订单
  • 在第一个模拟中使用mockFetch代替mockContentUpsert(当然,将mockFetch的定义上移之后)。
  • 仅更改“ @ / storage / local / local-storage-gateway”行,使第一个模拟成为第二个模拟的完整副本。

我得到的错误是...

  

ReferenceError:未定义mockContextUpsert

我无法理解为什么第二个模拟完美运行时第一个模拟不起作用。

这也可以,将模拟变量添加到第二个声明中(没有用,因为它们是不同的类,仅供参考)...

const mockContextUpsert = jest.fn()
const mockFetch = jest.fn()

jest.mock('@/storage/remote/remote-storage-gateway', () => {
    return jest.fn().mockImplementation((authContext) => {
        return {
            authContext: authContext,
            fetch: mockFetch,
            context: {
                upsert: mockContextUpsert
            }
        }
    })
})

这里模拟的类几乎相同。

更新

删除对GuestContext()的引用[这是附加的复杂性,此后已被删除,并且使该问题试图提出的实际问题感到困惑]

2 个答案:

答案 0 :(得分:0)

来自jest documentation的引用:

  

Jest会将jest.mock调用自动提升到模块顶部(在导入之前)

表示,当您尝试定义模拟mockGuestContext返回的函数时,尚未定义

您可以做的是创建一个自动模拟

import localStorageGateway from '@/storage/local/local-storage-gateway';
jest.mock('@/storage/local/local-storage-gateway');

// and since localStorageGateway is a function 
// jest will automatically create jest.fn() for it
// so you will be able to create authContext
const authContext = new GuestContext();

// and use it within the return value
localStorageGateway.mockReturnValue({
  authContext,
  context: {
    upsert: jest.fn(),
  }
})

答案 1 :(得分:0)

我最终解决了这个问题-这里的问题不是模拟本身,而是类被模拟。

LocalStorageGateway类用于在导入的模块Storage中创建私有实例,如下所示...

const guestLocal = new LocalStorageGateway(new GuestContext())

此静态上下文使模拟的构造函数在变量定义为Storage之前执行,这是第一个导入的模块之一。

有几种解决方法...

您可以更改此...

import Helper from '../../test-helper'

import Storage from '@/storage'
import GuestContext from '@/auth/guest-context'
import UserContext from '@/auth/user-context'

(insert mocks here)

到...

const mockContextUpsert = jest.fn()

import Helper from '../../test-helper'

import Storage from '@/storage'
import GuestContext from '@/auth/guest-context'
import UserContext from '@/auth/user-context'

例如(yuk?)。

或者,您也可以将mockContextUpsert包裹在一个包裹函数中(我之前的回答不是很好-足够好了)->这让我觉得很整洁。

const mockContextUpsert = jest.fn()
jest.mock('@/storage/local/local-storage-gateway', () => {
    return jest.fn().mockImplementation((authContext) => {
        return {
            authContext: authContext,
            context: {
                upsert: (cxt) => {
                    mockContextUpsert(cxt)
                }
            }
        }
    })
})

我也可以使guestLocal成为一个函数,但是我真的不想这样做,并且每次我想使用它时都要创建新的网关实例(这就是为什么它首先存在的原因)。如果Storage是一个类,它将在构造函数中实例化,但是不是,也没有真正的需要。

感谢@Teneff在此方面的投入,他的回答使我的大脑正确地思考了它。 未悬挂变量是关键-它们的工作方式不同-我的理解不正确,那就是任何mockXXXX都将悬挂在模拟调用之上,但事实并非如此“允许”。