2010-11-10 6 views
354

Ich versuche, einen Test für die Jasmine Test Framework schreiben, die einen Fehler erwartet. Im Moment verwende ich eine Jasmine Node.js integration from GitHub.Wie schreibe ich einen Test, der erwartet, dass ein Fehler in Jasmine geworfen wird?

In meiner Node-Modul habe ich den folgenden Code:

throw new Error("Parsing is not possible"); 

Jetzt versuche ich, einen Test zu schreiben, die diesen Fehler erwartet:

describe('my suite...', function() { 
    [..] 
    it('should not parse foo', function() { 
    [..] 
     expect(parser.parse(raw)).toThrow(new Error("Parsing is not possible")); 
    }); 
}); 

Ich habe auch versucht Error() und einige andere Varianten und nur kann nicht herausfinden, wie es funktioniert.

+3

Um Argumente an die Funktion übergeben getestet, ohne eine anonyme Funktion zu verwenden, versuchen Sie 'Function.bind': http://stackoverflow.com/ a/13233194/294855 –

Antwort

628

sollten Sie eine Funktion in den expect(...) Aufruf werden vorbei. Der Code, den Sie haben sich hier:

// incorrect: 
expect(parser.parse(raw)).toThrow(new Error("Parsing is not possible")); 

versucht, tatsächlich Anrufparser.parse(raw) in einem Versuch, das Ergebnis in expect(...) zu passieren,

Versuchen Sie stattdessen eine anonyme Funktion:

expect(function(){ parser.parse(raw); }).toThrow(new Error("Parsing is not possible")); 
+21

Wenn Sie keine Argumente übergeben müssen, können Sie auch einfach die erwartete Funktion übergeben: 'expect (parser.parse) .toThrow (...)' – SubmittedDenied

+47

Hilfreicher Tipp: Sie können einfach 'expect (blah) aufrufen .toThrow() '. Keine Argumente bedeutet überprüfen, dass es überhaupt wirft. Kein String-Matching erforderlich. Siehe auch: http://StackOverflow.com/a/9525172/1804678 – Jess

+1

Meiner Meinung nach ist es offensichtlicher, wenn der Test in einer anonymen Funktion verpackt wird. Außerdem bleibt es bei allen Tests konsistent, wenn Sie beispielsweise Parameter an die Zielfunktion übergeben müssen, um sie zu werfen. – Beez

55

Sie verwenden:

expect(fn).toThrow(e) 

Aber wenn man einen Blick auf die Funktion Kommentar haben werden (erwartet ist string):

294 /** 
295 * Matcher that checks that the expected exception was thrown by the actual. 
296 * 
297 * @param {String} expected 
298 */ 
299 jasmine.Matchers.prototype.toThrow = function(expected) { 

Ich nehme an, Sie wahrscheinlich es so schreiben sollte (mit Lambda - anonyme Funktion):

expect(function() { parser.parse(raw); }).toThrow("Parsing is not possible"); 

die im folgende Beispiel bestätigt:

expect(function() {throw new Error("Parsing is not possible")}).toThrow("Parsing is not possible"); 

Douglas Crockford empfiehlt dringend, diesen Ansatz, statt mit "neuen Fehler werfen()" (Prototyping Fahrt):

throw { 
    name: "Error", 
    message: "Parsing is not possible" 
} 
+3

Wenn man sich den Code toThrow anschaut, nimmt man glücklicherweise entweder ein Exception-Objekt/oder/eine Zeichenkette. Sehen Sie sich zum Beispiel die ankommenden Anrufe an expected.message an. –

+1

Es scheint, String als Nebeneffekt der Zeichenfolge zu ermöglichen, die keine Nachrichteneigenschaft hat – mpapis

+1

Vielen Dank, die funktionierte. Ich akzeptierte immer noch die Antwort von Pete, weil seine Antwort es mir klarer machte, dass ich ein Lambda benutzen sollte. Immer noch +1 :-) Danke! – echox

22

I Ersetzen Sie Jasmins toThrow-Matcher durch Folgendes, mit dem Sie die Namenseigenschaft der Ausnahme oder ihre Nachrichteneigenschaft abgleichen können. Für mich macht diese Tests einfacher zu schreiben und weniger spröde, wie ich folgendes tun:

throw { 
    name: "NoActionProvided", 
    message: "Please specify an 'action' property when configuring the action map." 
} 

und testen Sie dann mit den folgenden:

expect (function() { 
    .. do something 
}).toThrow ("NoActionProvided"); 

Diese mir Nachricht später zwicken die Ausnahme lässt, ohne zu brechen Tests, wenn die wichtige Sache ist, dass es die erwartete Art von Ausnahme warf.

