Mocha: ES6の矢印関数を使用すると、this.timeout()が失敗します

作成日 2015ĺš´12月21日  Âˇ  59コメント  Âˇ  ソース: mochajs/mocha

矢印関数に「usestrict」およびES6構文でNode> = 4を使用すると、mochaは失敗します。

describe('foo', () => {
  this.timeout(100);
});

# => TypeError: this.timeout is not a function

ES5構文の使用は機能します:

describe('foo', function() {
  this.timeout(100);
});

それで、モカはthisでどのような醜いトリックをしますか?

最も参考になるコメント

ありがとう。

なぜこれほど多くの「魔法」があり、最終的に問題が発生するのでしょうか。 なぜこれではないのですか?:

var mocha = require('mocha');

mocha.describe('foo', (suite) => {
  suite.timeout(100);

  suite.it('must love bar', () => ... );  
});

グローバルも問題のある魔法もありません...しかしJavaScriptだけです。

全てのコメント59件

関数をテストコンテキストにバインドします。これは、矢印関数を使用している場合は実行できません。 http://mochajs.org/から

screen shot 2015-12-21 at 8 06 34 am

すみません!

ありがとう。

なぜこれほど多くの「魔法」があり、最終的に問題が発生するのでしょうか。 なぜこれではないのですか?:

var mocha = require('mocha');

mocha.describe('foo', (suite) => {
  suite.timeout(100);

  suite.it('must love bar', () => ... );  
});

グローバルも問題のある魔法もありません...しかしJavaScriptだけです。

あなたが提案しているのは、大きな重大な変更であり、https://github.com/mochajs/mocha/issues/1969#issuecomment-160925915で議論されているものです。書き直すと、これらのタイプのセマンティクスが導入される可能性があります:)

知っておくといい。 ありがとう。

@ibcまあ、それはする必要があります

var mocha = require('mocha');

mocha.describe('foo', (suite) => {
  suite.timeout(100);

  suite.it('must love bar', (suite) => ... );  
});

しかし、2つの異なるスイート引数は同じタイプですか? おそらくそうではないので、そのようなさまざまなタイプを反映するためにさまざまな変数名があります

var mocha = require('mocha');

mocha.describe('foo', (suite) => {
  suite.timeout(100);

  suite.it('must love bar', (test) => ... );  
});

とにかく、矢印演算子はコンテキストを期待する関数では使用できません。

とにかく、すぐに#1969のBDD UIを壊すことは想定していませんが、説得することはできます。 既存のAPIを維持し、BDDUIを含む別のパッケージを導入することが私の望みでした。 Mochaには、既存のAPIを使用するバージョンのBDD UIが付属していますが、その後ラムダを使用して新しいバージョンのBDD UIパッケージをリリースできます。ユーザーは、そのパッケージに明示的にアップグレードするかどうかを選択できます。

describeまたはsuiteラッパーの代替ES6構文で、この問題が解決する可能性があります。

describe({ feature: 'create stuff' , do () {
    it('abc', () => {
    }); 
}})

これにより、少なくともスイートレベルでのバインドが可能になります。

これに関する更新はありますか? 私はこれを持っています

mocha = require('mocha');

mocha.describe('test', (suite) => {

suite.timeout(500);

suite.it('test', (done)=>
          )
    }
)

そしてTypeErrorを取得する:未定義のプロパティ 'timeout'を読み取ることができません

@mroienこれはモカのバグではありません。 矢印の構文は、 function 1:1で置き換えるものではありません。 その制限について読んでください

これから何かが来ましたか? 矢印関数が大好きで、必要のないときに「これ」を嫌う場合にのみ、提案されたソリューションが好きです。

タイムアウトはdoneにのみ関連するので、単にタイムアウト関数をdone関数にアタッチしてみませんか。

it('makes sense', done => {
    done.timeout(100);
});

@nomilousこれはまだ機能しません。 私も同様の問題を抱えています。 私の場合に機能するのは、 itブロック内でsetTimeout呼び出すことです。 例えば

it('description', done => {
     const func = () => {
          // assertions
     };
     setTimeout(func, 10000);
});

@nomilous同期またはpromiseを返すケースにもタイムアウトが発生する可能性があります。

@ andela-engmkwalusimbiこれは機能しないはずです。 @boneskullが書いたように:

@mroienこれはモカのバグではありません。 矢印の構文は、関数を1:1で置き換えるものではありません。 その制限について読んでください

まだこれについて疑問に思っている人は、矢印関数が何を意味するのかを理解してから、ここに戻って読んでください(これを私よりもはるかによく説明できるリソースがたくさんあります)。

この場合、この矢印関数が機能する唯一の方法は、 thisを利用する代わりに、 bdd APIを変更してcontextオブジェクトをすべてのRunnableの(フック、テスト)コールバックに渡す場合です。 this 。 それは悪い考えではありませんが、それは壊滅的な変化の地震なので、決して起こりません。 これの代わりに:

it('should do something', function (done) {
  this.timeout(9000);
  // stuff
  done();
});

次のようになります。

it('should do something', (context, done) => {
  context.timeout(9000);
  done();
});

それ以外の場合は下位互換性があるかどうかに関係なく、存在するすべての非同期Mochaテストが機能しなくなります。

it('should do something', function (context, done) {
  // context is unused, but 'done' is now the second parameter
  this.timeout(9000);
  done();
});

ただし、これを行う代替のbdd実装を提供することもできますが、これはデフォルトではありません。

それは私が「この問題がどこにあるのか」について私が持っている最も徹底的な説明についてです。 :笑顔:

多分それは次のメジャーバージョンのために考慮に入れることができますか? 代替のbdd実装を作成するのに十分重要な変更ではないと思います。 名前付き引数を持つことは、将来の開発にも役立つ可能性があり、次のようなテストミドルウェアを追加する簡単な方法を作成する可能性があります。

