4

ASP.NET WebFormsMVP を使用して作成されたプレゼンターをテストしようとしています。「監視コントローラー」パターンを使用して構築しているため、ビューはモデルからの更新を担当します。テキストボックス、ボタン、およびラベルを含むページの次の例を簡略化しました。テキストボックスに入力してボタンを押すと、テキストHelloWorld! <YOUR TEXT>がラベルに表示されます。

以下のサンプルコードですが、一言で言えば:

  1. button_click は View イベントを発生させます。
  2. プレゼンターはこの ViewEvent をサブスクライブし、引数 (つまりメッセージ) をキャッチします。
  3. プレゼンターが作業 (文字列連結) を実行し、モデルを更新します
  4. ビューは Model.Message プロパティに再バインドされ、すべて正常に機能します。

 

//Model
public class HelloWorldModel {
    public string Message { get; set; }
}

//Args
public class HelloWorldEventArgs : EventArgs {
    public string Message { get; set; }
}

//View
public interface IHelloWorldView : IView<HelloWorldModel> {
    event EventHandler<HelloWorldEventArgs> SendMessage;
}

//Presenter
public class HelloWorldPresenter : Presenter<IHelloWorldView> 
{
    private readonly EventHandler<HelloWorldEventArgs> SendMessageDelegate;

    public HelloWorldPresenter(IHelloWorldView view) : base(view)
    {
        SendMessageDelegate = ((s, e) => SendMessageReceived(e.Message));
        View.SendMessage += SendMessageDelegate;
    }

    public override void ReleaseView()
    {
        View.SendMessage -= SendMessageDelegate;
    }

    public void SendMessageReceived(string message)
    {
        View.Model.Message = string.Format("Hello World! - {0}", message);
    }
}

//View implementation
[PresenterBinding(typeof(HelloWorldPresenter))]
public partial class HelloWorld : MvpPage<HelloWorldModel>,IHelloWorldView
{
    protected void EchoButtonClick(object sender, EventArgs e)
    {
        if(SendMessage != null)
        {
            var args = new HelloWorldEventArgs {Message = MessageTextBox.Text};
            SendMessage(sender, args);
        }
    }

    public event EventHandler<HelloWorldEventArgs> SendMessage;
}

私の問題はテストにあります。

ビューはモデルから自分自身を更新する責任があるため、プレゼンターは Model.Message プロパティのみを設定します...そのため、単体テストでは次のことを行います。

  1. 私のモックIHelloWorldView
  2. モックでプレゼントをインスタンス化します。
  3. モックでイベントをトリガーする
  4. 現在、モックの Model.Message プロパティが設定されていることを確認します。

 

[TestMethod]
public void TestMethod1()
{
    var input = "My Message";
    var expected = string.Format("Hello World! - {0}", input);

    var mock = new Mock<IHelloWorldView>
    {
        DefaultValue = DefaultValue.Mock
    };
    var pres = new HelloWorldPresenter(mock.Object);

    mock.Raise(m => 
        m.SendMessage += null, 
        new HelloWorldEventArgs { Message = input });

    mock.VerifySet(view => 
        view.Model.Message = It.Is<string>(s => s == expected), 
        Times.Once());
}

しかし、モデルのプロパティを明示的にMessage仮想としてマークしない限り、これは機能しません。これは本当にやりたくないことです。例えば

//Model
public class HelloWorldModel {
    public string Message { get; set; }
}

私の他のオプションは、パッシブ ビュー パターンを使用し、IHelloWorldView で asp:label テキストを文字列プロパティとして公開し、それをプレゼンターから直接設定することです...その後、テストできるはずです。

  1. テストの観点からすると、パッシブ ビューの方が優れたアプローチですか?
  2. また、モデルをモックする必要がありますか(WebFormsMVPで可能かどうかはわかりませんか?または
  3. モデル仮想 OR のすべてのプロパティを作成する必要があること
  4. どこかでポイントを逃しましたか?
4

1 に答える 1

1

DefaultValue.Mock を使用してビュー モックを設定しているため、ビューには初期化された Model プロパティが含まれます。Moq を使用してモデルの値を確認する代わりに、モデルでメッセージを直接確認します。

Assert.That(mock.Object.Model.Message, Is.EqualTo(expected));

この小さな (しかし意味的には等しい) 変更の利点は、モックが突然スタブになり、核心的な実装の詳細ではなく最終結果をテストしていることです。あなたの質問に関しては、テスト容易性の観点からシステムを設計することは良いことですが、Moq フレンドリーにするためだけにすべてを仮想化またはインターフェース化することはしません。SOLID アーキテクチャを作成しますが、必要な Moq 対応ではありません。

于 2012-02-01T20:42:50.257 に答える