如何为Prism 7应用程序创建一个Spec-Flow测试?

3

我正在使用 Prism 7 创建一个新的 Windows 桌面应用程序,我最初使用了替换引导程序的新 PrismApplication 基类。一切都很好,直到我创建了 (SpecFlow-) 测试。

在测试应用程序初始化期间,我习惯于重复使用原始引导程序,只修改注册表。现在,基于新的派生自 Application 的系统,看起来像这样:

internal partial class App
{
    protected override IContainerExtension CreateContainerExtension()
    {
        var containerExtension = new Prism.Unity.Ioc.UnityContainerExtension();
        containerExtension.Instance.AddExtension( new LogExtension() );
        return containerExtension;
    }

    protected override Window CreateShell()
    {
        return Container.Resolve<MainWindow>();
    }

    protected override void RegisterTypes( IContainerRegistry containerRegistry )
    {
        containerRegistry.Register<IConfiguration, AppSettingsConfiguration>();
        containerRegistry.Register<IWindowsInterface, WindowsInterface>();
        // ... a lot of registrations removed here ...
    }
}

还有一个派生的测试应用程序,它做的一切都与创建shell无关:

private class MyApp : App
{
    protected override Window CreateShell()
    {
        return null;
    }
}

将初始化测试应用程序的操作包装在 BeforeScenario 钩子中:

[BeforeScenario]
public void InitializeApp()
{
    var app = new MyApp();
    app.Initialize();
    var containerRegistry = (IContainerRegistry)app.Container;

    containerRegistry.RegisterSingleton<TestWindowsInterface>();
    containerRegistry.Register<IWindowsInterface,TestWindowsInterface>();
    // ... some registration overrides removed here ...

    _objectContainer.RegisterInstanceAs<App>( app );
}

创建主窗口的步骤(CreateShell替代):

[When( @"I start the software" )]
public void WhenIStartTheSoftware()
{
    _container.RegisterInstanceAs( _container.Resolve<App>().Container.Resolve<MainWindowViewModel>() );
}

到目前为止,一切都很好,这个方案可行。但只有当您只有一个方案时才有效。一旦第二种情况开始,我们就会收到异常:

Cannot create more than one System.Windows.Application instance in the same AppDomain.

在以前,这不是一个问题,因为Bootstrapper只是一个普通的类,而不是由框架强制成为单例的PrismApplication

当然,我可以将整个注册过程放入普通类中,并使用它来初始化测试应用程序,但这意味着在PrismApplication的基础上创建自己的版本的引导程序。使用经典的Bootstrapper对我来说更有意义,但未来的版本中将删除它(因为它今天被标记为过时)。


你要自动化UI测试?那很不寻常。 - Andy
@GregBurghardt 应用程序正在 ReSharper 中的 NUnit 运行器中运行,这就是我的问题:我无法随意重新启动进程。 - Haukinger
2
@Andy 我进行整个应用程序的集成测试,除了视图和附加硬件之外,从视图模型到模拟硬件。测试视图模型并不是那么不寻常的事情,我们通过这种方式大大减少了手动测试的工作量,因为测试人员只需要检查视图和与真实硬件的交互...所有其他内容都经过预先测试,他们只需出于监管目的进行测试。 - Haukinger
你可能需要添加一个 [AfterScenario] 钩子来销毁/清理应用程序实例,也许?我不熟悉 Prism。 - Greg Burghardt
@Andy 当然不是。我在nunit中无头运行完整的应用程序,没有使用wpf框架,并使用一些虚假服务,以便例如prism的ViewModelLocator可以在没有wpf的情况下工作。因此,我最接近视图模型,我的specflow-steps操作这些视图模型,模拟用户与视图交互(在测试期间不存在,因为它们是通过wpf的数据绑定创建的,而wpf本身不存在)。使用真实的应用程序是问题所在,因为每个应用程序域只能有一个,而nunit会将其重用于程序集中的所有测试。 - Haukinger
显示剩余3条评论
1个回答

0

你将能够使用从 MarshalByRefObject 派生的类创建多个 Application 类的实例:

public class AppDomainWrapper : MarshalByRefObject
{
    public void DoSomething()
    {
        var app = new MyApp();
        app.Initialize();
        ...
        app.Shutdown();
    }
}

示例用法:

AppDomain appDomain = AppDomain.CreateDomain("AppDomain");
AppDomainWrapper app = appDomain.CreateInstanceAndUnwrap(typeof(AppDomainWrapper).Assembly.FullName, typeof(AppDomainWrapper).FullName) as AppDomainWrapper;
app.DoSomething();
AppDomain.Unload(appDomain);

MyApp创建的所有内容都将在封装的AppDomain中创建,而且所有在外部使用的内容也需要进行封送处理。所有步骤都在“常规”AppDomain中定义并运行。 - Haukinger
我知道,我正在寻找规避该限制的方法。 - Haukinger
@Haukinger:我想我只是给了你一个,即为每个“应用程序”创建一个新的“AppDomain”。 - mm8
你可以将每个测试运行隔离在单独的“AppDomain”中,或者在测试中模拟掉对“App”类的任何使用。这些是你的选择。 - mm8
我正在寻找一种方法来解决这个问题,以便我不必创建多个“Application”实例。 - Haukinger
显示剩余8条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接