TDDが役に立たなかったときに、コードの論理的な間違いを避ける方法は?


67

私は最近、イベントがどれくらい古いかを人間に優しい方法で示す小さなコードを書いていました。たとえば、イベントが「3週間前」または「1か月前」または「昨日」に発生したことを示すことができます。

要件は比較的明確であり、これはテスト駆動開発に最適なケースでした。テストを1つずつ作成し、各テストに合格するコードを実装しましたが、すべてが完全に機能するように見えました。本番でバグが現れるまで。

関連するコードは次のとおりです。

now = datetime.datetime.utcnow()
today = now.date()
if event_date.date() == today:
    return "Today"

yesterday = today - datetime.timedelta(1)
if event_date.date() == yesterday:
    return "Yesterday"

delta = (now - event_date).days

if delta < 7:
    return _number_to_text(delta) + " days ago"

if delta < 30:
    weeks = math.floor(delta / 7)
    if weeks == 1:
        return "A week ago"

    return _number_to_text(weeks) + " weeks ago"

if delta < 365:
    ... # Handle months and years in similar manner.

テストでは、今日、昨日、4日前、2週間前、1週間前などに発生するイベントのケースをチェックし、それに応じてコードをビルドしました。

私が逃したことは、イベントは昨日の前日に発生する可能性があり、1日前であるということです:例えば、26時間前に発生するイベントは1日前であり、今が午前1時であれば正確には昨日ではありません何かですが、deltaは整数であるため、1つになります。この場合、アプリケーションには「1日前」と表示されますが、これは明らかに予期せず、コードでは処理されません。以下を追加することで修正できます。

if delta == 1:
    return "A day ago"

を計算した直後delta

バグの唯一の否定的な結果は、このケースがどのように発生するのか疑問に思って30分浪費したことです(そして、コードでUTCが均一に使用されているにもかかわらず、タイムゾーンに関係していると信じています)が、その存在は私を悩ませています。次のことを示しています。

  • このような単純なソースコードであっても、論理的な間違いを犯すのは非常に簡単です。
  • テスト駆動開発は役に立ちませんでした。

また、気になるのは、このようなバグを回避する方法がわからないことです。コードを書く前にもっと考えることは別として、私が考えることができる唯一の方法は、決して起こらないと信じるケース(1日前は必然的に昨日だと思っていたように)に多くのアサートを追加し、それから毎秒ループすることです過去10年間、アサーション違反をチェックします。これは複雑すぎるようです。

そもそもこのバグを作成しないようにするにはどうすればよいですか?


38
テストケースを用意することで?それはあなたが後でそれを発見した方法のようで、TDDとメッシュします。
18

63
私がテスト駆動開発のファンではない理由を経験したばかりです-私の経験では、実稼働環境で検出されたほとんどのバグは誰も考えていないシナリオです。テスト駆動開発と単体テストはこれらに対して何もしません。(ただし、単体テストには、将来の編集を通じて導入されたバグを検出する価値があります。)
ローレンペクテル

102
私の後に繰り返します:「TDDを含む、特効薬はありません。」完璧なコードを生成するためにロボットで追跡できるプロセス、ルールセット、アルゴリズムはありません。あれば、プロセス全体を自動化して完了できます。
jpmc26

43
おめでとうございます、あなたはテストがバグの不在を証明できないという古い知恵を再発見しました。ただし、可能な入力ドメインのより良いカバレッジを作成するための手法を探している場合は、ドメイン、エッジケース、およびそのドメインの等価クラスを徹底的に分析する必要があります。TDDという用語が発明される前に古くから知られているすべての古い、よく知られた技術。
Doc Brown

80
私は陰気になろうとはしていませんが、あなたの質問は一見「自分が考えていないことをどう思いますか」と言い換えることができます。それがTDDとどう関係するのかわかりません。
ジャレッドスミス

回答:


57

これらは、赤/緑/リファクタリングのリファクタリング手順で通常見られる種類のエラーです。そのステップを忘れないでください!次のようなリファクタリングを検討してください(未テスト):

def pluralize(num, unit):
    if num == 1:
        return unit
    else:
        return unit + "s"

def convert_to_unit(delta, unit):
    factor = 1
    if unit == "week":
        factor = 7 
    elif unit == "month":
        factor = 30
    elif unit == "year":
        factor = 365
    return delta // factor

