5

Sto usando Topshelf per ospitare un servizio Windows scritto in C# e ora voglio scrivere alcuni test di integrazione. Il mio codice di inizializzazione si svolge in una classe lanciatore come il seguente:Test di integrazione con Topshelf per avviare un servizio Windows C#

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; 
     } 
    } 
} 

voglio scrivere alcuni test di integrazione per assicurarsi che log4net e Ninject avere istituito correttamente e TopShelf lancia il mio servizio. Il problema è che, una volta chiamato Run() sull'host di Topshelf, il codice si blocca e il codice di test non viene mai eseguito.

ho pensato di chiamare Launch() in un thread separato nella sezione SetUp dei miei test, ma poi ho bisogno di un po 'di hack per mettere in un Thread.Sleep(1000) per assicurarsi che i test non vengono eseguiti prima Launch() ha finito. Non riesco a utilizzare una sincronizzazione adeguata su di esso (ad esempio ManualResetEvent) perché Launch() non restituisce mai. Il codice attuale è:

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 
    } 
} 

Idealmente quello che sto cercando è un modo non-blocking del lancio del servizio e un modo programmatico di fermarsi di nuovo per mettere nel mio TearDown. Al momento il mio TearDown dispone solo del launcher (quindi lo TearDown lo strappa letteralmente!).

Qualcuno ha esperienza nel test dei servizi di Topshelf in questo modo? Posso fare quanto sopra facilmente usando lo standard ServiceHost ma preferisco di gran lunga la configurazione esplicita e la facilità di installazione in Topshelf.

risposta

2

https://github.com/Topshelf/Topshelf/blob/v2.3/src/Topshelf/Config/Builders/RunBuilder.cs#L113 Penso che sia quello che vuoi. AfterStartingService può essere utilizzato per impostare uno ManualResetEvent da un thread diverso.

Ora questo potrebbe funzionare per voi, ma questo sembra eccessivamente complicato e potrebbe essere convalidato solo mediante l'implementazione di dev/staging e test del fumo sul vostro sistema. Tuttavia, senza una maggiore comprensione del proprio ambiente, ciò potrebbe non essere possibile.

+3

Il collegamento è interrotto – SteveC

+0

@ SteveC non più. Il link è accessibile al momento. – dotnetguy

0

Ho avuto lo stesso problema oggi e ho scelto di isolare l'istanza e l'interazione del servizio dall'hosting Topshelf effettivo (che consiste in nient'altro che la risoluzione del servizio usando Ninject nel tuo caso).

Adam Rodger ha un punto giusto e dopo aver dato una rapida occhiata al metodo Run per lo ConsoleRunHost, in realtà si bloccherà per attendere uno ManualResetEvent e non restituirà il controllo fino al termine del servizio.

Al tuo posto, per codificare i test di fumo/regressione, appena ottenere il kernel e il modulo nel vostro metodo di SetUp, risolvere il servizio, fare le vostre prove e gettare nel TearDown

Problemi correlati