使用mocha.js连接多个文件的测试

时间:2014-06-11 01:17:31

标签: node.js unit-testing mocha

我试图将多个文件中的所有测试都加入到一个文件中,如下所示:

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

我非常确定这不是加入测试的最佳方式,我有一些难以找到如何做到这一点的例子:s

6 个答案:

答案 0 :(得分:94)

如果您希望将多个模块包含在您的describe层次结构中,就像您在问题中所做的那样,那么您所做的几乎就是,除非你想为Mocha编写一个自定义测试加载器。编写自定义加载器并不容易,或者使代码比现有代码更清晰。

这是我如何改变一些事情的一个例子。此示例中的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注册的每个测试之前运行其代码,无论它们是否出现在describe中的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一堆东西覆盖并保持全局只读变量或不保持状态的函数。我不喜欢像thgaskell的答案那样污染global对象,因为这个对象真正是全局的,即使在你的代码可能正在加载的第三方库中也是可访问的。这不是我在代码中可以接受的东西。

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

答案 1 :(得分:23)

虽然这可能与问题没有直接关系,但我所寻求的答案是:

$ mocha --recursive

将执行“test”文件夹的子目录中的所有测试。整齐。节省了必须维护我想要加载的测试列表,并且实际上总是运行所有内容。

答案 2 :(得分:14)

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

以下是您如何整理测试文件的示例。

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

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

<强> mocha.opts

--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 :(得分:4)

我知道这是一篇很老的帖子,但是我希望能够找到一个很好的解决方案,非常类似于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');
});

答案 4 :(得分:0)

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

我解决了这一问题,方法是导出“分组” describe,然后将其导入到我的测试文件中,并以编程方式将其添加到导入的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', () => {
        ...
    });
})

答案 5 :(得分:-12)

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