So testen Sie den Typ der ausgelösten Ausnahme in Jest


159

Ich arbeite mit einem Code, bei dem ich den von der Funktion ausgelösten Ausnahmetyp testen muss (Ist es TypeError, ReferenceError usw.)?

Mein aktuelles Testframework ist AVA und ich kann es als zweite Argumentmethode testen t.throws, wie hier:

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

Ich fing an, meine Tests in Jest umzuschreiben und konnte nicht herausfinden, wie ich das einfach machen konnte. Ist es überhaupt möglich?

Antworten:


221

In Jest müssen Sie eine Funktion an Expect (Funktion) .toThrow (Leerzeichen oder Fehlertyp) übergeben.

Beispiel:

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

Wenn Sie eine vorhandene Funktion testen müssen, um festzustellen, ob sie mit einer Reihe von Argumenten ausgelöst wird, müssen Sie sie in require () in eine anonyme Funktion einschließen.

Beispiel:

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

79

Ein bisschen komisch, aber funktioniert und imho ist gut lesbar:

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

CatchBlock fangen Sie Ihre Ausnahme, dann können Sie auf Ihrem erhöhten testen Error. Seltsam expect(true).toBe(false);ist erforderlich, um Ihren Test nicht zu bestehen, wenn nicht erwartet Errorwird, dass er geworfen wird. Andernfalls ist diese Linie niemals erreichbar ( Errorsollte vor ihnen angehoben werden).

BEARBEITEN: @Kenny Body schlägt eine bessere Lösung vor, die die Codequalität verbessert, wenn Sie verwenden 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");
  }
});

Weitere Erklärungen finden Sie in der Originalantwort: So testen Sie den Typ der ausgelösten Ausnahme in Jest


17
Dies ist eine sehr ausführliche Methode zum Testen auf Ausnahmen, wenn Jest bereits die Methode "Expect.toThrow ()" hat, um nach Ausnahmen zu suchen
gomisha

4
Ja, aber es wird nur der Typ, nicht die Nachricht oder anderer Inhalt getestet, und die Frage betraf die Testnachricht, nicht den Typ.
Bodolsog

2
Hah. Wirklich wie dieser, da mein Code einen Wert des ausgelösten Fehlers testen muss, damit ich die Instanz brauche. Ich würde die fehlerhafte Erwartung wie expect('here').not.toBe('here');zum Spaß schreiben :-)
Valery

4
@Valery oder: expect('to be').not.toBe('to be')im Shakespeare-Stil.
Michiel van der Blonk

2
am meisten unterschätzte Antwort!
Edwin Ikechukwu Okonkwo

40

Ich benutze eine etwas prägnantere Version:

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

2
Kurz und präzise.
Flapjack

31

Aufgrund meiner (wenn auch begrenzten) Exposition gegenüber Jest habe ich festgestellt, dass dies expect().toThrow()geeignet ist, wenn Sie NUR einen Fehler eines bestimmten Typs testen möchten:

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

ODER es wird ein Fehler mit einer bestimmten Meldung ausgegeben:

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

Wenn Sie versuchen, beides zu tun, erhalten Sie ein falsches Positiv. Wenn Ihr Code beispielsweise ausgelöst wird RangeError('Something bad happened!'), besteht dieser Test Folgendes:

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

Die Antwort von bodolsog, die die Verwendung eines try / catch vorschlägt, ist nah, aber anstatt zu erwarten, dass true falsch ist, um sicherzustellen, dass die erwarteten Zusicherungen im catch getroffen werden, können Sie stattdessen expect.assertions(2)zu Beginn Ihres Tests 2die Anzahl der erwarteten Zusicherungen verwenden . Ich bin der Meinung, dass dies die Absicht des Tests genauer beschreibt.

Vollständiges Beispiel zum Testen des Typs UND der Meldung eines Fehlers:

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

Wenn functionUnderTest()KEIN Fehler ausgegeben wird, werden die Zusicherungen getroffen, aber die schlagen expect.assertions(2)fehl und der Test schlägt fehl.


D'oh. Ich vergesse immer die erwartete Funktion für mehrfache Behauptungen von Jest (möglicherweise finde ich es persönlich nicht besonders intuitiv, aber es funktioniert definitiv in solchen Fällen!) Prost!
Kpollock

Das hat bei mir sehr gut funktioniert. Dies sollte verwendet werden.
Ankit Tanna

expect.hasAssertions()Möglicherweise eine bessere Alternative, wenn der Test keine Zusicherungen außerhalb hat catch, da Sie die Nummer nicht aktualisieren müssen, wenn Sie Zusicherungen hinzufügen / entfernen.
André Sassi

12

Ich habe es nicht selbst versucht, aber ich würde vorschlagen, Jests toThrow- Behauptung zu verwenden. Ich denke, Ihr Beispiel würde ungefähr so ​​aussehen:

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

Auch hier habe ich es nicht getestet, aber ich denke, es sollte funktionieren.


8

Jest hat eine Methode toThrow(error), um zu testen, ob eine Funktion beim Aufruf ausgelöst wird.

In Ihrem Fall sollten Sie es also so nennen:

expect(t).toThrowError(TypeError);

Die Dokumente


1
Für den Fall würde es nicht funktionieren: jest.spyOn(service, 'create').mockImplementation(() => { throw new Error(); });Wenn die verspottete Methode createnicht ist async.
Sergey

7

Mit dem modernen Scherz können Sie den abgelehnten Wert genauer überprüfen. Beispielsweise:

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

wird mit Fehler fehlschlagen

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

- Expected
+ Received

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

6

In der Dokumentation ist klar, wie das geht. Nehmen wir an, ich habe eine Funktion, die zwei Parameter akzeptiert und einen Fehler auslöst, wenn einer davon ist 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

Dein Test

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

Wenn Sie mit Promises arbeiten:

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

Das ist super hilfreich, danke, dass du mir Zeit gespart hast !!
Aditya Kresna Permana

3

Am Ende habe ich eine Convenience-Methode für unsere Test-Utils-Bibliothek geschrieben

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

Das gleiche kann mit Jests eigenen Funktionen gemacht werden. Siehe meine Antwort, wie dies getan werden kann - stackoverflow.com/a/58103698/3361387
Kenny Body

3

Neben Peter Danis 'Beitrag wollte er nur den Teil seiner Lösung hervorheben, der darin besteht, "eine Funktion in" Expect (Funktion) .toThrow (Leerzeichen oder Fehlertyp) zu übergeben ".

Wenn Sie in Jest auf einen Fall testen, in dem ein Fehler ausgelöst werden soll, müssen Sie innerhalb Ihrer erwarteten () Umhüllung der zu testenden Funktion eine zusätzliche Umbruchschicht für Pfeilfunktionen bereitstellen, damit sie funktioniert. Dh

Falsch (aber der logische Ansatz der meisten Leute):

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

Richtig:

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

Es ist sehr seltsam, sollte aber den Test erfolgreich ausführen.


1

Versuchen
expect(t).rejects.toThrow()


4
Warum try? Es gibt keinen Versuch - sondern eine Antwort. Wenn dies eine Antwort ist, gehen Sie bitte näher darauf ein. Was fügen Sie der vorhandenen Antwort hinzu?
Dwinder

7
Ich denke, @Razim hat gesagt, dass Sie die Lösung ausprobieren sollten, nicht einen Try-Catch.
Tom
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.