it('should do something', function ({ context, done }) { ...

ただし、これを行う代替のbdd実装を提供することもできますが、これはデフォルトではありません。

@boneskull新しいbdd-es6インターフェースは素晴らしいでしょう:)

.filter(i => i.val)ような配列関数などに本当に役立つ矢印関数が大好きですが、通常の関数を使用する場合の問題は何ですか? 毎回説明する必要がないので、グローバルに説明しておくと非常に便利だと思います。 また、 this魔法はいつからですか?(矢印)関数を理解していないからですか? 約束を返すことができるたびに変数を提供したくないのは間違いありません。そうしないと、ずっと前にavaのようなものに切り替えていたでしょう。 モカのシンプルさに関しては、#1969で説明されている通常/矢印関数に大きな変更はないはずだと思います。 また、エディターは単一のfをfunction () {\n\t\n}変換できるため、矢印関数の方が入力が速いとは言わないでください。

よくわかりませんが、矢印関数を使用するbefore()呼び出しをタイムアウトする解決策はありますか?

    before( async function () {
      data = await provider.getData();
      console.log(data);
      this.timeout(30*1000);
    });

効果はありません。 ここではまだ4秒のタイムアウトが発生しています。 これは私のテストスイートで唯一遅いことです。 問題を解決するためにmocha.optsでタイムアウトを30秒に設定できますが、30秒後にすべてのテストをタイムアウトする必要はありません。99%で4秒で問題がない場合は1回のAPI呼び出しだけです。

その間に私がそれを解決した方法は次のとおりです(最初のdescribe()は太い矢印構文の代わりにfunction使用していることに注意してください:

describe('Search API', function () {
    this.timeout(30*1000);

    context('search', () => {
        let data;

        before( async () => {
          data = await provider.getSearch();
        });

        it('returns results', () => {
          expect(data).to.exist;
          expect(data.results).to.be.instanceOf(Array);
          expect(data.results.length).to.be.above(0);
        });
    })
});

@chovy await provider.getData()タイムアウトが発生した後のタイムアウトを設定しています。
代わりにこれを使用してみてください:

before(async function () {
  this.timeout(30*1000); // set timeout first, then run the function
  data = await provider.getData();
  console.log(data);
});

よくわかりませんが、矢印関数を使用するbefore()呼び出しをタイムアウトする解決策はありますか?

これを明確にするために、現在、矢印関数を使用してモカのtimeoutを呼び出す方法はありません。 代替案(ただし、メリットがある)についての議論は、考えられる新しい(または少なくとも変更された)インターフェースについての議論です。

私がしばらく頭に置いていたことができることでした:

it('...', (done) => {
  ...
  done()
})

と

it('...', (t) => {
  t.timeout(500)
  t.tag('integration', 'api')
  ...
  t.done()
})

同じデフォルトのインターフェースを使用します。

同じデフォルトインターフェイスで両方をサポートすることで、既存のコードベースで矢印関数の使用を開始できます。 オンラインの多くのチュートリアルにある(done)構文は、フラグなどがなくても機能することを指摘する価値があります。

したがって、この実装では、パラメータとして従来のdone関数を取得しますが、ユーティリティ関数はそのdone関数オブジェクトのプロパティとして追加されます。

this.timeout()と、経過時間がレポートに表示されなくなります。

@dasilvacontinなぜ私たちが以前にそれを考えなかったのか

@dasilvacontinああ、覚えています。 あなたはそれを呼ばなければならないので。 あなたはしたくないかもしれません。

申し訳ありませんが、@ boneskull、「それを呼び出さなければならない」について詳しく説明できますか? モカがテストが非同期であると考える問題について話しているのですか?

2017ĺš´1月29日には、午前5時54分で、クリストファー・ヒラー[email protected]は書きました:

@dasilvacontinああ、覚えています。 あなたはそれを呼ばなければならないので。 あなたはしたくないかもしれません。

—
あなたが言及されたのであなたはこれを受け取っています。
このメールに直接返信するか、GitHubで表示するか、スレッドをミュートしてください。

また、「t」を使用するときに非同期テストを行う意図をどのように宣言しますか?

テープでは、常に「t.done」(APIでは「t.end」)を呼び出すか、予想されるアサーションの量(「t.plan」)を設定する必要があります。

オプションを使用してit()に3番目の引数を追加することは可能でしょうか? それはAPIを壊すことはありません。

it ('accepts lambda', (done)=>{ doWork();  done(); }, {timeout:60000});

@boneskull

コンテキストを最初に置く代わりに、それがオプションの2番目だった場合はどうなりますか?

これの代わりに:

it('should do something', function (done) {
  this.timeout(9000);
  // stuff
  done();
});

次のようになります。

it('should do something', (done, context) => {
  context.timeout(9000);
  done();
});
it('should do something', function (done, context) {
  // context is unused, but 'done' is now the second parameter
  this.timeout(9000);
  done();
});

ただし、これを行う代替のbdd実装を提供することもできますが、これはデフォルトではありません。

それは私が「この問題がどこにあるのか」について私が持っている最も徹底的な説明についてです。 😄

または、コンテキストを定義済みのパラメータにする必要がある場合

it('should do something', function (done, override) {
  // context is unused, but 'done' is now the second parameter
  override.timeout(9000);
  done();
});

しかし、私もデフォルト以外のインターフェースを取ります:)

doneを必要とするソリューションの欠点は、promiseを返す方が簡単な場合でも、 doneを使用する必要があることです。 自分で言えば、 returnよりも.then(()=>{done()}, done) functionとreturnほうがいいと思います。

@Flamencoこれは興味深いアイデアですが、関数を最後に持つ方がいいかもしれません(そうです、技術的には「魔法のような」方法ですが、それに直面してみましょう。パラメーターが関数であるかどうかを確認するのは簡単で、使用するのに十分直感的ですそして、そのような「魔法」が壊れる可能性のある他のある種の抽象化にモカが供給されているわけではありません。 このようなオプションオブジェクトを使用して、タグや保留中のテストの理由を提供することもできます。これらは両方とも、要求された機能です(GitHubの問題/ PRリストの検索ボックスでそれらを見つけることは、読者の練習問題として残されています)。同情することを認めます(彼らの不在を回避することが可能であるとしても、回避策よりも本物に利点があります)。

@ScottFreeCode私はdoneについては間違いなく同意します。私もそれを使いたくないのです。コンテキストを最初と最後に置く必要性についてコメントし、boneskullが提供する前述の例を使用しました。

コンテキストを渡すか、es6を実行するためにmochaにスイッチを設定するオプションが欲しいだけです。

その間、ダーピーに見えるfunction()呼び出しでタイムアウトの違いを必要とするいくつかのテストの説明をラップしています。

カスタムタイムアウトが必要な矢印関数からpromiseがmochaに返されるユースケースの回避策を見つけました。これは、他の人が役立つと思った場合に備えて共有したいと思います。

以下のように定義された次のwhen関数をテスト宣言に追加することにより、次のようになります。 it('does something', when(() => someFunctionReturningAPromise, customTimeout))矢印関数をあきらめることなく、モカタイムアウトを設定できます。

同様に、promiseのみを使用しているため、完了したコールバックの代わりに、最初のパラメーターをテストに再取得して、コンテキストに渡すことができます: it('can access the mocha test context', when(testContext => someFunctionThatNeedsContext(testContext))

const when = (lambda, timeout) =>
  function() { // return a plain function for mocha to bind this to
    this.timeout(timeout || this.timeout() || 1000)
    return lambda(this)
  }

説明するいくつかのテストケース:

const delay = timeout =>
  new Promise((resolve, reject) => setTimeout(resolve, timeout))

const deject = timeout => // similar to above, but a delayed reject
  new Promise((resolve, reject) => setTimeout(reject, timeout))

describe('mocha testing', () => {
  context('with only arrow functions', () => {
    context('tests that do not time out', () => {
      it('passes fast', when(() => delay(10), 100))
      it('does not usually time out', when(() => delay(2000), 2010))
    })
    context('tests that will time out', () => { // these should fail if the 'when' function works properly
      it('times out fast', when(() => delay(1000), 10)) // will fail in 10ms
      it('times out', when(() => delay(1000), 1000)) // will fail in about 1000ms
    })
    context('tests that will reject', () => { // this shows the when function works as expected when a test rejects
      it('fails fast', when(() => deject(10), 100))
    })
  })
})

@ astitt-リップルうん、または単にfunction () {}と書く... Wtf?

わかりました、ルカ、かみ傷。 :-)

矢印関数との違いは、戻りをスキップできることです。 で
es6タイプのセットアップ、これはすでにpromiseの一般的なパターンである可能性があります 'then'
チェーン。

あなたが提案するように、そして私が知る限り、関数ブロックを使用すると、
約束は明示的でなければなりません。 最低限、promiseベースのテスト機能
{...}が間違っている、テストは常にその約束を返さなければならないので、最小限
有効な自明化は実際には次のとおりです:function {return ...}。 それ以外の場合は
テストは、ディスパッチされたプロミスではなく、未定義をモカに返します...そして
テストの作者は悪い時間を過ごしています。

コードベース内のほとんどのコードがすでにpromise.thenからの矢印関数である場合
および/または関数型プログラミングスタイル、関数の戻り値を追加すると、次のようになります。
一貫性がありません。 代わりに、提案された「いつ」フォームが利用可能です。
従来の機能よりも矢印とより機能的なスタイルを好む
コールバックまたは関数の戻りスタイル。 そのより簡潔で、
decribe context it dsl私たちは皆、テストを書くのが好きだということに同意します。
非同期プログラミングの抽象化javascriptが処理するpromiseを説明する
良い。 また、私たちの仲間がいない場合でも、function + returnよりも短いです:
when(()=> ...)。

多分それはこのプロジェクトの好ましいスタイルではありません、私はそれを理解しています、そして
プロジェクトの変更として提案していません。 多分その偶数
あなたのwtfが意味するように非難することができます。 それはいいです。 モカは一緒に働く必要があります
pre-fpフレンドリーなjs。 下位互換性はファーストクラスの懸念事項です。 それか
また、理にかなっています。

これは長くて行き詰まったスレッドであり、これは1つの方法です。 1素敵な
javascriptについてのことは、1つの方法または1つのスタイルである必要はないということです
物事を成し遂げる。 スタイルについてはまったく同意する必要はありません。 機能的に
話すと、私の以前の投稿は人々に矢印と約束を使用する方法を提供します
モカへのアクセスをあきらめることなく、一貫してテストDSLで
コンテキスト、クリーンで関数型プログラミングに適した方法で、
以前に提案されました。

ありがとう。

コードベース内のほとんどのコードがすでに...関数型プログラミングスタイルである場合...

...次に、動作の設定にthis.mutatingMethod(currentConfiguration)を使用することは、特にすでに実行されている関数(またはサブルーチン)の動作を設定するために、 return (単なる構文)を記述するよりもはるかに一貫性がありません。 、そして一貫性のない外観は、実際に矛盾を導入するのではなく、その現実をより明白にするでしょう。

(誤解しないでください。JSで関数型プログラミングのアイデアの人気が高まっていることに非常に満足しています。しかし、 function / returnと=>の構文は関数型プログラミングに実際に不可欠ではなく、そのパラダイムで何がよりクリーンに動作/セマンティクス、その時点で矢印関数への切り替えはおそらく簡単です...)

this.timeoutは突然変異であり、関数型プログラミングのパラダイムから外れていることに同意します。 もちろん、その完全に一貫性がありません。 現在、this.timeout以外にテストごとにカスタムタイムアウトを宣言する方法はありますか?

mochaの現在の実装では、命令型/変異型のパラダイムに戻るか、テストタイムアウトごとの設定をあきらめる必要があるようです。 どちらか一方。

上記のwhen抽象化では、タイムアウトはwhenの2番目のパラメーターであり、機能スタイルをテストのレベルに維持できます。 FPモードから命令型プログラミングへのこの避けられない脱出を隠しますが、それは1か所で行います。 また、矢印関数にモカコンテキストへのアクセスを提供します。これは、テスト関数のパラメーター規則に違反しない限り不可能です。 したがって、誰かがテストランナーのアイデアを探求するまで、暫定的にこのプロジェクトの一部のユーザーのいくつかの問題を解決する可能性があります(この問題の履歴から判断します)。

また、私も誤解しないでください。 関数型プログラミングがチューリングマシンから派生した命令型/突然変異型プログラミングに完全に取って代わるとは思いません。 たとえば、ほとんどすべての場合、JSランタイムでは、関数型かどうかに関係なく、コードは最終的に、より伝統的な命令型(おそらく、c ++ですが、必ずしもそうではありません)で記述されたプログラムによって解釈されます。このプログラムは、ミューテーションを中心に記述されたオペレーティングシステムで実行されます。そして命令型のアイデア(おそらくC)。 メモリは固定リソースであり、不変のデータ構造はランタイムが私たちに告げる嘘です。 その基本的に必須のモデルは、コンピューティングのデフォルトであり、ここにとどまります。 しかし、それは関数型プログラミングがその上に共存できないという意味ではありません。 もしそうなら、FPコードが時々基礎となるモデルにドロップダウンしなければならないことは避けられません。 それは、私たちが手を挙げてそのすべての構文を言うことを意味するべきではないと思います。そして、function / returnを使用しましょう。

=>関数の代わりにfunction / returnを使用して関数型プログラミングを実行できるのと同じように、実際には、詳細に一定の許容範囲が与えられれば、Cで関数型プログラミングを実行できます。 約束を返すことを忘れないでください。 CのFPは、入力に少し時間がかかりますが、結局のところ、これは単なる構文です... / s

結局のところ、矢印関数を使用すると、ラムダ計算モデルで一般的な言語で作業するための実行可能で実用的な方法に徐々に近づくことができます。 これらの余分な文字を削除すると、小さいながらも重要な違いが生じます。 まだ多くの実際的な制限がありますが、これらの多くは解決可能であり、目前の主題はそれらの1つです。

いずれかの方法。 提案したヘルパー関数を使用しますが、他の人も自由に使用できるようになりました。 あなたのテストランナーソリューションを楽しみにしていますが、それまでの間、どの構文が重要かどうかについて私たち自身の意見を説得し続けることが特に生産的であるかどうかはわかりません。一つの方法です。 私は矢印が好きで、あなたは機能が好きです。 私の見方を変える説得力のある議論を見たことがありません。 私は1つにオープンですが、「function、wtfを使用するだけ」、「もっと冗長な_syntax_でfpを実行できる」など、ひざまずくよりもよく考えたほうがよいでしょう。

別の方法で問題を解決すれば、誰もwhenを使用する必要はありません。 言っ途切れる。 :-)

それは、私たちが手を挙げてそのすべての構文を言うことを意味するべきではないと思います。そして、function / returnを使用しましょう。

私は矢印が好きで、あなたは機能が好きです。

...次のようなひざまずくよりもよく考えたほうがよいでしょう:...「もっと冗長な構文でfpを実行できます」。

これは私が言ったこととはほとんど逆ですが、 thisをまだ使用している矢印関数はそもそもFPではなく、矢印関数を使用したOOになるという事実を考えていました(従来のJS関数を使用したFPの逆)。 言い換えれば、それが単なる異なる構文であるどころか、本当の問題は、構文の非互換性よりもパラダイムの非互換性が深いことです(Mochaは現在とにかく設計されているため)。

this完全にパラメーターに置き換えるために、Mochaの上に代替インターフェースを構築することはかなり可能であると確信しています。 テストを書く際にFPに行きたいのなら、モカのthisを矢印関数に渡す方法を考え出す以上のことをしなければならないことを明確にしておきたいと思います。 しかし私は、挑戦のその種に上昇するために非常に多くのです。 ; ^)

