Como pular programaticamente um teste no mocha?

142

Eu tenho um código em que certos testes sempre falham no ambiente de IC. Gostaria de desativá-los com base em uma condição do ambiente.

Como pular programaticamente um teste no mocha durante a execução do tempo de execução?

Gajus
fonte
3
Ignorar programaticamente um teste é abordado this.skip()em mochajs.org/#inclusive-tests e na resposta de @ zatziky abaixo. O restante das respostas são obsoletas para o Mocha v3 + #
Patrick
1
descreva.skip ('descrição', () => {}) / descreva apenas ('descrição', () => {}) / it.skip ('descrição', () => {}) / it. only ('description', () => {})
Jun711 21/02
alguma resposta aceita?
Paul Rooney

Respostas:

168

Você pode pular os testes colocando um x na frente do bloco de descrição ou bloco ou colocando um .skipdepois dele.

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

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

Você também pode executar um único teste colocando um .onlyno teste. por exemplo

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

Somente o bloco do recurso 2 seria executado nesse caso.

Não parece haver uma maneira de pular programaticamente os testes, mas você pode apenas fazer algum tipo de verificação em uma beforeEachinstrução e executar o teste apenas se o sinalizador estiver definido.

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
fonte
8
Sua segunda tentativa de solução não funcionará, porque a ordem de execução não é a que você pensa. Quando a beforeEachchamada é executada, o Mocha registra a função anônima (o "gancho") para uso futuro ; quando a describechamada é executada, o Mocha executa imediatamente a função anônima passada a ele. Assim, quando o tempo if (runTest)for executado, o beforeEach gancho não terá funcionado.
Louis
22
Como esta resposta tem 27 votos positivos? A pergunta é sobre ignorar programaticamente os testes, portanto, adicionar ".skip" ou ".only" não é útil. Em seguida, diz explicitamente que você não pode fazer o que o OP quer fazer, apesar do fato de que outras respostas lhe dizem como fazê-lo.
Graeme Perrow
3
Não vai funcionar, não uma resposta para a questão, ver resposta @Gajus' em vez
NorTicUs
1
Esta resposta tem méritos para uma pergunta diferente que não foi feita aqui. Eu não tenho o poder de mudar nada aqui. Veja a resposta this.skip ().
Andrew Martinez
3
isso não responde à pergunta
Ingo Renner
109

Existe uma maneira não documentada de ignorar programaticamente os testes:

// test.js

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

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

corrida:

$ mocha test.js


  foo
    - foo


  0 passing (9ms)
  1 pending

Isso é discutido em https://github.com/mochajs/mocha/issues/1901 .

Gajus
fonte
13
Os leitores podem saber que isso marca o todo describecomo ignorado (ou seja, todos os testes no describesão ignorados).
Louis
Documentação dos "testes pendentes" do Mocha: mochajs.org/#pending-tests
lasec0203
descreva.skip ('descrição', () => {}) / descreva apenas ('descrição', () => {}) / it.skip ('descrição', () => {}) / it. only ('description', () => {})
Jun711 21/02
Não entendo por que esse tipo de resposta é votado. é um hack - e não um preety.
Chenop 20/08/19
2
documentação real mochajs.org/#inclusive-tests , não é um truque, mas um método correto de excluir alguns testes com base nas configurações de tempo de execução. isto é, responde exatamente o que a pergunta original fez. Obrigado @xavdid
WowPress.host
41

Esta resposta funciona para o ES6 .

Ao invés de:

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

Você quer:

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

Isso ignora condicionalmente todos os testes no bloco de descrição SE a condição for falsa.

Ou, em vez de:

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

Você quer:

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

Isso ignora condicionalmente um teste se a condição for falsa.

