Comment sauter un test par programmation en moka?

142

J'ai un code où certains tests échoueront toujours dans l'environnement CI. Je voudrais les désactiver en fonction d'une condition d'environnement.

Comment ignorer par programme un test dans mocha pendant l'exécution du runtime?

Gajus
la source
3
Sauter un test par programme est couvert par this.skip()dans mochajs.org/#inclusive-tests et la réponse de @ zatziky ci-dessous. Le reste des réponses est obsolète pour Mocha v3 +
Patrick
1
describe.skip ('description', () => {}) / describe.only ('description', () => {}) / it.skip ('description', () => {}) / it. only ('description', () => {})
Jun711
une réponse acceptée?
Paul Rooney

Réponses:

168

Vous pouvez sauter les tests en plaçant un x devant le bloc describe ou it, ou en plaçant un .skipaprès.

xit('should work', function (done) {});

describe.skip('features', function() {});

Vous pouvez également exécuter un seul test en plaçant un .onlysur le test. par exemple

describe('feature 1', function() {});
describe.only('feature 2', function() {});
describe('feature 3', function() {});

Seul le bloc fonctionnalité 2 s'exécuterait dans ce cas.

Il ne semble pas y avoir de moyen d'ignorer les tests par programme, mais vous pouvez simplement effectuer une sorte de vérification dans une beforeEachinstruction et exécuter le test uniquement si l'indicateur a été défini.

