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

Posted

技术标签:

【中文标题】如何以编程方式跳过摩卡中的测试?【英文标题】:How to programmatically skip a test in mocha? 【发布时间】:2015-12-19 19:16:00 【问题描述】:

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

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

【问题讨论】:

以编程方式跳过测试由this.skip() 中的mochajs.org/#inclusive-tests 和@zatziky 的回答覆盖。 Mocha v3+ 的其余答案已过时 describe.skip('description', () => ) / describe.only('description', () => ) / it.skip('description', () => ) / it.only('description', () => ) 任何接受的答案? 【参考方案1】:

您可以通过在 describe 或 it 块前放置 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,
         
    

【讨论】:

您对解决方案的第二次尝试不会奏效,因为执行顺序不是您想的那样。当beforeEach调用执行时,Mocha记录匿名函数(“钩子”)以供将来使用,当describe调用执行时,Mocha立即 执行传递给它的匿名函数。所以当if (runTest) 被执行时,beforeEach hook 不会运行。 这个答案怎么会有 27 票?该问题询问以编程方式跳过测试,因此添加“.skip”或“.only”没有帮助。然后它明确表示你不能做 OP 想做的事,尽管其他答案告诉你该怎么做。 不起作用,不是问题的答案,请参阅@Gajus 的回复 此答案对于此处未提出的不同问题具有优点。我没有权力在这里改变任何东西。请参阅 this.skip() 答案。 这没有回答问题【参考方案2】:

使用 Mocha 的skip() 函数

它可用于静态禁用测试或整个套件,或在运行时动态跳过它。

这是一个运行时使用示例:

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

【讨论】:

读者可能想知道这会将整个describe 标记为已跳过(即describe 中的所有测试都已跳过)。 Mocha 的“待定测试”文档:mochajs.org/#pending-tests describe.skip('description', () => ) / describe.only('description', () => ) / it.skip('description', () => ) / it.only('description', () => ) 我不明白为什么这种答案被赞成。它是一个 hack - 而不是一个漂亮的。 实际文档 mochajs.org/#inclusive-tests ,无论如何它都不是 hack,而是基于运行时设置排除某些测试的正确方法。即它准确地回答了原始问题的问题。谢谢@xavdid【参考方案3】:

此答案适用于 ES6

代替:

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

你想要:

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

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

或者,而不是:

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

你想要:

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

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

【讨论】:

我明白你的建议,但你首先需要定义一个 contextual 描述如下:const contextualDescribe = shouldAvoidTests ? describe.skip : describe 然后你可以使用它:contextualDescribe('your it block', () => @Ser 为了获得一行,我使用了这样的东西:(condition ? describe : describe.skip)('your describe block', () => 如何异步执行?我需要根据 redis 标志查找跳过条件,这是一个异步操作(我们将功能标志存储在 redis 中)。 不建议在 mocha 中使用箭头函数:mochajs.org/#arrow-functions 只需传递一个functionasync function 然后您可以根据需要调用this.skip(),可能在执行一些异步操作以检查是否你需要运行测试。 您可以简单地写成condition && it('your it block', () => ,而不是(condition ? it : it.skip)('your it block', () => 。由于&& 的短路,如果condition 为假,它甚至不会被评估。【参考方案4】:

对于您所描述的相同场景,我使用从 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')

【讨论】:

同意!也许可以通过提前返回来成为一个班轮?喜欢:if (/* skipTestCondition */) return this.skip(); -- 编辑:作品:D【参考方案5】:

要跳过测试,请使用 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!");
    );

);

【讨论】:

【参考方案7】:

我不确定这是否符合“编程跳过”的条件,但为了有选择地跳过我们 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"

【讨论】:

这是跳过测试的方法之一。一个小例子将非常有用。但我绝对同意你分享的链接在开始时就有一个例子。 @马丁【参考方案8】:

我们可以编写一个干净的包装函数来有条件地运行测试,如下所示:

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

【讨论】:

我认为这是迄今为止这里提出的最优雅的解决方案。它可以轻松扩展以执行更复杂的逻辑,并且具有额外的好处,以这种方式跳过的测试在测试报告中标记为已跳过【参考方案9】:

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

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

