1

作成する必要がある既存の WinForms アプリケーションのフォームを使用して、初めて TDD を適用しようとしています。「C# におけるアジャイルの原則、パターン、およびプラクティス」を読みました。ここから、TDD に関する私の知識のほとんどが得られました。

この本の中で、著者は、View と Model に依存する Presenter を持つ Supervising Presenter と呼ばれる MVP のわずかに変更された形式で UI 開発を行うことを推奨しています。これにより、Presenter のコードがどのように見えるかが気に入っています。説明のために、簡単な例を次に示します。

class Presenter
{
  Public IDomainApi _api;
  Public IView _view;
  ...
  public void PerformOperation()
  {
    bool userDecidesToPerformOperation = _view.PromptUserToConfirmOperation();
    if( userDecidesToPerformOperation )
    {
       bool success = _api.PerformOperation();
       if( success)
         _view.AlertUserOperationSuccessful();
       else
         _view.AlertUserOperationFailed();
    }
  }
 }

これはすべてうまく機能します。テスト目的で、私は mockIDomainApiとmock を持っていIViewます。コントローラーの寿命が良好であることを確認できました。

実際のアプリケーション_apiは、IDomainApiネットワーク上で機能する の実際の実装であり、必要なすべての制御を実装_viewする のインスタンスです。FormIView

realIDomainApiが実行する一部の操作には時間がかかるため、Presenter メソッドを少し変更して、ユーザーに処理が行われていることを警告することにしました。プレゼンターは次のように変更されました。

  public void PerformOperation()
  {
    bool userDecidesToPerformOperation = _view.PromptUserToConfirmOperation();
    if( userDecidesToPerformOperation )
    {
       _view.NotifyPendingOperation("Performing operation ...");
       bool success = _api.PerformOperation();
       _view.PendingOperationCompleted();
       if( success)
         _view.AlertUserOperationSuccessful();
       else
         _view.AlertUserOperationFailed();
    }
  }

新しいメソッドを「実際の」IView実装に追加しました。渡されたテキストと、アクティビティを示すように設定された進行状況バー (マーキー設定) を含む単純なダイアログ ボックスが表示されるだけです。Presenter悲しいことに、テスト中に、実行中のスレッドが UI スレッドであるため (および_api.PerformOperation()完了を待ってブロックされているため) 、ダイアログの進行状況インジケーターがアクティブになっていないことがわかりました。

Presenterを作成および使用して別のスレッドで呼び出すコードを変更しようとしPresenterましたが、UI が正しくレンダリングされません (レンダリングは UI スレッドでのみ行われ、新しいスレッドでは行われません)。この問題を解決するには、拡張IViewして UI スレッドを公開し、そのスレッドで適切なメソッドを呼び出せるようにする必要IViewがありますが、これは Presenter コードを醜くし、WinForms に依存させるようです。この種のことを処理するためのより良い方法を見つけた人はいますか? これまでのところ、オンラインで検索すると、主に Web を使用した TDD に関する情報が得られる傾向があります。WinForms に固有のこれらのことのいくつかを実行する方法に関する優れたリソースを知っている人はいますか?

4

1 に答える 1

0

あなたの質問に対する答えは、TDD とはほとんど関係ありません。それは、非同期メソッド呼び出しに関するものです。

Presenterクラスの次の 3 行のコードを見てみましょう。

view.NotifyPendingOperation("...");
bool success = _api.PerformOperation(); 
_view.PendingOperationCompleted(); 

UI が UI スレッドで実行する必要があるすべてのものを覚えておいてください。では、UI スレッドがプログレス バーを自由に更新できるようにするには、他に何をバックグラウンド ワーカー スレッドに移行できるでしょうか?

プレゼンター自体が長時間 (>0.4 秒程度) の操作を実行しないと仮定すると、UI スレッドで実行しても害はありません。

ただし、_api.PerformOperation()実行時間の長いタスクである可能性が高いため、UI スレッドがブロックされるようです。したがって、このメソッド呼び出しのみを別のスレッドで実行することをお勧めします。

これを行うには多くの方法があり、すべてを詳細に説明することはできません。代わりに、いくつかの出発点を提供します。

  • を使用しSystem.ComponentModel.BackgroundWorkerて、バックグラウンド スレッドで API メソッドを実行します (イベントを介して) 。イベントのハンドラーでDoWork続行します..._view.PendingOperationCompletedRunWorkerCompleted

  • ...ただし注意: このイベントにハンドラー メソッドをサブスクライブすると、UI を更新してはならないバックグラウンド スレッドで呼び出されます。.BeginInvokeフォームで (Winforms のみのメカニズム) を実行_viewして UI スレッドに戻るか、System.Threading.SynchronizationContext(一般的な解決策であり、最初は理解しにくいため、Google でチュートリアルも参照してください!) を調べてください。

  • いわゆるEvent-based Async Pattern (EAP)IDomainApi.PerformOperationに準拠したというメソッドの非同期バージョンを実装します。このパターンの利点は、「完了」イベント ハンドラーが同じ同期で呼び出されることです。メソッド呼び出しを発行したコンテキスト (通常は同じスレッド上を意味します)。とは異なり、UI スレッドで自動的にコールバックされるため、 でメソッドを呼び出す必要はありません。PerformOperationAsyncBackgroundWorkerBeginInvoke_view

    MSDN には、EAP の実装方法について、やや難解な例がいくつかあります。すぐにあきらめないでください。把握しやすいチュートリアルについてもグーグルで検索すると、簡単に見つかります。

  • .NET 4 以降では、Task Parallel Library (TPL)、つまりこのTask<bool>場合のクラスを使用して、非同期プログラム ロジックを簡素化します。私の知る限り、TPLは下位レベルSynchronizationContextとEAPの上に構築されています(両方とも上記)。

  • C# 5 コード (Visual Studio 11 など) を作成している場合は、上記の TPL の上に構築されたasyncおよび言語機能を使用して、非同期プログラム ロジックをさらに簡素化できます。await

繰り返しますが、これらは、コードを非同期で実行し、UI スレッドを解放して UI 作業を実行する方法へのポインタにすぎません。これに不慣れな場合は、Google でさらにリソースを探してください。さらに詳しく説明することは、単純な答えではありません。

于 2012-05-16T22:42:11.077 に答える