私はTDDを間違っていました、そして、あなたは


私は最近ケントベックによってテスト駆動された開発本を読んでいました、そして、私がTDD間違っていたことを理解するために、それは私を長く連れて行きません.私は数年前にこの練習を始めました、そして、私はそれが間違った方法をしている私の最も野生の夢で決して考えなかったでしょう、しかし、私はここにいます.
最初にTDDの原則を修正しましょう.
  • 失敗したテストを書く
  • テストをパスするために最低限のコードを書き込む
  • 重複を削除する
  • 私が完全に間違っていたことは、ステップ2と3でした.

    TDDを行う間違った方法
    簡単なfizzbuzzの例を取ることを説明する.また、これを実行する前にこのカタの要件を見てみましょう.
  • 数の代わりに、数の代わりに「フィズ」を印刷してください
  • 5の倍数については、「バズ」を印刷してください
  • 3と5の倍数である数のために、印刷
    そこで、テストクラスを作成し、最初の失敗テストを書きます.
  • import XCTest
    
    class FizzBuzzTests: XCTestCase {
    
      func test_it_returns_fizz_for_multiple_of_three() {
        [3, 6, 9, 12].forEach {
          XCTAssertEqual("fizz", FizzBuzz.convert($0))
        }
      }
    
    }
    
    この段階では、コードもFizzBuzzと呼ばれるクラスや構造がないのでコンパイルされません.先に行きましょう.
    struct FizzBuzz {
    
    }
    
    また、変換メソッドがないのでコンパイルしません.
    struct FizzBuzz {
    
      static func convert(_ number: Int) -> String {    
    
      }
    
    }
    
    この時点で、“string”を返すと予想される関数の戻り値が不足しているというエラーが1つだけあります.
    今、私はTDDを行う間違った部分(私はそれを今でもTDDと呼ぶことができません)、恥を私に🤧), この方法の具体的な実装を直接以下のようにします.
    struct FizzBuzz {
    
      static func convert(_ number: Int) -> String {
        if number % 3 == 0 { return "fizz" }
        return ""
      }
    
    }
    
    今、私はコンパイルエラーがありません、そして、私がテストを実行するならば、それは正常に通ります、そして、あなたは私の顔に微笑を見ることができます.残りのテストを書き続けましょう.
    import XCTest
    
      func test_it_returns_fizz_for_multiple_of_three() {
        [3, 6, 9, 12].forEach {
          XCTAssertEqual("fizz", FizzBuzz.convert($0))
        }
      }
    
      func test_it_returns_buzz_for_multiple_of_five() {
        [5, 10, 20, 25].forEach {
          XCTAssertEqual("buzz", FizzBuzz.convert($0))
        }
      }
    
      func test_it_returns_fizzbuzz_for_multiple_of_three_and() {
        [15, 30, 45, 60].forEach {
          XCTAssertEqual("fizzbuzz", FizzBuzz.convert($0))
        }
      }
    
      func test_it_returns_the_original_number_if_not_divisible_by_three_or_five() {
        [1, 2, 4, 7].forEach {
          XCTAssertEqual("\($0)", FizzBuzz.convert($0))
        }
      }
    
    }
    
    では、すべてのテストをパスさせる完全なstructを書きましょう.
    struct FizzBuzz {
    
      static func convert(_ number: Int) -> String {
        if number % 3 == 0 && number % 5 == 0 { return "fizzbuzz" }
        if number % 3 == 0 { return "fizz" }
        if number % 5 == 0 { return "buzz" }
        return "\(number)"
      }
    
    }
    
    テストを実行すると、彼らはすべて合格する.私にとっては、失敗したテストを書いたので、テストを通過するコード(たとえ緑になるために必要なコードの最小量ではないとしても)、そして3番目のステップについては、リファクタリング段階を書いたので、これは完全に正しいものでした.さて、たぶんこんな感じでしょう.
    struct FizzBuzz {
    
      static func convert(_ number: Int) -> String {
        var result = ""
        if number % 3 == 0 { result += "fizz" }
        if number % 5 == 0 { result += "buzz" }
        return result.count > 0 ? result : "\(number)"
      }
    
    }
    
    私たちが同じ数の線を持っていても、テストはまだセクシーに見えます.この時点で、私はすべて幸せです、そして、私は1日それを呼びます.
    これはTDDがどのように働くかということではありません.これは失敗したテストを書いて、それを通過させるだけのサイクルです.ステップ2については、テストパスを作るために必要なコードの最小量を記述する状態?そして、我々が複製を取り除くことによってリファクタリングすることになっているステップ3?
    しかし、1つの特定の問題が発生します“1つの特定の問題は、”コードが動作しても問題ですか?はい、それは私のためです.こうすることは確かに働くかもしれません、しかし、それはTDDの中心的な原則に違反しています、そして、ケントが彼の本で言いました:
    きれいな、単純な解決が明白であるならば、それを入力してください.これは、テストパスをできるだけ早くして再要因化しなければならないということです.さあ、TDDをやってみましょう.

    TDDの正しい方法を行う(偽のそれは、あなたがそれを作るまで)
    今、私はどのようにTDDの間違った方法をやっていた見てきた、物事が本当に動作する方法を見てみましょう.そのために、私は上記と同じ例を取るつもりです.
    最初のステップは失敗テストを書くことです.十分簡単.
    import XCTest
    
    class FizzBuzzTests: XCTestCase {
    
      func test_it_returns_fizz_for_multiple_of_three() {
        [3, 6, 9, 12].forEach {
          XCTAssertEqual("fizz", FizzBuzz.convert($0))
        }
      }
    
    }
    
    番目のステップは、テストパスを作成するために必要な最小のコードを記述することです(この1つについては、私は構造体を作成し、変換メソッドを使用して、上記のように具体的な実装を入力します).今回は、コードはこのようになります.
    struct FizzBuzz {
    
      static func convert(_ number: Int) -> String {
        return "fizz"
      }
    
    }
    
    テストを実行するとき、もちろん、それは通過します.私たちはできるだけ早くグリーンに行きました.はい、これは正しい実装ではありませんが、覚えて、私たちはできるだけ早く、何があっても緑に行きたい.
    番目のステップは、重複を削除するリファクタリングです.ハム、OK、しかし、このコードでは、どこで複製ですか?通常、2つのコードの間の重複が表示されますが、ここで重複はテストのデータとコードのデータの間にあります💡). そこで、コードを正しい実装で置き換えます.
    struct FizzBuzz {
    
      static func convert(_ number: Int) -> String {
        var result = ""
        if number % 3 == 0 { result += "fizz" }
        return result.count > 0 ? result : "\(number)"
      }
    
    }
    
    そして、残りのテストのために全サイクルを繰り返すことができます.このようにすることは、「偽のIT」を強力にする効果があります.
  • 心理的な:緑色のバーを持つことは、赤いバーを持つこととは全く異なる感じ.バーが緑であるとき、あなたはどこに立っているかについてわかっています.そこから自信を持ってリファクタリングできます.
  • スコープコントロール:プログラマは将来のあらゆる問題を想像するのが得意です.つの具体的な例から始めて、そこから一般化することは、あなたに早急な懸念であなた自身を早めに混乱させるのを防ぎます.あなたが集中しているため、すぐに問題を解決するより良い仕事をすることができます.次のテストケースを実装する場合は、前のテストが動作することが保証されていることを知って、その1つに集中できます.

  • 結論
    私が完全に逃した部分は、リファクタリング1であると思います.私は、できるだけ早く何かのスタブまたはモックを使用せずに正しい実装で物事をできるようにすることによって閉じ込められました.二つ目のミスは、「リファクタ」という単語を聞いたとき、いつもコードを移動させることを意味していて、それがセクシーに見え、すべてがまだ動作しているかどうかを確かめるためにテストスイートを再実行していた.確かに、それはそのように考えてあなたを責めることができるリファクタリングですか?しかし、TDDの観点からは、単語の真の意味は、スタブ(一般的に一定の値)を削除し、正しい実装でそれらを置き換えることによって重複を削除することです.あなたがTDDについてもっと学びたいならば、私は非常にケントの本Amazon .