如何以编程方式跳过摩卡测试?


142

我有一个代码,其中某些测试在CI环境中始终会失败。我想根据环境条件禁用它们。

如何在运行时执行期间以编程方式跳过Mocha中的测试?


3
下面的mochajs.org/#inclusive-tests和@zatziky的答案中涵盖了this.skip()以编程方式跳过测试。答案的其余部分已经过时,摩卡V3 +
帕特里克

1
describe.skip('description',()=> {})/ describe.only('description',()=> {})/ it.skip('description',()=> {})/ it。 only('description',()=> {})
Jun711 '18

任何接受的答案?
保罗·鲁尼

Answers:


168

您可以通过在describe或it块的前面放置一个x或在它的后面放置一个x来跳过测试.skip

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

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

您还可以通过在测试上放置一个来运行单个.only测试。例如

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

在这种情况下,仅功能部件2块将运行。

似乎没有办法以编程方式跳过测试,但是您可以在beforeEach语句中进行某种形式的检查,并且仅在设置了标志的情况下才运行测试。

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

8
您第二次尝试解决方案将失败,因为执行顺序不是您认为的顺序。当beforeEach调用执行,摩卡记录匿名函数(“钩子”)未来的使用中,当describe调用执行,摩卡立即执行传递给它的匿名函数。因此,在if (runTest)执行时间之前,该beforeEach 钩子将不会运行。
路易

22
这个答案怎么有27个投票?该问题询问有关以编程方式跳过测试的问题,因此添加“ .skip”或“ .only”无济于事。然后,它明确表示您无法执行OP想要执行的操作,尽管其他答案告诉您如何执行此操作。
Graeme Perrow

3
无法正常工作,无法解决问题,请改用@Gajus的回复
-NorTicUs

1
对于没有在这里提出的其他问题,此答案有其优点。我没有权力在这里进行任何更改。请参阅this.skip()答案。
安德鲁·马丁内斯

3
这不能回答问题
Ingo Renner

109

有一种未记录的以编程方式跳过测试的方式:

// test.js

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

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

运行:

$ mocha test.js


  foo
    - foo


  0 passing (9ms)
  1 pending

这在https://github.com/mochajs/mocha/issues/1901中进行了讨论。


13
读者可能想知道这会将整个标记describe为已跳过(即,中的所有测试describe都已跳过)。
路易(Louis)

Mocha的“待定测试”文档:mochajs.org/#pending-tests
lasec0203

describe.skip('description',()=> {})/ describe.only('description',()=> {})/ it.skip('description',()=> {})/ it。 only('description',()=> {})
Jun711 '18

我不理解为什么赞成这种回答。这是一个骇客-而不是一个卑鄙的人。
chenop

2
实际文档mochajs.org/#inclusive-tests无论如何都不是hack btw,而是基于运行时设置排除某些测试的正确方法。即,它完全可以回答原始问题的要求。感谢@xavdid
WowPress.host

41

此答案确实适用于ES6

代替:

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

你要:

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

如果条件为假,则有条件地跳过describe块中的所有测试。

或者,代替:

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

你要:

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

如果条件为假,则有条件地跳过一个测试。


4
我得到你的建议是什么,但你首先需要定义一个情境描述是这样的: const contextualDescribe = shouldAvoidTests ? describe.skip : describe 那么你可以使用它: contextualDescribe('your it block', () => {
丝氨酸

3
@Ser要上一行,我使用了类似的方法:(condition ? describe : describe.skip)('your describe block', () => {
joshden

如何做到这一点异步?我需要基于redis标志查找跳过条件,redis标志是异步操作(我们将功能标志存储在redis中)。
Patrick Finnigan

我已经有一段时间了,但我也有这种需求,我想我只是将所有的摩卡咖啡包装在一个函数中,该函数在异步回调完成后被调用-无法记住确切的细节
danday74 '18

我曾经使用过这种技术,但现在对我却失败了。尝试简单地写作(it)('my test', () => {})
Cyrf

33

对于您所描述的相同情况,我使用从Mocha跳过运行时的方法。这是来自docs的复制粘贴:

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

  // make assertions
});

如您所见,它会根据环境跳过测试。我自己的情况是if(process.env.NODE_ENV === 'continuous-integration')


2
同意!也许可以通过提前归还成为一个班轮?像:if (/* skipTestCondition */) return this.skip();-编辑:作品:D
SidOfc

12

跳过测试,使用describe.skipit.skip

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

包括您可以使用的测试describe.onlyit.only


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

有关更多信息,访问https://mochajs.org/#inclusive-tests


6

这取决于您要如何以编程方式跳过测试。如果可以在运行任何测试代码之前确定跳过的条件,则可以根据条件调用itit.skip根据需要调用。例如,如果环境变量ONE设置为任何值,这将跳过一些测试:

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

});

如果要检查的条件只能在测试时确定,则情况会有些复杂。如果您不想访问严格来说不是测试API一部分的任何内容,则可以执行以下操作:

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

});

尽管我的第一个示例将测试标记为正式跳过(又称“待定”),但我刚刚显示的方法将避免执行实际测试,但不会将测试标记为正式跳过。他们将被标记为通过。如果您绝对希望跳过它们,那么我不知道除了访问测试API的一部分以外,其他任何方式都无法解决:

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

});

3