def best_unit(delta):
    if delta < 7:
        return "day"
    elif delta < 30:
        return "week"
    elif delta < 365:
        return "month"
    else:
        return "year"

def human_friendly(event_date):
    date = event_date.date()
    today = now.date()
    yesterday = today - datetime.timedelta(1)
    if date == today:
        return "Today"
    elif date == yesterday:
        return "Yesterday"
    else:
        delta = (now - event_date).days
        unit = best_unit(delta)
        converted = convert_to_unit(delta, unit)
        pluralized = pluralize(converted, unit)
        return "{} {} ago".format(converted, pluralized)

ここでは、より低レベルの抽象化で3つの関数を作成しました。これらの関数は、まとまりがあり、単独でテストするのが簡単です。意図した期間を省略した場合、より単純なヘルパー関数の親指のように突き出ます。また、重複を削除することにより、エラーの可能性を減らします。壊れたケースを実装するには、実際コードを追加する必要があります。

このようなリファクタリングされたフォームを見ると、他のより微妙なテストケースも容易に思い浮かびます。たとえば、負のbest_unit場合deltaはどうすればよいですか?

言い換えれば、リファクタリングはそれをきれいにするためだけのものではありません。これにより、コンパイラーができないエラーを人間が見つけやすくなります。


12
次のステップは国際化であり、そこpluralizeでは英語の単語のサブセットのみで作業することは不利になります。
デュプリケータ

@Deduplicatorは確かですが、ターゲットとする言語/文化に応じて、pluralize使用numunitて、何らかのキーを作成して、テーブル/リソースファイルからフォーマット文字列を取得するだけで済む可能性があります。または、異なるユニットが必要なため、ロジックを完全に書き直す必要があるかもしれません;
ハルク

4
このリファクタリングでも問題が残ります。つまり、「昨日」は朝の非常に早い時間(12:01直後)にはあまり意味がないということです。人間に優しい言葉で言えば、午後11時59分に発生したことは、時計が真夜中を過ぎても「今日」から「昨日」に突然変わることはありません。代わりに、「1分前」から「2分前」に変わります。「今日」は数分前に起こったことに関してはあまりにも粗く、「昨日」は夜更かしに問題を抱えています。
デビッドハンメン

@DavidHammenこれは使いやすさの問題であり、どの程度正確である必要があるかによって異なります。少なくとも1時間まで知りたい場合、「昨日」は良いとは思わないでしょう。「24時間前」はより明確で、時間数を強調するために一般的に使用される人間の表現です。「人間にやさしい」ようにしようとしているコンピューターは、ほとんど常にこの間違いを犯し、あまりにもあいまいな「昨日」に過度に一般化します。しかし、これを知るには、ユーザーにインタビューして、彼らの考えを確認する必要があります。正確な日付と時刻が必要な場合は、「昨日」は常に間違っています。
ブランディン

149

テスト駆動開発は役に立ちませんでした。

「1日前」のシナリオのテストがなかったというだけで、助けになったようです。おそらく、このケースが見つかった後にテストを追加しました。これはまだTDDです。バグが見つかったら、ユニットテストを作成してバグを検出し、修正します。

動作のテストを記述するのを忘れた場合、TDDには何の助けもありません。テストを書くのを忘れてしまい、実装を書かないでください。


2
開発者がtddを使用していなかった場合、他のケースも見逃す可能性がはるかに高いということを指摘できます。
カレブ

75
それに加えて、バグを修正するときにどれだけの時間を節約したかを考えてください。既存のテストを実施することで、彼らは変更が既存の動作を壊さないことを即座に知りました。そして、後で大規模な手動テストを実行することなく、新しいテストケースを追加してリファクタリングすることができました。
カレブ

15
TDDは、書かれたテストと同じくらい優れています。
マインドウィン

別の観察:このケースにテストを追加datetime.utcnow()すると、関数からそれを取り出すように強制し、代わりにnow(再現可能な)引数として渡すことにより、設計が改善されます。
トビー・スペイト

114

26時間前に発生するイベントは1日前になります

