mocha.jsを使用して複数のファイルからテストを結合する


87

複数のファイルからのすべてのテストを1つのファイルに結合しようとしています。次のようになります。

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

私はこれがテストに参加するための最良の方法ではないと確信しています、私はこれを行う方法の例を見つけるのにいくつかの困難があります:s


1
不思議なことに、なぜテストを1つのファイルにまとめる必要があるのですか?
thgaskell 2014年

2
ローカル変数と組織を共有するため
coiso 2014年

質問にテストを含めると、より理にかなっているかもしれません。(単体テストではなく)統合テストに傾倒しているようです。通常、テスト間で変数を共有する必要はありません。
thgaskell 2014年

2
そして大きな問題は、1つのhuuuugeファイルよりも20のファイルが欲しいということです
coiso 2014年

2
また、Mochaがスイートをどのように処理するかを概念で見る.only()describe.only()、テストのディレクトリ全体を実行できるようにすると便利な場合があります。それが私をここに連れてきた理由です。
クリス

回答:


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の内側に、彼らが表示されるかどうかdescribetopか、彼らがに表示され、インポートモジュールのいずれか。を使用する--recursiveと、beforeEachコードを各モジュールにコピーする必要があります。そうでない場合はbeforeEach、共通モジュールからインポートされた関数を呼び出すフックが各モジュールにあります。

また、afterフックはスイート内のすべてのテストの後に実行されます。これは、で複製することはできません--recursive--recursiveのコードを使用しafterて各モジュールに追加すると、テスト全体で1回だけではなく、モジュールごとに1回実行されます。

すべてのテストを単一の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年

たとえば、importTestと呼び出しの違いは何require('path')()ですか?
CherryNerd 2017年

@CreasolDevこのimportTest関数は単なる便利な関数です。それが行う重要なことは、require呼び出しをdescribeブロックでラップすることです。require呼び出しをラップすることが重要です。describeそうしないと、モジュールが独自のブロックに分離されず、インポートされたファイルによって設定されたフックが間違ったブロックに設定されます。importTestrequireラッピングなしのへの直接呼び出しに置き換えられた場合describe、モジュールa/ab/bはフックを共有します。たとえば、でbeforeEach設定されたフックは、のb/b各テストの前にも実行されa/aます。
Louis

1
私はあなたのトップレベルのdescribeのbeforeEachのようなロジックを実行しません。各ファイルに独自のbeforeEach「もの」を実行させます。これを行うと、テストを相互に結合し、関連のない実装になります。
PositiveGuy

1
また、importTest関数ではなく、それぞれのファイルで記述のラッピングを行います。それぞれのファイルのトップレベルの説明は、とにかくテストスイートの目的を説明する必要があります
PositiveGuy

35

これは質問に直接関連していないかもしれませんが、私が探していた答えは次のとおりでした。

$ mocha --recursive

「test」フォルダのサブディレクトリにあるすべてのテストを実行します。きちんとした。ロードしたいテストのリストを維持する必要がなくなり、実際には常にすべてを実行するだけです。


3
ベストアンサー!他の提案されたソリューションよりもはるかに簡単です。
caiosm1005 2016

12
@ caiosm1005この回答は、OPによって提示された問題を実際に解決しているわけではありません。確かに、OPが実行したいことを実行する必要がない場合は、これを使用する必要があります。ただし、各テストファイルを複数のdescribeブロック(describeファイルにまたがるブロック)でラップ--recursiveする場合は、それを実行しません。それはOPの問題を解決しないので、私はそれを「最良」とは言いません。
Louis

@ louis-それぞれの個別のファイルをdescribeブロックでラップできると思います
Ian Jamieson

4
@IanJamieson OPは、複数のファイルを1つの describeブロックでカバーしようとしています。質問を見てください。「Controllers」describeブロックには、とのテストが含まれている必要が./controllertests/messages.jsあり./controllertests/users.jsます。--recursiveモカの呼び出しに平手打ちしても、魔法のようにdescribe("Controllers"ブロックは作成されません。
Louis

3
@Louisただ助けようとしている。魔法のようにdescribeブロックを作成しようとしてあなたを怒らせたら申し訳ありません-それは実際にダンブルドア自身から行うことを学びました。
Ian Jamieson 2016年

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オプションを設定してください。

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
コントローラーとモデルのディレクトリにファイルのコードを追加してもよろしいですか?完全な例があれば素晴らしいと思います。
Gavin

@ Gavin-これらはテストスーツになるので、含まれますdescribe('mytest', function() { /* ..... etc */ });
Ian Jamieson

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エクスポートしてから、テストファイルにインポートし、プログラムでインポートしたに追加することで解決しました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ますか?知るか?記録のために、私は現在のトップアンサーよモカタグ。私はモカの内外を知っていますが、この答えを理解することはできません。
Louis

@Louisは、ループを使用してテストをn回実行したかったようです。
Akash Agarwal 2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.