在使用监督控制器模式时,我应该如何使用Moq视图对我的WebFormMVP演示者进行单元测试

时间:2012-01-30 17:48:23

标签: c# asp.net unit-testing moq webformsmvp

我正在尝试测试使用ASP.NET WebFormsMVP创建的Presenter。我正在使用“监督控制器”模式构建它,因此View负责从模型中更新自身。我简化了以下带有文本框,按钮和按钮的页面示例。标签。您输入文本框&amp;按下按钮,文本HelloWorld! <YOUR TEXT>将被放置在标签上。

下面的示例代码,但简而言之:

  1. button_click将引发查看事件。
  2. Presenter订阅此ViewEvent并捕获args(即消息)
  3. Presenter完成工作(字符串连接)并更新模型
  4. 视图重新绑定到Model.Message属性&amp;一切正常。
  5. //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;
    }
    

    我的问题在于测试。

    由于View负责从模型中更新自身,Presenter只设置Model.Message属性...因此在单元测试中,我想执行以下操作。

    1. 模拟我的IHelloWorldView
    2. 使用模拟实例化我的礼物。
    3. 在Mock上触发事件
    4. 验证当前是否设置了Mock的Model.Message属性。
    5. [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属性标记为虚拟而我不想做,否则这将无效。 e.g。

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

      我的其他选项是使用被动视图模式并在IHelloWorldView上将asp:标签Text作为字符串属性公开,并直接从Presenter设置...然后我应该能够测试它。

      1. 被动是否从测试的角度看待更好的方法?
      2. 我是否有必要另外模拟我的模型(我不确定WebFormsMVP中是否可行? OR
      3. 我需要制作Model Virtual的所有属性 OR
      4. 我错过了某个地方的观点吗?

1 个答案:

答案 0 :(得分:1)

您正在使用DefaultValue.Mock设置view-mock,因此您的视图将具有初始化的Model属性。不要使用Moq检查模型的值,只需直接在模型上检查消息:

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

这个小的(但在语义上相等)变化的美妙之处在于你的模拟突然变成了一个存根而你正在测试最终结果而不是细节的实现细节。至于你的问题,在可测试性方面设计你的系统是一件好事,但我不会开始虚拟化或接口所有东西只是为了使它对Moq友好;制作一个SOLID架构,而不是Moq-able。