4

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

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

  1. button_click 将引发查看事件。
  2. Presenter 订阅此 ViewEvent 并捕获 args(即消息)
  3. Presenter 完成工作(字符串连接)并更新模型
  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;
}

我的问题在于测试。

由于 View 负责从模型中更新自身,Presenter 只设置 Model.Message 属性......所以在单元测试中,我想做以下事情。

  1. 嘲笑我的IHelloWorldView
  2. 用 Mock 实例化我的 Present。
  3. 在 Mock 上触发事件
  4. 验证当前设置了 Mock 的 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; }
}

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

  1. 从测试的角度来看,被动视图是更好的方法吗?
  2. 我是否有必要同时模拟我的模型(我不确定在 WebFormsMVP 中是否可行?或者
  3. 我需要将我的模型的所有属性都设为虚拟或
  4. 我在某处错过了重点吗?
4

1 回答 1

1

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

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

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

于 2012-02-01T20:42:50.257 回答