Sinon: サンドボックスがエラーをスローします '存在しない独自のプロパティをスタブできません'

作成日 2017年08月18日  ·  14コメント  ·  ソース: sinonjs/sinon

2.4.1から3.2.1にアップグレードしようとしたところ、次の問題が発生しました。 このコードは2.4.1で機能します:

        const spy = sandbox.spy();
        sandbox.stub(window, 'google').value({
            maps: {
                LatLng: x => x,
                Map: spy
            }
        });

しかし、3.2.1では例外がスローされます: TypeError: Cannot stub non-existent own property google

移行ガイドには記載されていないため、リグレッションのようです。

Bug Regression

最も参考になるコメント

〜この動作を復元していただきありがとうございます。〜

存在しないプロパティのスタブ化をサポートするユースケースを追加したかった。

私のユースケースでは、構成オブジェクトのプロパティをスタブしています。 configオブジェクトにはさまざまなオプションのキーがあり、開発者のマシンからファイルをロードすることで初期化されます。 特定のテストを実行するとき、これらのキーの1つを既知の値に設定する必要があり、開発者のオブジェクトを元の状態に復元したいと思います。

sandbox.stub(serverSecrets, 'the_key_i_need_set').value(fakeValue)は、これを伝えるための非常に明確な方法です。 実行時にキーが設定されているかどうかはわかりませんが、同じ動作が得られるのは良いことです。

全てのコメント14件

#1512に関連。

プロパティが存在しない場合は、サンドボックスに追加する必要はありません。 単に上書きします。 しかし、ええ、それが以前に機能し、それが変更されるべきであると明示的に述べていない場合、それは回帰です。

ここで何をすべきかわからない。 ドキュメントを更新して、存在しない値をスタブすることは意味がなく、サポートされていない、またはそれを可能にするようにしますか?

プロパティが存在しない場合は、サンドボックスに追加する必要はありません。 単に上書きします。

プロパティをサンドボックスに追加することの良い点は、sinonが、 sandbox.restore()介して各テスト間でグローバルテスト環境をクリーンに保つのに役立つことです。 これは非常に便利な機能です。特に、APIを制御していないGoogleマップのようなサードパーティのライブラリを扱う場合に便利です。 3.xラインで動作させることができれば素晴らしいと思います。

また、完全な例を提供しないという罪を犯したことに気づきました。 私のサンドボックスは2.4.1形式で作成されています:

let sandbox;

before(() => { sandbox = sinon.sandbox.create(); })
afterEach(() => { sandbox.restore(); })

それが重要かどうかはわかりません。 早く提供しなかったことをお詫びします。

@ZebraFleshが説明しているようなシナリオでは、テキストフィクスチャをより明示的にしたいと思います。

// not so explicit, doesn't work with [email protected]
beforeEach(function() {
    const spy = sandbox.spy();
    sandbox.stub(window, 'google').value({
        maps: {
            LatLng: x => x,
            Map: spy
        }
    }); 
});
// more explicit, works with sinon<strong i="9">@2</strong>, sinon<strong i="10">@3</strong>
function setGoogleMapsFixture(sandbox) {
    window.google = {
        maps: {
            LatLng: x => x,
            Map: sandbox.spy()
        }
    };
}

function removeGoogleMapsFixture() {
    delete window.google;
}

beforeEach(function() {
    setGoogleMapsFixture(sandbox)
});

// not using afterEach, as this only needs to happen
// after the last test in this block is run
after(function() {
    removeGoogleMapsFixture();
});

上で概説したようなフィクスチャのより明示的な設定では、存在しない独自のプロパティのスタブを可能にするSinonの機能は必要ありません。

ここで何をすべきかわからない。 ドキュメントを更新して、存在しない値をスタブすることは意味がなく、サポートされていない、またはそれを可能にするようにしますか?

一部のシナリオ(@ZebraFleshで説明されているシナリオなど)では便利な場合があることは認識していますが、存在しない独自のプロパティをスタブすると、テストでミスが発生する可能性が高いと思います。彼らがスタブすることを目指していた既存のプロパティ。 制限しすぎずに、できる限り間違いの可能性を排除することを目指すべきです。

存在しない独自のプロパティをスタブすることはサポートされないままである必要があると思います。 ドキュメントを更新する必要があります。

@mroderickバグが少なくなる可能性があるという点で同意しますが、通常のスタブではすでにこれをサポートしています。 この動作のサポートを停止する必要がある場合は、一貫性を保つために、そこでも削除する必要があります。 サンドボックスは通常いくつかの可能性を追加するため、サンドボックスの外部でのみこの機能をサポートするのは奇妙なことです。 また、サポートを削除することは破壊的な機能であるため、大きなバンプも必要になります。

だからどちらか:

  • この壊れた機能を修正するには、サンドボックスのチェックをすぐに削除してください

または(?)

  • 通常のスタブとサンドボックス化されたスタブの両方の機能を削除します

    • 更新されたドキュメントで新しいメジャーバージョンをリリースする

上で概説したようなフィクスチャのより明示的な設定では、存在しない独自のプロパティのスタブを可能にするSinonの機能は必要ありません。

あなたのフィクスチャがあなたのテスト間で決して変化しないならば、それはうまくいくと思います。 しかし、私のフィクスチャはそうします。 簡単な例は、成功と失敗の両方のケースをカバーすることです。

