TDDでの赤ちゃんの歩数はどのくらいですか?


37

今日、私たちはTDDをトレーニングしていて、次の誤解のポイントを見つけました。

タスクは、入力 "1,2"が3である数値の合計を返すためのものです。(C#で)私が書いたのは:

numbers = input.Split(',');
return int.Parse(numbers[0]) + int.Parse(numbers[1]); //task said we have two numbers and input is correct

しかし、他の人はそれを別の方法で行うことを好みました。まず、入力 "1,2"について、次のコードを追加しました。

if (input == "1,2")
   return 3;

次に、入力 "4,5"のテストをもう1つ導入し、実装を変更しました。

if (input == "1,2")
   return 3;
else if (input == "4,5")
   return 9;

そしてその後、彼らは「さて、今はパターンが見える」と言って、私が最初にやったことを実装しました。

2番目のアプローチはTDDの定義により適していると思いますが、...厳密にすべきでしょうか?私にとっては、些細な赤ちゃんのステップをスキップして、何もスキップしないことを十分に確信している場合は、それらを「ツインステップ」に結合してもかまいません。私が間違っている?

更新。私はそれが最初のテストではないことを明確にしないことで間違いを犯しました。すでにいくつかのテストが行​​われているため、「return 3」は実際に要件を満たすための最も単純なコードではありませんでした。


25
私の同僚が「Ooahhh dazso cuuuuuute」を噴出するほど小さい
Adel

6
@アデル:朝食がほとんど詰まっていて、キーボードがいっぱいになっている、またはくしゃくしゃになっている
Binary Worrier

2
@Adel、非ネイティブスピーカーについては、このユーモアを理解することは私にとってかなり難しいですが、同僚が質問を好むと思います:)
SiberianGuy

8
@Idsa:子供たちの最初のステップ「Ooahhh dazso cuuuuuute」=「ああ、とてもかわいい」(歌、歌、非常にかわいい声で話された)が示されたとき、それは同僚の応答を置き換えますAdelによって書かれた単体テストを見て、単体テストの赤ちゃんのステップを見ると、「ああ、とてもかわいい」と言います。a-real-baby stepsへの反応=単体テスト「baby steps」への反応。
バイナリウォーリアー

3
@Binaryworrierは、私はあなたにparentessを説明するために時間を割いて本当のポイントを与えることがしたい
アンドリュー・T Finnell

回答:


31

テストに合格する最も簡単なコードを記述します。

私が見る限り、あなたのどちらもそうしなかった。

ベビーステップ1。

テスト:入力 "1,2"に対して、3である数値の合計を返します

テストを失敗させます。

throw NotImplementedException();

テストに合格する:

return 3;

ベビーステップ2。

テスト:入力 "1,2"に対して、3である数値の合計を返します

テスト:入力 "4,5"の場合、9である数値の合計を返します

2番目のテストは失敗するので、合格させます。

numbers = input.Split(',');
return int.Parse(numbers[0]) + int.Parse(numbers[1]);

(if ... returnのリストよりも簡単)

この場合、明らかな実装については間違いなく議論できますが、厳密に赤ちゃんのステップでそれを行うことについて話している場合、これらは正しいステップ、IMOです。

論点は、2番目のテストを書かないと、後から明るい火花が出て、コードを「リファクタリング」して読むことができるということです。

return input.Length; # Still satisfies the first test

そして、両方の手順を踏まずに、2番目のテストを赤くしたことはありません(テスト自体が疑わしいことを意味します)。


あなたのinput.Lengthの例については、同じ成功と私は両方のテストでキャッチされることはありませんいくつかの狂った間違った実装を想像することができます
SiberianGuy

@Idsa-はい、絶対に、そしてあなたが書くテストが多ければ多いほど、実装はもっと狂わなければなりません。input.Length特にメソッドへの入力がどこかのファイルからの測定値であり、誤ってmethodを呼び出した場合は、それほど取得されませんSize()
pdr

6
+1。TDDの学習方法に関しては、これが正しい方法です。一度学習すると、明白な実装に直接行くこともありますが、TDDの感覚をつかむには、これがはるかに優れています。
カールマナスター

