使用mocha.js加入来自多个文件的测试


87

我试图将来自多个文件的所有测试合并到一个文件中,如下所示:

  describe('Controllers', function() {
    describe('messages.js', function() {
      require('./controllertests/messages').test(options);
    })
    describe('users.js', function() {
      require('./controllertests/users').test(options);
    })
  })

我很确定这不是参加测试的最佳方法,我很难理解如何执行此操作的示例:


1
很好奇,为什么需要将测试合并到一个文件中?
thgaskell 2014年

2
共享局部变量和组织
coiso 2014年

如果将测试包含到问题中,可能会更有意义。听起来您可能倾向于集成测试(而不是单元测试)。通常,您不需要在测试之间共享变量。
thgaskell,2014年

2
而且最大的问题是,我希望拥有20个文件而不是1个huuuuge文件
coiso 2014年

2
另外,如果您用Mocha的概念看一下Mocha是如何处理套件的,.only()那么能够使它describe.only()仍然运行整个测试目录可能会很有用。那就是把我带到这里的原因。
克里斯(Chris

Answers:


113

如果你想包含多个模块您的describe层次结构就像你在你的问题做什么,你在做什么是相当多的,除非你想要写摩卡自定义测试装载机。编写自定义加载程序将不会比现在更容易,或者使您的代码更清晰。

这是我将如何更改一些事情的示例。test本示例中的子目录组织为:

.
└── test
    ├── a
    │   └── a.js
    ├── b
    │   └── b.js
    ├── common.js
    └── top.js

top.js

function importTest(name, path) {
    describe(name, function () {
        require(path);
    });
}

var common = require("./common");

describe("top", function () {
    beforeEach(function () {
       console.log("running something before each test");
    });
    importTest("a", './a/a');
    importTest("b", './b/b');
    after(function () {
        console.log("after all tests");
    });
});

importTest功能只是说明如何处理导入多个模块的重复而不必describe(... require...每次都重新键入整个内容。该common模块旨在容纳您需要在测试套件的多个模块中使用的模块。我实际上并没有在使用它top但是如果需要的话,可以在这里。

我将在此处指出,beforeEach在每次注册的每个测试之前,它将运行其代码,it无论它们出现在describein中top还是出现在任何导入的模块中。使用--recursive,必须将beforeEach代码复制到每个模块中,或者每个模块中都有一个beforeEach挂钩,以调用从公共模块导入的函数。

同样,该after挂钩将在套件中的所有测试之后运行。无法使用复制--recursive。如果您使用--recursive并将代码添加after到每个模块,则每个模块将执行一次,而不是整个模块执行一次测试。

top使用不能复制所有测试出现在单个标题下的内容--recursive。随着--recursive每个文件可以有describe("top",但是这将创建一个新的top为每个文件标题。

common.js

var chai = require("chai");

var options = {
    foo: "foo"
};

exports.options = options;
exports.chai = chai;
exports.assert = chai.assert;

在某些测试套件中,我使用了这样的模块,common避免重复执行require一堆操作,并保留不保持状态的全局只读变量或函数。我不想污染global想像thgaskell的回答那样对象,因为该对象是真正的全局对象,即使在您的代码可能正在加载的第三方库中也可以访问。我在代码中发现这不是可接受的。

a/a.js

var common = require("../common");
var options = common.options;
var assert = common.assert;

it("blah a", function () {
    console.log(options.foo);
    assert.isTrue(false);
});

b/b.js

it("blah b", function () {});

3
虽然我同意您不应污染global范围,但我将其用于断言库以保持测试文件的整洁。这并不像您要覆盖global.processglobal除非其他库显式调用global.XYZ,否则局部变量将被覆盖,这不太可能。它仅在测试期间持续。还没有伤害我,但是当它刺伤我时,我会告诉你的:)
thgaskell 2014年

importTestrequire('path')()例如打个电话有什么区别?
CherryNerd'3

@CreasolDev该importTest功能只是一个便捷功能。重要的是将require调用包装在一个describe块中。重要的是,必须将require调用包裹起来,describe否则模块将不会被隔离在自己的块中,并且导入文件设置的任何挂钩都将在错误的块上进行设置。如果importTest用直接调用替换为require没有包装describe,那么模块a/ab/b将分享挂钩。例如,beforeEach在中b/b进行的每个测试之前,也将运行一个插入设置a/a
路易斯

1
我不会在顶层描述中运行任何逻辑,例如beforeEach。让每个文件先做自己的事“每个”。如果这样做的话,您将把您的测试彼此耦合并且实现不相关的实现。
PositiveGuy

1
我还将在各自的文件中而不是在importTest函数中进行描述的包装。各个文件中的顶级描述无论如何都应该描述其测试套件的目的
PositiveGuy

35

尽管这可能与问题没有直接联系,但我一直在寻找的答案是:

$ mocha --recursive

将在“ test”文件夹的子目录中执行所有测试。整齐。省去了维护我要加载的测试列表的麻烦,实际上始终可以运行所有测试。


3
最佳答案!比其他建议的解决方案简单得多。
caiosm1005 '16

12
@ caiosm1005这个答案实际上并没有解决OP提出的问题。当然,如果您不需要做OP想要做的事情,那么您应该使用它。但是,如果要将每个测试文件包装在多个describe块中,则describe跨文件的块--recursive将不会这样做。鉴于它不能解决OP的问题,因此我不会将其称为“最佳”。
路易

@louis -我相信你可以用在每个单独的文件describe
伊恩·贾米森

4
@IanJamieson的OP是想有多个文件被覆盖的 describe块。看问题。在“控制器”describe块应包括的测试./controllertests/messages.js./controllertests/users.js。掌控--recursiveMocha调用不会神奇地创建一个describe("Controllers"块。
2016年

3
@Louis只是想帮助。对不起,如果我试图魔术般地制造describe积木冒犯了您-我实际上是从邓布利多学到的。
伊恩·贾米森

16

没有什么可以阻止您运行多个测试文件。通常,每个测试都不应依赖于另一个测试的结果,因此共享变量不是您想要执行的操作。

这是如何组织测试文件的示例。

.
├── app.js
└── test
    ├── common.js
    ├── mocha.opts
    │
    ├── controllers
    │   ├── messages-controller.js
    │   └── users-controller.js
    │
    └── models
        ├── messages-model.js
        └── users-model.js

然后在mocha.opts文件内部,确保设置该--recursive选项。

摩卡

--ui bdd
--recursive

如果通用模块要在所有文件,包括,您可以添加到common.js文件中。test目录根目录中的文件将在嵌套目录中的文件之前运行。

common.js

global.chai = require('chai');
global.assert = chai.assert;
global.expect = chai.expect;
chai.should();
chai.config.includeStack = true;

process.env.NODE_ENV = 'test';

// Include common modules from your application that will be used among multiple test suites.
global.myModule = require('../app/myModule');

3
有人介意为controllers和models目录中的文件添加代码吗?有一个完整的例子将是很棒的。
加文

@Gavin -这些将只是试衣服,这样他们就包含describe('mytest', function() { /* ..... etc */ });
伊恩·贾米森

8

我知道这是一个老帖子,但是我想了解一下对我来说是一个很好的解决方案,与OP提出的方法非常相似。

我正在从事的项目已经过良好的测试,并且测试还在不断增长。我最终使用了require它,因为它是同步的,因此无需过多更改体系结构就可以更轻松地组成测试:

// inside test/index.js

describe('V1 ROUTES', () => {
  require('./controllers/claims.test');
  require('./controllers/claimDocuments.test');
  require('./controllers/claimPhotos.test');
  require('./controllers/inspections.test');
  require('./controllers/inspectionPhotos.test');
  require('./controllers/versions.test');
  require('./services/login.v1.test');
});

describe('V2 ROUTES', () => {
  require('./services/login.v2.test');
  require('./services/dec-image.v2.test');
});

describe('V3 ROUTES', () => {
  require('./services/login.v3.test');
  require('./services/getInspectionPhotosv3.test');
  require('./services/getPolicyInfo.v3.test');
});

describe('ACTIONS', () => {
  require('./actions/notifications.test');
});

2

我遇到了类似的问题,即我对同一类别的类进行了一堆测试,我想将它们组合在一起以使在IDE中查看它们更加容易。我所有的测试和代码已经在使用ES6模块-我不想像require在其他示例中看到的那样重写所有模块以供使用。

我通过describe导出“分组”来解决它,然后将其导入到我的测试文件中,并以编程方式将其添加到import describe。我最终创建了一个辅助方法来抽象掉所有管道。

在someCategory.spec.js中

const someCategory= describe("someCategory", () => {});


// Use this just like a regular `describe` to create a child of this scope in another file
export default function describeMember(skillName, testFn) {
  return describe(skillName, function configureContext() {
    // Make context a child of `someCategory` context
    function Context() {}
    Context.prototype = someCategory.ctx;
    this.ctx = new Context();
    // Re-parent the suite created by `describe` above (defaults to root scope of file it was created in)
    this.parent.suites.pop();
    someCategory.addSuite(this);
    // Invoke the fn now that we've properly set up the parent/context
    testFn.call(this);
  });
}

在个别测试中:

import { default as describeCategoryMember } from './someCategory.spec';

describeCategoryMember('something', () => {
    describe('somethingElse', () => {
        ...
    });

    it('a test', () => {
        ...
    });
})

-11
describe( 'Running automation test, Please wait for all test to complete!'.red, function () {


    var run = require( './Test.js' );

    for ( var i = 0; i < 2; i++ ) {
        run.badLogin();
        run.loginLimited();
        run.acceptJob();
        run.drivingToJob();
        run.arrivedAtJob();
        run.towingJob();
        run.arrivedDestination();
        run.jobComplete();
        run.restrictionLicensePlate();
        run.newNodeMainMenu();
        run.newNodeMainMenuToDrafts();
        run.draftDelete();
        run.resetAllData();
        run.companyVehicle();
        run.actionsScreenClockInOut();
        run.mainMenuLogout();
        run.loginAdmin();
        run.actionsScreenLogout();
    }
} );

3
最好在代码中添加描述,以便其他人可以确定这是否是可接受的答案。
Suever,2016年

2
为什么循环?里面有什么./Test.js?谁知道?作为记录,我目前是mocha标签中的最高回答者。我从里到外都知道摩卡,但是我无法理解这个答案。
路易

@Louis似乎他想使用循环运行测试n次。
Akash Agarwal
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.