TypeScriptでライブラリを作っていて、ユニットテスト内でfsをモックしようとしたときにやり方がわからず苦労したので残しておきます。
環境
Node.js
v12.18.1
TypeScript
4.0.3
Jest
26.6.0
背景
GrafanaをWeb API経由で管理するライブラリのユニットテスト内でファイルを扱っていました。
以下のようなテスト対象のクラスがあるため、fsをユニットテスト内でモックするためにJestのmocking機能を利用しました。
Sample.ts
exportclassSample{readFile(source:string):string{if(!fs.existsSync(source){thrownewError();}else{returnfs.readFileSync(source,{encoding:"utf8"});}}}
モッキング方法
fs のモッキング方法1
こちらの記事でも取り上げられている方法になります。
しかし、こちらではうまくいきませんでした。
Sample.test.ts
jest.mock('fs',()=>({readFileSync:jest.fn(()=>`first¥n second¥n third`),}));import*asfsfrom"fs";import{Sample}from"./Sample";describe("Smaple test",()=>{beforeEach(()=>{// mockClearが定義されていないため、トランスパイルできないfs.readFileSync.mockClear();fs.existsSync.mockClear();});it("ファイルが存在しない",()=>{fs.existsSync.mockImplementation(()=>false);fs.readFileSync.mockImplementation(()=>"");constsample=newSample();expect(()=>sample.readFile("foo.txt")).toThrow();});it("ファイルが空でない",()=>{fs.existsSync.mockImplementation(()=>true);fs.readFileSync.mockImplementation(()=>"sample");constsample=newSample();constresult=sample.readFile("foo.txt");expect(result).toBe("sample");});});
モッキング方法2
ts-jestの中にあるUtilクラスを使って、モックを行う方法になります。
ts-jestはjestをTypeScript環境でも使うためのパッケージです。Jestの公式ドキュメントでも言及されているので、安心です。
使う際に気を付けることは使用しているAPIと同様にmockImplementationを実装する点です。
Sample.test.ts
// ここでts-jestのモック作成Utilをインポートimport{mocked}from"ts-jest/utils";// fsをモックjest.mock('fs');import{Sample}from"./Sample";describe("Smaple test",()=>{it("ファイルが存在しない",()=>{// 対象の関数をモックするmocked(fs.existsSync).mockImplementation((_)=>false);mocked(fs.readFileSync).mockImplementation((_,__)=>"sample");constsample=newSample();expect(()=>sample.readFile("foo.txt")).toThrow();});it("ファイルが空でない",()=>{// 対象の関数をモックするmocked(fs.existsSync).mockImplementation((_)=>true);mocked(fs.readFileSync).mockImplementation((_,__)=>"sample");constsample=newSample();constresult=sample.readFile("foo.txt");expect(result).toBe("sample");});});
結論
ts-jestのutilsを使うのがベストです。
毎回、mockImplementationを行う必要がありそうですが(もしかしたらいらないかも)、
テストコード内で共通関数を呼び出すなど工夫をすれば、そこまで気にしないで済みそうです。