【问题标题】:How can I use a separate AppDomain for each xUnit.net test method?如何为每个 xUnit.net 测试方法使用单独的 AppDomain?
【发布时间】:2014-01-29 20:26:52
【问题描述】:

xUnit 对整个测试程序集使用相同的 AppDomain,这是有问题的,因为我正在测试 UI 库并且需要为每个单独的测试创建一个新的 Application 实例。

当我运行单个测试时它可以工作,但是当我 Run All 第一个测试通过时,但所有后续测试都失败,Cannot create more than one System.Windows.Application instance in the same AppDomain 在我创建新的 Application 对象的那一行。

【问题讨论】:

标签: c# .net xunit.net


【解决方案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
    });
  }

  ...
}

【讨论】:

  • 嗯,这“有效”,但问题是即使 DoCallBack 方法中的测试失败,xUnit 也会报告测试成功。似乎异常被某种方式吞噬了
  • @Flagbug 你能举一个你的失败测试的例子吗?
  • @Flugbug 您是否设法传播异常以便 xUnit 可以检测到它?
  • 异常需要可序列化。如果没有,我发现您仍然会遇到“传播”异常,但这实际上是一个新异常,表明在单独的 AppDomain 中引发的原始异常未标记为可序列化。对我来说已经足够好了,因为据我所知,它仍然表明存在异常。
【解决方案2】:

也许,foreach 测试你可以在一个新的域中动态加载你的程序集。

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 方法以使对象具有更长的寿命或存在。如果您必须在 appdomains 之间进行通信,则需要 MarshalByRefObject。有关此内容的详细信息,请阅读 Microsoft 远程处理概念。

    2) 有时我们可能需要在 AppDomains 中进行程序集解析,如果它不接受在父域中加载的程序集,但在极少数情况下。

    【讨论】:

      猜你喜欢
      • 2019-07-05
      • 2021-04-07
      • 2020-01-02
      • 2011-03-23
      • 1970-01-01
      • 2016-11-07
      • 2019-09-12
      • 1970-01-01
      • 2011-02-12
      相关资源
      最近更新 更多