使用Moq验证事件注册
-
07-07-2019 - |
题
我正在开发一个试图实现MVP模式的asp.net(经典)应用程序使用此示例。在尝试对我的演示者进行单元测试并使用以下模式时,psuedocode看起来像这样
//base view interface
public interface IView
{
event EventHandler Init;
event EventHandler Load;
bool IsPostBack { get; }
void DataBind();
bool IsValid { get;}
}
//presenter psuedo code
public class SomePresenter
{
public SomePresenter(ISomeDomainService service, IView someView)
{
...
//HOW DO WE TEST/VERIFY THAT THIS REGISTRATION OCCURS?
someView.Init += OnInit;
someView.Load += OnLoad;
}
}
...
//consuming code that exercises the above code, that needs to be tested
var presenter = new SomePresenter(someDomainService, someView);
如何验证演示者是否正在执行预期的操作,即注册Init和Load事件?虽然可以使用Rhino在 Phil Haack的示例中轻松完成此操作嘲笑...
[Test]
public void VerifyAttachesToViewEvents()
{
viewMock.Load += null;
LastCall.IgnoreArguments();
viewMock.PostSaved += null;
LastCall.IgnoreArguments();
mocks.ReplayAll();
new PostEditController(viewMock,
this.dataServiceMock);
mocks.VerifyAll();
}
......我们怎么能用MOQ做到这一点?
解决方案
此功能似乎是目前无法使用在moq中,但可能会出现在未来的版本中(我看过4.0.812.4测试版,但它似乎并不存在)。
可能值得问这个问题,<!>“为什么SomePresenter
需要订阅View的Load
和Init
事件?<!>”;可能是因为Raise
类需要响应这些事件。因此,最好在Mock<IView>
上使用<=>方法来提升<=>和<=>事件,然后断言<=>做出正确的事情来回应它们。
其他提示
我知道#Dilip可能为时已晚,但这个答案对那些试图做同样事情的人有帮助。 这是测试类
public delegate void SubscriptionHandler<T>(string name, T handler);
public class SomePresenterTest
{
[Test]
public void Subscription_Test()
{
var someServiceMock = new Mock<ISomeDomainService>();
var viewMock = new Mock<IView>();
//Setup your viewMock here
var someView = new FakeView(viewMock.Object);
EventHandler initHandler = null;
someView.Subscription += (n, h) => { if ((nameof(someView.Init)).Equals(n)) initHandler=h; };
Assert.IsNull(initHandler);
var presenter = new SomePresenter(someServiceMock.Object, someView);
Assert.IsNotNull(initHandler);
Assert.AreEqual("OnInit", initHandler.Method?.Name);
}
}
FakeView 是一个实现如下的装饰器(注意事件:Init / Load {add; remove}):
public class FakeView : IView
{
public event SubscriptionHandler<EventHandler> Subscription;
public event SubscriptionHandler<EventHandler> Unsubscription;
private IView _view;
public FakeView(IView view)
{
Assert.IsNotNull(view);
_view = view;
}
public bool IsPostBack => _view.IsPostBack;
public bool IsValid => _view.IsValid;
public event EventHandler Init
{
add
{
Subscription?.Invoke(nameof(Init), value);
_view.Init += value;
}
remove
{
Unsubscription?.Invoke(nameof(Init), value);
_view.Init -= value;
}
}
public event EventHandler Load
{
add
{
Subscription?.Invoke(nameof(Load), value);
_view.Init += value;
}
remove
{
Unsubscription?.Invoke(nameof(Load), value);
_view.Init -= value;
}
}
public void DataBind()
{
_view.DataBind();
}
}
我花了一些时间来处理这个问题,我在项目中使用的解决方案是:
单元测试:
// Arrange
TestedObject.Setup(x => x.OnEvent1());
TestedObject.Setup(x => x.OnEvent2());
// Act
TestedObject.Object.SubscribeEvents();
TestedObject.Raise(x => x.Event1 += null);
TestedObject.Raise(x => x.Event2 += null);
// Assert
TestedObject.Verify(x => x.OnEvent1(), Times.Once());
TestedObject.Verify(x => x.OnEvent2(), Times.Once());
经过测试的方法:
this.Event1 += OnEvent1;
this.Event2 += OnEvent2;
因此,在调用要测试的方法之后,首先必须模拟将分配事件的方法,最后提升所有已订阅的事件。如果事件是真正订阅的,您可以检查Moq是否调用了指定的方法。
GLHF!
不隶属于 StackOverflow