(モカには、ステートフル、グローバル、またはさらに悪いことに両方の動作がいくつかありますが、現時点では、それらを一覧表示する簡単な方法を考え出す時間がありません。 Mochaを複数回実行することを取り巻く問題は、その一例です。)

現在、this.timeout以外にテストごとにカスタムタイムアウトを宣言する方法はありますか?

残念ながら、私はかなり確信しています。 構成設定のキー値マップ(JSオブジェクトとして)となるitへの追加パラメーターを受け入れるという提案は、誰かが望むなら、Mochaのまともな将来の解決策のように聞こえます。実装してみてください。

現在、this.timeout以外にテストごとにカスタムタイムアウトを宣言する方法はありますか?

残念ながら、私はかなり確信しています。

この詳細を確認していただきありがとうございます。 これは私が言っていたポイントを固めます。

頭のてっぺんから、構成設定のキー値マップ(JSオブジェクトとして)である追加のパラメーターを受け入れるという提案は、誰かがそれを実装してみたければ、Mochaのまともな将来の解決策のように聞こえます。

より一般的な解決策については+1。

しかし、私が言えることから、単一のパラメーターを渡すことはまだ実行可能であるように思われます。 thisをdoneコールバックと組み合わせます(したがって、 thisは関数になります)。 次に、パラメーターの数に関係なく、mochaにpromiseでラップされた各テストを実行させます(実際には2つ、タイムアウトの処理用に1つ、実際にテストを実行するために1つ)。 次に、関数の結果がpromiseであるかどうかを確認できます。 そうでない場合は、同期関数が戻った後にdone呼び出して、テストを終了します。 関数の結果が代わりにpromiseである場合は、それが解決される(または拒否される)のを待ちます。 タイムアウトが発生した場合は、テストを停止します(以前と同じ)。 テストがなんとかdoneを呼び出し、promiseを返す場合。 どちらの完了も解決前に呼び出されます。その場合、mochaは約束を待ってから、あいまいな完了シーケンスがあるためにテストに失敗する必要があります。 または、解決後に完了と呼ばれます。その場合、何らかの理由でテストを遡及的に失敗させる必要があります。または、問題が他の合理的な方法で通知されます。 申し訳ありませんが、それは多くの幅広いストロークですが、それはモカが何をしようとしているのか、そしてモカが遭遇する癖についての私の部外者の理解です。 これが実行可能な解決策になるのを妨げる可能性のある他の考慮事項は何ですか?

