En voici un pour les drogués du threading. J'ai cette méthode:Test de problème NMock par rapport à WPF et Dispatcher
public void RefreshMelts()
{
MeltsAvailable.Clear();
ThreadPool.QueueUserWorkItem(delegate
{
Dispatcher.BeginInvoke((ThreadStart)delegate
{
eventAggregator.GetEvent<BusyEvent>().Publish(true);
eventAggregator.GetEvent<StatusMessageEvent>().Publish(
new StatusMessage("Loading melts...", MessageSeverity.Low));
});
try
{
IList<MeltDto> meltDtos = meltingAppService.GetActiveMelts();
Dispatcher.Invoke((ThreadStart)delegate
{
foreach (MeltDto availableMelt in meltDtos)
{
MeltsAvailable.Add(availableMelt);
}
OnPropertyChanged("MeltsAvailable");
eventAggregator.GetEvent<BusyEvent>().Publish(false);
eventAggregator.GetEvent<StatusMessageEvent>().Publish(
new StatusMessage("Melts loaded", MessageSeverity.Low));
});
}
catch (ApplicationException ex)
{
log.Error("An error occurred in MeltsViewModel when attempting to load melts", ex);
Dispatcher.Invoke((ThreadStart)delegate
{
MeltsAvailable.Clear();
eventAggregator.GetEvent<StatusMessageEvent>().Publish(
new StatusMessage("Melt data could not be loaded because an error occurred; " +
"see the application log for detail",
MessageSeverity.High));
eventAggregator.GetEvent<BusyEvent>().Publish(false);
});
}
});
}
Ceci est défini dans un contrôle utilisateur WPF. MeltsAvailable est une ObservableCollection de MeltDtos. Ce code fonctionne très bien lors de l'exécution dans l'application elle-même. Le problème est que je voudrais créer un test unitaire, en utilisant NMock, pour vérifier les résultats de cette méthode - spécifiquement, qu'une fois appelée, la propriété MeltsAvailable a quelques éléments. Voici la méthode de test:
[TestMethod]
public void GetAvailableMeltsTest()
{
MeltDto mockMelt1 = new MeltDto();
MeltDto mockMelt2 = new MeltDto();
mockMelt1.MeltIdentifier = "TST0001";
mockMelt2.MeltIdentifier = "TST0002";
IList<MeltDto> availableMelts = new List<MeltDto>();
availableMelts.Add(mockMelt1);
availableMelts.Add(mockMelt2);
Expect.Exactly(1).On(service).Method("GetActiveMelts").Will(Return.Value(availableMelts));
MeltsViewModel vm = new MeltsViewModel(aggregator, logger, service, configManagerFactory); // All of these are mock objects
vm.RefreshMelts();
Thread.Sleep(millisecondDelayForEventPublish * 100);
mockery.VerifyAllExpectationsHaveBeenMet();
Assert.AreEqual(vm.MeltsAvailable.Count, 2);
Assert.AreEqual(vm.MeltsAvailable[0].MeltIdentifier, "TST0001");
Assert.AreEqual(vm.MeltsAvailable[1].MeltIdentifier, "TST0002");
}
Le test échoue systématiquement sur le premier Assert.AreEqual. vm.MeltsAvailable est vide à ce stade.
Si je bande tout le filetage et le laisser comme:
public void RefreshMelts()
{
MeltsAvailable.Clear();
IList<MeltDto> meltDtos = meltingAppService.GetActiveMelts();
foreach (MeltDto availableMelt in meltDtos)
{
MeltsAvailable.Add(availableMelt);
}
OnPropertyChanged("MeltsAvailable");
}
Le test passe. Donc, évidemment, il y a quelque chose qu'il n'aime pas dans les threads - mais même en activant Debug-> Exceptions-> CLR Exceptions-> Thrown, et en désactivant Just My Code, je ne reçois aucune exception dans RefreshMelts .
La partie la plus étrange est que l'appel Dispatcher.Invoke où je charge les objets MeltDto dans la collection MeltsAvailable ne semble jamais être appelé. Je peux couvrir toute la section avec des points d'arrêt, et ils ne sont jamais touchés. Boosting the Thread.Sleep temps dans mon test pour même aussi haut que dix secondes ne change rien.
Pourquoi? Pourquoi cette section ne s'exécute-t-elle pas? Pourquoi ne puis-je pas y entrer ou y pénétrer, pourquoi ne reçois-je pas d'exceptions, pourquoi cela fonctionne-t-il bien dans l'exécution, mais pas dans un test?
Merci beaucoup, Steve