web-dev-qa-db-fra.com

Moq - mock.Raise devrait déclencher l'événement dans l'unité testée sans avoir de configuration

J'ai une classe de présentateur, qui attache un événement de la vue injectée. Maintenant, je voudrais tester le présentateur réagissant correctement sur l'événement.

Voici l'interface de vue IView:

public interface IView 
{
    event EventHandler MyEvent;
    void UpdateView(string test);
}

C'est la vue mettant en œuvre IView

public partial class MyView : IView
{
    public event EventHandler MyEvent;

    public MyView()
    {
        this.combo.SelectedIndexChanged += this.OnSelectedIndexChanged;
    }

    public void UpdateView(string test)
    {
        this.textBox.Text = test;
    }

    private OnSelectedIndexChanged(Object sender, EventArgs e)
    {
        if (this.MyEvent != null)
        {
            this.MyEvent(sender, e);
        }
    }
}

Voici le présentateur sous test:

public class MyPresenter
{
    private IView _view;
    public MyPresenter(IView view)
    {
        this._view = view;
        this._view.MyEvent += this.OnMyEvent;
    }

    private void OnMyEvent(Object sender, EventArgs e)
    {
        this._view.UpdateView();
    }
}

Voici le test de test MyPresenter:

[TestClass]
public class MyPresenterFixture()
{
    private MyPresenter testee;
    private Mock<IView> mockView;

    [TestMethod]
    public void ShouldReactOnMyEvent()
    {
        // arrange
        this.mockView = new Mock<IView>(MockBehavior.Strict);
        this.testee = new MyPresenter(this.mockView.Object);

        // act
        this.mockView.Raise(mock => mock.MyEvent += null); // this does not fire

        // assert and verify
        this.mockView.Verify(mock => mock.UpdateView(It.IsAny<string>());
    }
}

J'utilise Moq 4. Est-il possible de faire ce que je veux?

Cordialement Yannik

34
Yannik

N'avez-vous pas besoin de passer l'argument? La signature de votre événement est EvenHandler, qui est
(object sender, EventArgs e).

this.mockView.Raise(mock => mock.MyEvent += null, new EventArgs());

Je n'ai jamais utilisé la surcharge que vous avez spécifiée ici ... mais cela ne semble pas correct.

68
Anderson Imes

Vous avez déclaré UpdateView () comme acceptant une chaîne, mais votre invocation de présentateur n'a pas d'argument chaîne (ou par défaut):

Invocation:

private void OnMyEvent(Object sender, EventArgs e)
{
    this._view.UpdateView();
}

Déclaration:

public void UpdateView(string test)
{
    this.textBox.Text = test;
}

Vérification:

mockView.Verify(mock => mock.UpdateView(It.IsAny<string>());

FWIW, je pense que l'événement à votre avis est un peu lourd, un simple changement serait de:

public interface IView
{
    void UpdateText(string test);
}

public class MyPresenter
{
    private readonly IView _view;
    public MyPresenter(IView view)
    {
        _view = view;
    }

    private void SelectItem(string item)
    {
        _view.UpdateText(item);
    }
}

public partial class MyView : IView
{
    private readonly MyPresenter _presenter;

    public MyView()
    {
        _presenter = new MyPresenter(this);
        combo.SelectedIndexChanged += OnSelectedIndexChanged;
    }

    public void UpdateText(string test)
    {
        textBox.Text = test;
    }

    private OnSelectedIndexChanged(Object sender, EventArgs e)
    {
        _presenter.SelectItem(combo.SelectedItem);
    }
}

Ensuite, vous pouvez simplement vérifier l'interaction avec la vue sans avoir d'événement supplémentaire à gérer:

    presenter.SelectItem("Burrito!");

    mockView.Verify(mock => mock.UpdateView("Burrito!");
3
Ritch Melton