テストを書く際にFPに行きたいのなら、モカのこれを矢印関数に渡す方法を考え出す以上のことをしなければならないでしょう。

同意した。 別の計算モデルに移行することには明確な変化があり、さらにjavascriptは、考慮すべきことがたくさんある複雑なエコシステムです。 ただし、私の特定のユースケースでは、タイムアウトを時々設定する(固定のデフォルト値ではなく、何らかの計算に基づいてより正確にするなど)ことが、MochaでFPテストを作成するときに遭遇した唯一の具体的な問題です(これまでのところ)少なくとも)。 それは素晴らしいです。 :+1:

そうは言っても、(FPでテストを書くことが一般的に何を意味するのかとは対照的に)特にモカに関係する差し迫った障害としてあなたが他に何を見ているのか知りたいです。

それは私が言ったこととはほとんど反対ですが

誤解や誤解があった場合は申し訳ありません。 私が書いたものの多くについては、返信に基づいて、意図したとおりに出会ったかどうかもわかりません。 残念なことに、私たちがそれに取り掛かった場合、おそらくFPが_理論_でどのように見えるべきかについてかなり緊密な合意に達するだろうと思います。 ただし、少なくとも一部のユーザー/ユースケースでは、現在利用可能なMochaのリリースで_practice_の実行可能な削減がどのように見えるかについては意見が分かれているようです。 ですから、私が提案したアドオン機能の主な問題があなたの側から正確に何であるかはよくわかりません。

