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?

Tranotheron
sumber

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

bodolsog
sumber
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')
Tal Joffe
sumber
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.

Tubuh Kenny
sumber
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.

Andrei CACIO
sumber
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

alexmac
sumber
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,
  }
Slava Baginov
sumber
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()
  })
})
Gilbert
sumber
4

Jika Anda bekerja dengan Promises:

await expect(Promise.reject(new HttpException('Error message', 402)))
  .rejects.toThrowError(HttpException);
Željko Šević
sumber
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)
    }
  }
kpollock
sumber
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.

Adrian
sumber
1

mencoba
expect(t).rejects.toThrow()

Razim Saidov
sumber
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