如何重置玩笑

Bra*_*Tom 10 javascript unit-testing mocking jestjs

我有一个这样的手动模拟crypto

// __mocks__/crypto.js

const crypto = jest.genMockFromModule('crypto')
const toString: Function = jest.fn(() => {
  return {}.toString()
})
const mockStringable = {toString}
const update: Function = jest.fn(() => mockStringable)
const deciper = {update}
crypto.createDecipheriv = jest.fn(() => deciper)

export default crypto
Run Code Online (Sandbox Code Playgroud)

基本上是这样测试的:

const crypto = require('crypto')
jest.mock('crypto')

describe('cookie-parser', () => {
  afterEach(() => {
    jest.resetAllMocks()
  })
  describe('decryptCookieValue', () => {
    it('should call the crypto library correctly', () => {
      const result = decryptCookieValue('test-encryption-key', 'test-encrypted-value')
      expect(crypto.pbkdf2Sync).toHaveBeenCalledTimes(2)
      expect(crypto.createDecipheriv).toHaveBeenCalled()
      // more tests, etc, etc, etc
      expect(crypto.createDecipheriv('', '', '').update).toHaveBeenCalled()
      expect(result).toEqual({}.toString())
    })
  })

  ...
Run Code Online (Sandbox Code Playgroud)

但是,如果在同一个测试文件中,我测试decryptCookieValue从内部调用的另一种方法crypto.createDecipheriv不再返回我的模拟解密,则此方法有效。而是返回未定义。例如:

describe('cookie-parser', () => {
  afterEach(() => {
    jest.resetAllMocks()
  })
  describe('decryptCookieValue', () => {
    it('should call the crypto library correctly', () => {
      const result = decryptCookieValue('test-encryption-key', 'test-encrypted-value')
      expect(crypto.pbkdf2Sync).toHaveBeenCalledTimes(2)
      expect(crypto.createDecipheriv).toHaveBeenCalled()
      expect(crypto.createDecipheriv('', '', '').update).toHaveBeenCalled()
      expect(result).toEqual({}.toString())
    })
  })
  ...
  ...
  describe('parseAuthenticationCookie', () => {
    it('should create the correct object', () => {

      // parseAuthenticationCookie calls decryptCookieValue internally

      const result = parseAuthenticationCookie('', '') // Fails because internal call to crypto.createDecipheriv stops returning mock decipher.
      expect(result).toEqual({accessToken: null})
    })
  })
})
Run Code Online (Sandbox Code Playgroud)

我认为这是重置手动模拟的一个问题,因为如果我接受以后的测试,并使用相同的周围测试工具将其全部移动到文件中,则效果很好。

// new test file
import crypto from 'crypto'
import { parseAuthenticationCookie } from './index'

jest.mock('crypto')

describe('cookie-parser', () => {
  afterEach(() => {
    jest.resetAllMocks()
  })
  describe('parseAuthenticationCookie', () => {
    it('should create the correct object', () => {

      // Works just fine now

      const result = parseAuthenticationCookie('', '')
      expect(result).toEqual({accessToken: null})
    })
  })
})
Run Code Online (Sandbox Code Playgroud)

我的评估在这里是否正确?如果是,在每次测试后如何重设手动模拟的状态?

小智 4

来自 Jest 文档:执行所有操作mockFn.mockClear(),并删除任何模拟的返回值或实现。参考: https: //jestjs.io/docs/en/mock-function-api#mockfnmockreset

在您的示例中,您假设调用resetAllMocks会将您的手动模拟设置回来,但事实并非如此。

您的测试在单独的文件中工作的原因是因为 jest 独立运行每个文件,这很好,因为您只能搞砸同一文件中的规范。

在您的特定情况下,可能会起作用的东西正在调用jest.clearAllMocks()(因为这将保留实现和返回值)。 clearMocksoptions 也可在 jest 配置对象中使用(默认为 false),如果您想清除每个测试中的所有模拟,这可能会很方便。希望这对您或遇到类似问题的其他人有所帮助。

额外提示(没有完全相关)如果您正在模拟一个正在由其他模块内部使用的模块,并且在某些特定测试中您想使用不同的模拟再次模拟该模块,请确保要求该模块正在使用模拟模块在该特定测试的内部再次进行,否则该模块仍将引用您在导入语句旁边指定的模拟。