Mocha-assume 只会在 myAssumptiontrue 时运行您的测试,否则它会跳过它(使用 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... */
        );
    );
);

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

所以测试失败不会给你任何新的信息。事实上,它甚至是一个误报:测试失败并不是因为“很酷的东西”不起作用,而是因为不满足测试的前提条件。使用mocha-assume,您通常可以避免此类误报。

【讨论】:

这真的很酷,可惜这个项目似乎被放弃了...... @VictorSchröder 好吧,我觉得没有人在使用它。如果我有时间,可能会在接下来的几周内考虑改进它。你能在 github 上打开一个 issue 告诉我你想看什么吗? 我还没有使用它,@David Tanzer,我刚刚发现你的想法真的很酷。我看到自己做了很多测试准备和有条件的跳过,这种界面更具可读性。我仍然必须尝试一下,但我想能够链接多个假设并支持异步函数作为假设会很酷。也许这一切都已经被支持了,我没有检查。 不过,这个答案中的第二个示例存在问题。 beforeAll 钩子不能保证在收集所有测试之前运行。实际上,它很可能只在之后运行,但在这种情况下,assuming(someAssumption) 将已经收到初始(未定义)值。还需要将该部分包装在一个函数中以达到预期的效果。【参考方案10】:

这并不是真正使用 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.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'
    
);

【讨论】:

【参考方案11】:

可以根据条件使用, 例如,声明一个 var,当条件失败时,使用 this.skip();

注意skip()在箭头函数中不起作用

let shouldRun: boolean;

before(function()
if ($('#nsErrorIframe').isDisplayed()) 
        driver.switchToFrame($('#nsErrorIframe'));
        if ($('.ns-error-wrapper').isDisplayed()) 
            console.log('PAGE IS NOT AVAILABLE');
            shouldRun = false;
            if ( shouldRun === false) 
                 this.skip();
                
                
  
);

【讨论】:

【参考方案12】:

假设我想跳过我的参数化测试,如果我的测试描述包含字符串“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

希望这会有所帮助! :)

【讨论】:

【参考方案13】:

我们的测试环境中有一些侥幸的测试,有时会使用这种方法关闭一些测试:

mocha --config ./config/parallelrc.cjs --parallel --jobs 3 -- tests/spec/**/index.js -g @flaky -i

我们在测试描述中标记了片状测试@flaky 并设置了特殊的-g 规则,这意味着mocha 只运行带有@flaky 标签的测试,接下来使用-i - 这意味着反转,所以mocha 只运行测试不是@flaky

所以,认为它对你有用)

【讨论】:

【参考方案14】:
mocha test/ --grep <pattern>

https://mochajs.org/

【讨论】:

【参考方案15】:

正如@danielstjules 回答here 一样,有一种方法可以跳过测试。此主题的@author 已从 github.com mochajs 讨论中复制了答案,但没有可用的 mocha 版本信息。

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

所以,在我的 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();
        

        ...

【讨论】:

【参考方案16】:

请不要。您的构建基础架构应承认在不同环境中不能始终如一地工作的测试。当 CI 构建运行的测试数量与本地不同时,它可能会非常令人迷惑。

它还破坏了可重复性。如果在服务器和本地运行不同的测试,我可能会在 dev 中测试失败并在 CI 中通过,反之亦然。没有强制功能,我无法快速准确地纠正失败的构建。

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

【讨论】:

考虑到功能测试在环境(本地和开发)之间的行为不一致是可以的。在您的 Pull Request 完成之前,您的 CI 应该会相应地失败。代码是记录这些不一致的正确位置。配置文件变通办法更有可能隐藏一些东西。这就是 it.skip 在代码中而不是配置文件中的原因。

以上是关于如何以编程方式跳过摩卡中的测试?的主要内容,如果未能解决你的问题,请参考以下文章

跳过测试文件 Jest 中的一项测试

如何配置 Maven 安装以跳过 Eclipse 中的测试?

您将如何以编程方式测试文件中的病毒? [关闭]

如何在手表模式下进行任何摩卡测试之前运行全局设置脚本

如何跳过 Django 中的单元测试?

摩卡在测试后没有退出