Jestでスローされた例外のタイプをテストする方法


161

関数でスローされた例外のタイプをテストする必要があるコードを使用しています(TypeError、ReferenceErrorなど)。

現在のテストフレームワークはAVAであり、次のt.throwsように2番目の引数メソッドとしてテストできます。

it('should throw Error with message \'UNKNOWN ERROR\' when no params were passed', (t) => {
  const error = t.throws(() => {
    throwError();
  }, TypeError);

  t.is(error.message, 'UNKNOWN ERROR');
});

私はテストをJestに書き直しましたが、簡単に行う方法が見つかりませんでした。それも可能ですか?

回答:


225

Jestでは、expect(function).toThrow(空白またはエラーのタイプ)に関数を渡す必要があります。

例:

test("Test description", () => {
  const t = () => {
    throw new TypeError();
  };
  expect(t).toThrow(TypeError);
});

既存の関数が一連の引数でスローされるかどうかをテストする必要がある場合は、expect()の無名関数内にラップする必要があります。

例:

test("Test description", () => {
  expect(() => {http.get(yourUrl, yourCallbackFn)}).toThrow(TypeError);
});

79

少し奇妙ですが、動作し、imhoは読みやすくなっています。

it('should throw Error with message \'UNKNOWN ERROR\' when no params were passed', () => {
  try {
      throwError();
      // Fail test if above expression doesn't throw anything.
      expect(true).toBe(false);
  } catch (e) {
      expect(e.message).toBe("UNKNOWN ERROR");
  }
});

Catchブロックして例外をキャッチすると、raisedでテストできますErrorexpect(true).toBe(false);予想Errorがスローされない場合にテストを失敗させるには、奇妙なことが必要です。それ以外の場合、この線に到達することはできません(Errorその前に上げる必要があります)。

編集:@Kenny Bodyは、使用するとコード品質を改善するより良いソリューションを提案します expect.assertions()

it('should throw Error with message \'UNKNOWN ERROR\' when no params were passed', () => {
  expect.assertions(1);
  try {
      throwError();
  } catch (e) {
      expect(e.message).toBe("UNKNOWN ERROR");
  }
});

詳細な説明付きの元の回答を参照してください:Jestでスローされた例外のタイプをテストする方法


18
これは、Jestがすでにexception.toThrow()で例外を確認する方法を持っている場合に、例外をテストする非常に詳細な方法です。jestjs.io
docs

4
はい。ただし、メッセージやその他のコンテンツではなく、タイプのみをテストします。質問は、タイプではなくテストメッセージに関するものでした。
bodolsog

2
ああ。私のコードがスローされたエラーの値をテストする必要があるので、インスタンスが必要なので、本当にこれと同じです。私はexpect('here').not.toBe('here');それの楽しみのためだけに間違った期待を書きます:-)
Valery

4
@Valeryまたは:expect('to be').not.toBe('to be')シェイクスピアスタイル。
Michiel van der Blonk 2018年

2
最も過小評価されている答え!
エドウィンIkechukwu Okonkwo 2018


33

私の(限定的ではあるが)Jestへの暴露からexpect().toThrow()、特定のタイプのエラーがスローされることをテストするだけの場合に適していることがわかりました。

expect(() => functionUnderTest()).toThrow(TypeError);

または、特定のメッセージでエラーがスローされます。

expect(() => functionUnderTest()).toThrow('Something bad happened!');

両方を実行しようとすると、誤検知が発生します。たとえば、コードがをスローする場合RangeError('Something bad happened!')、このテストは成功します。

expect(() => functionUnderTest()).toThrow(new TypeError('Something bad happened!'));

try / catchの使用を提案するbodolsogによる回答は近いですが、trueがfalseであると期待して、catchの期待アサーションがヒットすることを保証するのではなく、代わりexpect.assertions(2)に、テストの開始時に、2期待されるアサーションの数を使用できます。。これはテストの意図をより正確に説明していると思います。

エラーのタイプとメッセージをテストする完全な例:

describe('functionUnderTest', () => {
    it('should throw a specific type of error.', () => {
        expect.assertions(2);

        try {
            functionUnderTest();
        } catch (error) {
            expect(error).toBeInstanceOf(TypeError);
            expect(error).toHaveProperty('message', 'Something bad happened!');
        }
    }); 
});

functionUnderTest()がエラーをスローしない場合、アサーションはヒットしますが、expect.assertions(2)は失敗し、テストは失敗します。