1
「テスト」自体に関して質問があります。入力 "4,5"の新しいテストを作成するか、元のテストを変更しますか?
mxmissile

1
@mxmissile:新しいテストを作成します。それほど時間はかかりませんが、後でリファクタリングを行うときにあなたを保護するためのテストが2倍になります。
pdr

50

2番目の方法は、麻痺するほど愚かなことだと思います。私は十分に小さなステップを作成することの価値を理解していますが、それらの小さな接合子(赤ちゃんと呼ぶことさえできない)のステップを作成することは、単純で時間の無駄です。特に、あなたが解決しようとしている元の問題がそれ自身ですでに非常に小さい場合。

私はそれが訓練であり、原則を示すことについてより多くを知っています、しかし、私はそのような例が良いよりも悪いTDDを行うと思います。赤ちゃんの歩みの価値を示したいなら、少なくとも価値のある問題を使いましょう。


私が見上げると、新しい単語(愚か)を学習させるための+1と感謝
マージャンVenema氏

12
それを麻痺させるほど愚かだと言って+1。TDDはすべて素晴らしいものですが、現代の誇張されたプログラミング技術と同様に、迷子にならないように注意する必要があります。
stijn

2
「特に、あなたが解決しようとしている元の問題がそれ自身ですでに非常に小さい場合」-入力が一緒に追加される2つのintである場合、私はこれに同意しますが、「文字列を分割し、結果から2つのintを解析して追加する」と確信していません。現実の世界のほとんどの方法は、それよりもそれほど複雑ではありません。実際、2つのコンマ、非整数値などを見つけるなどのエッジケースをカバーするために、さらにテストが必要です。
pdr

4
@pdr:エッジケースを処理するために、さらにテストが必要だということに同意します。それらを記述し、実装を変更してそれらを処理する必要があることに気付いたときは、必ずそれを行います。私は、それを書き留めてそこから行くのではなく、最初の幸せな道、「明白な実装」への接合子のステップをとることに問題があると思います。私の体のすべての繊維が次の瞬間に消えるということを知っているというif文を書き出すことには価値がありません。
クリストフヴァンフレテレン

1
@ChristopheVanfleteren:ベックは明白実装を説明すると、彼は一例として、2つのintの合計を使用し、まだあなたがペア/レビューアが作るシンプルなコードと考えることができれば恥で死ぬつもりだ方法についての巨大な劇的な警告にスローテストパス。このシナリオのテストを1つだけ記述する場合、これは絶対的な確実性です。また、この問題を解決するための少なくとも3つの「明白な」方法を考えることができます:分割と追加、コンマを+に置き換えて評価する、または正規表現を使用する。TDDのポイントは、正しい選択に導くことです。
pdr

19

ケントベックは、彼の著書「Test Driven Development:By By Example」でこれを取り上げています。

あなたの例は「明白な実装」を示しています-あなたは合計2つの入力値を返したいです、そしてこれは達成するためのかなり基本的なアルゴリズムです。あなたの反例は、「あなたがそれを作るまで偽造する」ことになります(非常に単純なケースですが)。

明らかな実装はこれよりもはるかに複雑になる可能性があります-しかし、基本的にはメソッドの仕様が非常に厳しい場合に開始されます-たとえば、クラスプロパティのURLエンコードバージョンを返す-たくさんの時間を無駄にする必要はありません偽のエンコーディング。

一方、データベース接続ルーチンでは、もう少し考えてテストする必要があるため、明らかな実装はありません(すでに他のプロジェクトで何度か書いたとしても)。

本から:

私が実際にTDDを使用するとき、私は通常、これら2つの実装モードを切り替えます。すべてがスムーズに進み、入力するものがわかったら、私は明白な実装の後に明白な実装を入れます(私に明らかなことを確認するために毎回テストを実行します)コンピュータにはまだ明らかです)。予想外の赤いバーが表示されるとすぐに、バックアップを取り、実装を偽装し、適切なコードにリファクタリングします。自信が戻ったら、Obvious Implementationsに戻ります。


18

私はこれを法律の手紙に従っていると考えていますが、その精神ではありません。