問題の定義が不十分な場合、テストはあまり役に立ちません。カレンダーの日と時間で計算される日が混在していることは明らかです。カレンダーの日付に固執する場合、午前1時、26時間前は昨日ではありません。そして、時間に固執する場合、26時間前は時間に関係なく1日前に丸められます。


45
これは素晴らしいポイントです。要件が欠けていても、必ずしも実装プロセスが失敗したことを意味するわけではありません。それは、要件が明確に定義されていなかったことを意味します。(または、たまたま発生する人為的なミスをしただけです)
カレブ

これは私がしたかった答えです。仕様を「イベントがこの暦日であった場合、デルタを時間単位で提示します。それ以外の場合はデルタを決定するためにのみ日付を使用します」。
Baldrickk

1
私はこの答えが好きです。なぜなら実際の問題を指摘しているからです。つまり、時刻と日付は2つの異なる量です。それらは関連していますが、それらを比較し始めると、物事は急速に進みます。プログラミングでは、日付と時刻のロジックを正しく設定するのが最も困難なことです。多くのdateimplementationが基本的に0:00の時点として日付を保存することを本当に嫌います。それは多くの混乱をもたらします。
ピーターB

38

できません。TDDは、認識している可能性のある問題からユーザーを保護するのに最適です。あなたが考慮したことがない問題に遭遇した場合、それは役に立ちません。あなたの最善の策は、他の誰かにシステムをテストしてもらうことです。彼らはあなたが考えたことのないエッジケースを見つけるかもしれません。

関連資料: 大規模なソフトウェアでバグの絶対的なゼロ状態に達することは可能ですか


2
開発者以外の誰かがテストを作成することは常に良い考えです。つまり、両方の関係者がバグを本番にするには同じ入力条件を見落とす必要があるということです。
マイケルケイ

35

私が普段取っている2つのアプローチがあります。

まず、エッジケースを探します。これらは、動作が変わる場所です。あなたの場合、行動は正の整数日のシーケンスに沿ったいくつかのポイントで変化します。ゼロ、1、7などにエッジケースがあります。その後、エッジケースとその周辺にテストケースを記述します。-1日、0日、1時間、23時間、24時間、25時間、6日、7日、8日などにテストケースがあります。

2つ目は、行動のパターンです。数週間のロジックでは、1週間の特別な処理があります。おそらく、表示されていない他の各間隔にも同様のロジックがあります。ただし、このロジックは数日間存在しません。そのケースがなぜ異なるのかを検証可能に説明するか、ロジックを追加するまで、私は疑いを持ってそれを見ます。


9
これは、しばしば見過ごされているTDDの本当に重要な部分であり、私はめったに記事やガイドに語らなかっ見てきました-それはだ本当に私はそれがバグの90%の源だ見つけるとエッジケースと境界条件をテストすることが重要-のバイ-1つのエラー、
オーバーフロー

2
@GoatInTheMachine -それらの90%のバグの90%が.....夏時間への移行の周りにあるはは
カレブ

1
最初に可能なクラス等価クラスに分割し、次にクラスの境界でエッジケースを決定できます。私たちのこれは、開発努力よりも大きな努力です。それが価値があるかどうかは、可能な限りエラーのないソフトウェアを提供することがどれだけ重要か、期限は何であるか、そしてどれだけのお金と忍耐があるかによって決まります。
ピーター-モニカの復活

2
これは正解です。多くのビジネスルールでは、値の範囲を異なる方法で処理される場合の間隔に分割する必要があります。
abuzittin gillifirca

14

あなたはできません TDDとの要件に存在する論理エラーをキャッチ。それでも、TDDは役立ちます。結局、エラーを見つけて、テストケースを追加しました。しかし基本的に、TDD はコードがメンタルモデルに適合することのみを保証します。あなたのメンタルモデルに欠陥がある場合、テストケースはそれらをキャッチしません。

ただし、バグを修正すると同時に、既存の機能する動作が壊れていないことを確認したテストケースを念頭に置いてください。これは非常に重要です。1つのバグを修正することは簡単ですが、別のバグを導入することは簡単です。

これらのエラーを事前に見つけるには、通常、等価クラスベースのテストケースを使用します。この原則を使用すると、すべての等価クラスから1つのケースを選択し、次にすべてのエッジケースを選択します。

