Cara menguji jenis pengecualian yang dilontarkan di Jest


161

Saya sedang bekerja dengan beberapa kode di mana saya perlu menguji jenis pengecualian yang dilemparkan oleh fungsi (Apakah itu TypeError, ReferenceError dll.).

Kerangka pengujian saya saat ini adalah AVA dan saya bisa mengujinya sebagai t.throwsmetode argumen kedua , seperti di sini:

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');
});

Saya mulai menulis ulang tes saya untuk Jest dan tidak dapat menemukan cara untuk melakukannya dengan mudah. Apakah itu mungkin?

Jawaban:


225

Dalam Jest Anda harus meneruskan fungsi ke harapkan (fungsi). Ke Throw (kosong atau jenis kesalahan).

Contoh:

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

Jika Anda perlu menguji fungsi yang ada apakah melempar dengan seperangkat argumen, Anda harus membungkusnya di dalam fungsi anonim di harapkan ().

Contoh:

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

79

Agak aneh, tapi berfungsi dan imho bisa dibaca:

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");
  }
});

Catchblokir pengecualian Anda, maka Anda dapat menguji pada Anda dibesarkan Error. Aneh expect(true).toBe(false);diperlukan untuk gagal dalam tes Anda jika diharapkan Errortidak akan terlempar. Kalau tidak, garis ini tidak pernah bisa dijangkau ( Errorharus dinaikkan sebelum mereka).

EDIT: @Kenny Body menyarankan solusi yang lebih baik yang meningkatkan kualitas kode jika Anda gunakan 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");
  }
});

Lihat jawaban asli dengan lebih banyak penjelasan: Cara menguji jenis pengecualian yang dilemparkan di Jest


18
Ini adalah cara yang sangat verbal untuk menguji pengecualian ketika Jest sudah memiliki cara yang diharapkan.toThrow () untuk memeriksa pengecualian: jestjs.io/docs/en/expect.html#tothrowerror
gomisha

4
Ya, tetapi hanya menguji jenis, bukan pesan atau konten lain dan pertanyaannya adalah tentang pesan pengujian, bukan jenis.
bodolsog

2
Hah. Benar-benar seperti ini karena kode saya perlu menguji nilai kesalahan yang dilemparkan jadi saya perlu contoh. Saya akan menulis harapan yang salah seperti expect('here').not.toBe('here');hanya untuk bersenang-senang :-)
Valery

4
@Valery atau: expect('to be').not.toBe('to be')dalam gaya Shakespeare.
Michiel van der Blonk

2
jawaban yang paling diremehkan!
Edwin Ikechukwu Okonkwo

41

Saya menggunakan versi yang sedikit lebih ringkas:

expect(() => {
  //code block that should throw error
}).toThrow(TypeError) //or .toThrow('expectedErrorMessage')

2
Singkat dan tepat.
flapjack

33

Dari paparan saya (walaupun terbatas) ke Jest, saya telah menemukan yang expect().toThrow()cocok jika Anda ingin HANYA menguji kesalahan yang dilemparkan dari jenis tertentu:

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

ATAU kesalahan dilemparkan dengan pesan tertentu:

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

Jika Anda mencoba melakukan keduanya, Anda akan mendapatkan false positive. Misalnya jika kode Anda dilontarkan RangeError('Something bad happened!'), tes ini akan lulus:

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

Jawaban oleh bodolsog yang menyarankan menggunakan coba / tangkap dekat, tetapi daripada berharap benar menjadi salah untuk memastikan pernyataan harapan dalam tangkapan terkena, Anda dapat menggunakan expect.assertions(2)pada awal tes Anda di mana 2jumlah pernyataan yang diharapkan . Saya merasa ini lebih akurat menggambarkan maksud tes.

Contoh lengkap pengujian jenis dan pesan kesalahan:

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!');
        }
    }); 
});

Jika functionUnderTest()TIDAK melempar kesalahan, pernyataan akan dipukul tetapi expect.assertions(2)akan gagal dan tes akan gagal.


Doh. Saya selalu lupa tentang fitur beberapa pernyataan Jest yang diharapkan (mungkin saya secara pribadi tidak menganggapnya paling intutitif, tetapi pasti berfungsi untuk kasus seperti itu!) Cheers!
kpollock

Ini bekerja dengan sangat baik untuk saya. Ini harus digunakan.
Ankit Tanna

expect.hasAssertions()mungkin alternatif yang lebih baik ketika tes tidak memiliki pernyataan di luar catch, karena Anda tidak harus memperbarui nomor jika Anda menambah / menghapus pernyataan.
André Sassi

12

Belum mencobanya sendiri tapi saya akan menyarankan menggunakan pernyataan Jest's toThrow . Jadi saya kira contoh Anda akan terlihat seperti ini:

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);
});

Sekali lagi, belum mengujinya tetapi saya pikir itu harus berhasil.


8

Jest memiliki metode toThrow(error)untuk menguji bahwa suatu fungsi melempar ketika dipanggil.

Jadi, dalam kasus Anda, Anda harus menyebutnya demikian:

expect(t).toThrowError(TypeError);

Dok


1
Ini tidak akan berfungsi untuk kasus ini: jest.spyOn(service, 'create').mockImplementation(() => { throw new Error(); });jika metode yang diejek createtidak async.
Sergey

7

Lelucon modern memungkinkan Anda melakukan lebih banyak pemeriksaan pada nilai yang ditolak. Sebagai contoh:

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

akan gagal karena kesalahan

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

- Expected
+ Received

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

6

The dokumentasi jelas tentang cara untuk melakukan ini. Katakanlah saya memiliki fungsi yang mengambil dua parameter dan itu akan menimbulkan kesalahan jika salah satunya 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

Tes Anda

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()
  })
})

4

Jika Anda bekerja dengan Promises:

await expect(Promise.reject(new HttpException('Error message', 402)))
  .rejects.toThrowError(HttpException);

Ini sangat membantu, terima kasih telah menghemat waktu saya !!
Aditya Kresna Permana

3

Saya akhirnya menulis metode kenyamanan untuk perpustakaan alat uji kami

/**
 *  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)
    }
  }

Hal yang sama dapat dilakukan menggunakan fitur Jests sendiri. Lihat jawaban saya untuk bagaimana hal ini dapat dilakukan - stackoverflow.com/a/58103698/3361387
Kenny Body

3

Lebih jauh ke pos Peter Danis hanya ingin menekankan bagian dari solusinya yang melibatkan "[lewat] fungsi ke harapkan (fungsi). Ke Throw (kosong atau jenis kesalahan)".

Dalam Jest, ketika Anda menguji untuk kasus di mana kesalahan harus dilemparkan, dalam dugaan Anda () pembungkus fungsi dalam pengujian Anda perlu memberikan satu lapisan pembungkus fungsi panah tambahan agar berfungsi. Yaitu

Salah (tetapi pendekatan logis kebanyakan orang):

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

Baik:

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

Ini sangat aneh tetapi harus membuat pengujian berjalan dengan sukses.


1

mencoba
expect(t).rejects.toThrow()


4
Mengapa try? tidak ada coba - tapi jawab. Jika ini jawabannya, tolong jelaskan lebih lanjut. apa yang Anda tambahkan ke jawaban yang ada?
dWinder

7
Saya pikir @Razim mengatakan bahwa Anda harus mencoba solusinya, bukan menggunakan try catch.
Tom
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.