(順番に引用して返信しましたが、間違いなく、より重要なものは前ではなく後です。)


しかし、私が言えることから、単一のパラメーターを渡すことはまだ実行可能であるように思われます。 これをdoneコールバックと組み合わせます(これが関数になります)。 次に...これが実行可能なソリューションになるのを妨げる可能性のある他の考慮事項は何ですか?

下位互換性を破ると、より単純な設計に切り替えることができます。

下位互換性を維持する場合、これらのテストは両方とも合格する必要があり、タイムアウトする必要はありません。

it("runs immediately", () => {
  // call functions and assert whatever
})
it("runs asynchronously", doneWithSomeOtherName => {
  setTimeout(() => {
    // call functions and assert whatever
    doneWithSomeOtherName()
  }, 100)
})

そうでないことを証明するために、いくつかのサンプルコードを考え出すことを歓迎します(ただし、代わりにこのコメントの最後にある提案に焦点を当てることをお勧めします)が、それを実行できる設計はないと確信しています。また、このテストに合格し、タイムアウトしないようにします。

it("looks just like an asynchronous test with a different name for `done`, but never tells Mocha it's done", context => {
  context.configureByMutation("some value")
  // call functions and assert whatever
})

しかしまた、そこでの突然変異に注意してください。 これについては以下で詳しく説明します。


ただし、私の特定のユースケースでは、タイムアウトを時々設定する(固定のデフォルト値ではなく、何らかの計算に基づいてより正確にするなど)ことが、MochaでFPテストを作成するときに遭遇した唯一の具体的な問題です(これまでのところ)少なくとも)。 それは素晴らしいです。

:+1:!


そうは言っても、(FPでテストを書くことが一般的に何を意味するのかとは対照的に)特にモカに関係する差し迫った障害としてあなたが他に何を見ているのか知りたいです。

私はこれをかなり焦点を絞って伝えていなかったのではないかと思います...それで、もう少し要約できるかどうか見てみましょう。 (これのいずれかが拮抗的なものとして外れた場合も申し訳ありません。ここで考え方を変えようとしていることは認めますが、それは確かに意図されたものではありません。)Mochaのコードベースは、クラス階層とゲッターおよびセッタースタイルのほとんどです。 「オブジェクト指向」(そして、Mochaが持っている複数の問題または潜在的な問題があり、可変状態になると私は信じています)が、テストを作成してMochaに実行させるだけであれば、通常はテストコードに影響しません。 。 Mochaの命令型ミューティング構成を使用すると、奇妙なことができます。

it("imperatively sets the timeout multiple times", function(done) {
  this.timeout(5000)
  var context = this
  setTimeout(function() {
    context.timeout(1000)
    setTimeout(done, 500)
  }, 4000)
})

...しかし、そうする必要はありません。 関数型以外の言語で関数型プログラミングを行う多くの要素と同様に、命令型を乱用しないでください。

(例外が不純であるという議論もありますが、入力に基づいてスローされる例外については、まだ確信が持てません。これは、別の形式の出力と見なすことができます。したがって、アサーションを使用すると言う人もいます。そのスローは機能しませんが、現時点ではそれに取り組むつもりはありません。)

