最小のWinFormsでMVCアプローチを使用する

この記事では、長年使用してきたアプリケーションでの分離コードアプローチの実装例を使用して、MVCアプローチを使用してアプリケーションを構築する一般的な原則について説明します。



なりません:

•クラシックユニットテスト。

•コードビハインドの影響を軽減します。

•MVCでの予期しない発見。



次のようになります。

•単体テストとスタブ。

•MVC;

•既存の製品に基づいたアプローチの実装。





はじめに



データアプローチを使用する前に、私はエンタープライズシステムの通常の開発者として長い道のりを歩きました。 その過程で、単純で複雑な、絶対にステレオタイプ化されたイベントやものに出会った。 たとえば、開発が完了し、機能がテスト用に送信され、クリックすると、単純な欠陥から重大な違反に至るまで、多くのエラーが発生します。 より複雑なケース:機能が受け入れられ、ユーザーがフィードバックに積極的に参加し、機能を変更する必要が生じます。 機能を変更し、同じ方法で古い機能が機能しなくなったため、新しい機能には多くの要望が残っています。 急成長する機能をスナップアップするようなものが、バグの絶え間ない編集を開始します。 最初は時計でしたが、1週間でしたが、今では月が制限ではないことを知っています。 それが数時間または数日かかったとき、エラーは閉じられ、多かれ少なかれ流れました。 しかし、間違いが再発見されるとすぐに、地獄が始まりました。 テスト部門は絶えず誓い、開発者は絶えずエラーを修正し、開発された機能で新しいエラーを作ります。 フィードバックは、実際のユーザーから完全に否定的になります。 そして機能が成長し、成長しました。私は方法とアプローチを探していました。どうすれば自分の人生を簡素化できますか。 同時に、ユーザーインターフェイスの開発に開発者レベルでのテストを含めるというアイデアに長い間訪問しました。 ユーザーシナリオを作成したいという願望から、問題が発生したという事実に至りました。開発者からの製品の可用性に関する少なくともいくつかの客観的な基準がありません。 そして、私はもう少し広く考え始めました。そして、すべての肯定的な使用シナリオをいくつかのルールに入れようとすると、ルールセットを常にチェックします。これは、少なくとも次のリリースのユーザーが失敗した機能に圧倒されず、テスターが関与することを保証するためです予約制。 開発者にとっては、これらのルールが、自身の機能に関する作業を完了するための基準になると予測されました。



形式化



ルールを形式化するツールの検索が始まりました。 ユーザーおよびデータと対話するためのすべてのロジックは、フォームにありました。 もちろん、データベース、サービス、リモート処理など、さまざまな作業を行うレイヤーが分離されました。 しかし、ユーザーインターフェイスはロジックで飽和状態のままでした。 マッピングとは関係のないロジック。 最初の非常に論理的なステップで、フォームを視覚的にテストするためのツールを使用するように思われました。 クリックのルール-入力を収集し、テストに変換します。 たとえば、Visual Studio 2013 Ultimate、またはそのテンプレートの1つで、これを完全に行うことができます。 私は元気にいくつかのテストを作成し、この方法でテストを作成してから実行すると、大きな災害になることを認識しました。 システム全体を完全にロードし、必要なダイアログを表示して、対応するイベントをトリガーするのに多くの時間がかかりました。 これには、チェーン内のすべてのリンクの作業が必要でしたが、場所によっては不可能でした。 コードビハインドのフォームがないため、ユニットテストを完全に分離するためのすべての手順を自分で行いましたが、サーバー上で回転するサービスとロジックに常に使用していました。 ASP.NET MVCでの作業中に、表現からロジックを分離するアプローチがますます好きになりました。 簡単に言えば、ASP.NET MVCコントローラーを呼び出すことで、パブリックメソッドをプルするだけで、変更を加えてビューを返します。 このモデルをWinFormsに転送する方法について考え始め、ビューでイベントを使用してコントローラーメソッドを呼び出すという結論に達しました。 ビューインターフェイスを実装するクラスのイベントにバインドするコントローラークラスを常に持っているというルールを受け入れました。 したがって、コードビハインドからすべてのロジックコードをコントローラーコードに削除し、コントローラーは通常の単体テストを使用してテストを行い、データマネージャーのクラスとビュー自体にスタブを実装しました。 後に、ユニットテストのみでビュー自体をテストすることを学びました。 次に、私がこれにどのように来たかの例を示したいと思います。