it('handles the success case', () => {
        const spy = sandbox.spy();
        sandbox.stub(window, 'google').value({
            maps: {
                LatLng: x => x,
                Map: spy
            }
        });
        // ... test, including asserting that the spy was called
});

it('handles the failure case', () => {
        const msg = 'test error';
        sandbox.stub(window, 'google').value({
            maps: {
                LatLng: x => x,
                Map: sandbox.stub().throws(new Error(msg))
            }
        });
        // ... test, ignoring spy calls and instead focusing on error handling
});

2.xの動作には、 sandbox.restore()介して各テスト後にすべてが適切にクリーンアップされるという利点があります。 上で概説したより明示的なフィクスチャ設定の例を使用して、同じ効果を達成するためにafterEachフックの非所有プロパティを削除できると思います。

既存の独自のプロパティの名前を誤って入力して潜在的な間違いを引き起こす問題を解決するために、sinonはパブリックAPIを変更する可能性があります。

  • stub.ownValue() :スタブはプロパティのみを所有し、所有していないプロパティをスローします
  • stub.value() :所有していないプロパティのみをスタブし、独自のプロパティをスローします

APIはより明確になり、消費者は目前のタスクに適切なツールを選択することを余儀なくされます。

これは、#1508(通常のスタブを扱っていますが)hでの議論に非常に関連しています。ここで、 @ lucasfcostaは反対の見方をしています。つまり、 undefinedプロパティに対しては_投げるべきではありません_。 何に着手しても、通常のスタブとサンドボックスのスタブAPIでは_一貫性が必要である_と強く信じています。 ある場合にはそれをサポートすべきではなく、他の場合にはサポートすべきではありません。

現在の状況は次のとおりです。

  • 通常のスタブは1.xでスローされていましたが、これは2.0で変更され、現在はスローされません。
  • サンドボックスはスローに使用しませんでしたが、3.1(?)でスローを開始しました

そのため、しばらくの間、機能の同等性がありましたが、その後再び失われました...このジグザグはユーザーにとってあまり有益ではないと思うので、この議論を開始する必要があります。 より具体的なテストが行​​われる可能性があるという点でMorganに同意しますが、2つのメジャーリリースの動作を削除してから再度追加するのは好きではありません。 このリグレッションを元に戻すだけで、ノイズ(クライアントの修正、このトラッカーの質問/問題)が最小になると思います。

不便さは理解していますが、コードの変更を最小限に抑えて簡単に回避できるようです。

before(function() {
  window.google = 'This is a placeholder for sinon to overwrite.';
});

after(function() {
  delete window.google;
});

これにより、sinonコードを変更しないでおくことができます。

回帰と不十分なドキュメント

テストがあるため、これは予想される動作のようです。 私の意見にそれを反映するためにドキュメントを更新する必要があります。 それはメジャーで来たので、破壊的な変更は許容されます。

@fearphage現状を維持するということは、存在しないフィールドをスタブすることはサンドボックスではサポートされていない動作ですが、通常のスタブではサポートされている動作であることを意味します。 2つの機能セットが一致しないのは少し残念ではありませんか?

解決は#1557で実装されました

さまざまなスレッドを読んで、なぜこれが起こったのかがわかりますが、クラスプロトタイプに実装された関数を頻繁に使用するタイプスクリプトでは、本当に苦痛です。その場合、すべてが正常に見えるにもかかわらず、sinonがダミーを吐き出します。賢明です( keyof YourTypeは、プロトタイプチェーンのさらに下流で定義されているすべてのパブリック関数を喜んで許可するため)。

Typescriptはおそらくあなたたちにとって優先事項ではないと思いますが、JSでも、 myObject.callMe()が完全にうまく実行されるのは直感に反しているようですが、その場合はsinon.stub(myObject, "callMe")は実行されません。 その特定のオブジェクトがどのようにまとめられたかを調べて、スタブする方法を知っている必要はありません。

クラスがJSでよりネイティブなサポートを受けていることを考えると、これは幸せな道を作るための重要なユースケースだと本当に思います。

メソッドがオブジェクトで定義されていないというエラーが表示された場合は、エラーがプロトタイプにある可能性が高いことがわかります。 次に、 myObject.callMe = sinon.stub();を使用してオブジェクトを直接変更することは、それほど面倒なことではないようです。プロトタイプは変更されていないため、クリーンアップ/ティアダウン関数を作成する手間も省けます。

ええ、回避するのはそれほど難しいことではないと思います。物事がどのように実装されているかを認識するために、私にもっと認知的な負荷をかけているだけです。

また、予想外のように思われるため、同じオブジェクトの2つの連続する行のスタブコードが異なる理由と、分解でスタブの1つを手動で削除した理由を説明するために、テストにコメントを追加する必要があると感じました。しかし、もう1つはサンドボックスによって処理されました。

〜この動作を復元していただきありがとうございます。〜

存在しないプロパティのスタブ化をサポートするユースケースを追加したかった。

私のユースケースでは、構成オブジェクトのプロパティをスタブしています。 configオブジェクトにはさまざまなオプションのキーがあり、開発者のマシンからファイルをロードすることで初期化されます。 特定のテストを実行するとき、これらのキーの1つを既知の値に設定する必要があり、開発者のオブジェクトを元の状態に復元したいと思います。

sandbox.stub(serverSecrets, 'the_key_i_need_set').value(fakeValue)は、これを伝えるための非常に明確な方法です。 実行時にキーが設定されているかどうかはわかりませんが、同じ動作が得られるのは良いことです。

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