2009-07-13 1 views
5

Sto provando a scrivere un test dell'unità C# con il framework di test unità integrato di VS 2008 e il metodo che sto testando chiama Environment.Exit(0). Quando chiamo questo metodo nel mio test unitario, il mio test unitario viene interrotto. Il metodo dovrebbe infatti chiamare Exit, e voglio un modo per testarlo, e anche per testare il codice di uscita che usa. Come potrei farlo? Ho guardato allo Microsoft.VisualStudio.TestTools.UnitTesting Namespace ma non ho visto nulla di rilevante.Test unità VS2008 - metodo assertivo uscite

[TestMethod] 
[DeploymentItem("myprog.exe")] 
public void MyProgTest() 
{ 
    // Want to ensure this Exit's with code 0: 
    MyProg_Accessor.myMethod(); 
} 

Nel frattempo, qui è l'essenza del codice che voglio prova:

static void myMethod() 
{ 
    Environment.Exit(0); 
} 

Edit: ecco la soluzione che ho usato nel mio metodo di prova, grazie a RichardOD:

Process proc; 

try 
{ 
    proc = Process.Start(path, myArgs); 
} 
catch (System.ComponentModel.Win32Exception ex) 
{ 
    proc = null; 
    Assert.Fail(ex.Message); 
} 

Assert.IsNotNull(proc); 
proc.WaitForExit(10000); 
Assert.IsTrue(proc.HasExited); 
Assert.AreEqual(code, proc.ExitCode); 

risposta

4

Sembra un'idea davvero pessima. Environment.Exit (0), ovviamente farà come prescritto, quindi perché i test unitari si stanno rompendo.

Se si vuole ancora testare questo, è possibile avviare un processo separato e controllare il codice di ritorno, dare uno sguardo al pacchetto in Process.Start.

Suppongo che un'altra opzione sia il factoring di questo codice e l'iniezione di un test spy o l'utilizzo di un oggetto fittizio per verificare il comportamento corretto.

Forse si può fare qualcosa con Typemock Isolator- Credo che questo ti permetta di mock static methods.

+0

+1 sul TypeMock Isolator qui - è l'unica soluzione io sappia, che consente di intercettare e modelli assolutamente nulla. –

+0

Il pericolo di essere in grado di prendere in giro metodi statici è che non ti svezzi di usarli con la stessa facilità. In realtà trovo che (per il mio codice) sia costretto a lavorare molto duramente per avere metodi statici è una buona cosa dato che non li userò a meno che non siano la soluzione migliore. Questo aiuta a forzare lo sviluppo usando tecniche migliori, IMO. Il rovescio della medaglia è che sei costretto a saltare attraverso i cerchi quando interagisci con quei metodi statici quando hanno senso (o il framework non è costruito pensando ai test). – tvanfosson

+0

@ tvanfosson- Questo è un buon punto. Ecco perché molte persone (me compreso) cercano di evitare l'uso eccessivo di metodi statici durante la scrittura di codice verificabile. Le classi di framework .NET statiche sono un test del dolore e gli sviluppatori spesso devono ricorrere al codice wrapper per renderlo testabile (come da tua risposta). È possibile vedere molto dall'evoluzione dei moduli Web ASP.NET a ASP.NET MVC. – RichardOD

3

Non è possibile testare questo - Environment.Exit uccide completamente l'applicazione. Ciò significa che qualsiasi AppDomain che utilizza questo codice verrà scaricato completamente, indipendentemente dal fatto che si tratti dell'applicazione di produzione o del framework di test delle unità.

2

L'unica opzione qui sarebbe di prendere in giro la classe Ambiente con un metodo di uscita di fakie.

5

È necessario creare un wrapper per la classe Environment, quindi utilizzare il wrapper nel codice. Per i tuoi test unitari, inserisci una versione finta del wrapper. L'esempio seguente utilizza RhinoMocks per verificare che il metodo chiami il wrapper con l'argomento previsto.

public class EnvironmentWrapper 
{ 
    public virtual void Exit(int code) 
    { 
     Environment.Exit(code); 
    } 
} 


public class MyClass 
{ 
    private EnvironmentWrapper Environment { get; set; } 

    public MyClass() : this(null) { } 

    public MyClass(EnvironmentWrapper wrapper) 
    { 
     this.Environment = wrapper ?? new EnvironmentWrapper(); 
    } 

    public void MyMethod(int code) 
    { 
     this.Environment.Exit(code) 
    } 
} 


[TestMethod] 
public void MyMethodTest() 
{ 
    var mockWrapper = MockRepository.GenerateMock<EnvironmentWrapper>(); 

    int expectedCode = 5; 

    mockWrapper.Expect(m => m.Exit(expectedCode)); 

    var myClass = new MyClass(mockWrapper); 

    myclass.MyMethod(expectedCode); 

    mockWrapper.VerifyAllExpectations() 
} 
+1

+1. Bel esempio, se non stavo mangiando la mia cena stavo andando a codificare qualcosa lungo quelle linee! Il tuo codice mi ricorda il codice predefinito in ASP.NET MVC project AccountController class, che può essere solo una buona cosa. Personalmente cambierei l'ambiente EnvironmentWrapper Environment {get; impostato; } a un set privato, ma a parte questo bell'esempio. – RichardOD

+0

@RichardOD: concordato pubblico/privato. Aggiornerà. – tvanfosson

0

È possibile aggiungere un argomento per il metodo di passare un ambiente falso in cui il metodo exit() non lo faranno uscire.

Questo metodo parametrico può essere estratto dal metodo richiamato dall'applicazione e l'unità verifica la funzione estratta. In questo modo, non dovrai modificare la tua app.

0

L'unica cosa che mi viene in mente è qualcosa insieme:

static void myMethod() 
{ 
    DoEnvironmentExit(0); 
} 

static void DoEnvironentExit(int code) 
{ 
    #if defined TEST_SOLUTION 
     SomeMockingFunction(code); 
    #else 
     Environment.Exit(code); 
    #endif 
}