ドー。私は常にJestの複数のアサーション機能を期待していることを忘れています(おそらく、個人的に直感的に理解できないかもしれませんが、そのような場合には確実に機能します!)乾杯!
kpollock

これは私にとって完全にうまくいった。これを使用する必要があります。
Ankit Tanna

expect.hasAssertions()テストの外部catchにアサーションがない場合は、アサーションを追加または削除する場合に数値を更新する必要がないため、より良い代替案になる可能性があります。
アンドレサッシ

12

私自身は試していませんが、JestのtoThrowアサーションを使用することをお勧めします。だからあなたの例は次のようになると思います:

it('should throw Error with message \'UNKNOWN ERROR\' when no params were passed', (t) => {
  const error = t.throws(() => {
    throwError();
  }, TypeError);

  expect(t).toThrowError('UNKNOWN ERROR');
  //or
  expect(t).toThrowError(TypeError);
});

繰り返しますが、テストはしていませんが、動作するはずです。


8

Jestには、toThrow(error)関数が呼び出されたときに関数がスローすることをテストするメソッドがあります。

したがって、あなたのケースではそれをそう呼ぶべきです:

expect(t).toThrowError(TypeError);

ドキュメント


1
これはjest.spyOn(service, 'create').mockImplementation(() => { throw new Error(); });、モックされたメソッドcreateがそうでない場合には機能しませんasync
セルゲイ

7

現代の冗談では、拒否された値をさらにチェックすることができます。例えば:

const request = Promise.reject({statusCode: 404})
await expect(request).rejects.toMatchObject({ statusCode: 500 });

エラーで失敗します

Error: expect(received).rejects.toMatchObject(expected)

- Expected
+ Received

  Object {
-   "statusCode": 500,
+   "statusCode": 404,
  }

6

ドキュメントには、これを行う方法については明らかです。2つのパラメーターを受け取る関数があり、そのうちの1つがの場合はエラーがスローされるとしましょうnull

function concatStr(str1, str2) {
  const isStr1 = str1 === null
  const isStr2 = str2 === null
  if(isStr1 || isStr2) {
    throw "Parameters can't be null"
  }
  ... // continue your code

あなたのテスト

describe("errors", () => {
  it("should error if any is null", () => {
    // notice that the expect has a function that returns the function under test
    expect(() => concatStr(null, "test")).toThrow()
  })
})


3

test-utilsライブラリの便利なメソッドを作成してしまいました

/**
 *  Utility method to test for a specific error class and message in Jest
 * @param {fn, expectedErrorClass, expectedErrorMessage }
 * @example   failTest({
      fn: () => {
        return new MyObject({
          param: 'stuff'
        })
      },
      expectedErrorClass: MyError,
      expectedErrorMessage: 'stuff not yet implemented'
    })
 */
  failTest: ({ fn, expectedErrorClass, expectedErrorMessage }) => {
    try {
      fn()
      expect(true).toBeFalsy()
    } catch (err) {
      let isExpectedErr = err instanceof expectedErrorClass
      expect(isExpectedErr).toBeTruthy()
      expect(err.message).toBe(expectedErrorMessage)
    }
  }

Jests独自の機能を使用して同じことを行うことができます。これを行う方法については私の回答をご覧ください-stackoverflow.com/a/58103698/3361387
Kenny Body

3

ピーター・ダニスの投稿に加えて、「expect(function).toThrow(空白またはエラーのタイプ)に関数を渡す」という彼の解決策の一部を強調したかっただけです。

Jestでは、エラーがスローされるケースをテストする場合、テスト中の関数のexpect()ラッピング内で、機能するために1つの追加の矢印関数ラッピングレイヤーを提供する必要があります。すなわち

誤り(ただし、ほとんどの人の論理的なアプローチ):

expect(functionUnderTesting();).toThrow(ErrorTypeOrErrorMessage);

正しい:

expect(() => { functionUnderTesting(); }).toThrow(ErrorTypeOrErrorMessage);

これは非常に奇妙ですが、テストが正常に実行されるはずです。


1

試す
expect(t).rejects.toThrow()


4
なんでtry?試みはありませんが、答えはあります。これが答えである場合は、さらに詳しく説明してください。既存の答えに何を追加しますか?
dWinder

7
@Razimは、try catchを使用するのではなく、ソリューションを試す必要があると言っていたと思います。
トム
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.