動的言語でモックを作成しているときにタイプエラーはどのように検出されますか?


10

TDDの実行中に問題が発生。いくつかのテストに合格すると、一部のクラス/モジュールの戻り値の型が変わります。静的に型付けされたプログラミング言語で、以前にモックされたオブジェクトが他のクラスのテストで使用され、型の変更を反映するように変更されていない場合、コンパイルエラーが発生します。

ただし、動的言語の場合、戻り値の型の変更が検出されず、他のクラスのテストは引き続き成功します。もちろん、後で失敗するはずの統合テストがあるかもしれませんが、単体テストは誤ってパスします。これを回避する方法はありますか?

簡単なサンプルで更新しています(一部の人工言語)...

バージョン1:

Calc = {
    doMultiply(x, y) {return x * y}
}
//.... more code ....

// On some faraway remote code on a different file
Rect = {
    computeArea(l, w) {return Calc.doMultipy(x*y)}
}

// test for Rect
testComputeArea() { 
    Calc = new Mock()
    Calc.expect(doMultiply, 2, 30) // where 2 is the arity
    assertEqual(30, computeArea)
}

さて、バージョン2では:

// I change the return types. I also update the tests for Calc
Calc = {
    doMultiply(x, y) {return {result: (x * y), success:true}}
}

... Rectは実行時に例外をスローしますが、テストは引き続き成功します。


1
どのような答えは、これまでミスに思えることは質問を変え含む試験ではないということですclass Xが、のテストclass Yに依存するXので、それが生産のに対して実行するものとは異なる契約に対してテストされます。
Bart van Ingen Schenau 2013年

私は尋ねたSO上でこの質問を依存性注入に関して、自分自身。理由1:依存クラスを実行時に変更できる(テストを考えて)を参照してください。私たちはどちらも同じ考え方を持っていますが、優れた説明が不足しています。
Scott Coates 2013年

私はあなたの質問を読み直していますが、解釈が少し混乱しています。例を挙げていただけますか?
Scott Coates 2013年

回答:


2

これは、ある程度、動的言語でビジネスを行うためのコストの一部にすぎません。十分な柔軟性が得られます。それ以外の場合は、「自分で吊るすのに十分なロープ」として知られています。注意してください。

私にとって、この問題は、静的に型付けされた言語の場合とは異なるリファクタリング手法を使用することを提案しています。静的言語では、戻り値の型を部分的に置き換えるので、「コンパイラーに頼って」、どこが壊れるかを見つけることができます。安全に実行でき、おそらく、戻り値の型を適切に変更するよりも安全です。

動的言語ではこれを行うことはできないため、戻り値の型を置き換えるよりも、変更するほうがはるかに安全です。おそらく、それを必要とするクラスのために、新しいクラスをメンバーとしてそれに追加することによって、それを変更します。


2

コードが変更されてもテストに合格する場合は、テストに問題がある(つまり、アサーションが欠落している)か、コードが実際には変更されていません。

それはどういう意味ですか?まあ、あなたのテストはあなたのコードの部分間の契約を記述します。契約がある場合は、リストへの配列があると言うからの戻り値変更、「戻り値は反復可能でなければならない」ではない、実際に契約の変更をするため、必ずしもテストの失敗をトリガしません。

不足しているアサーションを避けるために、あなたは、このようなコードカバレッジ解析(それはあなたのコードの部分のテストがされている何を教えてくれませんが、それはのようなツールを使用することができます部品は間違いなく何を教えていないテスト)、循環的複雑度とNPATH複雑さを(これにより、完全なC1およびC2コードカバレッジを達成するために必要なアサーションの数の下限が得られます)およびミューテーションテスター(に変換、負の数を正に、オブジェクトをに入れるなど、コードに突然変異を挿入truefalsenullそれがテストを失敗させます)。


+1テストまたはコードの問題のいずれかは、実際には変更されませんでした。長年のC ++ / Javaに慣れるのにしばらく時間がかかりました。コードの動的言語のパーツ間のコントラクトは、何が返されるのではなく、返されるものに何が含まれ、何ができるかを示します。
MrFox 2013年

@suslik:実際、これは静的言語と動的言語ではなく、抽象データ型を使用したデータ抽象化とオブジェクト指向データ抽象化についてです。オブジェクトが完全に異なる型であり、完全に異なるクラスのインスタンスである場合でも、あるオブジェクトが別のオブジェクトをシミュレートする機能は、オブジェクト指向の全体的な考え方の基本です。または別の言い方をすると、2つのオブジェクトが同じように動作する場合、クラスの内容に関係なく、それらは同じ型になります。さらに言い換えると、クラスは型ではありません。残念ながら、JavaとC#はこれを間違っています。
イェルクWミッターク

モックされたユニットが100%カバーされ、アサーションが欠落していないと仮定します。「fooの場合はnullを返す必要がある」から「fooの場合は空の文字列を返す必要がある」などの微妙な変更はどうでしょうか。誰かがそのユニットとそのテストを変更した場合、一部の消費ユニットは壊れる可能性があり、モックのためにこれは透過的です。(いいえ:作成時またはモックモジュールの使用時に、「契約」ごとに、空でない文字列またはnullのみを返すことになっているため、戻り値として空の文字列を処理する必要はありません;))。(相互作用する両方のモジュールの適切な統合テストのみがこれをキャッチできます。)
try-catch-finally
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.