(ここで重要な部分:)私が得ようとしているのは、すでに複雑なコードベースに複雑さを追加するか、後方互換性のない変更を加える可能性があることです。 これらのいずれかを正当化する必要があります。 正当化が「テストをより機能的にする」である場合、それは良いことです(とにかく私の本では)。 テストをより機能的にする設計は、問題を起こす価値があるかもしれません(問題の程度によって異なります)。 しかし、「テストをより機能的にする」とは、「矢印関数を機能的にする」、つまり「矢印関数を機能的にしない」という意味で、ケースを大幅に弱めます(自己矛盾だけではない場合)。 より完全に:関連する1ビットの突然変異を保持しながら、テストをより機能的にそのビットの突然変異を取り除くことは、少なくともテストをより機能的にすることがポイントである場合には、そうなるでしょう。

しかし、私はおそらくこの接線からそれほど遠く離れるべきではありませんでした。 ソリューションについては、以下を参照してください。 😸


ですから、私が提案したアドオン機能の主な問題があなたの側から正確に何であるかはよくわかりません。

(ここでも重要な部分です:)実際には、メソッド呼び出しの代わりにtimeoutをパラメーターとして受け取るビットが好きです! それをMochaの残りの構成メソッドに一般化する方法を思い付くことができれば(それらはたくさんあります-そして私が正しく思い出せば同期テストに適用されるものもあります、それゆえ私たちは同じメソッドを単に追加することができないのはなぜですか? doneプロパティを使用して、 doneを介して構成を呼び出すことができる非同期テストを作成できるようにしますが、私は逸脱します)、それを確認したいと思います。 少なくとも、それを推奨したいと思うかもしれませんし、3番目のパラメーター(またはそのようなもの、おそらくit.configuredまたはit(...).configured(...)が渡されたときに実装をitに採用することさえできるかもしれませんit(...).configured(...)これ以上のパラメータ数のシェナニガンが必要ない場合は...)-これは、根本的な突然変異/必須事項に取り組み、矢印関数のサポートを取得する下位互換性のあるソリューションになると思います。方法」(とにかく私が主張しているのはそのようなものです):それは新しい動作に適合するからです。 回避策でthisを追いかけるのではなく、私が言うべきだったのは、パラメータ部分を拡張してみようということだと思います。

私はあなたがこのようなことをすることができるどこかで読んだことを誓います:

describe('a slow thing', () => {
 // test code...
}).timeout(5000);

これは、提供された関数のパラメーターコントラクトを変更しません。 今、私はそのようなものへの参照を見つけることができないので、多分私はそれを想像しただけです。

@ thom-nicこれは機能します! モカのすべての関数がそのコンテキストを返すので、それは理にかなっていると思います

return this;

矢印関数フォームを通常の関数に置き換えると、私と一緒に機能します

関数() { ..... }

こんにちはフォークス。 8月に議論を巻き起こした後、暗くなったことをお詫びします。私は非常に忙しく、実際にはほとんどその作業を完了/移行しました。

さまざまなユースケースについての詳細な回答と、それらを組み合わせるのがいかに難しいかを感謝します。 これは、私が読んだモカがサポートしなければならないさまざまなセットアップを最も簡潔に示したものです。 だから、それであなたの時間をありがとう。

振り返ってみると、モカのコンテキスト( this )にアクセスすることを強調しすぎたに違いないことは明らかですが、その側面は本当に便利な後付けでした。 私が実際にやろうとしていたことからどれほど簡単に注意を引くことができるかわかりませんでした。これは、一時的な拡張機能( when )をテストdslに追加して、1回限りの合理化を行うことで楽しんでいました。タイムアウトの調整(さらに、特定のスタイルのテストに共通するエラーを排除します。これについては、以下で説明します)。 this返すことは、私が追加しようと思ったもう1つの楽しいことでした。主なアイデア(したがって、 whenという名前)は、通常とは異なるタイムアウトが必要なケースを処理するためのものでした。

明らかに、バインドされたコンテキストにアクセスしたい場合は、ラッパーで持ち上げるのではなく、多くの人が提案しているように、 function直接使用できます。 それは問題ではありません。 😄それが一見奇妙に見えるかもしれないことは私には失われていません。 そもそもこの道をたどったいくつかのテストをどのように設定していたかを示しれば、全体像が完成することを願っています。 明確にするために、私はここで特定のスタイルを販売しようとはしていません。あなたに合ったものを使用してください。 これは私のために働いたものです。

Ok
まず、基本的に1つのことを実行するセットアップをテストしているが、広範囲の入力に対してテストしているという仮定から始めます。したがって、出力が正しいことを確認するために、一連のシナリオでこのことをテストする必要があります。 。 ただし、関連するアプリケーションコードは「1つのことを行う」ため、基礎となるテスト手順はほとんど常に同じです。 また、テストボディを不必要に複製/変更したくないのは、新しい入力のテストケースを追加する速度が遅くなり、最終的にはメンテナンスが不合理になるためです。

したがって、代わりに、サポートされる可能性のある入力を使用してアプリケーションコードを起動し、テストアクションを実行して、結果をアサートするのに十分な一般的な関数を記述します...私の場合、Promise抽象化を使用していたことを追加します(理由は省略します)、したがって、この一般化されたテスト手順関数は、当然、そのpromise.thenチェーンを返す必要があります。 パンとバターのes6のようなもの、これまでのところ良い。

テストシナリオが登場しました。すべてをテスト手順関数にパックしたため、テストケースは入力を効果的に定義し、関数を呼び出しています。

したがって、おそらく私はこのような一連のテストを作成し、すべてが機能しているように見えます。

it('does something', function() {
  testProcedureFunction('something','1')
})

よくフォローしていると、この例にはバグがあることにすでに気付いているでしょう。 returnが欠落しており、testProcedureFunctionはpromise(しゃれを意図したもの)に基づいて構築されているため、最後のアサーションが成功するか失敗するかに関係なく、常に成功します。 これはバグであり、追跡するのは非常に微妙な場合があります。 説明のために、testProcedureFunctionの記述方法とアプリケーションの記述方法によっては、開始時に同期コードがあり、テスト終了アサーションの代わりに爆発する場合でも、テストケースが失敗する可能性があります。すべてが大丈夫だと思う。

