2009-09-15 9 views
21

Estoy desarrollando una aplicación asp.net (clásica) que intenta implementar el patrón MVP using this example. Al tratar de probar mi unidad presentadora y usando el siguiente patrón, el psuedocode para que se parece a lo queVerificando el registro de eventos usando 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); 

¿Cómo verifico que está haciendo lo que se espera que el presentador es decir, de registrarse para los eventos de inicio y de carga? Si bien esto se hace fácilmente en el Phil Haack's example usando Rhino se burla ...

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

... ¿cómo podemos hacer esto utilizando MOQ?

+1

+1 - golpeó la cabeza contra la misma pared. – Gishu

Respuesta

14

Parece que esta funcionalidad es not currently available en moq, pero puede aparecer en una versión futura (eché un vistazo en la versión beta 4.0.812.4, pero no parece estar allí).

Puede valer la pena hacer la pregunta, "¿por qué SomePresenter necesita suscribirse a los eventos Load y Init de View?" Presumiblemente es porque la clase SomePresenter necesita responder a esos eventos. Por lo tanto, podría ser mejor utilizar el método Raise en su Mock<IView> para generar los eventos Load y Init, y luego afirmar que SomePresenter hizo lo correcto en respuesta a ellos.

+1

Pensé en eso, esencialmente hay dos partes para probar esta pieza de código. 1. Prueba de interacción ... que verifica el registro de eventos 2. Prueba basada en el estado ... que verifica que el controlador de eventos en el presentador se comporte como se esperaba. La prueba de unidad limpia sería probar cada uno de esos casos por separado. Una solución de (1) es agregar un par de métodos para la interfaz IView interfaz pública IView { ... public void RegisterForInit (manejador de sucesos de devolución de llamada); ... } y modificar el constructor presentador SomePresenter pública (...) { ... someView.RegisterFoInit (OnInit); } –

+0

y se deduce que no puede usar Strict Mocks desde MOQ si hay implicaciones de eventos involucradas. (gemido) – Gishu

+0

Enlace actualizado al problema de GitHub https://github.com/Moq/moq4/issues/49 con respecto a esta preocupación. – KevM

0

pasé algún tiempo con esta pregunta y la solución que estoy usando en mi proyecto es: Prueba

Unidad:

// 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étodo Probado:

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

Entonces, primero tiene que burlarse de los métodos que asignará a los eventos, después de llamarme que desea probar y, finalmente, plantear todos los eventos suscritos. Si el evento está realmente suscrito, puede consultar con Moq si se llama al método asignado.

GLHF!

+4

Esto es confuso. El método OnEvent1() está en el objeto bajo prueba, mientras que Raise() necesita ser llamado en el objeto burlado. ¿Se puede publicar el código de trabajo real con todas las clases que se muestran? –

0

Sé que quizás sea demasiado tarde para #Dilip, pero esta respuesta puede ser útil para aquellos que intentan hacer lo mismo. Aquí es la clase de prueba

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 es un decorador implementado de la siguiente manera (prestar atención a Eventos: Init/Cargar {añadir, retirar}):

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