这是那里的线程迷。我有这个方法:
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);
});
}
});
}
这是在 WPF 用户控件中定义的。MeltsAvailable 是 MeltDtos 的 ObservableCollection。此代码在应用程序本身中运行时运行良好。
问题是我想创建一个单元测试,使用 NMock 来验证这个方法的结果 - 具体来说,一旦它被调用, MeltsAvailable 属性就有一些项目。下面是测试方法:
[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");
}
测试在第一个 Assert.AreEqual 上始终失败。vm.MeltsAvailable 此时为空。
如果我剥离所有线程并将其保留为:
public void RefreshMelts()
{
MeltsAvailable.Clear();
IList<MeltDto> meltDtos = meltingAppService.GetActiveMelts();
foreach (MeltDto availableMelt in meltDtos)
{
MeltsAvailable.Add(availableMelt);
}
OnPropertyChanged("MeltsAvailable");
}
测试通过。
所以,很明显,它不喜欢线程的一些东西——但即使打开 Debug->Exceptions->CLR Exceptions->Thrown,并关闭 Just My Code,我在 RefreshMelts 中也没有任何异常。
最奇怪的部分是,我将 MeltDto 对象加载到 MeltsAvailable 集合中的 Dispatcher.Invoke 调用似乎从未被调用过。我可以用断点覆盖整个部分,它们永远不会被击中。在我的测试中将 Thread.Sleep 时间提高到甚至高达 10 秒并没有任何改变。
为什么?为什么该部分没有执行,为什么我不能进入或闯入它,为什么我没有收到异常,为什么它在执行中可以正常工作,但在测试中却不行?
非常感谢,史蒂夫