Domanda

Sto cercando di scrivere un test per il Jasmine quadro di prova, che si aspetta un errore. Al momento sto usando un Jasmine Node.js integrazione da GitHub .

Nel mio modulo Nodo Ho il seguente codice:

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

Ora cerco di scrivere un test che si aspetta che questo errore:

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

Ho provato anche Error() e alcune altre varianti e non riesce proprio a capire come farlo funzionare.

È stato utile?

Soluzione

Si dovrebbe essere passando una funzione nella chiamata expect(...). Il codice che avete qui:

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

sta cercando di realtà Chiama parser.parse(raw) nel tentativo di superare il risultato in expect(...),

Prova ad utilizzare una funzione anonima invece:

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

Altri suggerimenti

Si utilizza:

expect(fn).toThrow(e)

Ma se avrete uno sguardo sulla funzione di commento (previsto è 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) {

Credo che probabilmente si dovrebbe scrivere in questo modo (usando lambda - funzione anonima):

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

Ciò è confermato nel seguente esempio:

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

Douglas Crockford consiglia vivamente di questo approccio, invece di utilizzare "throw new Error ()" (modo prototipazione):

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

sostituisco matcher toThrow di Jasmine con la seguente, che consente di abbinare sulla proprietà nome del eccezione o la sua proprietà messaggio. Per me questo rende i test più facile da scrivere e meno fragile, come posso fare quanto segue:

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

e poi prova con il seguente:

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

Questo mi permette di modificare il messaggio di eccezione in seguito senza rompere le prove, quando la cosa importante è che ha gettato il tipo atteso di eccezione.

Questa è la sostituzione per toThrow che permette questo:

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

Una soluzione più elegante rispetto alla creazione di una funzione anonima che è unico scopo è quello di avvolgere un'altra, è quella di utilizzare di ES5 bind funzione. La funzione bind crea una nuova funzione che, quando viene chiamato, ha il suo set this parola chiave per il valore fornito, con una data sequenza di argomenti che precedono qualsiasi condizione quando viene chiamata la nuova funzione.

Al posto di:

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

Si consideri:

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

La sintassi legano consente di funzioni di test con diversi valori di this, e, a mio parere rende il test più leggibile. Vedi anche: https://stackoverflow.com/a/13233194/1248889

Come accennato in precedenza, un bisogno di funzione da passare a toThrow come lo è la funzione che stai descrivendo nel test: "Mi aspetto che questa funzione di gettare x"

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

Se si utilizza gelsomino Matchers è anche possibile utilizzare uno dei segue quando si adatti alla situazione;

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

o

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

Lo so che è più codice, ma si può anche fare:

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

Per gli amanti CoffeeScript

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

Per chi ancora potrebbe essere di fronte a questo problema, per me la soluzione inviata non ha funzionato e continuava a lanciare questo errore: Error: Expected function to throw an exception. poi mi sono reso conto che la funzione che mi aspettavo di gettare un errore era una funzione asincrona e mi aspettavo promessa di essere respinto e poi gettare l'errore e questo è quello che stavo facendo nel mio codice:

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

e questo è quello che ho fatto nella mia prova e ha funzionato:

it('Test should throw error if request not found', willResolve(() => {
         const promise = service.getRequestStatus('request-id');
                return expectToReject(promise).then((err) => {
                    expect(err.message).toEqual('REQUEST NOT FOUND');
                });
            }));
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top