各等価クラスの例として、今日、昨日、数日前、正確に1週間前、数週間前の日付を選択します。日付をテストするときは、テストでシステム日付が使用されていないことを確認しますが、比較には事前に決められた日付を使用します。これは、いくつかのエッジケースも強調します。1日の任意の時刻にテストを実行し、真夜中の直後、真夜中の直前、さらに真夜中にテストを実行するようにします。これは、テストごとに、テスト対象の4つの基本時間があることを意味します。

次に、他のすべてのクラスにエッジケースを体系的に追加します。今日のテストがあります。そのため、動作が切り替わる直前と直後に時間を追加します。昨日も同じです。1週間前などでも同じ

可能性としては、すべてのエッジケースを体系的に列挙し、それらのテストケースを書き留めることで、仕様に詳細が欠けていることがわかり、それを追加します。日付を処理することは、人々がしばしば間違えるものであることに注意してください。なぜなら、人々はしばしば異なる時間で実行できるようにテストを書くことを忘れるからです。

ただし、私が書いたことのほとんどはTDDとはほとんど関係がないことに注意してください。同等クラスを書き留め、独自の仕様がそれらについて十分に詳細であることを確認することについてです。それが論理エラーを最小限に抑えるプロセスです。TDDは、コードがメンタルモデルに準拠していることを確認するだけです。

テストケースを見つけるのは難しいです。同等クラスに基づくテストはすべての終わりではなく、場合によってはテストケースの数を大幅に増やすことができます。現実の世界では、これらのテストをすべて追加することは、多くの場合、経済的に実行可能ではありません(理論的には実行する必要があります)。


12

私が考えることができる唯一の方法は、私が決して起こらないと信じているケースに多くの主張を追加することです(1日前は必然的に昨日だと思っていたように)、そして過去10年間、毎秒ループして、アサーション違反。これは複雑すぎるようです。

何故なの?これはかなり良いアイデアのように聞こえます!

コードにコントラクト(アサーション)を追加することは、その正確性を改善するための非常に堅実な方法です。通常、それらを関数のエントリの前提条件および関数のリターンの事後条件として追加します。例えば、我々は、すべての値が返されたことを事後追加することができますいずれか「[番号] [単位]は前S」「A [単位]前」フォームのかを。規律ある方法で行われた場合、これは契約による設計につながり、高保証コードを記述する最も一般的な方法の1つです。

重大なことに、契約はテストすることを意図したものではありません。これらは、テストと同じくらいコードの仕様です。ただし、コントラクトを介してテストできます。テスト内のコードを呼び出し、どのコントラクトでもエラーが発生しない場合、テストはパスします。過去10年間のすべての秒をループするのは少しばかりです。ただし、プロパティベースのテストと呼ばれる別のテストスタイルを活用できます

PBTでは、コードの特定の出力をテストする代わりに、出力が何らかのプロパティに従うことをテストします。例えば、のいずれかのプロパティreverse()機能は、任意のリストのためということでlreverse(reverse(l)) = l。このようなテストを書く利点は、PBTエンジンに数百の任意のリスト(およびいくつかの病理学的なリスト)を生成させ、それらすべてにこのプロパティがあることを確認できることです。そうでない場合、エンジンは失敗したケースを「縮小」して、コードを壊す最小限のリストを見つけます。Pythonを書いているように見えますが、これはメインのPBTフレームワークとして仮説を持っています。

したがって、考えられないかもしれないよりトリッキーなエッジケースを見つける良い方法が必要な場合は、コントラクトとプロパティベースのテストを一緒に使用すると非常に役立ちます。もちろん、これは単体テストの作成に取って代わるものではありませんが、それを補強するものであり、エンジニアとして実際にできることです。


2
これはまさにこの種の問題に対する正しい解決策です。有効な出力のセットは簡単に定義できます(非常に単純な正規表現を与えることができます/(today)|(yesterday)|([2-6] days ago)|...)。次に、期待される出力のセットにない入力が見つかるまで、ランダムに選択した入力でプロセスを実行できます。このアプローチを取ることでしょう、このバグをキャッチしている、とないだろうバグが事前に存在する可能性があることを実現する必要があります。
ジュール

