测试 Gui 密集型 WPF 应用程序
我们(我的同事)有一个基于 GUI 的混乱的 12 yo 成熟应用程序,当前计划是添加新的对话框和内容。 WPF 中的其他 GUI,以及替换 WPF 中的一些旧对话框。同时,我们希望能够以可维护的方式测试 Monster - GUI 自动化。一些挑战:
- 应用程序规模庞大。
- 它不断获得新的功能。
- 它正在被改变(错误修复、补丁)。
- 它有一个后端,中间有一个层。如果你把它打死,它的状态就会变得不正常。
我们想要的是:
- 一些可以自动化测试WPF的工具。
- 自动发现对话框的输入和输出是什么。如果您添加一个不执行任何操作的标签,旧的测试应该仍然有效。但是,如果删除必要的文本字段,它应该会失败。如果测试套件易于维护、运行并且大部分时间都不会中断,那就太好了。
- 创建每个新对话框时都应考虑到可测试性。
此时我还不知道我到底想要什么,所以我将其标记为社区 wiki。如果必须测试一个基于 GUI 的大型应用程序(即使不是在 WPF 中),那么请在这里分享您的好的、坏的和丑陋的经历。
We (my colleagues) have a messy 12 y.o. mature app that is GUI-based, and the current plan is to add new dialogs & other GUI in WPF, as well as replace some of the older dialogs in WPF as well. At the same time we wish to be able to test that Monster - GUI automation in a maintainable way. Some challenges:
- The application is massive.
- It constantly gains new features.
- It is being changed around (bug fixes, patches).
- It has a back end, and a layer in-between. The state of it can get out of whack if you beat it to death.
What we want is:
- Some tool that can automate testing of WPF.
- auto-discovery of what the inputs and the outputs of the dialog are. An old test should still work if you add a label that does nothing. It should fail, however, if you remove a necessary text field. It would be very nice if the test suite was easy to maintain, if it ran and did not break most of the time.
- Every new dialog should be created with testability in mind.
At this point I do not know exactly what I want, so I am marking this as a community wiki. If having to test a huge GUI-based app rings the bell (even if not in WPF), then please share your good, bad and ugly experiences here.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
好吧,你的应用程序听起来很大!我可以分享我最近设计的一个应用程序的经验;它是一个 GUI,与服务器对话 Web 服务,而服务器又联系多个数据库和其他 Web 服务。客户群约为 15,000 名用户……无论哪种方式 - 无论您如何处理,这都是大量工作;好处是它可以帮助您不必每次发布时都把指甲咬掉!
MVVM
一般来说,我也会推荐 MVVM 模式,并在没有 GUI 的情况下进行尽可能多的测试。 GUI 测试实在是太难了!我喜欢 Josh Smith 在 MSDN 上的文章:“采用模型-视图-视图模型设计的 WPF 应用程序模式”(http://msdn.microsoft.com/en- us/magazine/dd419663.aspx)
测试脚本
这个应用程序的窍门是我们有很多东西要测试,它的核心在不断变化,而且(奇怪的是)没有有足够的人来完成每次迭代的测试工作。
我的解决方案是提出一个利用现有库的自定义测试工具。我们有一个简单的脚本引擎来读取文件并执行命令。实际上,我们开发了一个 DSL (http://en.wikipedia.org/wiki/Domain-specific_language)用于测试我们的特定应用程序。 DSL 包括一些简单的命令来表示它正在测试什么“窗口”、任何特定的“设置”信号,然后是一系列命令和断言。它看起来像这样:
每行的格式是
脚本进入目录组,“测试运行程序”加载它们,解析它们并执行它们。随时创建日志和报告非常有用,我添加了用于制作屏幕截图等的钩子,这非常有用。 如果您有兴趣实现类似的功能并且需要帮助,请告诉我。
这里方便的是我们可以对测试策略进行全面更改。
编写脚本变得非常简单,这一点很重要,因为您最终会得到很多很多脚本。控件是按名称发现的,因此您遵循约定(例如,“名称”可能是代码中的“NameTextBox”,或者“保存”可能是“SaveButton”)。
实际上,您也可以利用 NUnit 等作为您的测试运行程序。
注意 - 仅以交互方式运行测试,让 GUI 测试与 CI 配合使用是困难且有问题的...
数据和测试
这里的一件主要事情是数据管理是测试问题的重要组成部分,并且不容忽视。我们的“新鲜部署”也很长,但有些部分是外部的,我们无法控制数据的新鲜度。我们处理清理的方法是通过脚本提供挂钩,使我们能够在测试之前轻松删除对象。不是最佳的,但很少成为问题。
库
您可能会在“White” (White" 中找到最有用的库="http://white.codeplex.com/" rel="noreferrer">http://white.codeplex.com/) 它可以测试一般的 Windows 应用程序 – 即 WPF 和 WinForms。本质上,您最终会编写这样的代码:
如果您的应用程序进行异步调用,您将需要为测试运行程序制定一个策略,以了解异步调用何时完成,也许是通过状态栏或其他东西。这取决于你如何融入……
同样,需要做很多工作,但这是值得的。
PK:-)
OK, your app sounds large! I can share my experiences around an application we engineered recently; it was a GUI talking web services to a server that in turn contacted multiple databases and other web services. The client base was around 15,000 users… Either way - this is a lot of work no matter how you approach it; the upside is it will help you not chew your nails off each time you make a release!
MVVM
In general I would also recommend the MVVM pattern and do as much testing as possible without the GUI. GUI testing is just plain hard! I like Josh Smith’s article on MSDN: "WPF Apps With The Model-View-ViewModel Design Pattern" (http://msdn.microsoft.com/en-us/magazine/dd419663.aspx)
Test Scripting
The trick with this app was that we had a lot to test, the guts of it were constantly moving and there were (strangely enough) not enough people to get the testing job done for each iteration.
My solution was to come up with a custom testing tool that leveraged existing libraries. We had a simple script engine that read a file and executed commands. In effect we developed a DSL (http://en.wikipedia.org/wiki/Domain-specific_language) for testing our specific application. The DSL included some simple commands to signal what "window" it was testing, any specific "setup" signals and then a series of commands followed by assertions. It looked something like this:
The format of each line is
The scripts go into groups of directories and the "test runner" loads them up, parses them and executes them. Creating logs and reports as you go is useful, I got added in hook for making screen-shots etc which came in handy. If you are interested in implementing something likke this and would like a hand let me know.
The handy thing here was that we could make blanket changes to the test strategy.
Writing the scripts becomes pretty simple which is important because you end up with many, many scripts. The controls are discovered by name so you follow a convention (e.g. “Name” may be "NameTextBox" in code, or “Save” could be "SaveButton").
You can actually harness NUnit etc to be your test runner too.
NOTE - Just run the tests interactively, getting GUI test to work with CI is difficult and problematic...
Data and Testing
One major thing here is that the data management was a huge part of the test problem and cannot be overlooked. Our “fresh deployment” was also very long but some parts were external and we had no control over the freshness of the data. The way we handled the cleaning was to provide hooks through the scripting that allowed us to easily remove objects before tests. Not optimal but was rarely an issue.
Libraries
The library that you may find most useful in "White" (http://white.codeplex.com/) It can test windows apps in general – i.e both WPF and WinForms. Essentially you end up coding things like this:
If your app makes async calls you will need to come up with a strategy for the test runner to know when the async call is finished, perhaps though the status bar or something. It depend how you hook in…
Again, a lot of work but it’s worth it.
PK :-)
在我看来,WPF 的主要优势之一实际上是不需要特定于 UI 的测试的能力。使用 MV-VM 方法可以让您将逻辑从 UI/混乱的 GUI 区域中取出。拥有可单元测试的 ViewModel(尤其是在编写新对话框时!)可让您编写模拟 GUI 单击的单元测试。
我确实会重新考虑您希望通过迁移到 WPF 来实现什么目标,以及您希望通过 WPF GUI 的某种类型的自动化测试来实现什么目标。确定后,请查看 从 WinForms 过渡到 WPF(如果它仍然满足您的需求)。
One of the main strengths of WPF is actually the ability to NOT need UI specific testing, in my opinion. Using a M-V-VM approach would allow you to take the logic out of the UI/messy-GUI-area. Having a unit testable ViewModel (especially if you are writing new dialogs!) lets you write unit tests that emulate the clicking of your GUI.
I'd really reconsider what you want to accomplish by moving to WPF and what you want to achieve with some type of automated testing of a WPF GUI. Once this has been established, look into transitioning from WinForms to WPF if it still fits your needs.
正如 Jimmy Lyke 所说,大部分测试应该集中在 ViewModel 上。这包括为 ViewModel 编写单元测试 - 基本上是发送命令以及设置和获取属性。
一旦完成,95% 的测试就完成了。如果您想更进一步并测试超出手动“演练”测试范围的视图,您可以轻松地执行许多简单的“健全性检查”,以确保您不会意外删除重要的内容。文本框或使视觉指示器不可见。
以下每种技术都可以使用一些简单的自动化代码来自动化,这些代码使用“霰弹枪”方法,通过盲目运行可视化树并且对实际 UI 结构不进行任何假设。
要验证所有 ViewModel 数据是否已绑定,请查找所有 Visuals 和 Freezable(使用可视化树)并检查每个绑定属性的 BindingExpression 绑定路径。
要验证所有 ViewModel 数据是否以某种方式显示,请使用脚本更改 ViewModel 数据,并在每次更改后使用 RenderTargetBitmap 捕获 UI 并将其与数据更改之前进行比较,以确保 UI 已更改。
要验证属性值是否已正确更新,请查找所有 Visuals 和 Freezables,扫描并记录其上的所有绑定属性,然后更改 ViewModel,重新扫描并搜索对给定类型的任何属性的预期更改。 (要仔细检查,您可以对受影响的特定视觉对象使用位图比较技术。)
要验证所有命令是否均可访问,请设置已知的 ViewModel 状态,然后触发绑定到可见按钮的每个命令,以查看是否可以访问它们中的任何一个都会触发 ICommand 或以其他方式更新 ViewModel 状态。
为了有机会检查影响 UI 的任何更改,请保留一个数据库,其中包含一组不同窗口大小中各种 ViewModel 状态下每个视图的位图快照。当构建新版本的应用程序时,运行相同的快照系统并与以前的位图进行比较。如果有任何更改,请为 QA 人员生成一个手动任务,以直观地比较新旧位图,以查看是否有任何重要的更改。
视图上还可以进行其他测试自动化,但上面的内容将为您提供一个开始。
我必须再次指出,最好集中精力彻底测试 ViewModel。视图本身的错误非常罕见,通常可以快速检测到,并且修复起来通常很简单。但是,一旦 ViewModel 测试彻底,对视图测试进行一些自动化就有意义了。
As Jimmy Lyke says, most of your testing should be focused on the ViewModel. This consists of writing unit tests for the ViewModel - basically sending commands and setting and getting properties.
Once that is done, 95% of your testing is out of the way. If you want to take it a step further and test the view beyond the manual "walkthroughs" testing you would do anyway, there are a number of simple "sanity checks" you can easily automate to make sure you didn't accidentally delete an important TextBox or render a visual indicator invisible.
Each of the following techniques can be automated using some simple automation code that uses a "shotgun" approach by blindly running the visual tree and assuming nothing about the actual UI structure.
To verify that all the ViewModel data is bound, find all Visuals and Freezables (using the visual tree) and check each bound property for its BindingExpression's binding path.
To verify that all the ViewModel data is displayed somehow, vary the ViewModel data using a script and after each change uses RenderTargetBitmap to capture the UI and compare it with before the data change to make sure the UI has changed.
To verify that property values are being updated correctly, find all Visuals and Freezables, and scans and records all bound properties on them, then make the ViewModel change, rescan, and searche for the expected change to any property of the given type. (To double-check you can then use the bitmap comparison technique on the particular Visual affected.)
To verify that all commands are accessible, set a known ViewModel state then fire every command bound to a button that is visible to see if any of them trigger the ICommand or otherwise update ViewModel state.
To verify that a ViewModel property is actually editable by the user, change the content or selection of every visible TextBox, ComboBox, ListBox to see if any of them affect the property.
To get an opportunity to check any change that affects the UI, keep a database containing bitmap snapshots of each views in various ViewModel states in a set of different window sizes. When a new version of the app is built, run the same snapshot system and compare with the previous bitmaps. If anything at all has changed, generate a manual task for QA personnel to visually compare the old and new bitmaps to see if anything important has changed.
Other test automation is possible on the view, but the above will give you a start.
Again I must point out that it is best to focus on thoroughly testing the ViewModel. Bugs in the view itself are quite rare, typically detected quickly, and usually trivial to fix. But once ViewModel testing is thorough, it makes sense to do some automation of the view testing.
您有一个非常大的应用程序。我猜它有很多逻辑包含在表示层中,并且您永远不会有时间重构这个野兽以将视图与其余逻辑分开。
您在这里没有太多选择,但是:
You have a very large application. I'm guessing it has lots of logic wrapped up with the presentation layer and you'll never be given the time to refactor the beast to separate the view from the rest of the logic.
You don't have a lot of choices here, but:
为了测试 WPF 应用程序,我们在以下方面取得了成功:
可能是新的 VSTS 2010 功能,尽管我们还没有尝试过
To test WPF apps there are a few things we have had success with:
and possibly would be the new VSTS 2010 features, though we haven't tried them