无法在nodejs单元测试中模拟文件系统

时间:2018-02-27 12:08:25

标签: node.js unit-testing mocking fs

概述

我有一个用nodejs编写的简单模块,它使用fs-extra包来测试文件是否存在。模块在路径存在时抛出,否则进入下一个过程。这是源文件:

// - main.js -
import fs from 'fs-extra'

export default async (pathName) => {
  // Do not procceed if path already exists.
  if (await fs.pathExists(projectPath)) {
    throw new Error(chalk.red.bold(`${projectPath} already exists`))
  }

  // more logic here
}

我想编写一个测试波纹管逻辑的单元测试:

  • 如果存在filepath,我们希望抛出错误

我不想搞砸真正的文件系统 - 如果我的代码包含一些可能会破坏它的讨厌错误 - 所以我去了另一个解决方案,使用mock-fs模拟文件系统。这是spec文件:

// - main.js spec file -
import mainFunction from '../main'
import mockfs from 'mock-fs'

describe('test main function', () => {
  beforeEach(() => {
    mockfs({
      home: {
        user: {
          dummy: {}
        }
      }
    })
  })

  test('expect to throw', async () => {
    await mainFunction('/home/user/dummy')
  })

  afterEach(() => {
    mockfs.restore()
  })
})

问题是什么?

每次运行测试时,主函数都不会抛出。发生这种情况是因为mockfs伪文件系统是在spec文件中声明的,因此主源文件中的fs模块不知道mockfs伪文件系统并检查真实文件系统。当我的真实文件系统中没有名为/home/user/dummy的文件夹时,检查总是失败。

预期行为

spec文件中的

mainFunction应抛出

实际行为

spec文件中的

mainFunction不会抛出

其他信息

我想我可以将此单元测试转换为集成测试。但我不想。有没有解决这个问题?我必须使用其他套餐吗? 我的测试服是 Jest 22.3.0

1 个答案:

答案 0 :(得分:1)

经过一番搜索后,我找到了对分支进行单元测试的合适方法。我们真的不必使用mock-fs模块。我们只需要模拟pathExists模块的fs-extra方法,一次返回值false,一次返回值true。贝娄,我发布了我的spec文件的工作版本:

import mainFunction from '../main'

require('fs-extra').pathExists = jest.fn().mockReturnValueOnce(false).mockReturnValueOnce(true)

describe('test main function', () => {
  beforeEach(() => {
    jest.clearAllMocks()
  })

  test('expect to not throw', async () => {
    await expect(mainFunction('/dummy/path/does/not/matter')).resolves
  })

  test('expect to throw', async () => {
    await expect(mainFunction('/dummy/path/does/not/matter')).rejects.toBeInstanceOf(Error)
  })
})