【问题标题】:Start WPF app from unit test in its own AppDomain从自己的 AppDomain 中的单元测试启动 WPF 应用程序
【发布时间】:2014-06-20 15:58:45
【问题描述】:

我正在尝试从 nunit 运行 WPF 应用程序。由于每个 AppDomain 只能运行一个应用程序,因此我在每个验收测试中实例化一个新的 AppDomain。当我这样做时,我会遇到序列化异常。

namespace Tests
{
    [TestFixture, RequiresSTA, Serializable]
    public class ApplicationTests
    {
        private MainWindow mainWindow;
        private bool guiVisible;
        private App app;

        [TestCase("app domain name for instance of App")]
        [TestCase("app domain name for another instance of App")]
        public void ApplicationTest(string name)
        {
            AppDomain appDomain = AppDomain.CreateDomain(name);
            //appDomain.ExecuteAssembly(@"C:\Users\bp\Documents\Visual Studio 2013\Projects\WpfApplication1\WpfApplication1\bin\Debug\WpfApplication1.exe");

            CrossAppDomainDelegate action = () =>
            {
                app = new App();
                app.InitializeComponent();
                app.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() => AppOnActivated(null, null)));
                app.Run();
            };
            appDomain.DoCallBack(action);
        }

        private void AppOnActivated(object sender, EventArgs eventArgs)
        {
            if (!guiVisible)
            {
                mainWindow = (MainWindow)Application.Current.MainWindow;
                mainWindow.ButtonViewModel = new ButtonViewModel();
                mainWindow.ButtonViewModel.Name = "bla";

                guiVisible = true;
            }

            app.Shutdown();
        }
    }
}

我现在收到的异常:

System.Runtime.Serialization.SerializationException : 类型不是 为成员“Tests.ApplicationTests,Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'。

我创建了测试类[Serializable],这也无济于事。

非常感谢您的帮助。我只是想从 NUnit 测试启动我的 WPF 应用程序,以便我可以为我的应用程序编写验收测试。我不断遇到不同的墙壁,最终我选择的任何路径似乎都会导致死胡同......

非常感谢,

基础

【问题讨论】:

  • 这是您的整个测试代码还是您遗漏了什么?从异常看来,您已经在 CrossAppDomainDelegate lambda 中捕获了 this 指针(例如,通过使用某些字段或实例方法)。当您尝试在另一个 AppDomain 上执行代码时,它会尝试反序列化 ApplicationTests 类并失败(可能是因为不同的程序集基路径。)
  • @EliArbel 我用完整的测试文件更新了问题。我对AppDomains 不是很熟悉吗,你建议我做什么组装基础路径?也许更重要的是,我正在尝试做的事情可能的,对吧?

标签: c# wpf serialization nunit appdomain


【解决方案1】:

AppDomain 是 .NET 中的软件隔离进程。这意味着您不能只从另一个 AppDomain 引用属于一个 AppDomain 的对象。对象可以按值(序列化)复制,也可以使用MarshalByRefObject 通过引用复制。由于 WPF 的对象都不是这些,因此您不能在 AppDomains 中移动它们。

为了您的测试目的,您可以使用更简单的方法:在新的 AppDomain 中运行所有内容,并使用 SetDataGetData 方法传输数据以进行断言。

[TestCase("app domain name for instance of App")]
[TestCase("app domain name for another instance of App")]
public void ApplicationTest(string name)
{
    AppDomain appDomain = AppDomain.CreateDomain(name, 
        AppDomain.CurrentDomain.Evidence,
        AppDomain.CurrentDomain.SetupInformation);
    appDomain.DoCallBack(StartApp);
    Assert.IsTrue((bool)appDomain.GetData("GuiVisible"));
    AppDomain.Unload(appDomain);
}

// using a static method instead of a lambda makes sure
// you haven't captured anything
private static void StartApp()
{
    app = new App();
    app.InitializeComponent();
    app.Dispatcher.BeginInvoke(DispatcherPriority.Loaded,
       new Action(() => AppOnActivated()));
    app.Run();
}

private static void AppOnActivated()
{
    var mainWindow = (MainWindow)Application.Current.MainWindow;
    mainWindow.ButtonViewModel = new ButtonViewModel();
    mainWindow.ButtonViewModel.Name = "bla";

    AppDomain.CurrentDomain.SetValue("GuiVisible") = true;

    app.Shutdown();
}

【讨论】:

  • 你好,Eli,尝试了你的方法,不幸的是,当 appDomain.DoCallBack(StartApp); 被执行时,它让我进入了 4 号墙:An exception of type 'System.IO.FileNotFoundException' occurred in Tests.dll but was not handled in user code.。 (我在 StartApp 中输入了一个断点,没有命中)。我真的很惊讶像从单元测试中执行 WPF 应用程序这样的琐碎事情是多么繁琐......我希望这只会让你更有决心提供帮助,但我也可以想象相反的情况:)。提前谢谢,也非常感谢您提供额外的信息
  • 一定是因为AppDomain中的组装路径不同。我已经更新了答案,它现在应该可以工作了。
  • 您好 Eli,我正在专门研究这个方向,以便我可以测试应用程序的集成方面,而不是孤立地测试 ViewModels。有了您的额外反馈,我收到了另一个例外:System.IO.IOException : Assembly.GetEntryAssembly() returns null. Set the Application.ResourceAssembly property。添加Application.ResourceAssembly = Assembly.GetAssembly(typeof(App)); 并不能解决问题。你有更多提示吗?我还没准备好放弃:)。感谢您到目前为止的帮助!
  • 你需要在静态方法StartApp里面添加这个。
  • 天啊,突然那个该死的按钮变成了绿色!哦,伊莱,我会投票给你总统。我感觉我同时阅读了整个互联网,但是……最终的结果,多亏了你,是一个绿色测试!谢谢!
猜你喜欢
  • 2011-01-23
  • 1970-01-01
  • 2019-11-21
  • 1970-01-01
  • 1970-01-01
  • 2014-07-08
  • 2012-02-07
  • 1970-01-01
相关资源
最近更新 更多