2014-01-20 11 views
13

xUnit verwendet dieselbe AppDomain für die gesamte Testassembly. Dies ist problematisch, da ich eine UI-Bibliothek teste und eine neue Application Instanz für jeden einzelnen Test erstellen muss.Wie kann ich eine separate AppDomain für jede xUnit.net-Testmethode verwenden?

Es funktioniert, wenn ich einen einzelnen Test ausführen, aber wenn ich Run All der erste Test bestanden, aber alle nachfolgenden Tests fehlschlagen mit Cannot create more than one System.Windows.Application instance in the same AppDomain an der Linie, wo ich ein neues Application Objekt erstellen.

+0

Für jeden Test (dh Testverfahren) oder jeden Text "Fixture" –

+2

@PeterRitchie Für jede Testmethode (FACT) – Flagbug

+2

http://patrick.lioi.net/2013/04/18/isolating-execution/ –

Antwort

5

Vielleicht könnten Sie versuchen, Ihren Test class wie diese machen:

public class DomainIsolatedTests : IDisposable 
{ 
    private static int index = 0; 
    private readonly AppDomain testDomain; 

    public DomainIsolatedTests() 
    { 
    var name= string.Concat("TestDomain #", ++index); 
    testDomain = AppDomain.CreateDomain(name, AppDomain.CurrentDomain.Evidence, AppDomain.CurrentDomain.SetupInformation); 
    // Trace.WriteLine(string.Format("[{0}] Created.", testDomain.FriendlyName)); 
    } 

    public void Dispose() 
    { 
    if (testDomain != null) 
    {   
     // Trace.WriteLine(string.Format("[{0}] Unloading.", testDomain.FriendlyName)); 
     AppDomain.Unload(testDomain);   
    } 
    } 

    [Fact] 
    public void Test1() 
    { 
    testDomain.DoCallBack(() => { 
     var app = new System.Windows.Application(); 

     ... 
     // assert 
    }); 
    } 

    [Fact] 
    public void Test2() 
    { 
    testDomain.DoCallBack(() => { 
     var app = new System.Windows.Application(); 

     ... 
     // assert 
    }); 
    } 

    [Fact] 
    public void Test3() 
    { 
    testDomain.DoCallBack(() => { 
     var app = new System.Windows.Application(); 

     ... 
     // assert 
    }); 
    } 

    ... 
} 
+2

Hm, das "funktioniert", aber das Problem ist, dass selbst wenn ein Test in der DoCallBack-Methode fehlschlägt, xUnit meldet, dass der Test erfolgreich war. Scheint so, als ob die Ausnahme irgendwie verschluckt wird. – Flagbug

+0

@Flagbug könntest du ein Beispiel für deinen _failing_test geben? – IronGeek

+0

@Flugbug haben Sie es geschafft, die Ausnahme zu propagieren, damit xUnit sie erkennen kann? – khorvat

0

Vielleicht, foreach-Test Sie Ihre Assembly in einer neuen Domain dynamisch laden kann.

public static void DynamicExecution(String assemblyFileName, String uniqueDomName) 
{ 
    Boolean retVal = false; 

     AppDomain newDomain = AppDomain.CreateDomain(uniqueDomName); 
     YourClass yourClass = (YourClass)newDomain.CreateInstanceFromAndUnwrap(assemblyFileName, "YourClass"); 

     //do what you need with yourClass Object 


     AppDomain.Unload(newDomain); 
     newDomain = null; 
} 
0
AppDomain appDomain = AppDomain.CreateDomain("WorkerDomain " + Thread.CurrentThread.Name); 

var domain = (AppDomainWorker)appDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, typeof(AppDomainWorker).FullName); 

domain.Executor(); 

internal class AppDomainWorker 
{ 
    internal object Executor() 
    { 
     // your unit test can run here 
    } 
} 

Zwei weitere wichtige Dinge:

1) Sie könnten Klasse als MarshalByRefObject markieren müssen und InitializeLifetimeService Methode überschreiben, ein Objekt längere Lebensdauer oder Existenz haben . MarshalByRefObject wird benötigt, wenn Sie zwischen appdomains kommunizieren müssen. Details dazu finden Sie im Microsoft Remoting-Konzept.

2) Manchmal müssen wir vielleicht Montageauflösung in AppDomains, wenn es nicht die Assemblys in der übergeordneten Domäne geladen dauert, aber es ist in sehr seltenen Fällen.