テスト駆動設計-最初の実装経験

一般にTDDに捧げられた多くの記事、特にユニットテストは、原則としてかなり人工的な例で動作します。 たとえば、2つの数値を追加する関数を作成し、そのテストを作成しましょう。 正直なところ、このような例では、自動テストを使用する利点を評価することは困難です。



少し前に、私は小さなプロジェクションを見つけました。彼らは、テストに基づいて設計方法論を試すために特別に作成されたようです。 アプリケーションの結果が印象的でした! 猫に日常の開発で自動化されたテストを適用する必要があることをまだ疑っているすべての人を招待します。





叙情的な余談。 テストの役割について



ユニットテストを使用することの有用性について多くの記事が書かれていますが、その必要性に関する論争で多くのコピーが壊れています。 そして、私はかなり長い間執筆と定期的な単体テストの練習をしてきましたが、長い間、それらの使用の動機を明確に明確にすることができませんでした。

包括的な自動化されたテストに対する主な議論は、テストの作成に費やされる余分な時間です。 実際、自動化されたテストは他のタイプのテストに取って代わるものではありません。 アプローチは広く行き渡っています。「プログラムを作成してテスターに​​送信します(またはすぐに顧客に送信します!)。 エラーが見つかった場合 、それらを修正し、修正したバージョンを送信します。 そして、そのようなアプローチは、「作成されて忘れられた」状況で正当化することができます-作成されたプログラムを終了する必要がない場合、再作成します。



最新の柔軟な開発手法は、ソフトウェアを作成するためのまったく異なるアプローチを提供します。 プログラムに変更を加えることは、仮想的でありそうもない機会とは見なされませんが、作業の完全に普通の部分です。 これにより、開発者は変更しやすいコードを作成することができます。 コードの変更を簡素化するには、アプリケーションアーキテクチャを疎結合することをお勧めします。 そして、変更の隠れた結果を減らすために、自動化されたテストがあります。 変更を行う非常に早い段階で、予想される動作からのプログラムの逸脱を検出できます。

少し前に、私はすべてをその場所に置いた非常に簡単な真実に気付きました。 テストをコードへの何らかの追加として考慮する必要はありません。 テストは、アーキテクチャと同じコードの一部です。 テスト-これは、最小限の影響で変更を行うように適合させるコードの一部です。 アーキテクチャが優れていれば、テストを簡単に作成できます。 テストを適切に編成すればするほど、変更後の隠れた結果は少なくなります。 そして、結果として得られるコードの信頼性と品質が向上します。



テストを作成するかどうかを質問するたびに、自分にマントラを繰り返します。

「テストはコードへの追加ではなく、重要な部分です。



問題の声明



そこで、ネットワーク上の2台のコンピューター間の自動ファイル転送を整理するというタスクが設定されました。

明確化:あるコンピューターのフォルダーに表示されるファイルは、別のコンピューターのフォルダーに魔法のように転送する必要があります。

-はい、DropBoxです! -あなたは言います。

はい、これらの目的のために、クラウドストレージも使用できます。

1.ファイルの機密性はわずかであり、顧客はそれらをクラウドにアップロードすることを恥じています

2.ファイル転送は、受信者が「 少年のファイルはありましたか?」と言うことができないように詳細に記録する必要があります。



魔法として、ディスク上のフォルダーの変更を追跡し、すべての新しいファイルを受信者コンピューターで実行されているWebサービスに送信するサービスを使用することになっています。 成功した送信試行と失敗した送信試行のそれぞれを記録する必要があります。 さらに、ロギングは送信者と受信者の両方によって実行されます。

WCFとIISの使用は追加の要件として存在しますが、これはそれほど興味深いものではありません。



建築設計



おでこを決める


一見、プログラムのアーキテクチャは非常に単純です。 受信フォルダーでファイル待機サイクルを開始し、新しいファイルをそれぞれ読み取り、データを受信して​​特定のフォルダーに書き込む別のコンピューター上のサービスに送信します。







ロギングコンポーネントは再利用できます-これは非常に楽しいです。 すべてがシンプルで明確で、キーボードを使用して、プロジェクトをすばやく作成します...



