web-dev-qa-db-ja.com

jestでprocess.exitをスタブする

私は何かをするコードを持っています

_ function myFunc(condition){
  if(condition){
    process.exit(ERROR_CODE)
  }
 }
_

Jestでこれをテストするにはどうすればよいですか?プロセスが終了するため、exitprocessjest.fn()で上書きし、テストが機能しなかった後にそれを返す

17
Nick Ginanto

このスレッドの他の提案は、_process.exit_を使用したテストが無期限に実行されるという私の側でエラーを引き起こします。 TypeScriptでは次のオプションが機能しましたが、JavaScriptでも機能するはずです。

_const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {});
myFunc(condition);
expect(mockExit).toHaveBeenCalledWith(ERROR_CODE);
_

問題は、単にspyOnを使用すると、元のprocess.exit()関数が引き続き呼び出され、プロセススレッドが終了してテストがハングすることでした。最後にmockImplementationを使用すると、関数本体が提供された関数(この例では空)に置き換えられます。

このトリックは、たとえばstdoutに出力するテストにも役立ちます。例えば:

_const println = (text: string) => { process.stdout.write(text + '\n'); };
const mockStdout = jest.spyOn(process.stdout, 'write').mockImplementation(() => {});
println('This is a text.');
expect(mockStdout).toHaveBeenCalledWith('This is a text.\n');
_

これにより、出力された値をテストできるようになり、CLIコンソールの出力がランダムな改行で混乱しないという追加の利点があります。


注意事項:「jest.spyOn」呼び出しと同様に、モック実装を使用しているかどうかに関係なく、モックが長引くことによる奇妙な副作用を回避するために、後でそれを復元する必要があります。そのため、現在のテストケースの最後に次の2つの関数を呼び出すことを忘れないでください。

_mockExit.mockRestore()
mockStdout.mockRestore()
_
25
Epic Eric

ほとんどのグローバルJavaScriptオブジェクトでは、スタブに置き換えて、テスト後に復元を試みます。以下はprocessをモックするのに適しています。

  describe('myFunc', () => {
    it('should exit process on condition match', () => {
      const realProcess = process;
      const exitMock = jest.fn();

      // We assign all properties of the "real process" to
      // our "mock" process, otherwise, if "myFunc" relied
      // on any of such properties (i.e `process.env.NODE_ENV`)
      // it would crash with an error like:
      // `TypeError: Cannot read property 'NODE_ENV' of undefined`.
      global.process = { ...realProcess, exit: exitMock };

      myFunc(true);
      expect(exitMock).toHaveBeenCalledWith(ERROR_CODE);
      global.process = realProcess;
    });
  });

これは、実際のprocess.exitの実行を回避して、単体テストのクラッシュを回避するのに役立ちます。

2
joy

jest.spyOnこれは元のメソッドも呼び出すため:

const exit = jest.spyOn(process, 'exit');
//run your test
expect(exit).toHaveBeenCalledWith('ERROR_CODE');
2

私も同様の問題に直面しました。以下のコードで解決しました

const setProperty = (object, property, value) => {
    const originalProperty = Object.getOwnPropertyDescriptor(object, property)
    Object.defineProperty(object, property, { value })
    return originalProperty
}

const mockExit = jest.fn()
setProperty(process, 'exit', mockExit)

expect(mockExit).toHaveBeenCalledWith('ERROR_CODE')
1
MWright