タスクの説明



データをインポートするときに例外を変更するためのフォームの実装例について、上記のすべてを検討します。 例外は、3つのフィールドを持つエンティティです。これは、システムでテキストファイルを読み取るために必要です。 ユーザーの観点からすると、このフォームでは例外を追加、変更、削除できます。 新しい例外を追加した後、リストの最後に追加する必要があります。 例外が削除されると、フォーカスはリストの最初の項目に移動します。 この場合、フォームはMVCを実装しないコンテキストから呼び出されます。



表現の形式化



膨大な数のフォームに持ち込まれ、企業アプリケーションでは、インターフェイスに対する標準的なアプローチも使用するという結論に達しました。ボタンを備えたコントロールパネル-例外のアクション、表形式の例外リスト、閉じる基本ボタン。 したがって、インターフェイスで表示するには、次のものが必要です。

•テーブルを構築するための例外のリスト全体。

•例外に焦点が当てられています。

•焦点の例外の変更のイベント。

•イベントを追加します。

•イベントを削除します。

•閉じるボタンのクリックイベント。

•発見方法。

•クローズ方法。

•ビューを更新する方法。

後で、よりわかりやすいインターフェイスを実装するには、さらにいくつかのものが必要であることに気付きました。

•作成の可用性。

•除去の可用性。

•一括削除のすべての強調表示された例外のリスト。



これをすべてコードに変換することで、ビューインターフェイスを取得しました。

public interface IReplaceView { bool EnableCreate { get; set; } bool EnableDelete { get; set; } List<ReplaceSymbol> Replaces { set; } ReplaceSymbol FocusedReplace { get; set; } List<ReplaceSymbol> SelectedReplaces { get; set; } event EventHandler Closing; event EventHandler Creating; event EventHandler Deleting; event EventHandler FocusedChanged; void Open(); void Close(); void RefreshView(); }
      
      







コントローラーの形式化