停止停止停止。 しかし、TDDはどうですか? さて、このようなプログラムをどのようにテストするか考えてみましょう。 そして、実際には、1つの方法しかありません-何が起こるかを書いて実行し、見る方法です。 そして、検出されたエラーをクリーンアップします。 つまり プログラムをすばやく簡単に書く方法は、「古典的な」開発方法につながります。



そして今急いではいけません


タスクをもう少し注意深く見てください。

少しよく見ると、サービスの明らかな違いにもかかわらず、それらには多くの共通点があることがわかります。 実際、それぞれがソースからレシーバーにファイルを転送する問題を解決し、同時に転送の進行状況を記録します。 ソース/レシーバーのタイプのみが変更されます。







さらに、ソース、受信機、および送信機のインターフェースを実装するクラスは非常にシンプルで、簡単に自動テストできます。 そして、これらのクラスから、コンストラクターのように、サービスを簡単に送受信できます。





テストとプログラムを作成します



Classics TDDでは、最初にテストを作成し、次にクラスを作成する必要があります。 正直なところ、これは私にとって常にうまくいくとは限りません-明らかに、瞑想を続ける必要があるようです。 :-)しかし、作業コードとテストコードをほぼ同時に書くのは驚くほど簡単でした。 ほとんどの場合、最初に作業コードのスケッチを作成し、対応するクラスまたはメソッドをテストしてから、コードを作業状態にしました。



テストを作成する過程で、モックオブジェクトを使用して( dorofeevilyaのアドバイスでRhino Mocksを使用)、抽象インターフェースに依存するクラスの動作をテストすることの魅力を発見しました。 これは、たとえば、エラーの場合に送信機がプロトコルに対応するメッセージを書き込むことを確認するテストです。

[TestMethod] void test_that_failed_transfer_logs() { //  var mock = new MockRepository(); var writerMock = mock.StrictMock<IFileReceiver>(); var logMock = mock.StrictMock<INoDateLogger>(); //   var exception = new InvalidOperationException("transfer failed"); Expect.Call(() => writerMock.Receive(fileName, fileData)).Throw(exception); Expect.Call(() => logMock.WriteEvent(FileTransferEvent.Send, fileName, FileTransferStatus.Failed, MessageFormatter.AttemptFailed(1, exception))); mock.ReplayAll(); //  var sender = new FileSender (writerMock, logMock); sender.SendFile(fileName, fileData); //   mock.VerifyAll(); }
      
      







プログラムを実行する



したがって、すべてのクラスが作成され、すべてのテストに合格しました。 ウェブサービスを使用せずに最初の実行を行っています。これにより、追加の問題が発生しないように、最初に全体的なパフォーマンスを確認する必要があります。 レシーバーサービスをレシーバーフォルダーに変更することで、これを簡単に行うことができます。 あるフォルダから別のフォルダにファイルを転送するプログラムが判明しました。 結果は印象的です-プログラムは最初の起動で動作しました!



タスクを複雑にします-Webサービスを接続します。 IISの展開、サービスの構成と構成には数時間かかります。 Webサービスのレシーバーインターフェイスを実装するクラスを記述して接続するには、さらに25分かかります。 そして、すべてのインフラストラクチャの問題が解決されるとすぐに、プログラムは機能しました! つまり 書かれたクラスの実際の条件での予期しない動作に問題はありませんでした。



そして結論を​​導き出します



正直に言うと、その結果は私に大きな印象を与えました。 はい、開発には通常より時間がかかりました。このレベルの複雑さのアプリケーションの開発が必要です。 しかし、通常はかなりの時間がかかるデバッグフェーズは実質的にありませんでした! まず第一に、開発時間の増加は、mock-sを使用してテストを書いた経験がないことによるものです。 今、私は同じ原則を使用して次のプロジェクトを行っており、テストを書くのにそれほど時間はかかりません。



初期段階では、TDDの実装にはワールドビューの再構築が必要であり、開発時間の増加につながることが保証されていると言えます。 これは単に、新技術の開発への投資と見なされるべきです。 TDDの原則を使用して作成されたプログラムは、より良いだけでなく、変更や追加を行うのにはるかに適しています。 また、テストの作成が習慣になると、最初ほど時間はかかりませんが、自動的に行われます。



All Articles