Dies ist der Ersatz für toThrow, die dies ermöglicht:

jasmine.Matchers.prototype.toThrow = function(expected) { 
    var result = false; 
    var exception; 
    if (typeof this.actual != 'function') { 
    throw new Error('Actual is not a function'); 
    } 
    try { 
    this.actual(); 
    } catch (e) { 
    exception = e; 
    } 
    if (exception) { 
     result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected) || this.env.equals_(exception.name, expected)); 
    } 

    var not = this.isNot ? "not " : ""; 

    this.message = function() { 
    if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) { 
     return ["Expected function " + not + "to throw", expected ? expected.name || expected.message || expected : " an exception", ", but it threw", exception.name || exception.message || exception].join(' '); 
    } else { 
     return "Expected function to throw an exception."; 
    } 
    }; 

    return result; 
}; 
+3

Ein netter Ansatz, aber ist {name: '...', message: '...'} ein korrektes Error-Objekt in JavaScript? – Marc

+1

Netter Kommentar @Marc. Du hast Recht, die Namenseigenschaft ist nicht Standard. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error, aber ist das so falsch? – Jess

+3

@Jake! Ich habe einen besseren Weg gefunden !!!! Sie können einfach 'expect (blah) .toThrow()' nennen. Keine Argumente bedeutet überprüfen, dass es überhaupt wirft. Kein String-Matching erforderlich. Siehe auch: http://StackOverflow.com/a/9525172/1804678 – Jess

5

Für Coffee Liebhaber

expect(=> someMethodCall(arg1, arg2)).toThrow() 
7

Ich weiß, dass mehr Code, aber Sie können auch tun:

try 
    do something 
    @fail Error("should send a Exception") 
catch e 
    expect(e.name).toBe "BLA_ERROR" 
    expect(e.message).toBe 'Message' 
+0

Ich neige dazu, den 'selbst-dokumentierenden' Aspekt zu mögen ... macht es sehr offensichtlich, dass Sie einen Fehlerzustand testen – JRulle

19

Eine elegantere Lösung als das Erstellen einer anonymen Funktion, deren einziger Zweck darin besteht, einen anderen zu umhüllen, besteht darin, es5'szu verwendenFunktion. Die Bind-Funktion erstellt eine neue Funktion, deren this-Schlüsselwort auf den angegebenen Wert gesetzt wird, wobei eine bestimmte Argumentfolge vor dem Aufruf der neuen Funktion steht.

Statt:

expect(function() { parser.parse(raw, config); }).toThrow("Parsing is not possible");

Bedenken Sie:

expect(parser.parse.bind(parser, raw, config)).toThrow("Parsing is not possible");

Die bind-Syntax können Sie Funktionen mit unterschiedlichen this Werte testen, und meiner Meinung nach macht der Test besser lesbar. Siehe auch: https://stackoverflow.com/a/13233194/1248889

6

Wie bereits erwähnt, eine Funktion zu toThrow weitergegeben werden muss, da es die Funktion, die Sie beschreiben in Ihrem Test ist: „Ich habe diese Funktion erwarten werfen x“

expect(() => parser.parse(raw)) 
    .toThrow(new Error('Parsing is not possible')); 

Wenn Mit Jasmine-Matchers können Sie auch eine der folgenden verwenden, wenn sie der Situation entsprechen;

// I just want to know that an error was 
// thrown and nothing more about it 
expect(() => parser.parse(raw)) 
    .toThrowAnyError(); 

oder

// I just want to know that an error of 
// a given type was thrown and nothing more 
expect(() => parser.parse(raw)) 
    .toThrowErrorOfType(TypeError); 
+2

Es ist 'expect (foo) .toThrowError (TypeError);' in Jasmine 2.5: https://jasmine.github.io/2.5/Einführung –

0

Für alle, die noch könnten dieses Problem konfrontiert werden, für mich die entsandte Lösung nicht funktioniert haben und es hielt diesen Fehler zu werfen: Error: Expected function to throw an exception. ich später erkennen, dass die Funktion was ich erwartete, um einen Fehler zu werfen, war eine asynchrone Funktion und wurde erwartet, dass die Ablehnung abgelehnt wird und dann Fehler und das ist, was ich in meinem Code tat:

throw new Error('REQUEST ID NOT FOUND'); 

und das ist, was ich in meinem Test habe und es funktionierte:

it('Test should throw error if request not found', willResolve(() => { 
     const promise = service.getRequestStatus('some-id'); 
       return expectToReject(promise).then((err) => { 
        expect(err.message).toEqual('REQUEST NOT FOUND'); 
       }); 
      })); 
Verwandte Themen