Pracuję z kodem, w którym muszę przetestować typ wyjątku zgłaszanego przez funkcję (czy jest to TypeError, ReferenceError itp.?).
Mój obecny framework testowy to AVA i mogę go przetestować jako t.throws
metodę drugiego argumentu , jak tutaj:
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');
});
Zacząłem przepisywać moje testy w Jest i nie mogłem znaleźć, jak to łatwo zrobić. Czy to w ogóle możliwe?
javascript
unit-testing
jestjs
bartsmykla
źródło
źródło
expect(x).toThrow()
wymagax
odwołania do funkcji, która generuje. Jeśli zamiast tego zdaszexpect(x()).toThrow()
, JavaScript rozwiąże problemx()
, co prawdopodobnie spowoduje natychmiastowy błąd i prawdopodobnie zakończy się niepowodzeniem.To trochę dziwne, ale działa, a IMHO jest czytelne:
it('should throw Error with message \'UNKNOWN ERROR\' when no parameters 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
Blok łapie swój wyjątek, a następnie można przetestować w podniesioneError
. Dziwneexpect(true).toBe(false);
jest potrzebne, aby nie zdać testu, jeśli oczekiwaneError
nie zostanie rzucone. W przeciwnym razie ta linia nigdy nie jest osiągalna (Error
powinna zostać podniesiona przed nimi).@Kenny Body zasugerował lepsze rozwiązanie, które poprawi jakość kodu, jeśli używasz
expect.assertions()
:it('should throw Error with message \'UNKNOWN ERROR\' when no parameters were passed', () => { expect.assertions(1); try { throwError(); } catch (e) { expect(e.message).toBe("UNKNOWN ERROR"); } });
Zobacz oryginalną odpowiedź z dodatkowymi wyjaśnieniami: Jak przetestować typ rzuconego wyjątku w Jest
źródło
expect('here').not.toBe('here');
dla samej zabawy :-)expect('to be').not.toBe('to be')
w stylu Szekspira.Używam nieco bardziej zwięzłej wersji:
expect(() => { // Code block that should throw error }).toThrow(TypeError) // Or .toThrow('expectedErrorMessage')
źródło
Z mojego (choć ograniczonego) kontaktu z Jest, stwierdziłem, że
expect().toThrow()
jest odpowiedni, jeśli chcesz tylko przetestować, że wyrzucany jest błąd określonego typu:expect(() => functionUnderTest()).toThrow(TypeError);
Lub wyświetlany jest błąd z określoną wiadomością:
expect(() => functionUnderTest()).toThrow('Something bad happened!');
Jeśli spróbujesz zrobić jedno i drugie, otrzymasz fałszywie pozytywny wynik. Na przykład, jeśli twój kod wyrzuca
RangeError('Something bad happened!')
, ten test przejdzie:expect(() => functionUnderTest()).toThrow(new TypeError('Something bad happened!'));
Odpowiedź bodolsoga, która sugeruje użycie try / catch, jest bliska, ale zamiast oczekiwać, że prawda będzie fałszywa, aby zapewnić trafienie oczekiwanych asercji w catch, możesz zamiast tego użyć
expect.assertions(2)
na początku testu, gdzie2
jest liczba oczekiwanych stwierdzeń . Czuję, że to dokładniej oddaje intencję testu.Pełny przykład testowania rodzaju i komunikatu błędu:
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!'); } }); });
Jeśli
functionUnderTest()
nie nie wygeneruje błąd, twierdzenia będzie trafienie, aleexpect.assertions(2)
nie powiedzie się, a test nie powiedzie się.źródło
expect.hasAssertions()
może być lepszą alternatywą, gdy test nie ma żadnych potwierdzeń na zewnątrzcatch
, ponieważ nie musisz aktualizować liczby, jeśli dodasz / usuniesz potwierdzenia.toThrowWithMessage(type, message)
z projektu rozszerzonego.Sam tego nie próbowałem, ale sugerowałbym użycie asercji Jest toThrow . Więc myślę, że twój przykład wyglądałby mniej więcej tak:
it('should throw Error with message \'UNKNOWN ERROR\' when no parameters were passed', (t) => { const error = t.throws(() => { throwError(); }, TypeError); expect(t).toThrowError('UNKNOWN ERROR'); //or expect(t).toThrowError(TypeError); });
Ponownie, nie testowałem tego, ale myślę, że powinno działać.
źródło
Modern Jest pozwala na więcej sprawdzeń wartości odrzuconej. Na przykład:
const request = Promise.reject({statusCode: 404}) await expect(request).rejects.toMatchObject({ statusCode: 500 });
zakończy się błędem
Error: expect(received).rejects.toMatchObject(expected) - Expected + Received Object { - "statusCode": 500, + "statusCode": 404, }
źródło
W przypadku, gdy pracujesz z
Promise
s:await expect(Promise.reject(new HttpException('Error message', 402))) .rejects.toThrowError(HttpException);
źródło
Jest ma metodę,
toThrow(error)
aby sprawdzić, czy funkcja wyrzuca, gdy jest wywoływana.Więc w twoim przypadku powinieneś to tak nazwać:
expect(t).toThrowError(TypeError);
Dokumentacja .
źródło
jest.spyOn(service, 'create').mockImplementation(() => { throw new Error(); });
jeśli wyszydzana metodacreate
nie jestasync
.Dokumentacja jasno opisuje, jak to zrobić. Powiedzmy, że mam funkcję, która przyjmuje dwa parametry i zgłosi błąd, jeśli jeden z nich jest
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
Twój 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() }) })
źródło
W nawiązaniu do postu Petera Danisa , chciałem tylko podkreślić część jego rozwiązania polegającą na „[przekazaniu] funkcji do funkcji oczekującej (funkcja) .to rzucać (pusta lub rodzaj błędu)”.
W Jest, gdy testujesz przypadek, w którym powinien zostać wyrzucony błąd, w ramach pakowania funkcji w trakcie exp () testowanej funkcji musisz zapewnić jedną dodatkową warstwę zawijania funkcji strzałkowej, aby zadziałała. To znaczy
Błędne (ale logiczne podejście większości ludzi):
Dobrze:
expect(() => { functionUnderTesting(); }).toThrow(ErrorTypeOrErrorMessage);
To bardzo dziwne, ale powinno sprawić, że testy przebiegną pomyślnie.
źródło
Skończyło się na napisaniu wygodnej metody dla naszej biblioteki narzędzi testowych
/** * 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) } }
źródło
toThrowWithMessage(type, message)
dopasowanym, który jest całkiem niezły.Próbować:
źródło
try
? nie ma próby - ale odpowiedź. Jeśli to jest odpowiedź, opisz więcej. co dodajesz do istniejącej odpowiedzi?