Cách kiểm tra loại ngoại lệ ném trong Jest


160

Tôi đang làm việc với một số mã trong đó tôi cần kiểm tra loại ngoại lệ được ném bởi hàm (Có phải là TypeError, ReferenceError, v.v.).

Khung thử nghiệm hiện tại của tôi là AVA và tôi có thể kiểm tra nó như một t.throwsphương thức đối số thứ hai , như ở đây:

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

Tôi bắt đầu viết lại các bài kiểm tra của mình cho Jest và không thể tìm ra cách dễ dàng làm điều đó. Nó thậm chí có thể?

Câu trả lời:


221

Trong Jest, bạn phải truyền một hàm vào mong đợi (hàm) .toThrow (để trống hoặc loại lỗi).

Thí dụ:

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

Nếu bạn cần kiểm tra một hàm hiện có cho dù nó ném với một tập hợp các đối số, bạn phải bọc nó bên trong một hàm ẩn danh trong mong đợi ().

Thí dụ:

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

79

Một chút kỳ lạ, nhưng hoạt động và imho là tốt có thể đọc được:

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

Catchchặn bắt ngoại lệ của bạn, sau đó bạn có thể kiểm tra nâng cao của bạn Error. Strange expect(true).toBe(false);là cần thiết để thất bại bài kiểm tra của bạn nếu dự kiến Errorsẽ không được ném. Mặt khác, dòng này không bao giờ có thể truy cập ( Errornên được nâng lên trước chúng).

EDIT: @Kenny Body gợi ý một giải pháp tốt hơn giúp cải thiện chất lượng mã nếu bạn sử dụng 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");
  }
});

Xem câu trả lời ban đầu với nhiều giải thích hơn: Cách kiểm tra loại ngoại lệ ném trong Jest


17
Đây là một cách rất tiết thử nghiệm cho trường hợp ngoại lệ khi jest đã có cách expect.toThrow () kiểm tra đối với trường hợp ngoại lệ: jestjs.io/docs/en/expect.html#tothrowerror
gomisha

4
Có, nhưng nó chỉ kiểm tra loại, không phải tin nhắn hoặc nội dung khác và câu hỏi là về tin nhắn thử nghiệm, không phải loại.
bodolsog

2
Hah Thực sự thích cái này vì mã của tôi cần kiểm tra giá trị của lỗi đã ném nên tôi cần thể hiện. Tôi sẽ viết những kỳ vọng bị lỗi giống như expect('here').not.toBe('here');chỉ vì niềm vui của nó :-)
Valery

4
@Valery hoặc: expect('to be').not.toBe('to be')theo phong cách Shakespeare.
Michiel van der Blonk

2
câu trả lời bị đánh giá thấp nhất!
Edwin Ikechukwu Okonkwo

40

Tôi sử dụng một phiên bản ngắn gọn hơn một chút:

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

2
Ngắn gọn và chính xác.
flapjack

32

Từ sự tiếp xúc (mặc dù có giới hạn) của tôi với Jest, tôi đã thấy điều đó expect().toThrow()phù hợp nếu bạn muốn CHỈ kiểm tra một lỗi được đưa ra theo một loại cụ thể:

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

HOẶC một lỗi được ném với một thông báo cụ thể:

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

Nếu bạn cố gắng làm cả hai, bạn sẽ nhận được một dương tính giả. Ví dụ: nếu mã của bạn ném RangeError('Something bad happened!'), bài kiểm tra này sẽ vượt qua:

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

Câu trả lời của bodolsog trong đó gợi ý sử dụng thử / bắt là gần, nhưng thay vì kỳ vọng đúng là sai để đảm bảo các xác nhận kỳ vọng trong sản phẩm khai thác được thực hiện, thay vào đó, bạn có thể sử dụng expect.assertions(2)khi bắt đầu thử nghiệm trong đó 2số xác nhận dự kiến . Tôi cảm thấy điều này mô tả chính xác hơn ý định của bài kiểm tra.

