web-dev-qa-db-ja.com

mochaおよびnode.jsを使用したプライベート関数の単体テスト

Node.js向けに作成されたアプリケーションを単体テストするためにmochaを使用しています

モジュールにエクスポートされていない関数を単体テストすることは可能かと思います。

例:

foobar.jsにこのように定義された関数がたくさんあります

function private_foobar1(){
    ...
}

function private_foobar2(){
    ...
}

パブリックとしてエクスポートされたいくつかの関数:

exports.public_foobar3 = function(){
    ...
}

テストケースの構造は次のとおりです。

describe("private_foobar1", function() {
    it("should do stuff", function(done) {
        var stuff = foobar.private_foobar1(filter);
        should(stuff).be.ok;
        should(stuff).....

private_foobar1はエクスポートされないため、これは明らかに機能しません。

プライベートメソッドを単体テストする正しい方法は何ですか? mochaにはそれを行うための組み込みメソッドがありますか?

120
fstab

関数がモジュールによってエクスポートされない場合、モジュールの外部のテストコードによって呼び出すことはできません。これはJavaScriptの仕組みによるものであり、Mocha自体はこれを回避できません。

プライベート関数のテストが正しいことだと判断したいくつかの例では、モジュールがテストセットアップで実行されているかどうかを判断するためにチェックする環境変数を設定しました。テストセットアップで実行すると、テスト中に呼び出すことができる追加の関数がエクスポートされます。

ここでは「環境」という言葉が大まかに使用されています。それはprocess.envまたはモジュールと通信できる他の何かをチェックすることを意味するかもしれません。「あなたは今テストされています」。これをしなければならなかったインスタンスはRequireJS環境にあり、この目的でmodule.configを使用しました。

58
Louis

rewire モジュールを確認してください。モジュール内のプライベート変数と関数を取得(および操​​作)できます。

したがって、あなたの場合、使用法は次のようになります:

var rewire = require('rewire'),
    foobar = rewire('./foobar'); // Bring your module in with rewire

describe("private_foobar1", function() {

    // Use the special '__get__' accessor to get your private function.
    var private_foobar1 = foobar.__get__('private_foobar1');

    it("should do stuff", function(done) {
        var stuff = private_foobar1(filter);
        should(stuff).be.ok;
        should(stuff).....
175
barwin

プライベートメソッドをテストするための非常に良いワークフローです GoogleエンジニアのブログでPhilip Waltonが説明しています。

原理

  • 通常通りにコードを書く
  • プライベートメソッドを別のコードブロックでオブジェクトにバインドします。たとえば、_でマークします
  • 開始コメントと終了コメントでコードブロックを囲む

次に、ビルドタスクまたは独自のビルドシステム(例:grunt-strip-code)を使用して、本番ビルド用にこのブロックを削除します。

テストビルドはプライベートAPIにアクセスできますが、プロダクションビルドにはアクセスできません。

スニペット

次のようにコードを記述します。

var myModule = (function() {

  function foo() {
    // private function `foo` inside closure
    return "foo"
  }

  var api = {
    bar: function() {
      // public function `bar` returned from closure
      return "bar"
    }
  }

  /* test-code */
  api._foo = foo
  /* end-test-code */

  return api
}())

そして、そのようなあなたの単調な仕事

grunt.registerTask("test", [
  "concat",
  "jshint",
  "jasmine"
])
grunt.registerTask("deploy", [
  "concat",
  "strip-code",
  "jshint",
  "uglify"
])

より深く

後の記事で 、「プライベートメソッドのテスト」の「理由」について説明します

21
Rémi Becheras

シンプルにしたい場合は、プライベートメンバーもエクスポートしますが、いくつかの規則でパブリックAPIから明確に分離します。 _をプレフィックスとして付けるか、単一のprivateオブジェクトの下にネストします。

var privateWorker = function() {
    return 1
}

var doSomething = function() {
    return privateWorker()
}

module.exports = {
    doSomething: doSomething,
    _privateWorker: privateWorker
}
20
famousgarkin

この目的のためにnpmパッケージを作成しました。これは役に立つかもしれません: require-from

基本的に、次の方法で非パブリックメソッドを公開します。

module.testExports = {
    private_foobar1: private_foobar1,
    private_foobar2: private_foobar2,
    ...
}

note:testExportsは、もちろんexportsを除く、任意の有効な名前にすることができます。

そして、別のモジュールから:

var requireFrom = require('require-from');
var private_foobar1 = requireFrom('testExports', './path-to-module').private_foobar1;
5
DEADB17

Internal()という名前の特別な関数を追加し、そこからすべてのプライベート関数を返します。このInternal()関数がエクスポートされます。例:

function Internal () {
  return { Private_Function1, Private_Function2, Private_Function2}
}

// Exports --------------------------
module.exports = { PublicFunction1, PublicFunction2, Internal }

次のような内部関数を呼び出すことができます。

let test = require('.....')
test.Internal().Private_Function1()

私はこのソリューションが最も好きです:

  • 1つの関数Internal()のみが常にエクスポートされます。このInternal()関数は、プライベート関数をテストするために常に使用されます。
  • 実装は簡単です
  • 製品コードへの影響が少ない(追加機能は1つのみ)

@ barwinの回答に従い、rewireモジュールを使用してユニットテストを行う方法を確認しました。このソリューションが単に機能することを確認できます。

モジュールは、パブリック部分とプライベート部分の2つの部分で必要になります。パブリック関数の場合、標準的な方法でそれを行うことができます。

const { public_foobar3 } = require('./foobar');

プライベートスコープの場合:

const privateFoobar = require('rewire')('./foobar');
const private_foobar1 = privateFoobar .__get__('private_foobar1');
const private_foobar2 = privateFoobar .__get__('private_foobar2');

このテーマについて詳しく知るために、完全なモジュールテストを含む実用的な例を作成しました。テストにはプライベートスコープとパブリックスコープが含まれます。

詳細については、完全に説明している記事( https://medium.com/@macsikora/how-to-test-private-functions-of-es6-module-fb8c1345b25f )を確認することをお勧めします件名には、コードサンプルが含まれます。

1
Maciej Sikora

これは必ずしもあなたが探している答えではないことを知っていますが、私が見つけたのは、ほとんどの場合、プライベート関数がテストする価値がある場合、独自のファイルに入れる価値があるということです。

例えば。次のように、パブリックメソッドと同じファイルにプライベートメソッドを含める代わりに...

src/thing/PublicInterface.js


function helper1 (x) {
    return 2 * x;
}

function helper2 (x) {
    return 3 * x;
}

export function publicMethod1(x) {
    return helper1(x);
}

export function publicMethod2(x) {
    return helper1(x) + helper2(x);
}

...次のように分割します:

src/thing/PublicInterface.js

import {helper1} from './internal/helper1.js';
import {helper2} from './internal/helper2.js';

export function publicMethod1(x) {
    return helper1(x);
}

export function publicMethod2(x) {
    return helper1(x) + helper2(x);
}

src/thing/internal/helper1.js

export function helper1 (x) {
    return 2 * x;
}

src/thing/internal/helper2.js

export function helper2 (x) {
    return 3 * x;
}

そうすれば、helper1helper2を簡単にテストできます。Rewireやその他の「魔法」を使用せずに(デバッグ中や、新しい同僚にとっては理解しにくいことは言うまでもなく、TypeScriptに向かって動きます。そして、それらはinternalと呼ばれるサブフォルダー、またはそのようなものにあることで、意図しない場所での偶発的な使用を回避するのに役立ちます。


追伸:「プライベート」メソッドのもう1つの一般的な問題は、publicMethod1およびpublicMethod2をテストし、ヘルパーをモックしたい場合、通常はRewireのようなものが必要なことです。ただし、それらが別々のファイルにある場合、 Proxyquire を使用してそれを行うことができます。これは、Rewireとは異なり、ビルドプロセスに変更を加える必要がなく、読みやすく、デバッグが簡単で、動作しますTypeScriptでも同様です。

0

プライベートメソッドをテストに使用できるようにするには、次のようにします。

const _myPrivateMethod: () => {};

const methods = {
    myPublicMethod1: () => {},
    myPublicMethod2: () => {},
}

if (process.env.NODE_ENV === 'test') {
    methods._myPrivateMethod = _myPrivateMethod;
}

module.exports = methods;
0
MFB