web-dev-qa-db-ja.com

単純な(自己完結型)関数のテストを維持する必要はありますか?

このことを考慮:

public function polynominal($a, $b, $c, $d)
{
    return  $a * pow($x, 3) + $b * pow($x, 2) + $c * $x + $d;
}

上記の機能についてさまざまなテストを作成し、自分自身や他の人に「機能する」ことを証明するとします。

では、それらのテストを削除して、幸せに暮らしてみませんか?私の要点は、いくつかの機能が機能することが証明された後、継続的にテストする必要がないということです。次の理由により、これらの機能をテストする必要があります。

36
Dennis

回帰試験

それはすべて回帰テストについてです。

次の開発者があなたの方法を見て、魔法の数字を使用していることに気づいたと想像してください。彼は魔法の数字は邪悪であると言われたので、2つの定数を作成しました。それは彼があなたのすでに正しい実装を修正していたようではありません。

気が散って、彼は2つの定数を逆にします。

彼はコードをコミットしますが、コミットごとに実行される回帰テストがないため、すべてが正常に機能しているようです。

ある日(数週間後かもしれません)、何かが他の場所で壊れます。そして、どこか別の意味で、私はコードベースの完全に反対側の場所を意味します。これは、polynominal関数とは何の関係もないようです。 時間のかかるデバッグが原因です。この間、アプリケーションは本番環境で失敗し続け、顧客に多くの問題を引き起こします。

作成した元のテストを維持することで、このような痛みを防ぐことができます。気が散った開発者はコードをコミットし、ほぼ即座に彼が何かを壊したことに気づきました。このようなコードは製品にまで届きません。単体テストはさらに、エラーの場所について非常に正確です。それを解決することは難しくありません。

副作用...

実際、ほとんどのリファクタリングは回帰テストに大きく基づいています。小さな変更を加えます。テスト。合格した場合は、すべて問題ありません。

副作用は、テストがない場合、実質的にリファクタリングはコードを破壊する大きなリスクになることです。多くの場合、リファクタリングを実行する必要があることを経営陣に説明することはすでに困難です。以前のリファクタリングの試行で複数のバグが発生した後は、さらに困難になります。

テストの完全なスイートを用意することで、リファクタリングを促進し、より良い、よりクリーンなコードを作成できます。リスクなしで、定期的にさらにリファクタリングすることは非常に魅力的になります。

要件の変更

もう1つの重要な側面は、要件の変更です。 複素数を処理するため と尋ねられることがありますが、突然、バージョン管理ログを検索して以前のテストを見つけ、それらを復元して、新しいテストの追加を開始する必要があります。

なぜこの面倒なのか?後で追加するためにテストを削除する理由そもそもそのままにしておくこともできます。

78

バグがあり得ないほど単純なものは何もないからです。

あなたのコードは、一見するとバグがないように見えます。実際には、多項式関数の単純なプログラムによる表現です。

バグがあることを除いて...

public function polynominal($a, $b, $c, $d)
{
    return  $a * pow($x, 3) + $b * pow($x, 2) + $c * $x + $d;
}

$xはコードへの入力として定義されておらず、言語またはランタイム、またはスコープによっては、関数が機能しない、無効な結果が発生する、または 宇宙船がクラッシュする可能性があります の場合があります。


補遺:

あなたは今のところコードのバグがないと考えるかもしれませんが、それがいつまで続くかは言いがたいです。そのような些細なコードのテストを書くことは価値がないと主張されるかもしれませんが、すでにテストを書いていることは作業が完了し、それを削除することは具体的な安全策を削除することです。

追加の注意事項は、テストスイートが提供するカバレッジを適切に示すコードカバレッジサービス(coveralls.ioなど)です。コードのすべての行をカバーすることにより、実行するテストの量(品質でない場合)の適切なメトリックを提供します。多くの小規模なテストと組み合わせて、これらのサービスは少なくとも、バグが発生したときにないバグを探す場所を通知します。

最終的に、すでにテストを作成している場合は、そのままにしてください。削除することによるスペースまたは時間の節約は、バグが発生した場合の技術的な負債よりもはるかに少ないためです。

