为什么需要复制代码?抛弃 Cassini,让 Visual Studio 为您创建一个虚拟目录。如果 web 应用程序发生了变化,开发人员必须记住在运行 web 测试之前构建。我们发现这没什么大不了的,特别是如果您在 CI 中运行 Web 测试。
数据是一个巨大的挑战。据我所知,您必须在不完美的选择之间做出选择。以下是我们如何处理它。首先,我应该解释一下,我们正在使用一个大型复杂的遗留 WebForms 应用程序。另外我应该提到,域代码不适合从测试项目中创建测试数据。
这给我们留下了几个选择。我们可以:(a) 在构建下运行数据设置脚本,或 (b) 通过使用实际网站的 Web 测试创建所有数据。选项 (a) 的问题是测试与脚本在分钟级别上耦合在一起。一想到将 Web 测试代码与 T-SQL 同步,我就头疼。所以我们选择了(b)。
(b) 的一个好处是您的设置还可以验证应用程序的行为。问题是……时间。
理想情况下,测试应该是独立的,没有时间耦合(可以以任何顺序运行)并且不共享任何上下文(例如,公共测试数据)。处理此问题的常用方法是在每次测试时设置和删除数据。经过深思熟虑,我们决定打破这个规则。
我们使用 Gallio (MbUnit 3),它提供了一些很好的特性来支持我们的策略。首先,它允许您在夹具和测试级别指定执行顺序。我们有四个“设置”装置,它们的顺序是 -4、-3、-2、-1。它们以指定的顺序运行,并且在所有“非设置”装置之前运行,默认情况下,它们的顺序为 0。
我们的 Web 测试项目仅依赖于一件事的构建脚本:一个众所周知的用户名/密码。这是我可以忍受的耦合。随着设置测试的运行,他们构建了一个“数据上下文”对象,该对象包含数据(公司、用户、供应商、客户等)的标识符,以后在其他所有设备中使用(但从未更改)。(通过标识符,我不一定指键。在大多数情况下,我们的 Web UI 不会公开唯一键。我们必须使用名称或其他代理来导航应用程序以获取真正的标识符。更多内容见下文。)
Gallio 还允许您指定一个测试或夹具依赖于另一个测试或夹具。当先例失败时,将跳过依赖项。这通过防止可能导致很多混乱的“级联故障”来减少时间耦合的弊端。
一次创建基线测试数据,而不是在每次测试之前创建,这会大大加快速度。但是,设置测试仍可能需要 10 分钟才能运行。当我进行新测试时,我想经常运行并重新运行它们。输入另一个很酷的 Gallio 功能:氛围。Ambience 是围绕 DB4 的包装器,它提供了一种非常简单的方法来持久化对象。我们使用它来自动持久化数据上下文。因此,设置测试只能在数据库重建之间运行一次。之后,您可以重复运行任何或所有其他固定装置。
那么清理测试数据呢?我们不需要从已知状态开始吗?这是我们发现打破的规则。一个对我们有效的策略是对公司名称、用户名等使用长随机值。我们发现将测试运行保持在逻辑“数据空间”内并不是很困难,这样它就不会碰撞到其他数据中。当然,我担心有一天我会花几个小时追查一个假想失败的测试,结果却发现这是一些数据冲突。这是目前为我们工作的权衡。
我们正在使用Watin。我挺喜欢它的。另一个成功的关键是 Scott Bellware 提到的。在创建测试时,我们正在构建 UI 的抽象模型。所以代替这个:
browser.TextField("ctl0_tab2_newNote").TypeText("foo");
您将在我们的测试中看到这一点:
User.NotesTab.NewNote.TypeText("foo");
这种方法提供了三个好处。首先,我们从不重复魔术字符串。这大大降低了脆性。其次,测试更容易阅读和理解。最后,我们将大部分 Watin 框架隐藏在我们自己的抽象后面。在第二个示例中,只有 TypeText 是 Watin 方法。这将使其更容易随着框架的变化而变化。
希望这可以帮助。