5

我正在使用Topshelf来托管以C#编写的Windows服务,现在我想编写一些集成测试。我的初始化代码在发射类像下面的召开方式:使用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(),代码就会阻塞,所以我的测试代码永远不会运行。

我想在我的测试中SetUp部分调用Launch()在一个单独的线程,但后来我需要一个黑客位的放在一个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中的显式配置和易于安装。

回答

2

https://github.com/Topshelf/Topshelf/blob/v2.3/src/Topshelf/Config/Builders/RunBuilder.cs#L113我想是你想要的。 AfterStartingService可用于设置不同线程的ManualResetEvent

现在这可能会适合您,但这种感觉过于复杂,可以通过部署到dev/staging并对您的系统执行冒烟测试来验证。但是,如果不了解您的环境,那可能是不可能的。

+3

链接已损坏 – SteveC 2015-05-03 15:04:52

+0

@ SteveC不在了。该链接目前可以访问。 – dotnetguy 2016-05-05 04:52:36

0

今天我有同样的问题,我选择从实际的Topshelf托管(它只不过是在您的案例中使用Ninject解决您的服务而构成)来隔离服务实例和交互。

Adam Rodger有一个公平点,在快速查看ConsoleRunHost的Run方法后,它实际上会挂起以等待ManualResetEvent,并且在服务终止之前不会给您控制权。

在你的地方,编写你的烟/回归测试,只得到内核和模块到您的SetUp方法,解决了服务,做您的测试和部署其在TearDown

相关问题