2009-04-06 9 views
1

Je suis un peu confus à ce qui se passe ici. Je regarde l'exemple Puzzle d'Atomic Object montrant comment tester un modèle Model-View-Presenter Puzzle.zipC# Noob - Evénement de déclenchement dans une classe d'interface simulée - Comment ce code fonctionne-t-il?

La vue a un événement privé. La vue possède également une fonction Subscribe (déléguer) qui ajoute le délégué à l'événement. Le Presenter est passé dans un IView et un IModel. Pendant la construction, il souscrit à la vue et l'accroche à une fonction sur le modèle.

Pour les tests unitaires du Presenter, la classe View est raillée à l'aide de NMock. Donc, c'est juste une classe stupide, et la fonction Subscribe() ne fait rien. Bien sûr, pour tester le présentateur, vous devez simuler la vue et le modèle, puis déclencher l'événement dans la vue et vous assurer que la fonction du modèle a été appelée. Le code d'exemple fonctionne très bien - cependant, je ne comprends pas comment cela fonctionne !!

Quelques extraits:

private DynamicMock modelMock; 
    private IPuzzleModel model; 
    private DynamicMock viewMock; 
    private IPuzzleView view; 
    private SavedTypeOf moveRequestConstraint; 

    [SetUp] 
    public void SetUp() 
    { 
     modelMock = new DynamicMock(typeof(IPuzzleModel)); 
     modelMock.Strict = true; 
     model = modelMock.MockInstance as IPuzzleModel; 

     // Setup the view 
     viewMock = new DynamicMock(typeof(IPuzzleView)); 
     viewMock.Strict = true; 
     view = viewMock.MockInstance as IPuzzleView; 

     moveRequestConstraint = new SavedTypeOf(typeof(PointDelegate)); 
     viewMock.Expect("SubscribeMoveRequest", moveRequestConstraint); 

     // create the presenter 
     new PuzzlePresenter(model, view); 
    } 

    [Test] 
    public void test_MoveRequest_fromView() 
    { 
     Point point = new Point(1, 2); 
     modelMock.Expect("MoveRequest", point); 
     PointDelegate trigger = moveRequestConstraint.GetInstance as PointDelegate; 
     trigger(point); 
    } 

D'une certaine façon, le « déclencheur (point) » appel est effectivement connecté à la vue, et est à l'origine de l'événement privé dans le but de déclencher. Je ne peux pas comprendre comment cela fonctionne - je ne vois pas où il est connecté à l'instance de vue. Qu'est-ce que je rate? J'essaie d'utiliser NMock 2. Il semble que la variable moveRequestConstraint reçoive la valeur transmise à SubscribeMoveRequest() dans la fonction TestSetup. Cependant, c'est la syntaxe NMock 1 - et NMock 2 ne semble pas supporter cette syntaxe. Comment ferais-je avec NMock 2?

Répondre

1

Exécutez-vous un code de domaine dans votre test? Vous ne testez probablement rien sauf que le constructeur du présentateur ne lance pas d'exception. Par ailleurs, je vous recommande fortement d'utiliser RhinoMocks. Cela ressemblerait à ceci:

private IPuzzleModel model; 
private IPuzzleView view; 
private PointDelegate pointDelegate; 
private Point point; 

[SetUp] 
public void SetUp() 
{ 
    model = MockRepository.CreateMock<IPuzzleModel>(); 
    view = MockRepository.CreateMock<IPuzzleView>(); 

    // get the delegate passed to the mock when it is called 
    // This is one of the more complex things you do with mocks. 
    view.Stub(x => x.Subscribe(Arg<PontDelegate>().Is.Anything) 
     .WhenCalled(call => pointDelegate = (PointDelegate)call.Arguments[0];); 

    point = new Point(1, 2); 
} 

[Test] 
public void test_MoveRequest_fromView() 
{ 
    PuzzlePresenter presenter = new PuzzlePresenter(model, view); 

    // make sure the Delegate method was called and the delegate 
    // is available 
    Assert.IsNotNull(pointDelegate); 

    // fire the delegate. 
    pointDelegate(point); 

    // check if the model was called. 
    model.AssertWasCalled(x => x.MoveRequest(point)); 
} 
0

J'ai rencontré le même problème en essayant de faire fonctionner Presenter First avec NMock2. Après un peu de recherche, j'ai trouvé un post dans le forum NMock2 sur SourceForge.

[Test] 
public void test_MoveRequest_fromView() 
{ 
    Mockery mockery = new Mockery(); 
    IPuzzleView view = mockery.NewMock<IPuzzleView>(); 
    IPuzzleModel model = mockery.NewMock<IPuzzleModel>(); 

    CollectAction collect = new CollectAction(0); 
    Expect.Once.On(view).Method("SubscribeMoveRequest").Will(collect); 
    Expect.Once.On(model).Method("MoveRequest"); 

    new PuzzlePresenter(model, view); 
    Point point = new Point(1, 2); 
    PointDelegate del = collect.Parameter as PointDelegate; 
    del(point); 
    mockery.VerifyAllExpectationsHaveBeenMet(); 
} 

Essayez le code ci-dessus - ne l'avez pas essayé mais cela devrait fonctionner. Il ne lit pas bien comme le reste de NMock2 mais le code de test original dans NMock ne l'a pas non plus.

MISE À JOUR:

Et il semble que la dernière NMock2 (2.0.3411.37113) prend également en charge une version générique de CollectAction, vous pouvez aussi le faire:

PointDelegate savedPointDelegate = null; 
CollectAction<PointDelegate> collect = new CollectAction<PointDelegate>(0, 
    delegate(PointDelegate del) { savedPointDelegate = del; }); 
... 
savedPointDelegate(point); 

ci-dessous est ma tentative amélioration de la lisibilité, mais ce n'est pas tellement d'amélioration:

Expect.Once.On(view).Method("SubscribeMoveRequest").Will(
    Collect.Argument<PointDelegate>(0, delegate(PointDelegate del) { savedPointDelegate = del; })); 

public class Collect 
{ 
    public static CollectAction<T> Argument<T>(int index, CollectAction<T>.Collect collectDelegate) 
    { 
     CollectAction<T> collect = new CollectAction<T>(index, collectDelegate); 
     return collect; 
    } 
} 
Questions connexes