2009-09-15 9 views
21

Je développe une application asp.net (classique) qui tente d'implémenter le modèle MVP using this example. En essayant de tester mon unité présentateur et en utilisant le modèle suivant, le psuedocode pour qui ressemble siVérification de l'enregistrement d'un événement à l'aide de Moq

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

Comment puis-je vérifier que le présentateur fait ce que devrait dire l'enregistrement des événements Init et charge? Bien que cela se fait facilement dans le Phil Haack's example en utilisant Rhino se moque ...

[Test] 
public void VerifyAttachesToViewEvents() 
{ 
    viewMock.Load += null; 
    LastCall.IgnoreArguments(); 
    viewMock.PostSaved += null; 
    LastCall.IgnoreArguments(); 
    mocks.ReplayAll(); 
    new PostEditController(viewMock, 
     this.dataServiceMock); 
    mocks.VerifyAll(); 
} 

... Comment pouvons-nous faire cela en utilisant MOQ?

+1

+1 - frapper ma tête contre le même mur. – Gishu

Répondre

14

Il semblerait que cette fonctionnalité soit not currently available dans moq, mais pourrait apparaître dans une prochaine version (j'ai jeté un oeil dans la version bêta de 4.0.812.4, mais il ne semble pas être là).

Il peut être utile de se poser la question suivante: «Pourquoi SomePresenter doit-il s'abonner aux événements Load et Init de View? Vraisemblablement, c'est parce que la classe SomePresenter doit répondre à ces événements. Il peut donc être préférable d'utiliser la méthode Raise sur votre Mock<IView> pour déclencher les événements Load et Init, puis d'affirmer que SomePresenter a bien réagi à ces événements.

+1

J'ai réfléchi à cela, essentiellement il y a deux parties pour tester ce morceau de code. 1. Test d'interaction ... qui vérifie l'enregistrement d'un événement 2. Test basé sur l'état ... qui vérifie que le gestionnaire d'événements dans le présentateur se comporte comme prévu. Le test d'unité propre consisterait à tester chacun de ces cas séparément. Une solution pour (1) est d'ajouter quelques méthodes à l'interface IView interface publique IView {... RegisterForInit public void (rappel EventHandler); ... } et modifier le constructeur du présentateur à SomePresenter public (...) {... someView.RegisterFoInit (OnInit); } –

+0

et il s'ensuit que vous ne pouvez pas utiliser Strict Mocks de MOQ si des abonnements à des événements sont impliqués. (gémissement) – Gishu

+0

Mise à jour du lien vers le numéro GitHub https://github.com/Moq/moq4/issues/49 concernant cette préoccupation. – KevM

0

J'ai passé quelque temps avec cette question et la solution que je me sers dans mon projet est:

test Unité:

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

méthode éprouvée:

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

Donc, d'abord, vous devez vous moquer des méthodes que vous allez affecter les événements, après avoir appelé le moi thod que vous voulez tester, et enfin élever tous les événements souscrits. Si l'événement est réellement abonné, vous pouvez vérifier avec Moq si la méthode assignée est appelée.

GLHF!

+4

Ceci est déroutant cependant. La méthode OnEvent1() est sur l'objet testé, tandis que Raise() doit être appelée sur l'objet simulé. Pouvez-vous poster le code de travail réel avec toutes les classes montrées? –

0

Je sais qu'il est peut-être trop tard pour #Dilip, mais cette réponse peut être utile pour ceux qui essaient de faire la même chose. Voici la classe de test

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 est un décorateur mis en œuvre comme suit (attention aux événements: Init/Charger {ajouter, supprimer}):

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