もちろん、テストは実際には次のようになります。

it('does something', function() {
  return testProcedureFunction('something','1')
})

これで、ほとんどの場合、このテストは1行になることがわかりました。 実際には、入力がより大きなタイムアウトが必要になるような場合を除いて、すべてのケースが1行になります。 古典的なjs関数と矢印の違いの中に、ここで役立つ矢印関数の特定の側面があります。中括弧が省略されている場合、単一ステートメントの矢印関数には暗黙の戻り値があります。 function {...}を書く代わりに、テストで=> ...使用する場合、矢印と中括弧の欠如についてこれらのケースを簡単にスキャンし、この欠落したreturn含めることはできないとすぐに推測できます。

そのようです:

it('does something', () => testProcedureFunction('something','1'))

これらのケースの1つが他のケースよりも時間がかかる場合はどうなりますか? もちろん、タイムアウトは次のように設定できます。

it('does something slow', function() {
  this.timeout(10000)
  return testProcedureFunction('somethingSlow','2')
})

または、誰かが間違いを犯して最初にこれを行うかもしれません(もちろん機能しません):

it('does something slow', () => {
  this.timeout(10000)
  return testProcedureFunction('somethingSlow','2')
})

しかし今、私たちは始めたところに戻っています、コードベースは繰り返すために熟したパターンを持っています、それは行方不明のリターンバグの影響を受けやすいです(将来の私、または機能を追加する次の人のどちらかによって-要点はそれは簡単です間違えると、見過ごされる可能性があり、追跡するのが難しい場合があります)。 when関数はこれを解決し、矢印を再び一貫して使用できるようにします。

it('does something slow', when(() => testProcedureFunction('somethingSlow','2'), 10000))

(注:上記の.timeout(5000)ドットチェーンの提案を機能させることができませんでした。使用する必要のあるモカのバージョンが原因である可能性があります。もう覚えていませんが、試す!)
(注2、 when使用は、 thisパラメーターの巻き上げトリックを使用していないことに注意してください-それは実際には単なる後付けでした)。

おそらく、欠落している約束のリターンのバグにフラグを立てることができるリンターがあります(または、より現実的には、すべての関数にrhsを使用してreturnステートメントを強制します)。 しかし、それは当時の選択肢ではありませんでした。さらに、矢印の構文が短くなり、(主観的/個人的に)読みやすく、操作しやすくなり、スケールがfunctionから離れてしまいました。 。

だからあなたはそれを持っています。

近いうちにまた返答する時間があるかどうかわからないので、少なくとも有益で明確であり、「矢印からモカコンテキストへのアクセス」全体をめぐる論争の一部をベッド。

最後に、関数vs =>が長い間混乱していることに気付いたので、矢印がthisアクセスできない理由を何気なく読んでいる人にはわからない場合に備えて、このリンクを削除します。 それは私が見つけた関数と矢印の最も明確な説明であり、それらを完全に自信を持って使用するのに十分な違いを最終的に理解するのに役立ちました。

https://hacks.mozilla.org/2015/06/es6-in-depth-arrow-functions/

@ thom-nic itで機能しますが、 describeでは機能しません。

describe('my test suite', () => {

  it('test case 1', () => {
    // ...
  }).timeout('10s');  // Works on `it`. This test case doesn't timeout

  it('test case 2', () => {
    // ...
  });  // This test case timeouts.

}).timeout('10s');  // Doesn't work on `describe`. Tests are already created when runs to here.

@ thom-nic、通常の関数形式を使用できます

describe('my test suite', function() {
this.timeout(n);

...
}

これについて不平を言う人は誰でも矢印の機能を理解していません。

矢印関数は新しい派手なES6のものではなく、古典的なfunction () {}に取って代わることになっています。 矢印関数の唯一の目的は、親からthisを継承することです。ここで、クラシックfunction ()は独自のthisます。

はい、完全なES6構文を使用している場合でも、関数の正しいコンテキストでthisを使用する場合は、 function ()を使用する必要があります。 何をしようとしているかに応じて、ES6アプリケーションでfunction ()と() =>両方を使用する必要があります。

this.timeout()はit('....', () => { ... }) this.timeout()では機能しません。コールバックは親のdescribe()関数からthisを継承しているため、 this.timeout()は機能しません。そのレベルで理にかなっています。

ラムダ関数では、呼び出しで宣言せずに、関数に単一の引数を自動的に送信することもできませんか?

(param)=> aFunction
... then(aFunction)

function(){}は 'this'にバインドできますが、()=>は 'ロックインされています'

矢印関数は、受信者が呼び出されたのと同じコンテキストで事前に決定された「this」を期待する場合、従来の関数を置き換える必要があります(また、入力するコードを減らすことでメリットが得られます)。

'this'を呼び出したときに 'this'以外のものにしたい場合を除いて、function()は絶対に使用しないでください。

@フラメンコ...

ラムダ関数では、呼び出しで宣言せずに、関数に単一の引数を自動的に送信することもできませんか?

あなたがそれをどのように表現しているのかを_正確に_理解しているかどうかはわかりません。
「関数への引数の送信」に関しては、太い矢印は1つの例外を除いて通常の関数と同じように機能します。引数が1つしかない場合は、括弧を省略できます。

() => console.log("hi"); //zero arguments requires empty parenthesis
a => console.log(a); //you can optionally leave the parenthesis off for 1 argument
(a,b) => console.log(`${a} ${b}`); //2..n arguments requires parenthesis

関数が単一の式である限り、太い矢印を使用すると、中括弧とreturnキーワードを省略して値を_返す_ことができます。
だからあなたが持っていたら...

setTimeout(function(a,b) { doSomething(); return calculateSomething(a,b); }, 5000);

...そしてそれを太い矢印関数に変換したい場合、関数本体に複数のステートメントがあるため、中括弧とreturnキーワードを振ることはできません。 あなたはこのようにします...

setTimeout((a,b) => { doSomething(); return calculateSomething(a,b); }, 5000);

もし、むしろあなたが始めたのなら...

setTimeout(function(a,b) { return calculateSomething(a,b); }, 5000);

...次に、単一の式を返すだけで使用できるほど単純な関数を扱っています...

setTimeout((a,b) => calculateSomething(a,b), 5000);

それはずっと読みやすくなりました!
私はcodefoster.com/levelup-arraysでこれについてもう少し書いた。

JavaScriptには、OOPからFPまで、厳密な型安全性からミックスイン/ダックタイピングまで、さまざまなコーディングスタイルがあります。 さらに、これらのスタイルにはそれぞれ高度なパターンがあります(つまり、OOPキャンプでの依存性注入、FPキャンプでのカリー化/モナド)。

コーディングスタイルがFPに近く、 thisが使用されておらず、矢印関数を使用してボイラープレートを削減している場合、 thisを保持する必要があると、高度なテスト(パラメーター化されたテスト、作成など)のオーバーヘッドが増えます。 DSL)。

