web-dev-qa-db-fra.com

Comment puis-je exécuter les tests asynchrones Mocha (NodeJS) dans l'ordre?

Cette question concerne le cadre de test Mocha pour NodeJS.

Le comportement par défaut semble être de démarrer tous les tests, puis de traiter les rappels asynchrones au fur et à mesure qu'ils arrivent.

Lors de l'exécution de tests asynchrones, je voudrais exécuter chaque test après la partie asynchrone de la précédente a été appelée.

Comment puis-je faire ceci?

50
fadedbee

Le point n'est pas tant que "le code structuré s'exécute dans l'ordre dans lequel vous l'avez structuré" (étonnant!) - mais plutôt comme le suggère @chrisdew, les ordres de retour pour les tests asynchrones ne peuvent pas être garantis. Pour reformuler le problème - les tests qui sont plus bas dans la chaîne (exécution synchrone) ne peuvent pas garantir que les conditions requises, définies par les tests asynchrones, seront prêtes au moment de leur exécution.

Donc, si vous exigez que certaines conditions soient définies dans les premiers tests (comme un jeton de connexion ou similaire), vous devez utiliser des hooks comme before() qui testent ces conditions avant de continuer.

Enveloppez les tests dépendants dans un bloc et exécutez un asyncbefore hook sur eux (notez le "fait" dans le bloc avant):

var someCondition = false

// ... your Async tests setting conditions go up here...

describe('is dependent on someCondition', function(){

  // Polls `someCondition` every 1s
  var check = function(done) {
    if (someCondition) done();
    else setTimeout( function(){ check(done) }, 1000 );
  }

  before(function( done ){
    check( done );
  });

  it('should get here ONLY once someCondition is true', function(){ 
    // Only gets here once `someCondition` is satisfied
  });

})
35
papercowboy

Je suis surpris par ce que vous avez écrit en l'utilisant. J'utilise mocha avec des tests de style bdd (décrire/it), et j'ai juste ajouté quelques console.logs à mes tests pour voir si vos revendications tiennent avec mon cas, mais apparemment ils ne le font pas.

Voici le fragment de code que j'ai utilisé pour voir l'ordre de "end1" et "start1". Ils ont été correctement commandés.

describe('Characters start a work', function(){
    before(function(){
      sinon.stub(statusapp, 'create_message');
    });
    after(function(){
      statusapp.create_message.restore();
    });
    it('creates the events and sends out a message', function(done){
      draftwork.start_job(function(err, work){
        statusapp.create_message.callCount.should.equal(1);
        draftwork.get('events').length.should.equal(
          statusapp.module('jobs').Jobs.get(draftwork.get('job_id')).get('nbr_events')
        );
        console.log('end1');
        done();
      });
    });
    it('triggers work:start event', function(done){
      console.log('start2');
      statusapp.app.bind('work:start', function(work){
        work.id.should.equal(draftwork.id);
        statusapp.app.off('work:start');
        done();
      });

Bien sûr, cela aurait pu arriver aussi par accident, mais j'ai beaucoup de tests, et s'ils couraient en parallèle, j'aurais certainement des conditions de course que je n'ai pas.

S'il vous plaît, reportez-vous également à ce problème dans le suivi des problèmes mocha. Selon lui, les tests sont exécutés de manière synchrone.

9
Akasha

utilisez étapes mocha

il garde les tests séquentiels, qu'ils soient asynchrones ou non (c'est-à-dire que vos fonctions done fonctionnent toujours exactement comme elles l'ont fait). C'est un remplacement direct de it et à la place vous utilisez step

6
WiR3D

Je voulais résoudre ce même problème avec notre application, mais la réponse acceptée ne fonctionnait pas bien pour nous. Surtout dans le someCondition ne serait jamais vrai.

Nous utilisons des promesses dans notre application et celles-ci ont facilité la structuration des tests en conséquence. La clé reste cependant de retarder l'exécution via le hook before:

var assert = require( "assert" );

describe( "Application", function() {
  var application = require( __dirname + "/../app.js" );
  var bootPromise = application.boot();

  describe( "#boot()", function() {
    it( "should start without errors", function() {
      return bootPromise;
    } );
  } );

  describe( "#shutdown()", function() {
    before( function() {
      return bootPromise;
    } );

    it( "should be able to shut down cleanly", function() {
      return application.shutdown();
    } );
  } );
} );
5
Der Hochstapler