Node.js 开玩笑+;MockImplementationOnce+;第二次不工作了

Node.js 开玩笑+;MockImplementationOnce+;第二次不工作了,node.js,unit-testing,jestjs,Node.js,Unit Testing,Jestjs,我正在使用JEST框架对node.js项目进行单元测试。我使用mockImplementationOnce模拟第三方库方法,如下所示: 开玩笑的模仿('abc',()=>{ 返回{a:{b:jest.fn()}; }); const abcjs=需要(“abc”) 第一个测试成功执行,但第二个测试调用实际方法,而不是模拟。 我尝试在每次之后重置模拟,但都没有帮助。我昨天在模拟aws sdk时遇到了同样的问题 事实证明,在模拟了整个模块一次之后,就不能在同一个文件中再次重写该模拟的行为 我很惊讶您

我正在使用JEST框架对node.js项目进行单元测试。我使用mockImplementationOnce模拟第三方库方法,如下所示: 开玩笑的模仿('abc',()=>{ 返回{a:{b:jest.fn()}; }); const abcjs=需要(“abc”)

第一个测试成功执行,但第二个测试调用实际方法,而不是模拟。
我尝试在每次之后重置模拟,但都没有帮助。

我昨天在模拟aws sdk时遇到了同样的问题

事实证明,在模拟了整个模块一次之后,就不能在同一个文件中再次重写该模拟的行为

我很惊讶您的第一个测试居然通过了,尽管您的默认模拟函数只是一个没有任何返回值的jest.fn()。

这里有一个完整的讨论-

线程的最终解决方案:

//不模拟整个模块
const abcjs=需要(“abc”);
描述(“第一次测试”,()=>{
测试(“应返回true”,异步()=>{
//尝试使用jest.spyOn()而不是jest.fn
jest.spyOn(abcjs.a,'b').mockImplementationOnce(()=>Promise.resolve(true));
//这里的expect语句
});
});
描述(“第二次测试”,()=>{
jest.restoreAllMocks();//{
jest.spyOn(abcjs.a,'b').mockImplementationOnce(()=>Promise.resolve(false));
//这里的expect语句
});
});

基本上,不要模拟整个模块,而只模拟您想要从中获得的功能。

也许这可以作为您的参考。如果是我,那么想法是这样的:

将其视为您所指的第三方库方法

/**
 * Module dependencies.
 */
const abcjs = {
    a: { b: () => null }
}
然后我想象的测试场景是

describe('a test scenario', () => {
    afterEach(() => {
        // Restores all mocks back to their original value.
        // only works when the mock was created with jest.spyOn;
        jest.restoreAllMocks()
    })

    describe('1st test', () => {
        test('should return true', async () => {
            jest.spyOn(abcjs.a, 'b').mockImplementation()
            /**
              * Accepts a value that will be returned for one call to the mock function. Can be chained so that
              * successive calls to the mock function return different values. When there are no more
              * `mockResolvedValueOnce` values to use, calls will return a value specified by `mockResolvedValueOnce`. 
              */
            abcjs.a.b.mockResolvedValueOnce(true).mockResolvedValueOnce('isTrue')

            let resultExpected = await abcjs.a.b()
            
            // Ensures that a mock function is called an exact number of times.          
            expect(abcjs.a.b).toHaveBeenCalledTimes(1)
            // Used when you want to check that two objects have the same value.
            expect(resultExpected).toEqual(true)

            // try to invoked the function for second times...
            resultExpected = await abcjs.a.b()

            // Ensures that a mock function is called an exact number of times...
            // which is the second time !
            expect(abcjs.a.b).toHaveBeenCalledTimes(2)
            // Used when you want to check that two objects have the same value.
            expect(resultExpected).toEqual('isTrue')
        })
    })

    describe('2nd test', () => {
        test('should return false', async () => {
            jest.spyOn(abcjs.a, 'b').mockImplementation()
            abcjs.a.b.mockResolvedValueOnce(false)

            const resultExpected = await abcjs.a.b()

            expect(abcjs.a.b).toHaveBeenCalledTimes(1)
            expect(resultExpected).toEqual(false)
        })
    })
})
如果是我,我宁愿用这个来回报承诺
mockFn.mockResolvedValue(value)
mockFn.mockRejectedValue(value)
而不是
mockImplementation(()=>Promise.resolve(value))


这只是我可以描述的一种测试方法。希望这能给你一个想法。

但我还是收到了同样的错误。现在我在第一个测试用例本身中收到错误。现在第二个测试显示调用ctrl函数时模拟方法未定义。我已经更新了我的答案,使用
jest.spyOn
,而不是
jest.fn
,并在最后标记
mockImplementationOnce
,如图所示-实际上我正在使用spyOn进行实验。但对于第二次测试来说,这并不是嘲笑。它调用实际的方法。当我们需要添加jest.restoreAllMocks()时也是如此;无论是现在还是以后,每一种事情都会发生???
jest.restoreAllMocks
将函数还原为其在被模拟之前的原始功能。因此,如果您愿意,可以在每次之后将其放入
。此外,只要您再次模拟您的函数,您的第二次测试也应该通过。你能在你的问题中更新你的代码吗?
describe('a test scenario', () => {
    afterEach(() => {
        // Restores all mocks back to their original value.
        // only works when the mock was created with jest.spyOn;
        jest.restoreAllMocks()
    })

    describe('1st test', () => {
        test('should return true', async () => {
            jest.spyOn(abcjs.a, 'b').mockImplementation()
            /**
              * Accepts a value that will be returned for one call to the mock function. Can be chained so that
              * successive calls to the mock function return different values. When there are no more
              * `mockResolvedValueOnce` values to use, calls will return a value specified by `mockResolvedValueOnce`. 
              */
            abcjs.a.b.mockResolvedValueOnce(true).mockResolvedValueOnce('isTrue')

            let resultExpected = await abcjs.a.b()
            
            // Ensures that a mock function is called an exact number of times.          
            expect(abcjs.a.b).toHaveBeenCalledTimes(1)
            // Used when you want to check that two objects have the same value.
            expect(resultExpected).toEqual(true)

            // try to invoked the function for second times...
            resultExpected = await abcjs.a.b()

            // Ensures that a mock function is called an exact number of times...
            // which is the second time !
            expect(abcjs.a.b).toHaveBeenCalledTimes(2)
            // Used when you want to check that two objects have the same value.
            expect(resultExpected).toEqual('isTrue')
        })
    })

    describe('2nd test', () => {
        test('should return false', async () => {
            jest.spyOn(abcjs.a, 'b').mockImplementation()
            abcjs.a.b.mockResolvedValueOnce(false)

            const resultExpected = await abcjs.a.b()

            expect(abcjs.a.b).toHaveBeenCalledTimes(1)
            expect(resultExpected).toEqual(false)
        })
    })
})