Як перевірити тип викинутого винятку в Jest


161

Я працюю з деяким кодом, де мені потрібно перевірити тип виключення, кинутого функцією (це TypeError, ReferenceError тощо).

Моя поточна основа тестування - AVA, і я можу протестувати це як t.throwsметод другого аргументу , як тут:

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 вам потрібно передати функцію очікувати (функцію) .toThrow (порожня або тип помилки).

Приклад:

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

Якщо вам потрібно перевірити існуючу функцію, чи вона кидає з набором аргументів, вам доведеться загорнути її всередині анонімної функції в очікуванні ().

Приклад:

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

79

Трохи дивно, але працює і імхо добре читається:

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блок зловити ваш виняток, тоді ви можете протестувати на піднятому Error. Дивний expect(true).toBe(false);необхідний, щоб провалити тест, якщо очікуваний Errorне буде кинутий. В іншому випадку ця лінія ніколи не буде доступною ( Errorповинна бути піднята перед ними).

EDIT: @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 вже є спосіб очікування
gomisha

4
Так, але він перевіряє лише тип, а не повідомлення чи інший вміст. Питання стосувалося тестового повідомлення, а не типу.
bodolsog

2
Ха-ха. Дійсно, як цей, як мій код повинен перевірити значення викинутої помилки, тому мені потрібен екземпляр. Я б написав несправедливе очікування, як expect('here').not.toBe('here');просто заради задоволення від цього :-)
Валерій

4
@ Валері або: expect('to be').not.toBe('to be')у стилі Шекспіра
Міхель ван дер Блок

2
найбільш занижена відповідь!
Edwin Ikechukwu Okonkwo

41

Я використовую трохи більш стисну версію:

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

2
Короткий і точний.
flapjack

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

Відповідь bodolsog, яка передбачає використання спроби / лову, є близькою, але замість того, щоб очікувати, що правда буде хибною, щоб гарантувати, що твердження про очікування в улові потрапили, ви можете замість цього використати 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)тест не вдасться, а тест закінчиться.


D'oh. Я завжди забуваю про те, що я очікую на кілька тверджень Jest (можливо, я просто не вважаю це найбільш інтуїтивним, але це безумовно працює для таких випадків!) Привіт!
kpollock

Це для мене спрацювало чудово. Це слід використовувати.
Анкіт Танна

expect.hasAssertions()може бути кращою альтернативою, коли тест не має жодних тверджень зовні catch, тому що вам не доведеться оновлювати номер, якщо ви додаєте / видаляєте твердження.
Андре Сассі

12

Я сам не пробував цього, але я б запропонував скористатися твердженням Джеста для того, щоб скасувати . Тож я думаю, що ваш приклад виглядав би приблизно так:

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

З документації зрозуміло, як це зробити. Скажімо, у мене є функція, яка приймає два параметри, і вона видасть помилку, якщо один з них є 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

Я написав зручний метод для нашої бібліотеки тестових утиліт

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

Далі до поста Пітера Даніса просто хотілося підкреслити частину його рішення, що передбачає "[передачу] функції в очікування (функцію) .toThrow (порожня або помилка типу)".

У Jest, коли ви перевіряєте на випадок, коли має бути видалена помилка, в рамках очікування () обгортання функції, яку випробовуєте, потрібно надати ще один додатковий шар стрічки для обгортання, щоб він працював. Тобто

Неправильно (але логічний підхід більшості людей):

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

Право:

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

Це дуже дивно, але слід змусити тестування пройти успішно.


1

спробуйте
expect(t).rejects.toThrow()


4
Чому try? немає спроб - але відповідь. Якщо це відповідь, уточнюйте детальніше. що ви додаєте до існуючої відповіді?
dWinder

7
Я думаю, що @Razim казав, що ви повинні спробувати рішення, а не використовувати спробу.
Том
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.