Hallo Ich habe ein Problem beim Testen eines Ereignisses mit NUnit
. Ich bin mir nicht einmal sicher, ob das ein Einheits- oder Funktionstest sein sollte. Lassen Sie mich Ihnen die Beispielklasse zeigen erste (ich versuche OnValueInjected
Ereignis zu testen):Wie kann ein Ereignis während des Komponententests abgefangen werden?
public class Foo
{
private IBar CurrentBar { get; set; }
public event EventHandler<MoveEventArgs> OnValueInjected;
public Foo()
{
StartFoo();
}
private async void StartFoo()
{
await Task.Factory.StartNew(() =>
{
while (State != FooState.Finished)
{
IResult result = CurrentBar.WaitForValue(); // This is blocking function, wait for a value
OnValueInjected?.Invoke(this, new ResultEventArgs(result));
// .. rest of the loop
}
});
}
public void InjectValue(int a, int b)
{
CurrentBar.Inject(a,b);
}
}
Also, im Grunde, was ich versuche zu dem Ereignis abonnieren zu tun ist, rufen InjectValue
und prüfen, ob die Veranstaltung hieß. Wie folgt aus:
[Test]
public void FooOnValueInjectedTest()
{
bool OnValueInjectedWasRasied = false;
IFoo foo = new Foo();
foo.OnValueInjected += (s, e) => OnValueInjectedWasRasied = true;
foo.InjectValue(0,0);
Assert.AreEqual(true, OnValueInjectedWasRasied);
}
Ziemlich einfach, aber es sieht aus wie InjectValue
zu langsam ist. Der Test ist fehlgeschlagen..Ich denke es ist zu langsam, denn wenn ich Thread.Sleep
zwischen InjectValue
und Assert
hinzufüge funktioniert.
foo.InjectValue(0,0);
Thread.Sleep(1000);
Assert.AreEqual(true, OnValueInjectedWasRasied);
Gibt es eine bessere Möglichkeit, ein solches Ereignis zu testen? Dank
fixierte ich meine Klasse, so ist es so, dass jetzt:
public class Foo
{
private AutoResetEvent AutoReset { get; }
private IBar CurrentBar { get; set; }
public event EventHandler<MoveEventArgs> OnValueInjected;
public Foo()
{
AutoReset = new AutoResetEvent(false);
StartFoo();
}
private async void StartFoo()
{
await Task.Factory.StartNew(() =>
{
while (State != FooState.Finished)
{
IResult result = CurrentBar.WaitForValue(); // This is blocking function, wait for a value
OnValueInjected?.Invoke(this, new ResultEventArgs(result));
AutoReset.Set();
// .. rest of the loop
}
});
}
public void InjectValue(int a, int b)
{
if (CurrentBar.Inject(a,b))
{
AutoReset.WaitOne();
}
}
}
Nun, wollen Sie * * Ihre 'InjectValue' zurückzukehren, bevor die Ereignishandler auf jeden Fall angesprochen wurden? Sie sehen im Grunde das natürliche Ergebnis von Asynchronität ... es geht nicht wirklich um Ereignisse, sondern um asynchrone Ausführung. –
@JonSkeet hmm .. technisch, sagst du, dass "InjectValue" blockiert werden konnte, bis 'OnValueInjected' ausgelöst wurde? Ich habe nicht wirklich darüber nachgedacht .. –
Wenn Sie * dieses Verhalten * wollten, könnten Sie es sicherstellen, ja. Ob Sie es tun oder nicht, ist eine andere Sache. –