Verifying event registration using Moq

后端 未结 4 1890
悲&欢浪女
悲&欢浪女 2020-12-15 16:08

I\'m developing an asp.net (classic) application trying to implement the MVP pattern using this example. In trying to unit test my presenter and using the following pattern,

相关标签:
4条回答
  • 2020-12-15 16:36

    It would appear that this functionality is not currently available in moq, but may appear in a future version (I had a look in the 4.0.812.4 beta, but it doesn't seem to be there).

    It may be worth asking the question, "why does SomePresenter need to subscribe to the View's Load and Init events?" Presumably it is because the SomePresenter class needs to respond to those events. So it might be better to use the Raise method on your Mock<IView> to raise the Load and Init events, and then assert that SomePresenter did the right thing in response to them.

    0 讨论(0)
  • 2020-12-15 16:37

    I spent some time with this question and the solution which I'm using in my project is:

    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());
    

    Tested method:

    this.Event1 += OnEvent1;
    this.Event2 += OnEvent2;
    

    So, first you have to mock the methods which you will assign the events, after you call the method which you want to test, and finally raise all subscribed events. If the event is really subscribed, you can check with Moq if the assigned method is called.

    GLHF!

    0 讨论(0)
  • 2020-12-15 16:55

    The moq 4.13 introduced this feature. Now it is possible to verify if add\remove has been invoked. Therefore four new methods have been introduced:

    1. SetupAdd
    2. SetupRemove
    3. VerifyAdd
    4. VerifyRemove

    Example

    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: Notice that in order to verify at least one setup should be added. The reason is to keep backward compatibility with the older version of moq.

    0 讨论(0)
  • 2020-12-15 17:01

    I know it's maybe too late for #Dilip, but this answer can be helpful for those who are trying to do the same. Here is the test class

    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 is a decorator implemented as follow (pay attention to 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();
        }
    }
    
    0 讨论(0)
提交回复
热议问题