大きな関数を小さな関数にリファクタリングするときに追加の単体テストを作成することの価値は何ですか?


8

複雑な単体テスト機能がある場合:

def do_everything():
    # turn twizzles
    # push buttons
    # move mountain

そして、それをいくつかの小さな単位にリファクタリングします:

def do_everything():
    turn_twizzles()
    push_buttons()
    move_mountain()

def turn_twizzles():
    # turn twizzles

def push_buttons():
    # push buttons

def move_mountain():
    # move mountain

これらの小さなユニット用の追加の単体テストを書くのに時間を無駄にしていますか?

回答:


15

の動作をカバーする単体テストはすでにあると思いますdo_everything()か?turn_twizzles()プライベートメソッドとして壊れているなどの場合は、外部の動作を変更していないため、テストを変更する必要はありません。

ただしturn_twizzles()、公開されている場合は、新しい機能を導入しているため(クラスの外部から観察)、これをテストすることは重要です。


2
なぜこの回答が反対票を投じられたのかわかりません。それは短く、要点があり、そのアドバイスでは100%スポットしています。
David Arno

これは非常に明確な答えです、ありがとう。問題(@Samuelが最初に言及したことに対する信用)は、天候の問題か、パブリックインターフェイスが変更されていないかです。
アダムテリー

これは完全ではないため、反対票を投じます。新しい関数がパブリックAPIの一部ではなかったとしても、テストを書くことは非常に役立ちます。do_everything()のテストが失敗したとしましょう:エラーはどこにありますか?3つのサブ関数すべてのテストがある場合は、簡単に見つけることができます。これはテストを作成する利点であり、ここで言及する必要があります。
marstato 2017年

1
@marstato:テストを実装の詳細に結び付けるので、プライベートメソッドを単体テストすることは一般に悪い考えと見なされます。
JacquesB 2017年

@JaxquesBそれは一般的に悪いことではありません。通常の統合テストよりも正確なものは、実装の詳細に関係していると言えます。ただし、これらのテストは、正しい機能を証明するためではなく、バグの追跡に役立つため、とにかく記述します。アクセス修飾子は常に主観的です。privateプログラミング言語のキーワードは、コードの一部へのアクセスを制限する多くの方法の一つです。
marstato 2017年

12

場合によります。より正確には、それは

  • 元の機能の複雑さ(非常に複雑な場合は、各部分を独自にテストすることで成果が得られます)
  • 小さな機能の複雑さ(それ自体が複雑な部分である場合、それらを個別にテストすると、よりきめの細かいテストと、欠陥の場合のより正確な根本原因の検出につながります)
  • 既存の単体テスト(それらがすべての「パーツ」に対して十分なカバレッジをすでに生成している場合、個別のテストを記述する価値はおそらくないでしょう)
  • これらの小さな関数を元の関数の「実装の詳細」に保持したい場合、または保持しない場合(前者の場合、小さな関数の単体テストを作成すると、この目標に対して逆効果になります)。

特に、それらの「小さい関数」が例のように簡単ではないが、入力パラメーターの多少複雑なリストがある場合、小さい関数がテストされることを保証するために、元の関数の十分な単体テストを生成することは本当に難しくなる可能性があります。すべての「興味深い」入力の組み合わせ。これは、より小さな関数の特定の単体テストを作成する明確な兆候でもあります。

したがって、この質問に明確な「はい」または「いいえ」はありません。ケースごとに決定する必要があるトレードオフです。


6

場合はturn_twizzlespush_buttonsと、move_mountain公共およびその他のコードによって呼び出され、その後、私はそれが個別にこれらの関数をテストするためのテストをリファクタリングすることが重要だと思います。

ユニットテストに:残念ながら、あなたのリファクタリング後、あなたは問題を抱えているdo_everythingあなたは模擬できるようにする必要がありturn_twizzlespush_buttonsmove_mountaindo_everything依存関係をモックしないでテストを作成することは、統合テストになります-テスト計画によっては必ずしも悪いことではありませんが、すでに3つの小さな関数を個別にテストしているので、あまりメリットはありません。これは、このコンポーネントを再設計し、他のオブジェクトと協力してのすべての作業を行う適切なタイミングかもしれませんdo_everything

、、が外部から呼び出されない場合turn_twizzlespush_buttonsmove_mountainプライベートとしてマークする必要があります。また、とは別にテストすることはお勧めしませんdo_everything。これは、外から見てdo_everything、最小単位になるためです(他のものがアクセスできないため)。プライベートメソッドを使用してメソッドを分割する方法についても、この回答をご覧ください。


4
私は「としてこれをdownvotedしているユニットテストにdo_everythingあなたはモックすることができる必要があるturn_twizzlespush_buttonsmove_mountain...」「単体テスト」のナンセンスの定義に依存します。
David Arno

1
@公平を期してデビッド、サミュエルは答えでそれを認めます。ちょっと。
GnP

4

いいえ。追加の単体テストはより正確です。場合はmove_mountain失敗し、その後、単一のテストは、非常に具体的に何が悪かったのかと言う失敗します。

この精度により、デバッグ時間が短縮されます。これは貴重なことです。また、テストの焦点が絞られているため、全機能を介して同じ機能をテストするよりも実行が速く、迅速なフィードバックが得られるため、貴重です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.