2016-05-17 64 views
11

Ho un interfaccia come questa:Come si genera un evento quando viene chiamato un metodo usando Moq?

public interface IMyInterface 
{ 
    event EventHandler<bool> Triggered; 
    void Trigger(); 
} 

e ho un oggetto preso in giro nel mio test di unità in questo modo:

private Mock<IMyInterface> _mockedObject = new Mock<IMyInterface>(); 

voglio fare qualcosa di simile:

// pseudo-code 
_mockedObject.Setup(i => i.Trigger()).Raise(i => i.Triggered += null, this, true); 

Tuttavia non sembra che Raise sia disponibile nell'interfaccia ISetup che viene restituita. Come faccio a fare questo?

risposta

14

Il tuo pseudo-codice era quasi azzeccato. È necessario utilizzare Raises anziché Raise. Controlla il Moq Quickstart: Events per le versioni Moq 4.x e vedrai dove hai commesso l'errore.

_mockedObject.Setup(i => i.Trigger()).Raises(i => i.Triggered += null, this, true); 

Ecco la snippet form GitHub

// Raising an event on the mock 
mock.Raise(m => m.FooEvent += null, new FooEventArgs(fooValue)); 

// Raising an event on a descendant down the hierarchy 
mock.Raise(m => m.Child.First.FooEvent += null, new FooEventArgs(fooValue)); 

// Causing an event to raise automatically when Submit is invoked 
mock.Setup(foo => foo.Submit()).Raises(f => f.Sent += null, EventArgs.Empty); 
// The raised event would trigger behavior on the object under test, which 
// you would make assertions about later (how its state changed as a consequence, typically) 

// Raising a custom event which does not adhere to the EventHandler pattern 
public delegate void MyEventHandler(int i, bool b); 
public interface IFoo 
{ 
    event MyEventHandler MyEvent; 
} 

var mock = new Mock<IFoo>(); 
... 
// Raise passing the custom arguments expected by the event delegate 
mock.Raise(foo => foo.MyEvent += null, 25, true); 
+0

Questa è la lettera per lettera esattamente quello che ho in parte pseudo codice della mia domanda. Stavo chiedendo perché questa non è una sintassi valida; Alza non è disponibile quando si chiama l'installazione. – SoaperGEM

+0

Sì, lo è. Quale versione di Moq stai usando? L'ho provato nel mio codice ed è lì. Hai appena fatto un refuso. Controlla il link che ho incluso. – Nkosi

+0

'Raise' viene eseguito sul mock stesso non sul setup – Nkosi

4

Così ho capito quello che stavo facendo male. Ho intenzione di pubblicare la risposta qui, ma dare il merito a Nkosi perché non ho davvero fatto la domanda correttamente, e mi ha fornito molte informazioni utili.

Con un metodo asincrono su una simulazione, è necessario innanzitutto specificare che restituisce un'attività prima di poterla attivare eventi. Così, nel mio esempio (rendendosi conto che avrei dovuto avere Task Trigger(); come la firma del metodo, questo è il codice che cercavo:

_mockedObject.Setup(i => i.Trigger()) 
    .Returns(Task.FromResult(default(object))) 
    .Raise(i => i.Triggered += null, this, true); 

Apparentemente questo può essere semplificata ulteriormente in C# 4.6, a questo:

_mockedObject.Setup(i => i.Trigger()) 
    .Returns(Task.CompletedTask) 
    .Raise(i => i.Triggered += null, this, true); 
1

Espansione sulla risposta di SoaperGEM, tutti i metodi che restituiscono qualcosa (indipendentemente dal tipo) devono avere il valore restituito specificato prima di attivare l'evento. Poiché i metodi asincroni restituiscono Task, i metodi asincroni rientrano in questa categoria. a string, e stavo cercando di capire perché non potevo innesca l'evento con l'oggetto Mock. Poi ho provato a tornare prima e ha funzionato bene.

Prendendo l'esempio di SoaperGEM, e assumendo Trigger() restituisce una stringa:

_mockedObject.Setup(i => i.Trigger()) 
    .Returns("somestring") 
    .Raises(i => i.Triggered += null, this, true); 
Problemi correlati