我正在编写Windows服务,我想针对事件处理程序编写单元测试,以检查它们如何管理工作线程。我已经成功地管理了OnStart,OnStop和OnPause,但OnContinue让我有些焦虑。
Windows服务
Program.Main()
这不会产生任何异常 - 它只是将服务设置为运行。
MyService.cs 这有一个手动重置事件:
private static ManualResetEvent _resetEvent = new ManualResetEvent(false);
MyService.OnStart()
这将创建一个Worker线程,以便主线程可以继续侦听来自服务控制管理器的事件
MyService.OnStop()
检查Workerthread.IsAlive是否为true,如果是,则调用.Abort()就可以了。
MyService.OnPause()
检查Worker的ThreadState是否为Suspended | SuspendRequested,如果没有,则调用_resetEvent上的.Reset()。
注意:目前不确定这些是否是理想状态,或者我是否应该查看状态'WaitSleepJoin'。
MyService.OnContinue()
检查Worker的ThreadState是否为Suspended | SuspendRequested,如果是,则在_resetEvent上调用.Set()。
MyTests
OnStart()测试
这很简单,我只是调用Event Handler,它看到没有Worker线程,所以创建一个。
OnStop()测试
稍微复杂一些。在测试中,我创建了一个调用委托的线程,该委托将其发送到睡眠状态。然后我使用Reflection将其设置为Service中的Worker线程私有属性,然后调用OnStop()事件处理程序。这会找到正在休眠的已启动的工作线程,因此将其中止。
OnPause()测试
与OnStop()测试类似,但是我没有创建一个休眠线程,而是创建一个遍历一个小循环的循环(这个循环足够大,持续几秒钟)。当我调用OnPause()方法时,它找到正在工作的工作线程,并在_resetEvent上调用.Reset()。
OnContinue()测试
所以我的计划是模式化OnPause和OnStop测试,但这次创建一个当前暂停的工作线程。但是,在.NET 4.5中,Thread.Suspend()已过时。
因此我创建了一个本地ManualResetEvent [每单元测试一个;我有OnContinue()事件处理程序的多个单元测试],在我的委托方法中,工作线程正在运行,我将其设置为调用.WaitOne()。如果我运行一个测试,那么工作正常。但如果我将它们全部一起运行,那么每个测试的Unique ManualResetEvent似乎都会影响其他测试。
来自一个单元测试的示例代码,我创建了工作线程并将其注入到服务的私有线程方法中:
const BindingFlags InstanceFlags =
BindingFlags.Instance | BindingFlags.NonPublic;
PropertyInfo prop = t.GetProperty("MyWorkerThread", InstanceFlags);
EventWaitHandle wh2 = new ManualResetEvent(true);
var thread = new Thread(() =>
{
var sb = new Lazy<StringBuilder>();
for (int i = 0; i < 10000000; i++)
{
wh2.WaitOne();
sb.Value.Append(i.ToString());
}
});
thread.Start();
prop.SetValue(service, thread, null);
所以当我在另一个测试中复制它,但是有“wh3”而不是“wh2”时,那么我的测试似乎都会绊倒自己。
工具 使用Visual Studio 2013和NUnit测试运行器。
如果有人能够指出我出错的地方,或者更好的是,请指出一个更好的方法来实现这一目标,我将不胜感激。
非常感谢
格里夫