@Jules プロパティのチェック/テストも参照してください。私は通常、開発中にプロパティテストを作成して、予想外のケースをできるだけ多くカバーし、一般的なプロパティ/不変条件について考えさせます。回帰などの1回限りのテストを保存します(著者の問題はその例です)
Warbo

1
テストでそれほど多くのループを実行すると、非常に長い時間がかかり、ユニットテストの主な目標の1つであるテストを高速で実行できなくなります。
CJデニス

5

これは、少しモジュール性を追加すると便利だった例です。エラーが発生しやすいコードセグメントを複数回使用する場合は、可能であればそれを関数でラップすることをお勧めします。

def time_ago(delta, unit):
    delta_str = _number_to_text(delta) + " " + unit;
    if delta == 1:
        return delta_str + " ago"
    else:
        return delta_str = "s ago"

now = datetime.datetime.utcnow()
today = now.date()
if event_date.date() == today:
    return "Today"

yesterday = today - datetime.timedelta(1)
if event_date.date() == yesterday:
    return "Yesterday"

delta = (now - event_date).days

if delta < 7:
    return time_ago(delta, "day")

if delta < 30:
    weeks = math.floor(delta / 7)
    return time_ago(weeks, "week")

if delta < 365:
    months = math.floor(delta / 31)
    return time_ago(months, "month")

5

テスト駆動開発は役に立ちませんでした。

テストを書いている人が敵対者である場合、TDDはテクニックとして最適に機能します。ペアプログラミングではない場合、これは難しいので、これについて考える別の方法は次のとおりです。

  • テスト中の関数が作成したとおりに機能することを確認するためのテストを作成しないでください。それを意図的に破るテストを書いてください。

これは、TDDの有無にかかわらず正しいコードの作成に適用される別の技術であり、実際にコードを作成するよりもおそらく(そうでないとしても)複雑なものです。それはあなたが練習する必要があるものであり、その何かは単一の、簡単で、単純な答えではありません。

堅牢なソフトウェアを作成するためのコアテクニックは、効果的なテストを作成する方法を理解するためのコアテクニックでもあります。

関数の前提条件-有効な状態(つまり、関数がメソッドであるクラスの状態についてどのような仮定を立てているか)および有効な入力パラメーターの範囲を理解する-各データ型には可能な値の範囲があります-そのサブセット関数によって処理されます。

関数の入力時にこれらの仮定を明示的にテストし、違反が記録またはスローされること、および/またはそれ以上の処理を行わずに関数エラーが発生することを確認する以外に何もしない場合、ソフトウェアが本番で失敗しているかどうかをすぐに知ることができますエラー耐性があり、敵対者のテスト作成スキルを向上させます。


NB。事前条件と事後条件、不変条件などに関するすべての文献と、属性を使用してそれらを適用できるライブラリがあります。個人的に私はそれほど正式に行くのが好きではありませんが、検討する価値があります。


1

これは、ソフトウェア開発に関する最も重要な事実の1つです。バグのないコードを書くことは絶対に不可能です。

TDDを使用しても、考えていないテストケースに対応するバグが発生することはありません。また、気付かないうちに不正確なテストを書いて、バグのあるテストに合格する不正確なコードを書くことからあなたを救うことはありません。そして、これまでに作成された他のすべてのソフトウェア開発手法には、同様の穴があります。開発者として、私たちは不完全な人間です。結局のところ、100%バグのないコードを書く方法はありません。それは決して起こらず、決して起こりません。

これは、あなたが希望を捨てるべきだと言うことではありません。完全に完璧なコードを書くことは不可能ですが、ソフトウェアが非常に実用的であるようなまれなエッジケースに現れるバグがほとんどないコードを書くことは非常に可能です。実際にはバグのある動作示さないソフトウェアを書くことは非常に可能です。

