Как я могу использовать отдельный AppDomain для каждого метода тестирования xUnit.net?
xUnit использует те же AppDomain
для всей тестовой сборки, это проблематично, поскольку я тестирую библиотеку пользовательского интерфейса и вам нужно создать новый экземпляр Application
для каждого отдельного теста.
Это работает, когда я запускаю один тест, но когда я Run All
прошел первый тест, но все последующие тесты терпят неудачу с Cannot create more than one System.Windows.Application instance in the same AppDomain
в строке, где я создаю новый объект Application
.
Ответы
Ответ 1
Возможно, вы могли бы попробовать сделать свой тест class
следующим образом:
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
Возможно, foreach Test вы можете динамически загружать свою сборку в новый домен.
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;
}
Ответ 3
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
}
}
Еще две важные вещи:
1) Возможно, вам нужно будет пометить класс как MarshalByRefObject
и переопределить метод InitializeLifetimeService
, чтобы объект был более продолжительным или существовал. MarshalByRefObject
потребуется, если вам нужно общаться между доменами приложения. Подробнее об этом читайте в концепции Microsoft Remoting.
2) Иногда нам понадобится разрешение сборки в AppDomains, если оно не принимает сборки, загруженные в родительский домен, но это очень редко.