経験豊富な開発者なら誰でも、コーディングスタイルに合わせてテストフレームワークを事前にラップできますが、それはフレームワークが「すぐに使える」ものではないことを意味します。 これは、アップグレード、プラグインの採用、新しいエンジニアのオンボーディングのための余分な作業につながります。

thisを使用せず、代わりに通常はコンテキストオブジェクトとなるものをパラメータとしてdescribe 、 itに渡す代替のbddインターフェイスのアイデアが好きです。 itとフック。

しかし、IIRCの実装はそれほど簡単ではありません。 しかし、試みを見るのはクールだろう。

これが深刻な副作用の原因になっていることは知っていますが、done-or-contextパラメーターをこのように処理できませんでしたか?

it("runs immediately", () => {
  // call functions and assert whatever
})
it("runs asynchronously", doneOrContext => {
  setTimeout(() => {
    // call functions and assert whatever
    doneOrContext();
  }, 100)
})



md5-b1fe6f00c87a2916712cf6a4df16e142



it("runs immediately using the parameter as a context", doneOrContext => {
  doneOrContext.configureByMutation("some value");
  // As well as changing config, also flags to Mocha that this test is treating the
  // parameter as a context object and is therefore not async.
  // Call functions and assert whatever
})



md5-b1fe6f00c87a2916712cf6a4df16e142



it("runs asynchronously using the parameter as a context", doneOrContext => {
  doneOrContext.configureByMutation("some value");
  doneOrContext.setAsync(); // Flags to Mocha that even though the parameter has been used as
  // a context object, the test is in fact asynchronous.
  setTimeout(() => {
    // call functions and assert whatever
    doneOrContext();
    // or doneOrContext.done()
  }, 100)
})

以下のスクリプトを使用しましたが、同じタイムアウト超過エラーが発生しました。

Myscript:

describe( "getBillingDetail"、async function(){
this.timeout(55000);
it.only( "指定された有効なジョブ名を確認してください"、async関数(完了){
this.timeout(55000);
var result = await url.getBillingDetail( '12254785565647858');
console.log(result);
assert.equal(result、true);
});
});

エラー:55000msのタイムアウトを超えました。 非同期テストとフックの場合は、「done()」が呼び出されていることを確認してください。 Promiseを返す場合は、それが解決されることを確認してください。

完了したコールバックを非同期関数に渡さないでください

下位互換性のあるプロトタイプソリューションを作成しました。 今のところ、これは別個のモジュールですが、機能は簡単に適切なmochaマージできます。

https://github.com/papercuptech/mocha-lambda

迅速な方法

require('mocha-lambda')
// now a global '_tst' can be used where 'this' was before

describe('suite', () => {
  beforeEach(() => {
    _tst.answer = 42
  })

  it('provides "this" as "_tst"', function() {
    assert(this === _tst)
  })

  it('works', () => {
    assert(_tst.answer === 42)
    _tst.skip()
  })
})

明示的な命名用(およびTypeScriptで動作)

// if you were previously explicitly importing api (describe, it, etc.) from 'mocha',
// you will have to change to importing from 'mocha-lambda', until (or if) this
// gets merged into mocha proper
import ctx, {describe as d, it as i} from 'mocha-lambda'

d('suite', () => {
  // ctx() is a function that returns "this" as appropriate
  i('works using ctx()', () => {
    ctx().skip()
  })
})

import {Context} from 'mocha'
// ctx() can also rename global
ctx('t')
declare var t: Context
d('suite', () => {
  // ctx() is a function that returns "this" as appropriate
  i('works using renamed global', () => {
    t.skip()
  })
})

@papercuptechリンクが404見つかりません。

Woops ..はプライベートリポジトリでした。 現在公開中

npm imocha-lambdaもできます

@aleung @ linesh-シンプルさ、これは#3485に取って代わられました

ありがとう。

なぜこれほど多くの「魔法」があり、最終的に問題が発生するのでしょうか。 なぜこれではないのですか?:

var mocha = require('mocha');

mocha.describe('foo', (suite) => {
  suite.timeout(100);

  suite.it('must love bar', () => ... );  
});

グローバルも問題のある魔法もありません...しかしJavaScriptだけです。

@ thom-nicの回答を参照して、クリーンでトリックを実行しました

私はあなたがこのようなことをすることができるどこかで読んだことを誓います:

describe('a slow thing', () => {
 // test code...
}).timeout(5000);

これは、提供された関数のパラメーターコントラクトを変更しません。 今、私はそのようなものへの参照を見つけることができないので、多分私はそれを想像しただけです。

@ thom-nicソリューションは私のために働いた、ありがとう!

このページは役に立ちましたか?
0 / 5 - 0 評価