赤ちゃんの手順は次のとおりです。

可能な限りシンプルですが、シンプルではありません。

また、メソッドの動詞は sum

if (input == "1,2")
   return 3;

合計ではなく、特定の入力のテストです。


4

私にとっては、いくつかの些細な実装手順をわずかに些細なものにまとめるのは問題ないようです-私もいつもそうしています。私は、TDDを毎回手紙に追うことについて信心深くする必要はないと思います。

OTOHこれは、上記の例のような本当に些細な手順にのみ適用されます。一度に完全に心に留めることができない、および/または結果について110%の確信がない場合、より複雑なものについては、一度に1ステップずつ進むことを好みます。


1

この質問が示すように、TDDの道を最初に設定するとき、ステップのサイズは混乱を招く問題になる可能性があります。テスト駆動型アプリケーションの作成を初めて開始したときによく尋ねた質問は次のとおりです。私が書いているテストは、アプリケーション開発の促進に役立ちますか?これは些細なことのように思えるかもしれませんが、一部とは関係ありませんが、しばらくは私と一緒にハングアップします。

これで、アプリケーションの作成に着手するとき、通常はテストから始めます。テストのステップのどれだけが、私がやろうとしていることの理解に大きく関係しています。クラスの振る舞いが頭の中でほとんどわかっていると思うなら、そのステップは大きなものになります。私が解決しようとしている問題があまり明確でない場合、ステップは単にXという名前のメソッドに行くことを知っていて、それがYを返すことです。この時点で、メソッドはパラメータさえも持たず、メソッドの名前と戻り値の型が変更される可能性があります。どちらの場合も、テストが私の開発を後押ししています。彼らは私のアプリケーションに関することを教えてくれます:

私の頭の中にあるこのクラスは実際に働くのでしょうか?

または

一体どうやってこんなことをするつもりなの?

ポイントは、瞬きで大きなステップと小さなステップを切り替えることができるということです。たとえば、大きなステップが機能せず、明確な方法がわからない場合は、小さなステップに切り替えます。それでもうまくいかない場合は、さらに小さなステップに切り替えます。それから、私が本当に行き詰まった場合、三角測量のような他のテクニックがあります。

私のようにあなたが開発者でありテスターではない場合、TDDを使用するポイントはテストを書くことではなく、コードを書くことです。小規模なテストにメリットが与えられない場合でも、大量の小さなテストの作成にこだわらないでください。

TDDを使ったトレーニングを楽しんでいただけたでしょうか。私見では、より多くの人々がテスト感染した場合、世界はより良い場所になります:)


1

単体テストに関する入門書では、同じアプローチ(本当に、本当に小さいように見えるステップ)を読み、「どれだけ小さいのか」という質問に対する答えとして、次のような(言い換え)が好きでした。

ステップが機能することの自信についてです。必要に応じて、本当に大きな一歩を踏み出すことができます。しかし、しばらく試してみれば、当然のことと思っている場所に多くの見当違いの自信を見つけるでしょう。したがって、テストは、事実に基づいた信頼を構築するのに役立ちます。

だから、多分あなたの同僚は少し恥ずかしがり屋です:)


1

テストが成功する限り、メソッドの実装が無意味であるという点ではありませんか?2番目の例では、テストの拡張はより速く失敗しますが、どちらの場合でも失敗するようにできます。


1
あなたが時間を無駄にすることを全く気にしないなら、それは無関係です
SiberianGuy

1

私は、どちらも最も単純な実装ではないと言っている人々に同意しています。

方法論が非常に厳密な理由は、可能な限り多くの関連するテストを書くことを義務付けているからです。1つのテストケースの定数値を返し、それをパスと呼ぶのは問題ありません。強制的に戻って、あなたが本当にあなたのプログラムからナンセンス以外のものを得るために欲しいものを指定することができます。このような些細なケースを使用すると、いくつかの点で自分自身を撃ちますが、原則は、「多すぎる」ことをしようとするときに仕様のギャップにミスが忍び込み、要件を可能な限りシンプルな実装にレンダリングすることですテストは、実際に必要な動作の固有の側面ごとに作成する必要があります。


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