44
user69037

はい。 100%の信頼度で確実に言うことができる場合:この関数は編集されず、失敗する可能性のあるコンテキストで実行されることはありません-言うことができる場合、テストを削除し、毎回数ミリ秒を節約できますCIビルド。

しかし、それはできません。または、多くの機能を使用することはできません。また、すべてのテストを常に実行するというルールを持つ方が、満足できる信頼度のしきい値を正確に決定し、特定の関数の不変性と不可謬性にどれだけの信頼性があるかを正確に決定するよりも簡単です。

そして処理時間は安いです。節約されたこれらのミリ秒は、何度も乗算されても、すべての関数に時間をかけて質問することを正当化するのに十分に足りません。もう一度テストする必要がないという十分な自信がありますか?

21
Carl Manaster

他の答えで述べられていることはすべて正しいですが、もう1つ追加します。

ドキュメント

ユニットテストは、適切に記述されている場合、関数が何を実行するか、その入出力の期待は何か、さらに重要なことは、どのような動作が期待できるかを開発者に正確に説明できます。

バグを見つけやすくなり、混乱を減らすことができます。

誰もが多項式、幾何学、または代数さえ覚えているわけではありません:)しかし、バージョン管理にチェックインされた優れた単体テストは私にとって覚えています。

ドキュメントとしてどのように役立つかについての例は、Jasmineの紹介をご覧ください。 http://jasmine.github.io/Edge/introduction.html ロードに数秒待ってから、スクロールしてください底に。単体テストの出力として文書化されたJasmine API全体が表示されます。

[@Warboからのフィードバックに基づいて更新]テストは最新の状態であることが保証されています。最新でない場合、テストは失敗します。CIが使用されている場合、通常、ビルドが失敗します。外部ドキュメントはコードとは関係なく変更されるため、必ずしも最新のものではありません。

12
Brandon

リアリティチェック

私は、予算編成とスケジュールの間にテストが「時間の無駄」であり、顧客がバグに対処すると「品質保証の基本的な部分」であるという厳しい環境にあったので、私の意見は他の意見よりも流動的です。

予算があります。あなたの仕事は、あなたがその予算でできる最高の製品を手に入れることです。あなたが一緒にこすることができる「最高」のどんな定義に対しても(それは定義するのが簡単な言葉ではありません)。話の終わり。

テストはaインベントリのツールです。あなたはそれを使うべきですそれは良いツールだからです、何百万、あるいはおそらく何十億ドルも節約した長い歴史を持つ。機会があれば、これらの単純な関数にテストを追加する必要があります。それはいつかあなたの肌を救うかもしれません。

しかし、現実の世界では、予算とスケジュールの制約があるため、それは起こらないかもしれません。自分を手順の奴隷にしないでください。テスト機能はいいですが、ある時点で、コードよりも言葉で開発者用ドキュメントを書く方が工数を費やすので、次の開発者はそれほどテストを必要としません。または、コードベースのリファクタリングに費やした方がよい場合があるため、難しい獣を維持する必要はありません。または、その時間を上司に予算とスケジュールについて話し合って、次のラウンドの資金調達が終わったときに彼らが何に入札するのかをよりよく理解できるようにするほうがよいでしょう。

ソフトウェア開発はバランスです。あなたが時間を費やすより良い方法がなかったことを確実にするために、あなたがしていることの機会費用を常に数えてください。

2
Cort Ammon

はい、テストを実行し、実行し続け、合格します。

ユニットテストは、自分(および他の人)を自分(および自分自身)から保護するためにあります。

なぜテストを続けるのが良い考えなのか。

  • 新しい要件と追加機能に直面して以前の要件の機能を検証する
  • リファクタリングの演習が正しいことを確認する
  • 内部ドキュメント-これは、コードの使用が想定される方法です
  • 回帰テスト、状況の変化
    • 変更により古いコードが壊れますか?
    • 変更には、現在の関数またはコードに対する追加の変更要求または更新が必要ですか?
  • テストはすでに書かれているので、そのままにしておいてください。すでに費やされた時間と費用により、将来的にメンテナンスコストが削減されます
0
Niall