しかし、それを書くには、バグのあるソフトウェアを作成するという事実を受け入れる必要があります。ほとんどすべての最新のソフトウェア開発プラクティスは、バグが最初に現れるのを防ぐか、必然的に生じるバグの結果から自分自身を保護するかのいずれかを中心に構築されています。

  • 徹底的な要件を収集することで、コード内の不正な動作を確認できます。
  • クリーンで慎重に設計されたコードを記述すると、最初にバグが発生するのを避けやすくなり、バグを特定するときにバグを修正しやすくなります。
  • テストを書くことで、ソフトウェアで起こりうる最悪のバグの多くがどのようなものであるかを記録し、少なくともそれらのバグを回避できることを証明できます。TDDはコードの前にそれらのテストを生成し、BDDは要件からそれらのテストを導き出し、旧式のユニットテストはコードの記述後にテストを生成しますが、これらはすべて将来の最悪の回帰を防ぎます。
  • ピアレビューとは、コードが変更されるたびに、少なくとも2組の目がコードを見ていることを意味し、バグがマスターにスリップする頻度を減らします。
  • バグトラッカーまたはバグをユーザーストーリーとして扱うユーザーストーリートラッカーを使用するということは、バグが発生したときに、それらを追跡し、最終的に対処することを意味します。
  • ステージングサーバーを使用するということは、メジャーリリースの前に、すべてのショーストッパーのバグが現れて対処する機会があることを意味します。
  • バージョン管理を使用すると、重大なバグを含むコードが顧客に出荷される最悪のシナリオで、事態を整理しながら緊急ロールバックを実行し、信頼できる製品を顧客の手に戻すことができます。

特定した問題の究極の解決策は、バグのないコードを書くことを保証できないという事実と戦うことではなく、それを受け入れることです。開発プロセスのすべての分野で業界のベストプラクティスを採用すれば、完璧ではないものの、仕事に十分耐えられるコードをユーザーに一貫して提供できます。


1

あなたは以前にこのケースについて考えたことがなかったため、そのためのテストケースを持っていませんでした。

これは常に発生し、正常なことです。すべての可能なテストケースを作成するのにどれだけの労力を費やすかは、常にトレードオフになります。すべてのテストケースを検討するのに無限の時間を費やすことができます。

航空機の自動操縦では、単純なツールよりもはるかに多くの時間を費やします。

入力変数の有効な範囲について考え、これらの境界をテストすることがしばしば役立ちます。

さらに、テスターが開発者とは異なる人物である場合、多くの場合、より重要なケースが見つかります。


1

(そして、コードでUTCが均一に使用されているにもかかわらず、タイムゾーンに関係していると信じています)

これは、ユニットテストをまだ行っていないコードのもう1つの論理的な間違いです。)-メソッドは、UTC以外のタイムゾーンのユーザーに対して誤った結果を返します。計算する前に、「今」とイベントの日付の両方をユーザーのローカルタイムゾーンに変換する必要があります。

例:オーストラリアでは、現地時間の午前9時にイベントが発生します。UTC日付が変更されたため、午前11時に「昨日」と表示されます。


0
  • 他の人にテストを書かせてください。このようにして、実装に不慣れな人が、あなたが考えていないまれな状況をチェックするかもしれません。

  • 可能であれば、テストケースをコレクションとして挿入します。これにより、次のような行を追加するのと同じくらい簡単に別のテストを追加できyield return new TestCase(...)ます。これは、「1週間前のすべての秒でコードが返すものを見てみましょう」というテストケースの作成を自動化する探索的テストの方向に進むことができます。


0

すべてのテストに合格した場合、バグはないと誤解されているように見えます。実際には、すべてのテストに合格した場合、既知の動作はすべて正しいです。未知の動作が正しいかどうかはまだわかりません。

うまくいけば、TDDでコードカバレッジを使用しています。予期しない動作の新しいテストを追加します。次に、予期しない動作のテストだけを実行して、コードを実際に通過するパスを確認できます。現在の動作がわかったら、それを修正するために変更を加えることができます。すべてのテストに再び合格すると、適切に実行したことがわかります。

これは、コードにバグがないことを意味するものではなく、以前よりも優れているということだけでなく、既知の動作がすべて正しいということです!

TDDを正しく使用するということは、バグのないコードを書くことを意味するのではなく、書くバグが少なくなるということです。あなたは言う:

要件は比較的明確でした

これは、要件で1日以上ではなく1日以上の動作が指定されたことを意味しますか?書面による要件を逃した場合、それはあなたの責任です。コーディング中に要件が不完全であることに気付いた場合、良いことです!要件に取り組んだすべての人がそのケースを逃した場合、あなたは他の人より悪くありません。誰もが間違いを犯し、それらが微妙であればあるほど、見逃しやすくなります。ここで重要なことは、TDD すべてのエラーを防ぐわけではないということです!


