2011-09-19 11 views
7

Estoy escribiendo la prueba de la unidad y recibo una excepción cuando trato de plantear el evento de la simulación de la clase abstracta. Aquí está el código de ejemplo:C# y Moq, plantear el evento declarado en la interfaz de la clase de simulacro

public abstract class AbstractBase : EntityObject 
    {} 

    [TestMethod] 
    public void MyTest() 
    { 

     var mock = new Mock<AbstractBase>(); 
     var notificationMock = entityMock.As<INotifyPropertyChanged>(); 

     var propertyChangedMapper = new PropertyChangedMapper(); 

     bool eventReceived = false; 
     propertyChangedMapper.MyPropertyChanged += 
      (sender, eventArgs) => 
       { 
        eventReceived = true; 
       }; 

     propertyChangedMapper.Subscribe((AbstractBase)notificationMock.Object); 

     Assert.IsFalse(eventReceived); 

     notificationMock.Raise(e=>e.PropertyChanged += null, 
            new PropertyChangedEventArgs("Property1")); 

     Assert.IsTrue(eventReceived); 
    } 

Obviamente, podría utilizar simulacro en INotifyPropertyChanged y el evento se ha levantado muy bien, pero en el interior de PropertyChangedMapper necesito a emitir el emisor a AbstractBase el que falla si se utiliza Mock<INotifyPropertyChanged>

EDITAR: Según sugerencia usando Mock.As<>() parece ser el camino correcto, el único problema anterior es que el evento resucitado de notificationMock no tiene nada que ver con la simulación original del objeto. Código:

 notificationMock.Object.PropertyChanged += (s, e) => 
     { 
      var result = "this one is fired as it should"; 
     }; 

     mock.Object.PropertyChanged += (s, e) => 
     { 
      var result = "this one is not called but is actually what I need"; 
     }; 

     notificationMock.Raise(e => e.PropertyChanged += null, 
       new PropertyChangedEventArgs("Property1")); 
+0

No importa a cuál llame, siempre que se llame. Mi suposición es que podrías configurar uno u otro. Pero establecer ambas conducirá al simulacro de elegir internamente una sobre otra. –

+0

Para obtener más pruebas de que no importa a qué se llama, considere que el sistema de tipo funciona de manera similar para los miembros virtuales y sus reemplazos. Por ejemplo, si agregó a AbstractBase una anulación para el evento INPC de EntityObject, no hay forma de que ningún código que consuma AbstractBase fuerce la invocación de la versión de EntityObject. Incluso si seleccionas EntityObject, se llamará al miembro de AbstractBase. Una vez que se invalida un miembro base, solo la clase derivada puede acceder al miembro base original. –

Respuesta

1

Usted puede ser capaz de hacer el molde deseado, si usted hace su simulacro de un mult-simulado. Dado que Moq mocks está vinculado a un tipo individual a través del argumento genérico, debe agregar progresivamente interfaces o superclases adicionales al simulacro, y luego usar el producto final en su prueba. Un ejemplo rápido de cómo hacer esto está a continuación.

var baseMock = new Mock<AbstractBase>(); 
var inpcMock = baseMock.As<INotifyPropertyChanged>(); 

// ...setup event... 

propertyChangedMapper.Subscribe(inpcMock.Object); 

// ... assertions ... 
+1

¡Gran característica! Sin embargo, parece que el evento NO se ha levantado a través de 'inpcMock.Raise (e => e.PropertyChanged + = null, new PropertyChangedEventArgs ("Property1")); '- ¿Alguna idea de por qué? – Paul

+0

Consulte la actualización anterior – Paul

1

Dada la forma en que lo hace, no hay implementación del evento. La interfaz en sí misma es solo el contrato que dice "Tengo un evento PropertyChanged". Si desea plantear ese evento, debe proporcionar un controlador, incluso si no hace nada. Implementa el evento PropertyChanged en tu clase simulada para plantear el evento.

ACTUALIZACIÓN:

probar este código para su AbstractBase:

public abstract class AbstractBase : INotifyPropertyChanged 
{ 
    public virtual event PropertyChangedEventHandler PropertyChanged; 
    private void NotifyPropertyChanged(String info) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(info)); 
     } 
    } 
} 
+0

Entonces, ¿qué debería hacerse exactamente para resolver esta excepción? – Paul

+1

Como código como "clase abstracta pública AbstractBase: INotifyPropertyChanged {}" no se puede compilar, creo que acaba de acortar el código aquí ... – David

+0

@Paul: ver actualización. –

1

Es el caso PropertyChanged declarada como un evento virtual?

public abstract class AbstractBase : INotifyPropertyChanged 
{ 
    public virtual event PropertyChangedEventHandler PropertyChanged; 
} 

(Ver también:. Jon Skeet on virtual events)

+0

Consulte la edición anterior – Paul

+0

Supongo que no tengo claro el problema. Su código original funcionó bien para mí (sin todas las cosas 'As <>()'). – ladenedge

+0

Hacer que el evento funcione virtual también, pero solo si esta es mi clase que implementa los eventos. Al heredar de clases base que ya tienen una implementación, no hay forma de hacer que los eventos sean virtuales. Gracias por tu respuesta. – Paul

Cuestiones relacionadas