テスト駆動開発を行っているときに、テストに基づいて生成されたコードによって仮想プログラムを完全に開発できるかどうかを考えました。つまり、テストに合格するためのコードを作成するジェネレーターを使用する機能はありますか。プログラミング言語の未来は、テストを書くことだけでしょうか?
3 に答える
少なくともそのような技術の最初の世代では、開発者は生成されたコードの正確性に非常に懐疑的であるため、これは難しい問題になると思います。したがって、人間のレビューも関与する必要があります。
私が言いたいことの簡単な例として、考えられるすべてのシナリオをカバーするサンプル入力と予想される出力を使用して、関数に対して 10 個のテストを作成するとします。プログラムは、初歩的な switch ステートメントだけで、これらすべてのテストに合格するコードを自明に生成できます (10 個の入力が、期待される出力と一致しました)。このコードは明らかに正しくありませんが、それを確認するには人間が必要です。
これは単純な例です。switch ステートメントを生成しないかもしれないが、実際には正しくない解決策を生成し、はるかに微妙な方法で間違っている可能性がある、より洗練されたプログラムを想像することは難しくありません。したがって、少なくとも最初は、これらの線に沿った技術は深いレベルの懐疑論に直面するだろうという私の提案.
コードを完全に生成できる場合、ジェネレーターの基礎は、コードを正確に記述する仕様でなければなりません。このジェネレーターは、ある言語を別の言語にクロスコンパイルするコンパイラーのようなものになります。
テストはそのような言語ではありません。彼らは、コード機能の特定の側面が有効であり、変更されていないと主張するだけです。そうすることで、リファクタリングされても壊れないようにコードを足場にします。
しかし、これら 2 つの開発方法をどのように比較すればよいでしょうか。
1) ジェネレーターが正しく機能する場合、仕様は常に正しいコードに変換されます。このコードは設計によってテストされており、追加のテストは必要ないと仮定します。生成されたコードよりもジェネレーターのTDDの方が優れています。
2) 生成されたコードにつながる仕様を持っているか、コードが機能することを保証するテストとして表現された仕様を持っているかは、私の目にはまったく同等です。
3) 両方の開発方法を組み合わせることができます。仕様からテスト済みのジェネレーターを使用してプログラム フレームワークを生成し、生成されたコードを TDD を使用して強化します。注意: この場合、1 つのプロジェクトで 2 つの異なる開発サイクルが実行されます。つまり、仕様が変更されたときに生成されたコードを常に再生成できること、および追加のコードが生成されたコードに正しく適合することを確認する必要があります。
ほんの一例です。UML クラス図からコードを生成できるツールを想像してみてください。これは、TDD でメソッドを開発できる方法で行うことができますが、クラスの構造は UML で定義されているため、これを再度テストする必要はありません。
将来的には可能ですが、簡単なテストを使用してコードを生成できます。
assertEquals(someclass.get_value(), true)
しかし、ブラックボックス統合テストから正しい出力を得ることは、NP完全な問題であると私が推測するものです:
assertEquals(someclass.do_something(1), file_content(/some/file))
assertEquals(someclass.do_something(2), file_content(/some/file))
assertEquals(someclass.do_something(2), file_content(/some/file2))
assertEquals(someclass.do_something(3), file_content(/some/file2))
これは、結果のコードが常に /some/file に書き込まれるということですか? 結果のコードは常に /some/file2 に書き込む必要があるということですか? どちらかが真実である可能性があります。テストに合格するために最小限のセットのみを実行する必要がある場合はどうなりますか? コンテキストを知らず、非常に正確で限定的なテストを作成しないと、(この時点で) テスト作成者が意図したことをコードで理解することはできません。