web-dev-qa-db-ja.com

Mochaのdescribe()の役割は何ですか?

公式Mochaサイト のドキュメントには、この例が含まれています。

describe('User', function(){
  describe('#save()', function(){
    it('should save without error', function(done){
      var user = new User('Luna');
      user.save(function(err){
        if (err) throw err;
        done();
      });
    })
  })
})

describe関数にテストをネストする時期と、describeの基本的な目的は何かを知りたいです。 describeに渡された最初の引数をプログラミング言語のコメントと比較できますか?コンソールの出力にdescribeの何も表示されません。読みやすさのみを目的としていますか、またはこの機能には他の用途がありますか?

このように使用すると何か問題はありますか?

describe('User', function(){
    describe('#save()', function(){
        var user = new User('Luna');
        user.save(function(err){
            if (err) throw err;
            done();
        })
    })
})

このようにすると、テストに合格します。

63

it呼び出しは個々のテストを識別しますが、it自体は、テストスイートが構造化である方法についてMochaに何も伝えません。 describe呼び出しを使用する方法は、テストスイートに構造を与えるものです。 describeを使用してテストスイートを構造化することのいくつかを次に示します。議論のために簡略化されたテストスイートの例を次に示します。

function Foo() {
}

describe("Foo", function () {
    var foo;
    beforeEach(function () {
        foo = new Foo();
    });
    describe("#clone", function () {
        beforeEach(function () {
            // Some other hook
        });
        it("clones the object", function () {
        });
    });
    describe("#equals", function () {
        it("returns true when the object passed is the same", function () {
        });
        it("returns false, when...", function () {
        });
    });
    afterEach(function () {
        // Destroy the foo that was created.
        // foo.destroy();
    });
});

function Bar() {
}

describe("Bar", function () {
    describe("#clone", function () {
        it("clones the object", function () {
        });
    });
});

FooBarが本格的なクラスであると想像してください。 Fooにはcloneおよびequalsメソッドがあります。 Barにはcloneがあります。上記の構造は、これらのクラスのテストを構造化する方法の1つです。

#表記は、一部のシステム(jsdocなど)でインスタンスフィールドを示すために使用されます。したがって、メソッド名とともに使用する場合、クラスではなくクラスのインスタンスで呼び出されるメソッドを示します。メソッド(クラス自体で呼び出されます)。テストスイートは、#がなくても同様に実行されます。

バナーを提供する

Mochaのレポーターの一部は、作成するレポートでdescribeに付けた名前を示しています。たとえば、specレポーター($ mocha -R specを実行することで使用できます)は、以下を報告します。

  Foo
    #clone
      ✓ clones the object 
    #equals
      ✓ returns true when the object passed is the same 
      ✓ returns false, when... 

  Bar
    #clone
      ✓ clones the object 


  4 passing (4ms)

実行する部品の選択を支援

一部のテストのみを実行する場合は、--grepオプションを使用できます。したがって、Barクラスのみに関心がある場合は、$ mocha -R spec --grep Barを実行して、出力を取得できます。

  Bar
    #clone
      ✓ clones the object 


  1 passing (4ms)

または、すべてのクラスのcloneメソッドのみに関心がある場合は、$ mocha -R spec --grep '\bclone\b'を実行して出力を取得します。

  Foo
    #clone
      ✓ clones the object 

  Bar
    #clone
      ✓ clones the object 


  2 passing (5ms)

--grepに指定された値は正規表現として解釈されるため、\bclone\bを渡すと、cloneclonesなどの単語ではなく、clonedという単語のみを要求しています。

フックを提供する

上記の例では、beforeEachおよびafterEach呼び出しはフックです。各フックは、フックの親であるit呼び出し内にあるdescribe呼び出しに影響します。さまざまなフックは次のとおりです。

  • beforeEachは、it呼び出し内の個々のdescribeの前に実行されます。

  • afterEachは、it呼び出し内の個々のdescribeの後に実行されます。

  • before呼び出し内の個々のitのいずれかが実行される前に1回実行されるdescribe

  • after呼び出し内の個々のitがすべて実行された後に1回実行されるdescribe

これらのフックを使用して、リソースを取得したり、テストに必要なデータ構造を作成したり、テストの完了後にリソースを解放したり、必要に応じてこれらの構造を破棄したりできます。

質問の最後に表示するスニペットはエラーを生成しませんが、テストはitで定義されているため、実際にはテストは含まれていません。

71
Louis

私の知る限りでは、describeは実際には人間のためだけにあります...したがって、アプリのさまざまな領域を見ることができます。 nレベルの深さまでネストできます。

describe('user',function(){
    describe('create',function(){}
});

ルイの優れた答えに加えるのは難しい。 skipおよびonly関数である、彼が言及しなかった記述ブロックにはいくつかの利点があります。

_describe.skip(...) {
...
}
_

この記述とすべてのネストされた記述をスキップし、次の間に機能します。

_describe.only(...) {
...
}
_

その記述とそのネストされた記述のみを実行し、機能します。 skip()およびonly()修飾子もit()関数に適用できます。

5
Guy

Describeはテストの目的を理解するために使用されるだけであり、テストを論理的にグループ化するためにも使用されます。データベースAPIをテストしているとしましょう。すべてのデータベーステストは外部記述の下にある可能性があるため、外部記述はすべてのデータベース関連を論理的にグループ化します。テストするデータベース関連のAPIが10個あるとしましょう。各内部記述関数は、それらのテストが何であるかを定義します。

2
Karthic Rao

Describeの特定の役割は、テストされているコンポーネントとそのコンポーネントのメソッドもテストされていることを示すことです。

たとえば、ユーザープロトタイプがあるとします

var User = function() {
    const self = this;

    function setName(name) {
        self.name = name
    }

    function getName(name) {
        return self.name;
    }


    return{setName, getName};
}

module.exports = User;

また、テストする必要があるため、単体テスト用のスペックファイルが作成されます

var assert = require('assert');
var User = require("../controllers/user.controller");

describe("User", function() {
    describe('setName', function() {
        it("should set the name on user", function() {
            const pedro = new User();

            name = "Pedro"
            pedro.setName(name);
            assert(pedro.getName(), name);
        });
    });
});

Describeの目的はテストするコンポーネントを示しており、ネストされたdescribeメソッドはどのメソッドをテストする必要があるかを示していることがわかりやすい

0
Pedro Machado