开玩笑地监视模块功能

Posted

技术标签:

【中文标题】开玩笑地监视模块功能【英文标题】:Spying on module functions in jest 【发布时间】:2019-05-08 01:14:52 【问题描述】:

我正在用 jest 编写测试,其中我想监视一些 lodash 函数,我在模块中单独导入(反对将整个 lodash 模块导入为_),例如

/** matrix.js **/
import shuffle from 'lodash/shuffle'
import pick from 'lodash/pick'

// ...

/**
 * Shuffles the order of the rows in the matrix. If a column/variable name
 * is specified, only the rows in this column are shuffled.
 *
 * @export
 * @param array matrix The matrix to be shuffled
 * @param array columns  Array containing the variable/column to be shuffled
 * @returns array
 */
export function shuffleVert (matrix, columns) 
  if (typeof (columns) === 'undefined' || (isArray(columns) && columns.length === 0)) 
    return shuffle(matrix)
   else if (!isArray(columns)) 
    throw new TypeError('Invalid argument for columns specified to shuffleVert. Expects an array containing column names')
   else 
    let grouped = unstack(matrix)
    let cols = pick(grouped, columns)
    cols = Object.entries(cols).reduce((prev, [key, values]) => 
      prev[key] = shuffle(values)
      return prev
    , )
    return stack( ...grouped, ...cols )
 

shuffleVert 函数将矩阵的所有行或指定列的行打乱。因为很难测试随机输出的函数,据我所知,我只想测试一下lodash的shuffle和pick函数是否在被测函数内部被调用过。

我目前在我的测试模块中实现了一个有效的间谍程序,但我认为它不是传统的或有效的,我只是认为必须有更好的方法来做到这一点......

/* matrix.test.js */
import 
  shuffleVert,
 from 'matrix'

/** Generate a mock functions to spy on lodash */
const mockShuffle = jest.fn()
jest.mock('lodash/shuffle', () => a => 
  const shuffle = jest.requireActual('lodash/shuffle')
  mockShuffle()
  return shuffle(a)
)

const mockPick = jest.fn()
jest.mock('lodash/pick', () => (a, b) => 
  const pick = jest.requireActual('lodash/pick')
  mockPick()
  return pick(a, b)
)

describe('reverseRows', () => 
  let srcMatrix
  beforeEach(() => 
    srcMatrix = [
       number: 1, word: 'one' ,
       number: 2, word: 'two' ,
       number: 3, word: 'three' 
    ]
    mockShuffle.mockClear()
    mockPick.mockClear()
  )

  it('should shuffle the rows of the entire matrix with no argument for columns', () => 
    shuffleVert(srcMatrix)
    // 2 is weird, but seems correct.
    // It appears the shuffle function calls itself recursively
    expect(mockShuffle).toHaveBeenCalledTimes(2)
  )

  it('should only shuffle the rows of columns that were specified', () => 
    shuffleVert(srcMatrix, ['word'])
    expect(mockShuffle).toHaveBeenCalledTimes(2)
    expect(mockPick).toHaveBeenCalledTimes(2)
  )
)

我知道 jest 有一个 spyOn 功能,但它似乎只适用于对象方法,因此

import * as lodash from 'lodash'
const shuffleSpy = jest.spyOn(lodash, 'shuffle')

导致错误Cannot spyOn on a primitive value; undefined given

一般来说,窥探模块方法的最佳方法是什么?有没有更好的实现来做我想要实现的目标?或者这已经是要走的路了?

【问题讨论】:

lodash 是否在 package.json 中指定?看起来 lodashjest.spyOn(lodash, 'shuffle') 中未定义。 是的,lodash 存在并在整个应用程序中使用。 您解决了这个问题吗?我目前正在努力解决同样的问题。 这太早了,所以我真的不记得我是如何解决这个问题的。我认为我采取了与使用玩笑间谍完全不同的方法...... 这能回答你的问题吗? How to spy on a default exported function with Jest? 【参考方案1】:

请试试这个,让我知道它是否适合你

import  shuffleVert  from 'matrix';
const shuffleVertRef = 
    shuffleVert
;
let spyShuffleVert;

beforeEach(() => 
    spyShuffleVert = jest.spyOn(shuffleVertRef, "shuffleVert");


afterEach(() => 
    jest.clearAllMocks();


it('should shuffle the rows of the entire matrix with no argument for columns', () = 
    let srcMatrix = [
         number: 1, word: 'one' ,
         number: 2, word: 'two' ,
         number: 3, word: 'three' 
    ];

    shuffleVert(srcMatrix);
    expect(spyShuffleVert).toHaveBeenCalledTimes(2);

然后,如果您想检查任何其他函数的执行时间,只需将它们添加到一个/那个常量并在下面spyOn 它们。

我也没有完全理解这一点,但从我读到的少量内容来看,最新版本的 javascript 有一个称为“单一事实来源”的原则,这是某些事情正常工作所必需的。

【讨论】:

感谢您的建议。我很久以前问过这个问题,我想我采取了完全不同的方法来解决这个问题,所以我没有现成的代码来尝试你的建议。如果我再次遇到同样的情况(毫无疑问)我会试试的!

以上是关于开玩笑地监视模块功能的主要内容,如果未能解决你的问题,请参考以下文章

开玩笑地模拟 useDispatch 并在功能组件中使用该调度操作来测试参数

如何开玩笑地模拟 i18next 模块

开玩笑 - 使用 spyOn 函数时,确保不调用被监视的函数

如何在玩笑中模拟/监视 useState 钩子?

projects.map 不是 jest-cli 的功能

开玩笑 - 用“模拟”前缀模拟不起作用