2009-09-15 13 views
21

Sto sviluppando un'applicazione asp.net (classica) che tenta di implementare il pattern MVP using this example. Nel tentativo di unità di testare il mio presentatore e utilizzando il seguente modello, la psuedocodarlo per il quale assomiglia in modoVerifica registrazione evento tramite 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); 

Come faccio a verificare che il presentatore sta facendo ciò che è previsto vale a dire la registrazione per gli eventi Init e carico? Anche se questo è fatto facilmente nel Phil Haack's example usando Rhino prende in giro ...

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

... come possiamo farlo usando MOQ?

+1

+1 - ha colpito la mia testa contro lo stesso muro. – Gishu

risposta

14

Sembrerebbe che questa funzionalità sia not currently available in moq, ma potrebbe apparire in una versione futura (ho avuto un aspetto nella versione 4.0.812.4 beta, ma non sembra esserci).

Può valere la pena di porre la domanda "perché SomePresenter è necessario sottoscrivere gli eventi Load e Init della Visualizzazione?" Presumibilmente è perché la classe SomePresenter deve rispondere a quegli eventi. Quindi potrebbe essere preferibile utilizzare il metodo Raise su Mock<IView> per aumentare gli eventi Load e Init e quindi asserire che SomePresenter ha fatto la cosa giusta in risposta a loro.

+1

Ci ho pensato, in sostanza ci sono due parti per testare questo pezzo di codice. 1. Test di interazione ... che verifica la registrazione dell'evento 2. Test basato sullo stato ... che verifica che il gestore eventi nel presentatore si comporti come previsto. Il test dell'unità pulita sarebbe di testare ciascuno di questi casi separatamente. Una soluzione per la (1) è quello di aggiungere un paio di metodi per l'interfaccia IView interfaccia pubblica IView { ... public void RegisterForInit (EventHandler callback); ... } e modificare il costruttore presentatore di SomePresenter pubblico (...) { ... someView.RegisterFoInit (OnInit); } –

+0

e ne consegue che non è possibile utilizzare Mittenti rigorosi da MOQ se sono coinvolte sottoscrizioni di eventi. (lamentarsi) – Gishu

+0

Link aggiornato al problema GitHub https://github.com/Moq/moq4/issues/49 riguardo a questa preoccupazione. – KevM

0

ho trascorso qualche tempo a questa domanda e la soluzione che sto utilizzando nel mio progetto è: prova

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

metodo collaudato:

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

Quindi, prima devi prendere in giro i metodi a cui assegnerai gli eventi, dopo che avrai chiamato me thod che vuoi testare e infine aumentare tutti gli eventi sottoscritti. Se l'evento è realmente sottoscritto, è possibile verificare con Moq se viene chiamato il metodo assegnato.

GLHF!

+4

Ciò è tuttavia confuso. Il metodo OnEvent1() si trova sull'oggetto sotto test, mentre Raise() deve essere chiamato sull'oggetto mocked. Puoi pubblicare codice di lavoro effettivo con tutte le classi mostrate? –

0

So che forse è troppo tardi per #Dilip, ma questa risposta può essere utile per coloro che stanno cercando di fare lo stesso. Ecco la classe di 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 è un decoratore implementato come segue (prestare attenzione a Eventi: Init/Load {aggiungere, togliere}):

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