コントローラーの全体的な形式化は、データマネージャーとプレゼンテーション自体を受け入れなければならないということです。これにより、上記のインターフェイスがサポートされます。 コードに変換して、私は受け取った:

 public class ReplaceController : IReplaceController { private IReplaceView _view = null; private IReplaceStorage _replaceStorage = null; public ReplaceController(IReplaceView view, IReplaceStorage replaceStorage) { Contract.Requires(view != null, "View can't be null"); Contract.Requires(replaceStorage != null, "ReplaceStorage can't be null”); _view = view; _replaceStorage = replaceStorage; } }
      
      





このコントローラーでは、コントラクトを使用してパラメーターをチェックしますが、記事ではこれは重要ではありません。



テスト中



作成と形式化を行うと、なぜこれがすべてだったのかを忘れることができます。 すべてのために、仕事の完全性を評価するための適切な基準を取得することにより仕事の質を改善する。 したがって、彼はすぐにルールをテストに形式化し始めました。 コンストラクターでコントローラーによって受け入れられるインターフェースを実装するには、単にスタブを実装します。



空の除外リストをダウンロード



この場合、例外を作成するためのボタンが使用可能でなければならず、例外を削除するためのボタンは使用可能ではなく、フォーカスされている要素はnullであり、選択された要素のリストは空ですが、nullではありません。 受信したコードへの変換:

 [TestMethod] public void LoadEmptyReplaces() { var emptyReplaces = new List<ReplaceSymbol>(); var storage = new StubIReplaceStorage() { ReplaceSymbolsGet = () => { return emptyReplaces; }, }; ReplaceSymbol focusedReplace = null; var loadedReplaces = new List<ReplaceSymbol>(); var selectedReplaces = new List<ReplaceSymbol>(); var enableCreate = false; var enableDelete = false; var view = new StubIReplaceView() { FocusedReplaceGet = () => { return focusedReplace; }, FocusedReplaceSetReplaceSymbol = x => { focusedReplace = x; if (x != null) { selectedReplaces.Add(x); } }, ReplacesSetListOfReplaceSymbol = x => { loadedReplaces = x; }, EnableCreateSetBoolean = x => { enableCreate = x; }, EnableDeleteSetBoolean = x => { enableDelete = x; }, SelectedReplacesGet = () => { return selectedReplaces; }, }; var controller = new ReplaceController(view, storage); controller.Open(); view.FocusedChangedEvent(null, null); Assert.IsNotNull(loadedReplaces, "           null"); Assert.IsTrue(loadedReplaces.Count == 0, "           ,       "); Assert.IsNull(focusedReplace, "          "); Assert.IsNotNull(selectedReplaces, "        null"); Assert.IsTrue(selectedReplaces.Count == 0, "            "); Assert.IsTrue(enableCreate, "        "); Assert.IsFalse(enableDelete, "       ,     "); }
      
      







その他の規則



その後、残りのルールを形式化して、テストのリストを受け取りました。これにより、コントローラーの機能に対する作業の準備状況をすぐに評価することができました。 クライアント自体を実行しないでください。





実装を見る



その後、上記のインターフェイスを実装するビュー自体を作成しました。 彼のために、面白いPrivateObjectクラスを使用して小さなテストを作成しました。これにより、オブジェクトに実装されたプライベートメソッドを呼び出すことができます。 たとえば、次のような削除テストを受けました。

 [TestMethod] public void DeleteOneReplaceView() { var replaces = GetTestReplaces(); var storage = new StubIReplaceStorage() { ReplaceSymbolsGet = () => { return replaces; }, }; var controller = new ReplaceController(_view, storage); Task.Run(() => { controller.Open(); }).Wait(WaitTaskComplited); var privateObject = new PrivateObject(_view); privateObject.Invoke("RiseDeleting"); Assert.IsTrue(replaces.Count == 2, "       "); Assert.IsNotNull(_view.FocusedReplace, "        "); Assert.AreEqual(replaces.First().Source, _view.FocusedReplace.Source, "           "); Assert.IsTrue(_view.SelectedReplaces.Count == 1, "         "); Assert.AreEqual(_view.FocusedReplace.Source, _view.SelectedReplaces.First().Source, "           "); Assert.IsTrue(_view.EnableCreate, "        "); Assert.IsTrue(_view.EnableDelete, "          "); }
      
      





残りのルールを正式にした後、私はテストのリストを受け取りました。これにより、仕事に適したプレゼンテーションの準備状況をすぐに評価することができました。 繰り返しますが、クライアント自体を実行しないでください。 機能の各部分を徐々に実装して、私は絵を得ました:



その後、すでに実際のマネージャーとプレゼンテーションを使用して、コントローラーコードで呼び出しを行いました。

 _replaceView = new ReplaceView(); _replaceController = new ReplaceController(_replaceView, _importer);
      
      





アプリケーション全体を起動し、作業の最終結果を確認しました。 すべてが私が築いたとおりに機能しました。 テスト部門は満足し、顧客は満足し、肯定的なフィードバックを受け取ります。 他に何が必要ですか?





あなたがWindowsフォームをどのように扱っているかについてのコメントや私の話をとてもうれしく思います。 最初のレビューでは、私のパンツで私がMVPに来たことを正しく認識しています。これは絶対に真実です。

ご清聴ありがとうございました! あなたが私に時間を無駄にしないことを願っています。



All Articles