2009-09-15 12 views
21

Ich entwickle eine asp.net (klassische) Anwendung, die versucht, das MVP-Muster using this example zu implementieren. Bei dem Versuch, zu Einheit meines Moderator testen und das folgende Muster verwenden, sucht der psuedocode, für die wie soÜberprüfen der Ereignisregistrierung mit 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); 

Wie kann ich überprüfen, dass der Moderator macht was erwartet wird, das heißt für die Init und Load-Ereignisse registriert? Während dies leicht in der Phil Haack's example geschieht mit Rhino spottet ...

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

... wie können wir dies mit MOQ tun?

+1

+1 - schlug meinen Kopf gegen die gleiche Wand. – Gishu

Antwort

14

Es scheint, dass diese Funktionalität not currently available in Moq ist, aber möglicherweise in einer zukünftigen Version (ich hatte in der Beta 4.0.812.4, aber es scheint nicht zu sein).

Es kann sich lohnen, die Frage zu stellen, "warum muss SomePresenter die Load und Init Ereignisse der Ansicht abonnieren?" Vermutlich liegt es daran, dass die Klasse SomePresenter auf diese Ereignisse reagieren muss. So könnte es besser sein, die Raise Methode auf Ihrem Mock<IView> zu verwenden, um die Load und Init Ereignisse zu erhöhen, und dann behaupten, dass SomePresenter das richtige Ding als Antwort auf sie getan hat.

+1

Ich dachte darüber nach, im Wesentlichen gibt es zwei Teile zum Testen dieses Stück Code. 1. Interaktionstest ..., der die Ereignisregistrierung überprüft 2. Statusbasierter Test ... der überprüft, ob sich der Ereignishandler im Präsentator wie erwartet verhält. Der saubere Komponententest würde jeden dieser Fälle separat testen. Eine Lösung für (1) ist ein paar Methoden, um die IView-Schnittstelle public interface IView { ... public void RegisterForInit (Eventhandler Rückruf) hinzuzufügen; ... } und ändern Sie den Moderator Konstruktor öffentlichen SomePresenter (...) { ... someView.RegisterFoInit (OnInit); } –

+0

und es folgt, dass Sie Strict Mocks von MOQ nicht verwenden können, wenn Ereignissubskriptionen beteiligt sind. (ächzen) – Gishu

+0

Aktualisierter Link zum GitHub-Problem https://github.com/Moq/moq4/issues/49 bezüglich dieses Problems. – KevM

0

ich einige Zeit mit dieser Frage verbracht, und die Lösung, die ich in meinem Projekt verwenden ist:

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

Getestet Methode:

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

Also zuerst müssen Sie die Methoden verspotten, denen Sie die Ereignisse zuweisen werden, nachdem Sie mich anrufen thod, die Sie testen möchten, und heben Sie schließlich alle abonnierten Ereignisse. Wenn das Ereignis wirklich abonniert ist, können Sie mit Moq überprüfen, ob die zugewiesene Methode aufgerufen wird.

GLHF!

+4

Dies ist jedoch verwirrend. OnEvent1() -Methode ist für das zu testende Objekt, während Raise() für das Mocked-Objekt aufgerufen werden muss. Können Sie den aktuellen Arbeitscode mit allen angezeigten Klassen posten? –

0

Ich weiß, es ist vielleicht zu spät für #Dilip, aber diese Antwort kann hilfreich sein für diejenigen, die versuchen, das gleiche zu tun. Hier ist die Testklasse

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 ein Dekorateur wie folgt implementiert ist (achten Sie auf Events: Init/Load {hinzuzufügen, entfernen}):

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