我不确定这是否可以称为“程序性跳过”,但是为了有选择地跳过针对我们CI环境的某些特定测试,我使用了Mocha的标记功能(https://github.com/mochajs/mocha/wiki/Tagging)。在describe()it()消息中,您可以添加诸如@ no-ci之类的标签。要排除这些测试,您可以在package.json中定义一个特定的“ ci目标”,并使用--grep--invert参数,例如:

"scripts": {
  "test": "mocha",
  "test-ci" : "mocha --reporter mocha-junit-reporter --grep @no-ci --invert"
}

这是跳过测试的方法之一。一个小例子将非常有用。但我绝对同意,您共享的链接在开始时就有一个例子。@martin
克里希纳·普拉文

2

您可以使用我的软件包mocha-assume来以编程方式跳过测试,但只能从测试外部进行。您可以这样使用它:

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

Mocha-assume仅在myAssumptionis 时运行您的测试true,否则它将it.skip通过一条很好的消息跳过它(使用)。

这是更详细的示例:

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

以这种方式使用它,可以避免级联失败。假设"Does something cool"在someAssumption不成立的情况下测试总是会失败的-但是这个假设已经在(中Tests that verify someAssuption is always true")中进行了测试。

因此,测试失败不会为您提供任何新信息。实际上,它甚至是假阳性的:测试没有失败是因为“有些酷”没有用,而是因为没有满足测试的前提条件。与mocha-assume您经常可以避免这种误报。


真是太酷了,很可惜该项目似乎被放弃了……
VictorSchröder

@VictorSchröder好吧,我给人的印象是没有人在使用它。如果有时间的话,可能会在接下来的几周内进行改进。您可以在github上打开一个问题,然后告诉我您想看到的内容吗?
David Tanzer

我尚未使用它,@ David Tanzer,我刚刚发现您的想法很酷。我看到自己做了大量的测试准备工作和有条件的跳过工作,并且这种界面更具可读性。我仍然必须尝试一下,但是我想能够链接多个假设并支持异步功能作为假设会很酷。也许所有这些都已得到支持,但我还没有检查。
维克多·施罗德

1
但是,此答案中的第二个示例存在问题。beforeAll不能保证在收集所有测试之前运行该挂钩。实际上,它很可能仅在之后运行,但在这种情况下,assuming(someAssumption)它已经收到了初始(未定义)值。还需要将该部分包装在一个函数中以实现所需的效果。
维克多·施罗德

2

我们可以编写一个很好的clean wrapper函数来有条件地运行测试,如下所示:

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

然后可以要求并在测试中使用它,如下所示:

ifConditionIt('Should be an awesome test', (done) => {
  // Test things
  done();
});

我认为这是到目前为止提出的最优雅的解决方案。它可以轻松扩展以执行更复杂的逻辑,并且具有额外的优势,即以这种方式跳过的测试在测试报告中被标记为“跳过”
Joshua Evans

0

假设我的测试描述包含字符串“ foo”,我想跳过参数化测试,我可以这样做:

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

就您而言,我相信如果您想检查环境变量,则可以使用NodeJS:

process.env.ENV_VARIABLE

例如(警告:我还没有测试这段代码!),也许是这样的:

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

您可以将ENV_VARIABLE设置为您要键入的值,然后使用该值跳过或运行测试。(仅供参考,NodeJS的process.env的文档位于:https : //nodejs.org/api/process.html#process_process_env

我不会完全相信此解决方案的第一部分,我找到并测试了答案,它非常适合通过以下资源基于简单条件跳过测试:https : //github.com/mochajs/mocha/issues / 591

希望这可以帮助!:)


0

这并不是真正使用mocha的功能,而是对其进行了调整以获得我想要的行为。

我想在量角器式摩卡测试中跳过所有后续的“是”,而其中一个“失败”。这是因为一旦旅程测试的一个步骤失败了,几乎可以肯定其余的都会失败,并且如果他们使用浏览器等待元素出现在页面等上,则可能花费很长时间并占用构建服务器。

当仅运行标准Mocha测试(而不是量角器)时,可以通过将“ skipSubsequent”标志附加到测试的父项(描述)来使用全局beforeEach和afterEach钩子来实现,如下所示:

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


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

当尝试使用量角器进行摩卡时,“ this”的范围已更改,并且上面的代码不起作用。您最终收到一条错误消息,例如“错误调用done()”,并且量角器暂停。

相反,我最终得到了下面的代码。这不是最漂亮的方法,但是最终用this.skip()替换了其余测试功能的实现。如果/当mocha的内部版本随更高版本更改时,这可能会停止工作。

通过调试和检查mocha的内部结构,通过反复试验找出了问题所在……当测试失败时,这有助于使浏览器测试套件更早完成。

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


-2

@danielstjules 在这里回答时有一种跳过测试的方法。这个主题的@author复制了github.com mochajs讨论的答案,但是没有可用版本的mocha的信息。

我正在使用grunt-mocha-test模块将摩卡测试功能集成到我的项目中。跳到最后一个(现在)版本-0.12.7带this.skip()实现的摩卡版本2.4.5。

所以,在我的package.json中

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

然后

npm install

这让我对这个钩子感到满意:

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

        ...

-2

请不要。构建基础架构应承认在整个环境中无法始终如一地工作的测试。当配置项构建的运行测试数量与本地运行数量不同时,这可能会令人迷惑。

同样,它也增加了可重复性。如果在服务器和本地服务器上运行不同的测试,则我可以使测试在开发中失败并通过CI,反之亦然。没有强制功能,我无法快速,准确地纠正失败的构建。

如果必须关闭环境之间的测试,而不是有条件地运行测试,请标记测试并使用过滤器以消除在某些构建目标中不起作用的测试。这样,每个人都知道发生了什么事,并且缓和了他们的期望。它还使每个人都知道测试框架中存在不一致之处,并且有人可能会找到一种使它们再次正常运行的解决方案。如果您只是使测试静音,他们甚至可能都不知道存在问题。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.