【问题标题】:.NET UI Testing (both Unit and Integration).NET UI 测试(单元和集成)
【发布时间】:2012-07-12 12:38:04
【问题描述】:

我的任务是提出一种解决方案,以在 UI 级别进行有效的单元测试和集成测试。不幸的是,我们在 Windows 窗体中有很多代码隐藏。我们还有一个棕地项目,我们正在慢慢迁移到 WPF(新功能在 WPF 中,当需要进行重大更改时将旧功能迁移到 WPF)。

WPF 中的所有内容都经过了单元测试(数据库除外)。我使用的是 MVVM 方法,所以几乎所有的代码都在那里。

但是,部署前的测试需要花费大量时间,我们需要一种方法来自动化其中的大部分。

也就是说,我所指的这个测试需要在 UI 上进行。

Windows 窗体部分必须进行集成测试,因为部分逻辑在代码隐藏中完成,部分在数据库中完成。

WPF 窗口应在 UI 级别进行单元测试,但也应进行集成测试。

我知道对于一个问题来说这是一个很大的问题,但是有人有什么建议吗?

【问题讨论】:

  • 对于 UI 测试,您可以使用 Microsoft 测试管理器来指定您的测试用例并记录 UI 测试。
  • 您可以使用 MS Coded UI 测试。

标签: .net unit-testing user-interface integration-testing


【解决方案1】:

我完全同意托比约恩的回答,但想补充几点:

从小处着手

页面对象模式是简化测试的好方法,但您会发现要正确抽象化需要很长时间。首先抽象出你需要的东西,然后随着时间的推移慢慢添加。

增值

不要过分尝试编写端到端回归测试。相反,专注于编写增加价值的测试。例如,证明应用程序启动时没有错误的单个测试非常有用,并且可以为您的构建过程提供早期反馈。从那里干出来。

平衡“深”与“浅”

测试用户界面有几种不同的理念。在它们之间建立一个组合。

显而易见的方法是使用类似生产的设置来测试应用程序,以证明应用程序可以“从前端”运行。这些是“深度”集成测试,可以运行代码的所有部分并且很有用。它们也可能非常缓慢,因为它们通常依赖于外部服务等。通常,为了可靠,应用程序必须在测试运行之间重新启动以确保有效的环境。

对这种方法稍作修改是使用已存根的服务(假产品目录、假身份验证提供程序等)测试应用程序。这些是“浅层”测试,证明用户界面在集成在一起时可以正常工作。它们通常运行快一点,因为它们不需要考虑相同的物理限制,例如网络延迟。您可以更多地关注演示细节和其他极端情况。

进一步的修改是隔离部分用户界面并在测试工具中运行它们。这些测试将比以前的方法运行得更快,因为它们不会有启动整个应用程序的相同开销。使用这些测试来断言颜色和高度专业化的表示问题。

稳定时迭代

如果您打算编写功能测试来代替手动回归测试,您可能会发现最好等到开发稳定该功能后再为其编写自动化。如果您在开发过程中开始编写自动化,您将不断地重写测试。如果您想在开发过程中实现自动化,请记住:从小处着手。

获得早期反馈

UI 的自动化测试(也称为功能测试)很有用,但它可能非常非常缓慢。 (我见过运行需要几个小时才能完成。)如果您每天运行一次整个测试套件,您会发现反馈循环太长,这会导致误报、维护问题等。

如果可能,请尝试将功能测试集成到构建过程中。如果测试套件花费的时间过长,请找到一种方法来集成一些测试,以便您的构建管道可以验证 重要测试构建。

【讨论】:

  • 我完全同意你的回答:)
【解决方案2】:

(这个答案是关于如何集成测试您的代码:WinForms 和 WPF。)

我没有适合您的专利解决方案,只有投入大量时间和精力使测试易于维护的建议。

确保您可以在 Visual Studio 中修改和运行测试。

不得不为测试启动不同工具的额外负担可能足以让开发人员不这样做(我已经看到它发生了)。所以试着找到一个允许这样做的UI testing tool

不要记录测试。

虽然很舒服,但记录的测试生成的代码很难阅读和理解,并且很可能包含许多无关紧要的细节。如果您需要对测试进行更改,您可能必须重新记录它们。测试将更多地是系统工作方式的文档,而不是您希望它如何工作的规范。

为您的测试创建共享基础架构。

在代表窗口行为的对象中为窗口/窗体创建抽象。通过这种方式,您可以隐藏这些对象中的实现细节,使实际测试紧凑且易于阅读。一旦你有了这个基础设施,就很容易添加新的测试。此外,如果实现细节发生变化,您只能在一个地方对测试进行更改:在基础架构中。

在网络测试领域,这称为page object pattern

C# 中的测试示例:

ApplicationFake application = new ApplicationFake();

// ApplicationFake.Start() starts the application resulting in that main form opens.
// Start() returns an object that represents the actions that the user can perform on
// the main form.
// The Start() method might contain an assert that the main form was actually opened.
MainFormFake mainForm = application.Start();

// Performing an action that opens a new form returns a representation of the new form,
// in this case the object SomeFormFake.
SomeFormFake someForm = mainForm.ClickOpenSomeFormButton();

// The form fakes exposes properties that returns the forms' observable state.
Assert.That(someForm.Title, Is.EqualTo("Some Form's Title"));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-18
    相关资源
    最近更新 更多