web-dev-qa-db-fra.com

Test d'échec prévu en moka

En utilisant Mocha, je tente de tester si un constructeur génère une erreur. Je n'ai pas été capable de faire cela en utilisant la syntaxe expect, alors j'aimerais faire ce qui suit:

it('should throw exception when instantiated', function() {
  try {
    new ErrorThrowingObject();
    // Force the test to fail since error wasn't thrown
  }
  catch (error) {
   // Constructor threw Error, so test succeeded.
  }
}

Est-ce possible?

13
bibs

Vous pouvez essayer d’utiliser la construction de Chaithrow. Par exemple:

expect(Constructor).to.throw(Error);
10
Mark F

devrait.js

Utiliser la bibliothèque should.js avec should.fail

var should = require('should')
it('should fail', function(done) {
  try {
      new ErrorThrowingObject();
      // Force the test to fail since error wasn't thrown
       should.fail('no error was thrown when it should have been')
  }
  catch (error) {
   // Constructor threw Error, so test succeeded.
   done();
  }
});

Alternative vous pouvez utiliser le devrait throwError

(function(){
  throw new Error('failed to baz');
}).should.throwError(/^fail.*/)

Chai

Et avec chai en utilisant le throw api

var expect = require('chai').expect
it('should fail', function(done) {
  function throwsWithNoArgs() {
     var args {} // optional arguments here
     new ErrorThrowingObject(args)
  }
  expect(throwsWithNoArgs).to.throw
  done()
});
30
Noah

Chai a maintenant

should.fail() et expect.fail()

https://github.com/chaijs/chai/releases/tag/2.1.0

11
shaunc

2017 répondez si vous avez besoin de le faire avec un code asynchrone : using wait et ne nécessitant aucune autre bibliothèque .

it('Returns a correct error response when making a broken order', async function(){
  this.timeout(5 * 1000);
  var badOrder = {}
  try {
    var result = await foo.newOrder(badOrder)
    // The line will only be hit if no error is thrown above!
    throw new Error(`Expected an error and didn't get one!`)
  } catch(err) {
    var expected = `Missing required field`
    assert.equal(err.message, expected)
  }
});

Notez que l'affiche ne faisait que du code de synchronisation, mais je m'attends à ce que beaucoup de personnes utilisant async soient dirigées ici par le titre de la question! 

8
mikemaccana

Mocha utilise par défaut Assert de node.js ( https://nodejs.org/api/assert.html ). Vous n'avez besoin d'aucune bibliothèque externe pour vérifier si une méthode génère une erreur. 

Assert a une méthode - assert.throws, elle a trois paramètres, mais seulement deux sont vraiment importants ici:

  • fonction - ici fonction passe, pas appel de fonction
  • error - ici pass ou constructeur d'objet ou fonction pour vérifier l'erreur

Imaginons que vous ayez une fonction appelée sendMessage(message) qui lève une erreur lorsque le paramètre message n'est pas défini. Code de fonction:

function sendMessage(message) {
  if (!message || typeof message !== 'string') {
     throw new Error('Wrong message');
  }
  // rest of function
}

Ok, donc pour le tester, vous avez besoin d’une fonction supplémentaire pour couvrir les entrées. Pourquoi? Parce que assert.throws ne donne aucune possibilité de passer des paramètres à la fonction à tester.

Donc au lieu de

// WRONG
assert.throws(sendMessage, Error); // THIS IS WRONG! NO POSSIBILITY TO PASS ANYTHING

vous devez créer une fonction anonyme:

// CORRECT
assert.throws(() => {
  sendMessage(12);  // usage of wanted function with test parameters
}, Error)

Pouvez-vous voir la différence? Au lieu de passer directement de fonction à un autre, j’ai mis l’appel de fonction dans une fonction anonyme afin de l’appeler avec une entrée préparée.

Qu'en est-il du deuxième paramètre. Cela dépend de quel type d'erreur doit être généré, dans l'exemple ci-dessus, un objet Error a été lancé, j'ai donc dû y mettre Error. À la suite de cette action, assert.throws compare si l'objet jeté est un objet du même type. Si au lieu de Error quelque chose de différent sera lancé, cette partie doit être modifiée. Par exemple, au lieu de Error, je jetterai une valeur de type String.

function sendMessage(message) {
  if (!message || typeof message !== 'string') {
     throw 'Wrong message'; // change to String
  }
  // rest of function
}

Maintenant l'appel d'essai

assert.throws(() => {
  sendMessage(12); // usage of wanted function with test parameters
}, (err) => err === 'Wrong message')

Au lieu de Error dans le deuxième paramètre, j'ai utilisé la fonction de comparaison afin de comparer l'erreur renvoyée à l'attente.

4
Maciej Sikora

La réponse acceptée par MarkJ est la voie à suivre et beaucoup plus simple que d’autres ici.

function fn(arg) {
  if (typeof arg !== 'string')
    throw TypeError('Must be an string')

  return { arg: arg }
}

describe('#fn', function () {
  it('empty arg throw error', function () {
    expect(function () {
      new fn()
    }).to.throw(TypeError)
  })

  it('non-string arg throw error', function () {
    expect(function () {
      new fn(2)
    }).to.throw(TypeError)
  })

  it('string arg return instance { arg: <arg> }', function () {
    expect(new fn('str').arg).to.be.equal('str')
  })
})
3
Andre Figueiredo

Si vous ne voulez pas encombrer de sources dans le paramètre expect, ou si vous avez beaucoup d'arguments à transmettre et que cela devient vraiment moche, vous pouvez toujours le faire avec la syntaxe d'origine, en utilisant les arguments done. fourni (mais a été ignoré à l'origine):

it('should throw exception when instantiated', function(done: Done) {
  try {
    new ErrorThrowingObject();
    done(new Error(`Force the test to fail since error wasn't thrown`));
  }
  catch (error) {
    // Constructor threw Error, so test succeeded.
    done();
  }
}

Puisque vous utilisez done ici, cela vous permet d’exécuter du code arbitraire au-dessus de celui-ci dans try, puis de spécifier exactement où vous voulez enregistrer l’erreur dans votre source.

Normalement, une personne peut être tentée par throw ou assert(false), mais celles-ci seront toutes deux capturées par la catch de la try et vous obligeront à effectuer une méta-vérification pour déterminer si l'erreur que vous avez détectée était l'erreur attendue de votre test ou si c'était la détermination finale que votre test a échoué. C'est juste un gâchis.

1
Ian MacDonald

Si vous utilisez should.js vous pouvez faire (new ErrorThrowingObject).should.throw('Option Error Text or Regular Expression here')

Si vous ne voulez pas une bibliothèque séparée, vous pouvez aussi faire quelque chose comme ça:

it('should do whatever', function(done) {
    try {
        ...
    } catch(error) {
        done();
    }
}

De cette façon, vous savez que l'erreur est interceptée si le test se termine. Sinon, vous obtiendrez une erreur de délai d'attente. 

1
Max

Avec Chai throw (ES2016)

http://chaijs.com/api/bdd/#method_throw

Pour plus de clarté ... Cela fonctionne

it('Should fail if ...', done => {
    let ret = () => {
        MyModule.myFunction(myArg);
    };
    expect(ret).to.throw();
    done();
});

Ça ne marche pas

it('Should fail if ...', done => {
    let ret = MyModule.myFunction(myArg);
    expect(ret).to.throw();
    done();
});
0
SandroMarques