beforeEach(function(){
    if (wrongEnvironment){
        runTest = false
    }
}

describe('feature', function(){
    if(runTest){
         it('should work', function(){
            // Test would not run or show up if runTest was false,
         }
    }
}
KJ3
la source
8
Votre deuxième tentative de solution ne fonctionnera pas, car l'ordre d'exécution n'est pas celui que vous pensez. Lorsque l' beforeEachappel s'exécute, Mocha enregistre la fonction anonyme (le «hook») pour une utilisation future , lorsque l' describeappel s'exécute, Mocha exécute immédiatement la fonction anonyme qui lui est passée. Ainsi, au moment de l' if (runTest)exécution, le beforeEach hook ne sera pas exécuté.
Louis
23
Comment cette réponse a-t-elle 27 votes positifs? La question porte sur le saut de tests par programme, donc l'ajout de ".skip" ou ".only" n'est pas utile. Ensuite, il dit explicitement que vous ne pouvez pas faire ce que le PO veut faire, malgré le fait que d'autres réponses vous disent comment le faire.
Graeme Perrow
3
Cela ne fonctionnera pas, pas de réponse à la question, voir la réponse de @Gajus à la place
NorTicUs
1
Cette réponse a des mérites pour une question différente qui n'a pas été posée ici. Je n'ai pas le pouvoir de changer quoi que ce soit ici. Voir la réponse this.skip ().
Andrew Martinez
3
cela ne répond pas à la question
Ingo Renner
110

Il existe un moyen non documenté de sauter des tests par programme:

// test.js

describe('foo', function() {
  before(function() {
    this.skip();
  });

  it('foo', function() {
    // will not run
    console.log('This will not be printed');
  });
});

fonctionnement:

$ mocha test.js


  foo
    - foo


  0 passing (9ms)
  1 pending

Ceci est discuté dans https://github.com/mochajs/mocha/issues/1901 .

Gajus
la source
14
Les lecteurs voudront peut-être savoir que cela marque le tout describecomme ignoré (c'est-à-dire que tous les tests du describesont sautés).
Louis du
Documentation des "tests en attente" de Mocha: mochajs.org/#pending-tests
lasec0203
describe.skip ('description', () => {}) / describe.only ('description', () => {}) / it.skip ('description', () => {}) / it. only ('description', () => {})
711
Je ne comprends pas pourquoi ce genre de réponse est voté. c'est un hack - et pas un preety.
chenop
2
documentation réelle mochajs.org/#inclusive-tests , ce n'est en aucun cas un hack btw, mais une méthode correcte d'exclusion de certains tests en fonction des paramètres d'exécution. c'est-à-dire qu'il répond exactement à ce que la question initiale a posée. Merci @xavdid
WowPress.host
42

Cette réponse fonctionne pour ES6 .

Au lieu de:

describe('your describe block', () => {

Tu veux:

(condition ? describe : describe.skip)('your describe block', () => {

Cela saute conditionnellement tous les tests du bloc de description SI la condition est fausse.

Ou, au lieu de:

it('your it block', () => {

Tu veux:

(condition ? it : it.skip)('your it block', () => {

Cela saute conditionnellement un test SI la condition est fausse.

danday74
la source
4
Je comprends ce que vous suggérez, mais vous devez d'abord définir une description contextuelle comme celle-ci: const contextualDescribe = shouldAvoidTests ? describe.skip : describe vous pouvez ensuite l'utiliser: contextualDescribe('your it block', () => {
Ser
3
@Ser Pour obtenir sur une seule ligne, j'ai utilisé quelque chose comme ceci:(condition ? describe : describe.skip)('your describe block', () => {
joshden
Comment faire cette asynchrone? Je dois rechercher la condition de saut en fonction d'un indicateur redis, qui est une opération asynchrone (nous stockons les indicateurs de fonctionnalité dans redis).
Patrick Finnigan
Cela fait un moment mais j'ai eu ce genre de besoin avant aussi, je pense que je viens d'envelopper tous les trucs de moka dans une fonction qui a été appelée après le rappel async terminé
je
J'avais l'habitude d'utiliser cette technique mais maintenant elle échoue pour moi. essayez simplement d'écrire(it)('my test', () => {})
cyrf
33

J'utilise le saut d'exécution de Mocha pour le même scénario que celui que vous décrivez. C'est le copier-coller de la documentation :

it('should only test in the correct environment', function() {
  if (/* check test environment */) return this.skip();

  // make assertions
});

Comme vous pouvez le voir, il ignore le test basé sur l'environnement. Ma propre condition est if(process.env.NODE_ENV === 'continuous-integration').

Amio.io
la source
2
D'accord! Peut-être être un one-liner en faisant un retour anticipé peut-être? Comme: if (/* skipTestCondition */) return this.skip();- edit: works: D
SidOfc
12

pour sauter des tests, utiliser describe.skipouit.skip

describe('Array', function() {
  it.skip('#indexOf', function() {
    // ...
  });
});

pour inclure des tests que vous pourriez utiliser describe.onlyouit.only


describe('Array', function() {
  it.only('#indexOf', function() {
    // ...
  });
});

Plus d'informations sur https://mochajs.org/#inclusive-tests

lfender6445
la source
6

Cela dépend de la manière dont vous souhaitez ignorer le test par programmation. Si les conditions de saut peuvent être déterminées avant l'exécution de tout code de test, vous pouvez simplement appeler itou it.skipau besoin, en fonction d'une condition. Par exemple, cela sautera certains tests si la variable d'environnement ONEest définie sur une valeur quelconque:

var conditions = {
    "condition one": process.env["ONE"] !== undefined
    // There could be more conditions in this table...
};

describe("conditions that can be determined ahead of time", function () {
    function skip_if(condition, name, callback) {
        var fn = conditions[condition] ? it.skip: it;
        fn(name, callback);
    };

    skip_if("condition one", "test one", function () {
        throw new Error("skipped!");
    });

    // async.
    skip_if("condition one", "test one (async)", function (done) {
        throw new Error("skipped!");
    });

    skip_if("condition two", "test two", function () {
        console.log("test two!");
    });

});

Si les conditions que vous souhaitez vérifier ne peuvent être déterminées qu'au moment du test, c'est un peu plus compliqué. Si vous ne souhaitez pas accéder à quelque chose qui ne fait pas à proprement parler partie de l'API de test, vous pouvez le faire:

describe("conditions that can be determined at test time", function () {
    var conditions = {};
    function skip_if(condition, name, callback) {
        if (callback.length) {
            it(name, function (done) {
                if (conditions[condition])
                    done();
                else
                    callback(done);
            });
        }
        else {
            it(name, function () {
                if (conditions[condition])
                    return;
                callback();
            });
        }
    };

    before(function () {
        conditions["condition one"] = true;
    });

    skip_if("condition one", "test one", function () {
        throw new Error("skipped!");
    });

    // async.
    skip_if("condition one", "test one (async)", function (done) {
        throw new Error("skipped!");
    });

    skip_if("condition two", "test two", function () {
        console.log("test two!");
    });

});

Alors que mon premier exemple marquait les tests comme étant formellement ignorés (aka "en attente"), la méthode que je viens de montrer évitera simplement d'effectuer le test proprement dit, mais les tests ne seront pas marqués comme formellement ignorés. Ils seront marqués comme réussis. Si vous voulez absolument les faire sauter, je ne connais aucun moyen d'accéder à des parties qui ne font pas à proprement parler partie de l'API de test:

describe("conditions that can be determined at test time", function () {
    var condition_to_test = {}; // A map from condition names to tests.
    function skip_if(condition, name, callback) {
        var test = it(name, callback);
        if (!condition_to_test[condition])
            condition_to_test[condition] = [];
        condition_to_test[condition].push(test);
    };

    before(function () {
        condition_to_test["condition one"].forEach(function (test) {
            test.pending = true; // Skip the test by marking it pending!
        });
    });

    skip_if("condition one", "test one", function () {
        throw new Error("skipped!");
    });

    // async.
    skip_if("condition one", "test one (async)", function (done) {
        throw new Error("skipped!");
    });

    skip_if("condition two", "test two", function () {
        console.log("test two!");
    });

});
Louis
la source
3

Je ne suis pas sûr que cela soit qualifié de «saut de programmation», mais afin de sauter de manière sélective certains tests spécifiques pour notre environnement CI, j'utilise la fonction de marquage de Mocha ( https://github.com/mochajs/mocha/wiki/Tagging ). Dans describe()ou it()messages, vous pouvez ajouter une balise comme @ no-ci. Pour exclure ces tests, vous pouvez définir une "cible ci" spécifique dans votre package.json et utiliser --grepet des --invertparamètres tels que:

"scripts": {
  "test": "mocha",
  "test-ci" : "mocha --reporter mocha-junit-reporter --grep @no-ci --invert"
}
Martin
la source
C'est l'une des façons de sauter les tests. Un petit exemple serait vraiment utile. Mais je suis tout à fait d'accord que le lien que vous avez partagé a un exemple au départ lui-même. @martin
Krishna Pravin
2

Vous pouvez utiliser mon package mocha-assume pour sauter les tests par programme, mais uniquement en dehors des tests. Vous l'utilisez comme ceci:

assuming(myAssumption).it("does someting nice", () => {});

Mocha-assume n'exécutera votre test que lorsque myAssumptionc'est true, sinon il l'ignorera (en utilisant it.skip) avec un joli message.

Voici un exemple plus détaillé:

describe("My Unit", () => {
    /* ...Tests that verify someAssuption is always true... */

    describe("when [someAssumption] holds...", () => {
        let someAssumption;

        beforeAll(() => {
            someAssumption = /* ...calculate assumption... */
        });

        assuming(someAssumption).it("Does something cool", () => {
            /* ...test something cool... */
        });
    });
});

En l'utilisant de cette façon, vous pouvez éviter les échecs en cascade. Supposons que le test "Does something cool"échoue toujours lorsque certaines hypothèses ne tiennent pas - Mais cette hypothèse a déjà été testée ci-dessus (in Tests that verify someAssuption is always true").

L'échec du test ne vous donne donc aucune nouvelle information. En fait, c'est même un faux positif: le test n'a pas échoué parce que "quelque chose de cool" n'a pas fonctionné, mais parce qu'une condition préalable au test n'était pas remplie. avec mocha-assumevous pouvez souvent éviter ces faux positifs.

David Tanzer
la source
C'est vraiment cool, triste que le projet semble abandonné ...
Victor Schröder
@ VictorSchröder Eh bien, j'avais l'impression que personne ne l'utilisait. Je pourrais envisager de l'améliorer dans les prochaines semaines, si j'avais le temps. Pouvez-vous ouvrir un problème sur github et me dire ce que vous aimeriez voir?
David Tanzer le
Je ne l'utilise pas encore, @David Tanzer, je viens de trouver votre idée vraiment cool . Je me vois faire beaucoup de préparation aux tests et de sauts conditionnels et ce type d'interface est beaucoup plus lisible. Je dois encore essayer, mais j'imagine que ce serait cool de pouvoir enchaîner plusieurs hypothèses et prendre en charge les fonctions asynchrones comme hypothèses. Peut-être que tout cela est déjà pris en charge, je n'ai pas vérifié.
Victor Schröder le
1
Il y a un problème, cependant, avec le deuxième exemple de cette réponse. L' beforeAllexécution du hook n'est pas garantie avant que tous les tests ne soient collectés. En fait, il est très probable qu'il ne s'exécute qu'après, mais dans ce cas, assuming(someAssumption)il aurait déjà reçu la valeur initiale (non définie). Il est également nécessaire d'envelopper cette partie dans une fonction pour obtenir l'effet souhaité.
Victor Schröder le
2

Nous pouvons écrire une belle fonction de wrapper propre pour exécuter des tests conditionnellement comme suit:

function ifConditionIt(title, test) {
  // Define your condition here
  return condition ? it(title, test) : it.skip(title, test);
}

Cela peut ensuite être requis et utilisé dans vos tests comme suit:

ifConditionIt('Should be an awesome test', (done) => {
  // Test things
  done();
});
dcr24
la source
Je pense que c'est de loin la solution la plus élégante présentée ici. Il peut être étendu facilement pour faire une logique plus compliquée, et a l'avantage supplémentaire que les tests sautés de cette manière sont marqués comme ignorés dans le rapport de test
Joshua Evans
0

Disons que je voulais ignorer mon test paramétré si ma description de test contenait la chaîne "foo", je ferais ceci:

// Skip parametrized test if description contains the string "foo"
(test.description.indexOf("foo") === -1 ? it : it.skip)("should test something", function (done) {
    // Code here
});

// Parametrized tests
describe("testFoo", function () {
        test({
            description: "foo" // This will skip
        });
        test({
            description: "bar" // This will be tested
        });
});

Dans votre cas, je crois que si vous vouliez vérifier les variables d'environnement, vous pourriez utiliser NodeJS:

process.env.ENV_VARIABLE

Par exemple (Attention: je n'ai pas testé ce bout de code!), Peut-être quelque chose comme ceci:

(process.env.NODE_ENV.indexOf("prod") === -1 ? it : it.skip)("should...", function(done) {
    // Code here
});

Là où vous pouvez définir ENV_VARIABLE comme étant ce que vous saisissez, et en utilisant cette valeur, ignorez ou exécutez le test. (Pour info, la documentation du process.env de NodeJS est ici: https://nodejs.org/api/process.html#process_process_env )

Je ne prendrai pas le crédit complet pour la première partie de cette solution, j'ai trouvé et testé la réponse et cela a parfaitement fonctionné pour sauter des tests basés sur une condition simple via cette ressource: https://github.com/mochajs/mocha/issues / 591

J'espère que cela t'aides! :)

Rubicon
la source
0

Cela n'utilise pas vraiment les fonctionnalités de moka, mais plutôt le peaufiner pour obtenir le comportement que je voulais.

Je voulais sauter tout «c'est» ultérieur dans mes tests de moka de rapporteur et un «il» a échoué. En effet, une fois qu'une étape d'un test de parcours a échoué, il était presque certain que le reste échouerait, et pourrait prendre beaucoup de temps et monopoliser le serveur de construction s'ils utilisent le navigateur, attend que les éléments apparaissent sur une page, etc.

Lorsque vous exécutez simplement des tests moka standard (pas de rapporteur), cela peut être réalisé avec les crochets globaux beforeEach et afterEach en attachant un drapeau `` skipSubsequent '' au parent du test (décrire) comme ceci:

    beforeEach(function() {
      if(this.currentTest.parent.skipSubsequent) {
            this.skip();
      }
    }); 


    afterEach(function() {
      if (this.currentTest.state === 'failed') {
        this.currentTest.parent.skipSubsequent = 'true'
      }
    })

En essayant cela avec le rapporteur et le moka, la portée de «ceci» a changé et le code ci-dessus ne fonctionne pas. Vous vous retrouvez avec un message d'erreur comme «erreur d'appel terminé ()» et le rapporteur s'arrête.

Au lieu de cela, j'ai fini avec le code ci-dessous. Pas la plus jolie, mais elle finit par remplacer l'implémentation des fonctions de test restantes par un this.skip (). Cela cessera probablement de fonctionner si / quand les éléments internes de mocha changent avec les versions ultérieures.

Il a été découvert grâce à des essais et des erreurs en déboguant et en inspectant les composants internes de mocha ... cela permet de compléter les suites de tests du navigateur plus tôt lorsque les tests échouent.

beforeEach(function() {

    var parentSpec = this.currentTest.parent;

    if (!parentSpec.testcount) {
        parentSpec.testCount = parentSpec.tests.length;
        parentSpec.currentTestIndex = 0;
    } else {
        parentSpec.currentTestIndex = parentSpec.currentTestIndex + 1;
    }

    if (parentSpec.skipSubsequent) {

        parentSpec.skipSubsequent = false;
        var length = parentSpec.tests.length;
        var currentIndex = parentSpec.currentTestIndex;

        for (var i = currentIndex + 1; i < length; i++) {
            parentSpec.tests[i].fn = function() {
                this.skip();
            };
        }
    }
});


afterEach(function() {
    if (this.currentTest.state === 'failed') {
        this.currentTest.parent.skipSubsequent = 'true'
    }
});
Paul Silvester
la source
-2

Comme @danielstjules a répondu ici il existe un moyen de sauter le test. @author of this topic a copié la réponse de la discussion mochajs de github.com, mais il n'y a aucune information sur la version de mocha disponible.

J'utilise le module grunt-mocha-test pour intégrer la fonctionnalité de test moka dans mon projet. Passer à la dernière version (pour l'instant) - 0.12.7 m'apporte la version 2.4.5 mocha avec l'implémentation de this.skip ().

Donc, dans mon package.json

  "devDependencies": {
    "grunt-mocha-test": "^0.12.7",
    ...

Puis

npm install

Et ça me fait plaisir avec ce crochet:

describe('Feature', function() {

    before(function () {

        if (!Config.isFeaturePresent) {

            console.log('Feature not configured for that env, skipping...');
            this.skip();
        }
    });
...

    it('should return correct response on AB', function (done) {

        if (!Config.isABPresent) {

           return this.skip();
        }

        ...
Victor Perov
la source
-2

Veuillez ne pas le faire. Un test qui ne fonctionne pas de manière cohérente dans tous les environnements doit être reconnu comme tel par votre infrastructure de build. Et cela peut être très désorientant lorsque les builds CI ont un nombre de tests différents que local.

En outre, cela gâche la répétabilité. Si différents tests s'exécutent sur le serveur et en local, je peux avoir des tests échouant en dev et passant en CI ou vice versa. Il n'y a pas de fonction de forçage et je n'ai aucun moyen de corriger rapidement et avec précision une construction qui a échoué.

Si vous devez désactiver les tests entre les environnements, au lieu d'exécuter des tests de manière conditionnelle, marquez vos tests et utilisez un filtre pour éliminer les tests qui ne fonctionnent pas dans certaines cibles de build. De cette façon, tout le monde sait ce qui se passe et cela tempère leurs attentes. Cela permet également à tout le monde de savoir qu'il y a des incohérences dans le cadre de test, et que quelqu'un pourrait avoir une solution qui les remet en marche correctement. Si vous désactivez simplement le test, ils pourraient même ne pas savoir qu'il y a un problème.

Jason
la source