danday74
fonte
4
Entendi o que você está sugerindo, mas primeiro você precisa definir uma descrição contextual como esta: const contextualDescribe = shouldAvoidTests ? describe.skip : describe então você pode usá-lo: contextualDescribe('your it block', () => {
Ser
3
@ Ser Para entrar em uma única linha, usei algo como isto:(condition ? describe : describe.skip)('your describe block', () => {
joshden
Como fazer isso assíncrono? Preciso procurar a condição de ignorar com base em um sinalizador redis, que é uma operação assíncrona (armazenamos sinalizadores de recursos em redis).
Patrick Finnigan
Já faz um tempo, mas eu também tinha esse tipo de necessidade antes, acho que envolvi todas as coisas do mocha em uma função que foi chamada depois que o retorno de chamada assíncrona foi concluído - não consigo lembrar os detalhes exatos
danday74
Eu costumava usar essa técnica, mas agora ela falha para mim. tente simplesmente escrever(it)('my test', () => {})
cyrf
33

Eu uso o tempo de execução pulando do Mocha para o mesmo cenário que você está descrevendo. É a pasta de cópia dos documentos :

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

  // make assertions
});

Como você pode ver, pula o teste com base no ambiente. Minha própria condição é if(process.env.NODE_ENV === 'continuous-integration').

Amio.io
fonte
2
Acordado! Pode ser uma linha, fazendo um retorno antecipado, talvez? Como: if (/* skipTestCondition */) return this.skip();- edit: works: D
SidOfc 7/19/19
12

para pular testes, use describe.skipouit.skip

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

para incluir testes que você poderia usar describe.onlyouit.only


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

Mais informações em https://mochajs.org/#inclusive-tests

lfender6445
fonte
6

Depende de como você deseja pular programaticamente o teste. Se as condições para ignorar puderem ser determinadas antes da execução de qualquer código de teste, você poderá chamar itou it.skipconforme necessário, com base em uma condição. Por exemplo, isso ignorará alguns testes se a variável de ambiente ONEestiver configurada com qualquer valor:

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!");
    });

});

Se as condições que você deseja verificar puderem ser determinadas apenas no momento do teste, é um pouco mais complicado. Se você não deseja acessar nada que não seja estritamente parte da API de teste, faça o seguinte:

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!");
    });

});

Enquanto meu primeiro exemplo foi marcar os testes como ignorados formalmente (também conhecido como "pendente"), o método que acabei de mostrar evita realizar o teste real, mas os testes não serão marcados como ignorados formalmente. Eles serão marcados como aprovados. Se você deseja que eles sejam ignorados, não conheço nenhuma maneira de acessar partes que não estão falando adequadamente da API de teste:

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
fonte
3

Não tenho certeza se isso se qualifica como "salto programático", mas para pular seletivamente alguns testes específicos para o nosso ambiente de IC, eu uso o recurso de marcação do Mocha ( https://github.com/mochajs/mocha/wiki/Tagging ). Em describe()ou it()mensagens, você pode adicionar uma tag como @ no-ci. Para excluir esses testes, você pode definir um específico "target ci" em sua package.json e uso --grepe --invertparâmetros como:

"scripts": {
  "test": "mocha",
  "test-ci" : "mocha --reporter mocha-junit-reporter --grep @no-ci --invert"
}
Martin
fonte
Essa é uma das maneiras de pular testes. Um pequeno exemplo seria realmente útil. Mas eu definitivamente concordo que o link que você compartilhou tem um exemplo no início. @martin
Krishna Pravin
2

Você pode usar meu pacote mocha-assume para pular os testes programaticamente, mas apenas de fora dos testes. Você usa assim:

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

O Mocha-assume apenas executará seu teste quando myAssumptionestiver true, caso contrário, o ignorará (usandoit.skip ) com uma boa mensagem.

Aqui está um exemplo mais detalhado:

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... */
        });
    });
});