Ví dụ đầy đủ về việc kiểm tra loại AND thông báo lỗi:

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

Nếu functionUnderTest()KHÔNG ném lỗi, các xác nhận sẽ bị đánh nhưng expect.assertions(2)sẽ không thành công và kiểm tra sẽ thất bại.


Cô ơi. Tôi luôn quên về tính năng nhiều xác nhận mong đợi của Jest (có thể cá nhân tôi không thấy nó là phức tạp nhất, nhưng nó chắc chắn hoạt động cho những trường hợp như vậy!) Chúc mừng!
kpollock

Điều này làm việc hoàn toàn tốt cho tôi. Điều này nên được sử dụng.
Ankit Tanna

expect.hasAssertions()có thể thay thế tốt hơn khi thử nghiệm không có bất kỳ xác nhận nào bên ngoài catch, vì bạn không phải cập nhật số nếu bạn thêm / xóa các xác nhận.
André Sassi

12

Tôi đã không thử nó nhưng tôi sẽ đề nghị sử dụng xác nhận toThrow của Jest . Vì vậy, tôi đoán ví dụ của bạn sẽ trông giống như thế này:

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

Một lần nữa, tôi đã không kiểm tra nó nhưng tôi nghĩ nó sẽ hoạt động.


8

Jest có một phương thức toThrow(error)để kiểm tra rằng hàm sẽ ném khi nó được gọi.

Vì vậy, trong trường hợp của bạn, bạn nên gọi nó như vậy:

expect(t).toThrowError(TypeError);

Các tài liệu


1
Nó sẽ không hoạt động cho trường hợp: jest.spyOn(service, 'create').mockImplementation(() => { throw new Error(); });nếu phương pháp giả định createlà không async.
Serge

7

Jest hiện đại cho phép bạn thực hiện nhiều kiểm tra hơn về giá trị bị từ chối. Ví dụ:

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

sẽ thất bại với lỗi

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

- Expected
+ Received

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

6

Các tài liệu rõ ràng về cách làm điều này. Giả sử tôi có một hàm có hai tham số và nó sẽ báo lỗi nếu một trong số chúng là 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

Bài kiểm tra của bạn

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

Trong trường hợp bạn đang làm việc với Promises:

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

Điều này là siêu hữu ích, cảm ơn vì đã tiết kiệm thời gian của tôi !!
Aditya Kresna Permana

3

Tôi đã kết thúc việc viết một phương pháp thuận tiện cho thư viện utils thử nghiệm của chúng tôi

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

Điều tương tự có thể được thực hiện bằng cách sử dụng các tính năng riêng của Jests. Xem câu trả lời của tôi để biết cách thực hiện - stackoverflow.com/a/58103698/3361387
Kenny Body

3

Hơn nữa bài đăng của Peter Danis chỉ muốn nhấn mạnh một phần giải pháp của anh ấy liên quan đến "[truyền] một chức năng thành mong đợi (chức năng) .toThrow (để trống hoặc loại lỗi)".

Trong Jest, khi bạn kiểm tra trường hợp cần ném lỗi, trong phạm vi bao bọc () mong đợi của bạn đang kiểm tra, bạn cần cung cấp thêm một lớp gói chức năng mũi tên để nó hoạt động. I E

Sai (nhưng cách tiếp cận logic của hầu hết mọi người):

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

Đúng:

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

Nó rất lạ nhưng sẽ làm cho thử nghiệm chạy thành công.


1

thử
expect(t).rejects.toThrow()


4
Tại sao try? không có thử - nhưng trả lời. Nếu đây là câu trả lời xin hãy giải thích thêm. những gì bạn thêm vào câu trả lời hiện có?
dWinder

7
Tôi nghĩ rằng @Razim đã nói rằng bạn nên thử giải pháp, không sử dụng thử bắt.
Tom
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.