Проверка регистрации событий с использованием Moq
Я занимаюсь разработкой приложения asp.net(classic), пытающегося реализовать шаблон MVP , используя этот пример. При попытке выполнить модульное тестирование моего докладчика и использовать следующий шаблон, 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...
[Test]
public void VerifyAttachesToViewEvents()
{
viewMock.Load += null;
LastCall.IgnoreArguments();
viewMock.PostSaved += null;
LastCall.IgnoreArguments();
mocks.ReplayAll();
new PostEditController(viewMock,
this.dataServiceMock);
mocks.VerifyAll();
}
... как мы можем сделать это с помощью MOQ?
Ответы
Ответ 1
Похоже, что эта функциональность недоступна в настоящее время в moq, но может появиться в будущей версии (я посмотрел в 4.0.812.4 бета, но он, похоже, не существует).
Возможно, стоит задать вопрос: "Почему SomePresenter
нужно подписаться на события View Load
и Init
?" Предположительно, это потому, что класс SomePresenter
должен отвечать на эти события. Поэтому лучше было бы использовать метод Raise
на вашем Mock<IView>
, чтобы поднять события Load
и Init
, а затем утверждать, что SomePresenter
сделал правильную вещь в ответ на них.
Ответ 2
Я знаю, возможно, слишком поздно для #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 - это декоратор, реализованный следующим образом (обратите внимание на Events: 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();
}
}
Ответ 3
moq 4.13
представил эту функцию. Теперь можно проверить, был ли вызван add\remove
. Поэтому были введены четыре новых метода:
SetupAdd
SetupRemove
VerifyAdd
VerifyRemove
Пример
var mock = new Mock<IAdder<EventArgs>>();
mock.SetupAdd(m => m.Added += (sender, args) => { });
mock.Object.Added += (sender, args) => { };
mock.Object.Added += (sender, args) => { };
mock.VerifyAdd(m => m.Added += It.IsAny<EventHandler>(), Times.Exactly(2));
NB. Обратите внимание, что для проверки необходимо добавить хотя бы одну настройку. Причина заключается в том, чтобы сохранить обратную совместимость со старой версией moq
.
Ответ 4
Я потратил некоторое время на этот вопрос, и решение, которое я использую в своем проекте:
Unit test:
// 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!