0

このような単純なソースコードであっても、論理的な間違いを犯すのは非常に簡単です。

はい。テスト駆動開発はそれを変えません。それでも、実際のコードとテストコードにバグを作成できます。

テスト駆動開発は役に立ちませんでした。

ああ、でもやった!まず第一に、バグに気付いたとき、あなたはすでに完全なテストフレームワークを配置しており、テストのバグ(および実際のコード)を修正する必要がありました。第二に、最初にTDDを実行していなかった場合に、さらに多くのバグがあったことを知りません。

また、気になるのは、このようなバグを回避する方法がわからないことです。

できません。NASAでさえ、バグを回避する方法を見つけていません。私たちより少ない人間もそうではありません。

コードを書く前にもっと考えることは別として、

それは誤りです。TDDの最大の利点の1つは、より少ない思考でコーディングできることです。これらのすべてのテストは、少なくとも回帰をかなりよくキャッチするからです。また、特にTDDを使用する場合でも、そもそもバグのないコードを提供することは期待されていません(または、開発速度が低下するだけです)。

私が考えることができる唯一の方法は、決して起こらないと信じているケースに多くの主張を追加することです(1日前は必然的に昨日だと思っていたように)、そして過去10年間、毎秒ループしてアサーション違反。これは複雑すぎるようです。

これは、現在実際に必要なものだけをコーディングするという教義と明らかに矛盾します。あなたはそれらのケースが必要だと思ったので、そうでした。これは重要ではないコードです。あなたが言ったように、あなたは30分間それについて不思議に思っていることを除いて損害はなかった。

ミッションクリティカルなコードの場合、実際にあなたが言ったことを行うことができますが、日常の標準コードではできません。

そもそもこのバグを作成しないようにするにはどうすればよいですか?

あなたはしません。テストを信頼して、ほとんどのリグレッションを見つけます。red-green-refactor-cycleを維持し、実際のコーディングの前/実行中にテストを作成し、(重要!)red-greenスイッチを作成するために必要な最小限の量を実装します(それ以上でもそれ以上でもありません)。これにより、少なくとも肯定的なテストカバレッジが得られます。

バグが見つかった場合ではなく、そのバグを再現するテストを作成し、最小限の作業でバグを修正して、テストを赤から緑に変更します。


-2

どんなに一生懸命努力しても、コード内の考えられるすべてのバグをキャッチすることはできないことを発見しました。

つまり、これは、すべてのバグをキャッチしようとしても無駄になるということです。したがって、0バグではなく、より優れたコード、より少ないバグを持つコードを記述する方法として、TDDなどの手法のみを使用する必要があります。

つまり、これらの手法を使用する時間を短縮し、開発ネットをすり抜けるバグを見つけるための代替方法に費やす時間を節約する必要があります。

統合テストやテストチームなどの代替手段、システムテスト、ログの記録と分析。

すべてのバグをキャッチできない場合は、すり抜けるバグの影響を軽減するための戦略を立てる必要があります。とにかくこれを行う必要がある場合、最初からそれらを停止しようとする(無駄に)ことを試みるよりも、これに多くの労力をかける方が理にかなっています。

結局のところ、テストの作成に大金を費やしても無意味であり、顧客に製品を提供した最初の日は、特にそのバグを見つけて解決する方法がわからない場合は、倒れます。事後分析および配信後のバグ解決は非常に重要であり、ほとんどの人が単体テストの作成に費やすよりも注意が必要です。複雑な部分の単体テストを保存し、前もって完璧にしようとしないでください。


これは非常に敗北です。That in turn means you should spend less time using these techniques-しかし、あなたはそれがより少ないバグで役立つと言っただけですか?!
JᴀʏMᴇᴇ

@JᴀʏMᴇᴇあなたが最もあなたのbuck.Iのために強打を取得します彼らは自分のコードにしたより、彼らはテストを書く10回を費やすことを誇りに思っている、人を知っている技術で、より実践的な態度と、彼らはまだバグが持っているそうであること賢明ではなく、独断的に、テスト技術については不可欠です。とにかく統合テストを使用する必要があるため、単体テストよりも統合テストに力を入れてください。
gbjbaanb
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.