我正在使用Topshelf来托管用C#编写的Windows服务,现在我想编写一些集成测试。我的初始化代码保存在启动器类中,如下所示:
public class Launcher
{
private Host host;
/// <summary>
/// Configure and launch the windows service
/// </summary>
public void Launch()
{
//Setup log4net from config file
log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(DEFAULT_CONFIG));
//Setup Ninject dependency injection
IKernel kernel = new StandardKernel(new MyModule());
this.host = HostFactory.New(x =>
{
x.SetServiceName("MyService");
x.SetDisplayName("MyService");
x.SetDescription("MyService");
x.RunAsLocalSystem();
x.StartAutomatically();
x.Service<MyWinService>(s =>
{
s.ConstructUsing(() => kernel.Get<MyWinService>());
s.WhenStarted(w => w.Start());
s.WhenStopped(w => w.Stop());
});
});
this.host.Run(); //code blocks here
}
/// <summary>
/// Dispose the service host
/// </summary>
public void Dispose()
{
if (this.host != null && this.host is IDisposable)
{
(this.host as IDisposable).Dispose();
this.host = null;
}
}
}
我想编写一些集成测试,以确保正确设置log4net和Ninject,并且Topshelf启动我的服务。问题是,一旦你在Topshelf主机上调用Run()
,代码就会阻塞,所以我的测试代码永远不会运行。
我想在我的测试的Launch()
部分中的一个单独的线程中调用SetUp
但是我需要一些黑客来放入Thread.Sleep(1000)
来确保测试在Launch()
完成之前不要运行。我无法在其上使用正确的同步(例如ManualResetEvent
),因为Launch()
永远不会返回。目前的代码是:
private Launcher launcher;
private Thread launchThread;
[TestFixtureSetUp]
public void SetUp()
{
launcher = new Launcher();
launchThread = new Thread(o => launcher.Launch());
launchThread.Start();
Thread.Sleep(2500); //yuck!!
}
[TestFixtureTearDown]
public void TearDown()
{
if (launcher != null)
{
launcher.Dispose(); //ouch
}
}
理想情况下,我正在寻找的是一种启动服务的非阻塞方式,以及一种将其再次停止放入TearDown
的程序化方法。目前我的TearDown
只是放置了发射器(所以TearDown
确实撕下了它!)。
有没有人有过以这种方式测试Topshelf服务的经验?我可以使用标准ServiceHost
相对容易地完成上述操作,但我更喜欢Topshelf中的显式配置和易于安装。
答案 0 :(得分:2)
https://github.com/Topshelf/Topshelf/blob/v2.3/src/Topshelf/Config/Builders/RunBuilder.cs#L113我认为这就是你想要的。 AfterStartingService
可用于从不同的线程设置ManualResetEvent
。
现在这可能对您有用,但这感觉过于复杂,只需部署到dev / staging并对系统进行冒烟测试即可验证。但是,如果不了解您的环境,那可能是不可能的。
答案 1 :(得分:0)
我今天遇到了同样的问题,我选择将服务实例和交互与实际的Topshelf托管隔离开来(只包括在你的情况下使用Ninject解析你的服务)。
Adam Rodger有一个公平的观点,在快速查看ConsoleRunHost
的Run方法之后,它实际上会挂起来等待ManualResetEvent
并且不会给你控制权直到服务终止。
在您的位置,为了编码您的冒烟/回归测试,只需将内核和模块放入您的SetUp
方法,解析服务,进行测试并将其置于TearDown