Usando dessa maneira, você pode evitar falhas em cascata. Digamos que o teste "Does something cool"sempre falha quando alguma suposição não é válida - mas essa suposição já foi testada acima (emTests that verify someAssuption is always true" ).

Portanto, a falha no teste não fornece novas informações. De fato, é até um falso positivo: o teste não falhou porque "algo legal" não funcionou, mas porque uma pré-condição para o teste não foi atendida. com mocha-assumevocê muitas vezes você pode evitar esses falsos positivos.

David Tanzer
fonte
Isso é muito legal, triste que o projeto pareça ter sido abandonado ...
Victor Schröder
@ VictorSchröder Bem, tive a impressão de que ninguém estava usando. Pode procurar melhorar nas próximas semanas, se eu tiver tempo. Você pode abrir um problema no github e me dizer o que gostaria de ver?
David Tanzer 14/01
Ainda não o estou usando, @ David Tanzer, acabei de achar sua ideia muito legal . Eu me vejo fazendo a preparação do teste e pulando condicional bastante e esse tipo de interface é muito mais legível. Ainda tenho que tentar, mas imagino que seria legal poder encadear várias suposições e dar suporte a funções assíncronas como suposições. Talvez tudo isso já seja suportado, eu não verifiquei.
Victor Schröder
1
Há um problema, porém, com o segundo exemplo nesta resposta. Não beforeAllé garantido que o gancho funcione antes de todos os testes serem coletados. Na verdade, é muito provável que seja executado apenas depois, mas nesse caso o assuming(someAssumption)já teria recebido o valor inicial (indefinido). É necessário agrupar essa parte em uma função para obter o efeito desejado.
Victor Schröder
2

Podemos escrever uma boa função de wrapper limpo para executar condicionalmente os testes da seguinte maneira:

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

Isso pode ser necessário e usado em seus testes da seguinte maneira:

ifConditionIt('Should be an awesome test', (done) => {
  // Test things
  done();
});
dcr24
fonte
Penso que esta é de longe a solução mais elegante apresentada aqui. Ele pode ser estendido facilmente para criar lógicas mais complicadas e possui o bônus adicional de que os testes ignorados dessa maneira são marcados como ignorados no relatório de teste
Joshua Evans
0

Digamos que eu queira pular meu teste parametrizado se a descrição do teste contiver a string "foo", eu faria o seguinte:

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

No seu caso, acredito que se você quiser verificar variáveis ​​de ambiente, poderá usar os NodeJS:

process.env.ENV_VARIABLE

Por exemplo (Aviso: não testei esse código!), Talvez algo como isto:

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

Onde você pode definir ENV_VARIABLE como o que você está usando e, usando esse valor, pule ou execute o teste. (FYI, a documentação para o process.env do NodeJS está aqui: https://nodejs.org/api/process.html#process_process_env )

Não aceitarei crédito completo pela primeira parte desta solução, encontrei e testei a resposta e ela funcionou perfeitamente para ignorar testes com base em uma condição simples por meio deste recurso: https://github.com/mochajs/mocha/issues / 591

Espero que isto ajude! :)

Rubicon
fonte
0

Isso não é realmente usar os recursos do mocha, mas sim ajustá-lo para obter o comportamento que eu queria.

Eu queria pular qualquer 'é' subsequente nos meus testes de transferidor mocha e um 'ele' falhou. Isso ocorreu porque, uma vez que uma etapa de um teste de jornada falhou, era quase certo que o restante falharia, e pode levar um longo tempo e sobrecarregar o servidor de compilação se eles estiverem usando o navegador aguarda que os elementos apareçam em uma página etc.

Ao apenas executar testes mocha padrão (não transferidor), isso pode ser alcançado com os ganchos globais beforeEach e afterEach, anexando um sinalizador 'skipSubsequent' ao pai do teste (descreva) assim:

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


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

Ao tentar isso com transferidor e mocha, o escopo de 'this' foi alterado e o código acima não funciona. Você acaba com uma mensagem de erro como 'chamada de erro concluída ()' e o transferidor é interrompido.

Em vez disso, acabei com o código abaixo. Não é a mais bonita, mas acaba substituindo a implementação das funções de teste restantes por um this.skip (). Provavelmente, isso parará de funcionar se / quando os internos do mocha mudarem com versões posteriores.

Foi descoberto através de algumas tentativas e erros depurando e inspecionando os componentes internos do mocha ... ajuda a tornar os conjuntos de testes do navegador mais rápidos quando os testes falham.

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
fonte
-2

Como @danielstjules respondeu aqui há uma maneira de pular o teste. O autor deste tópico copiou a resposta da discussão do github.com mochajs, mas não há informações sobre qual versão do mocha está disponível.

Estou usando o módulo grunt-mocha-test para integrar a funcionalidade de teste do mocha no meu projeto. Passando para a última versão (por enquanto) - 0.12.7, me traz a versão 2.4.5 do mocha com a implementação deste.skip ().

Então, no meu package.json

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

E depois

npm install

E isso me deixa feliz com esse gancho:

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
fonte
-2

Por favor não. Um teste que não funcione consistentemente em ambientes deve ser reconhecido como tal pela sua infraestrutura de construção. E pode ser muito desorientador quando as compilações de IC têm um número diferente de testes executado que o local.

Também estraga a repetibilidade. Se testes diferentes forem executados no servidor e no local, eu posso ter testes falhando no dev e passando no CI ou vice-versa. Não há função forçante e não tenho como corrigir rápida e precisamente uma compilação com falha.

Se você precisar desativar os testes entre ambientes, em vez de executar condicionalmente, marque seus testes e use um filtro para eliminar testes que não funcionam em determinados destinos de construção. Dessa forma, todo mundo sabe o que está acontecendo e tempera suas expectativas. Ele também permite que todos saibam que há inconsistência na estrutura de teste, e alguém pode ter uma solução que os faça funcionar corretamente novamente. Se você silenciar o teste, eles talvez nem saibam que há um problema.

Jason
fonte