J'écris des tests unitaires pour une application multi-thread, où je dois attendre qu'un événement spécifique soit déclenché pour que je sache que l'opération asynchrone est terminée. Par exemple, lorsque j'appelle repository.add(something)
, j'attends l'événement AfterChange avant de faire une assertion. J'ai donc écrit une fonction utilitaire pour le faire:Comment passer un événement en paramètre en C#
public static void SyncAction(EventHandler event_, Action action_)
{
var signal = new object();
EventHandler callback = null;
callback = new EventHandler((s, e) =>
{
lock (signal)
{
Monitor.Pulse(signal);
}
event_ -= callback;
});
event_ += callback;
lock (signal)
{
action_();
Assert.IsTrue(Monitor.Wait(signal, 10000));
}
}
Cependant, le compilateur empêche de faire passer l'événement hors de la classe. Y a-t-il un moyen d'y parvenir?
Voici la solution utilisant la réflexion.
public static void SyncAction(object target_, string event_, Action action_)
{
SyncAction(
new List<Pair<object, string>>() { new Pair<object, string>(target_, event_) },
action_);
}
public static void SyncAction(IEnumerable<Pair<object, string>> events_, Action action_)
{
var events = events_
.Select(a => new Pair<object, EventInfo>(a.First, a.First.GetType().GetEvent(a.Second)))
.Where(a => a.Second != null);
var count = events.Count();
var signal = new object();
var callback = new EventHandler((s, e) =>
{
lock (signal)
{
--count;
Monitor.Pulse(signal);
}
});
events.ForEach(a => a.Second.AddEventHandler(a.First, callback));
lock (signal)
{
action_();
while (count > 0)
{
Assert.IsTrue(Monitor.Wait(signal, 10000));
}
}
events.ForEach(a => a.Second.RemoveEventHandler(a.First, callback));
}
Am en utilisant la 2ème approche, et essayer de la réflexion. Rx n'a pas encore approuvé dans mon entreprise que je ne peux pas attendre. Mais certainement, il sera beaucoup plus facile d'écrire des cas de test en utilisant Rx. –