簡體   English   中英

模擬的 `fs.createFileSync` 和 `fs.unlinkSync` 沒有被調用

[英]Mocked `fs.createFileSync` and `fs.unlinkSync` are not getting called

我有一個函數可以做很多事情,但其中之一是它將文件復制到一個特殊的目錄,用它做一些事情(在不使用fs模塊的情況下調用一些東西與該文件進行交互),然后刪除復制的文件一旦完成。

import { copyFileSync, unlinkSync } from 'fs';

myOtherFunction(path: string) {
  ...
}

myIOFunction(somePath: string) {
  var copyPath = resolve('otherDir/file2.csv');
  copyFileSync(somePath, copyPath);
  try {
    myOtherFunction(copyPath);
  } finally {
    unlinkFileSync(copyPath);
  }
}

export myFunction() {
  ...
  myIOFunction(resolve('file1.csv));
}

由於只有myFunction()被導出(它是唯一應該能夠直接與之交互的東西),我必須通過它對myOtherFunction()myIOFunction()進行單元測試。 其中一部分是copyFileSyncunlinkFileSync

我的測試看起來像這樣:

import * as fs from 'fs';
import myFunction from './myFile';

...

it("tests something involving input/output", () => {
  mockCopyFile = spyOn(fs, 'copyFileSync');
  mockUnlinkFile = spyOn(fs, 'unlinkSync');

  ...

  myFunction();

  expect(mockCopyFile).toHaveBeenCalledWith(resolve('file1.csv'), resolve('otherDir/file2.csv'));
  expect(mockUnlinkFile).toHaveBeenCalled();

  ...
});

試驗是用,無論是錯誤失敗mockCopyFile也不mockUnlinkFile被調用。 問題是,對應的函數調用-我已經通過了調試測試階梯,他們執行沒有問題。 所以問題一定是間諜沒有正確地依附自己。

我不知道如何他們被調用。 我試過在被測試的文件fs.unlinkFileSync() import * as fs from 'fs'fs.copyFileSync() / fs.unlinkFileSync() 我試過將beforeAll()放在beforeAll()函數中。 這兩種解決方案都沒有幫助。 我在同一個測試規范中嘲笑其他幾個不直接相關的方法調用,它們都按預期工作; 只有這個不是,我不知道為什么。


我的package.json包括以下依賴項:

  "scripts": {
    "test": "tsc && jasmine",
  },
"devDependencies": {
    "@types/jasmine": "^3.5.10",
    "@types/node": "^13.7.7",
    "@types/pg": "^7.14.3",
    "copyfiles": "^2.2.0",
    "jasmine": "^3.5.0",
    "jasmine-core": "^3.5.0",
    "jasmine-ts": "^0.3.0",
    "js-yaml": "^3.13.1",
    "mock-fs": "^4.11.0",
    "morgan": "^1.10.0",
    "nodemon": "^2.0.2",
    "swagger-ui-express": "^4.1.3",
    "ts-node": "^8.7.0",
    "typescript": "^3.8.3"
  },
  "dependencies": {
    "@types/express": "^4.17.3",
    "chokidar": "^3.3.1",
    "cors": "^2.8.5",
    "csv-writer": "^1.6.0",
    "dotenv": "^8.2.0",
    "express": "^4.17.1",
    "murmurhash": "0.0.2",
    "pg": "^7.18.2",
    "pg-format": "^1.0.4",
    "winston": "^3.2.1"
  }

我的jasmine.json看起來像這樣:

{
  "spec_dir": "dist",
  "spec_files": [
    "**/*[sS]pec.js"
  ],
  "helpers": [
    "helpers/**/*.js"
  ],
  "stopSpecOnExpectationFailure": false,
  "random": true
}

tsconfig

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "module": "commonjs",
    "esModuleInterop": true,
    "target": "es6",
    "moduleResolution": "node",
    "sourceMap": true,
    "outDir": "dist",
    "typeRoots": [
      "node_modules/@types",
      "node_modules/@types/node"
    ],
  },
  "lib": [
    "es2015"
  ]
}

Jasmine spyOn函數返回一個Spy類對象,它不代表任何函數調用,但它有關於spyOn函數的輔助方法。 您必須直接向fs.<function>調用expect以檢查它是否被調用:

import * as fs from 'fs';
import * as path from 'path';
import { myFunction } from '../src/myFunction';

describe('MyFunc', () => {
  it("tests something involving input/output", () => {
    spyOn(fs, 'copyFileSync');
    spyOn(fs, 'unlinkSync');

    myFunction();

    expect(fs.copyFileSync).toHaveBeenCalledWith(
      path.resolve('file1.csv'),
      path.resolve('otherDir/file2.csv')
    );
    expect(fs.unlinkSync).toHaveBeenCalled();
  });
});

您可以使用此 GitHub 存儲庫測試一個簡單的重現示例: https : //github.com/clytras/fs-jasminte-ts-mocking

git clone https://github.com/clytras/fs-jasminte-ts-mocking.git
cd fs-jasminte-ts-mockin
npm i
npm run test

更新

看來,你有esModuleInterop設置為true內部tsconfig.json 這意味着當您import * as fs from 'fs' ,不會保留fs對象的單個實例。

您可以將esModuleInterop設置為false並使您的測試通過toHaveBeenCalledtoHaveBeenCalledWith ,但這可能會破壞您項目的其他一些功能。 您可以在此處了解有關esModuleInterop功能的更多信息了解 tsconfig 文件中的 esModuleInterop

如果您不想將esModuleInterop設置為false ,那么您必須像在 ES6 Javascript 中一樣導入fs ,如下所示:

import fs from 'fs'; // Use plain default import instead of * as
import path from 'path';
import { myFunction } from '../src/myFunction';

describe('MyFunc', () => {
  it("tests something involving input/output", () => {
    spyOn(fs, 'copyFileSync');
    spyOn(fs, 'unlinkSync');

    myFunction();

    expect(fs.copyFileSync).toHaveBeenCalledWith(
      path.resolve('file1.csv'),
      path.resolve('otherDir/file2.csv')
    );
    expect(fs.unlinkSync).toHaveBeenCalled();
  });
});

我還注意到您的配置文件中缺少這些內容:

  1. 如果不這樣做,則必須使用jasmine-console-reporter

    • npm i -D jasmine-console-reporter
    • package.json test腳本更改為"test": "tsc && jasmine --reporter=jasmine-console-reporter"
  2. jasmine.json ,將ts-node/register/type-check.js到 helpers 中,例如:

     { ... "helpers": [ "helpers/**/*.js", "../node_modules/ts-node/register/type-check.js" ], }

現在你的測試應該通過了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM