65.9K
CodeProject 正在变化。 阅读更多。
Home

BizUnit Context 教程

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.47/5 (4投票s)

2006年11月19日

CPOL

13分钟阅读

viewsIcon

63855

本文将介绍如何使用 BizUnit 框架的关键部分——Context 对象。

引言

BizUnit 是一个高度可扩展的测试框架。Context 对象是 BizUnit 的核心元素之一。不幸的是,文档并未说明用户如何利用它,开发者只能通过 NDoc 文档中的一些代码片段自行理解。

本教程首先简要介绍 BizUnit,然后介绍 Context 对象,并解释如何在基于 BizUnit 的测试中使用它。在适用的情况下,它将使用官方文档中的示例,并在文档信息不甚清晰的地方进行补充。它不会复制方法和属性列表等内容,因此,如需详尽参考,请回溯文档。本文将解释三种主要的上下文加载器步骤,未来的文章将探讨自定义步骤以及 Context 在单元测试和系统测试中的高级用法。

请注意,其中一些文件路径是指向 BizUnit 源代码结构和功能测试(例如,TestData 文件夹是附随源代码的单元测试集中的一个特定文件夹),因此我假设您已获取代码并能跟上。

作者附注:2006年11月23日:根据收到的反馈,我已更新本文,增加了一个关于 BizUnit 基础知识的部分。

2007年3月24日更新:对于尚未接触过该项目的人,我已启动 BizUnitExtensions 开源项目,您可以下载 BizUnit 核心的 bug 修复以及大量附加步骤。

2007年5月5日更新:Kevin 已将 BizUnit 迁移到 CodePlex,并发布了一些包含 bug 修复和增强的新版本。Context 已进行大量增强,并将尽快记录。Extensions 项目将不再在其常规版本中发布 Core,以避免社区中关于应使用哪个源代码的混淆。

BizUnit - 基础知识

BizUnit 是一个为 BizTalk 设计的单元测试工具。它也是一个可扩展的框架,允许开发者编写更多测试来丰富开箱即用的功能。它使用 NUnit。

有关 BizUnit 的介绍,您可以阅读这篇由该工具的作者 Kevin Smith 撰写的文章。您也可以看看 CodeProject 上 Naveen 的文章

基本上,BizUnit 以黑盒模式工作。假设我们有一个编排,它从文件位置获取数据,然后将其提交到队列或 Web 服务,最后写入数据库。现在,如果我们想手动测试它,我们就必须创建一个示例文件,将其放置在对应于编排“接收位置”的文件夹中,然后检查它是否已到达队列,并最终到达数据库(如果 Web 服务本身记录了 SOAP 请求,我们可以检查相应日志文件中是否存在条目)。

使用 BizUnit,我们可以自动化手动完成的步骤。我们可以创建一个包含所有示例文件的文件夹(这是必要的手动步骤),并编写 BizUnit 步骤来复制文件到接收位置,以及检查队列、日志文件和数据库。

事实证明,由于大多数步骤涉及复制文件、发布到 SOAP 端点以及检查队列、数据库和事件日志,因此该工具也可用于测试非 BizTalk 项目。我们可以简单地忽略与 BizTalk 相关的步骤,例如 BAMQueryStep。

(注意:实际上并没有 LogFileReader 步骤,因为我们都有不同的日志文件格式,但可以编写一个,或者如果我们有固定的格式,我们可以使用 XmlContextLoaderRegExLoader 从文件中提取内容并进行检查。)

与所有自动化测试一样,当您需要执行一次或两次此步骤时,手动完成很容易,但当数据条件开始增长,并且您需要将自动化测试作为自动化构建和发布流程的一部分时,它就变得无价。此外,在进行集成测试并需要验证消息在各种服务和组件之间的流转时,手动测试根本无法持续。

它的问题在于,对于大型测试脚本,BizUnit 脚本很快就会变得笨重。例如,如果有一个测试用例,其中数据从指定源文件读取,加载到目标,然后进行验证,可能还会移动到其他地方(例如 MSMQ 队列或数据库),您可能会发现文件名和文件夹名称在测试步骤中重复。此外,如果您已将此数据(文件夹名称、文件名、连接字符串等)存储在配置文件中,例如用于处理非 BizTalk 工件的 NUnit 测试,那么在测试 XML 文件中硬编码所有这些内容是不必要的,而且随着测试库的增长,维护起来会非常困难。

这就是“Context”对象大显身手的地方。

Context 对象

Context 对象代表一个在 BizUnit 测试步骤之间传递的状态对象。在 BizUnit 系统内部,Context 对象会被传递给每个单独的测试步骤。它不能在 TestFixture 类中初始化和使用,但在自定义步骤中可用。在与测试用例对应的 XML 文件中,可以使用指定的步骤(预先编写或自定义)读取和操作 Context。

在 BizUnit 系统内部,状态可以写入或从 Context 中读取。Context 还为测试步骤提供辅助方法,以一种一致的方式读取其配置,以及记录信息、警告、错误和数据。当测试执行时,输出窗口中提供的详细信息是由使用 Context 类生成的。因此,如果您正在编写自定义步骤,则应使用 Context 类中提供的方法来记录异常、错误和警告等。

您还可以使用它来存储诸如名称-值对之类的信息,这有助于自定义步骤的逻辑。(当然,这并非强制。由于自定义步骤仅仅是您自己的类,您可以根据需要定义和使用自己的私有成员变量。)

正如我在上面的“基础知识”部分提到的,大型脚本很快就会变得难以维护,因此 Context 的另一个重要用途是存储跨测试步骤使用的配置数据。对于仅使用少量步骤的非常简单的测试用例,这可能看起来不是很有用,但随着测试用例越来越大,并且数据出现重复时,将参数存储在 Context 中就变得至关重要。

使用 Context:基础知识

思考 Context 的一个简单方法是,它可以像 NAnt 属性一样使用。在 NAnt 中,我们会声明一个属性变量,赋予它一个特定名称并存储一个值。然后在所有任务中,您只需使用 ${propertyname} 引用该属性,系统就会获取相应的值。

在 BizUnit 中,开箱即用地,我们首先创建一个 FileValidate 步骤来指向我们的配置文件。此步骤将文件加载到内存中(为避免丢失文件,请将 <DeleteFile> 设置为 false)。之后,我们可以使用 XmlContextLoaderTextContextLoaderRegExContextLoader 从源文件中提取数据。

上下文加载器的选择取决于数据的格式。XmlContextLoader 要求您提供 XPath 表达式,允许它导航源数据并提取值。RegExContextLoader 要求提供一个正则表达式应用于源数据(严格来说,只要正则表达式正确,文件是 XML 还是文本都无关紧要)。TextContextLoader 略有不同。它的工作方式类似于 Substring() 方法和旧的 VB6 Mid$() 函数,查找指定的模式、索引和字符串长度来从文件中检索数据。(有关详细示例,请参阅下文。)

哪些步骤支持上下文配置数据?

大多数步骤(一个显著的例外是 DotNetObjectInvoker)都支持配置数据。这在文档中并不十分清楚(尽管有时会有些提示)。在 XML 节点中(对应于步骤中的任何元素),我们需要使用属性“takeFromCtx = <contextkeyname>”,系统将在执行步骤时查找上下文。

例如,考虑以下 FileCreateStep。在此,已使用适当的上下文加载器加载了上下文。

<TestStep assemblyPath="" 
  typeName="Microsoft.Services.BizTalkApplicationFramework.BizUnit.FileCreateStep">
<SourcePath takeFromCtx="sourcefilename"></SourcePath>
<CreationPath takeFromCtx="targetfilename"></CreationPath>
</TestStep>

SourcePathCreationPath 元素中,我们使用 takeFromCtx 属性并为其提供系统应查找的上下文键名。系统会在运行时进行替换。

与 NAnt 的不同之处

上下文变量的一个非常重要的限制是,除了简单的上下文查找之外,没有运行时“宏扩展”行为。

例如,在 NAnt 任务中,我们可以将各种属性(以及系统属性)连接在一起,所以如果我们想要一个完整的文件名,我们可以使用类似以下的内容:

${source.path}\${file.name}.${file.extension}

系统随后会将属性名称替换为相应的值,并使用提供的符号(如 \ 和文件扩展名之前的点)来获得完整的文件名。目前,这在 BizUnit 中无法实现,尽管可以通过重载 Context 类的方法来应用宏扩展,当检测到 $ 和 {} 等适当符号时。

XmlContextLoader

概述

XmlContextLoader 会评估源数据的 XPath 表达式,并将值添加到上下文中。

示例

以下是此测试步骤的 XML 表示的示例。在此示例中,已使用文件验证步骤(未显示)验证了文件的存在,并且该文件包含所有上下文变量。

本示例中使用的实际文件包含在源代码中,位于 TestData 文件夹内。文件名是 XmlContextData.xml。内容如下所示:

<Variables> 
  <sourcefilename>c:\temp\test.xml</sourcefilename> 
  <targetfilename>c:\temp\testtarget.xml</targetfilename> 
  <connectionstring>Persist Security Info=False;Integrated Security=SSPI;
     database=Northwind;server=(local);Connect Timeout=30</connectionstring> 
  <sourcefolder>c:\temp\</sourcefolder> 
  <targetfolder>c:\temp\</targetfolder> 
</Variables>

现在,当我们使用 ContextLoader 时,我们可以使用正确类型的上下文加载器(如 XmlContextLoaderRegExContextLoader)将文件的所有内容加载到上下文中。

这里,我们使用的是 XmlContextLoader,XPath 表达式代表源文件中数据的导航路径(即,'Variables' 是顶级元素,'sourcefilename' 和 'targetfilename' 是包含我们要加载到上下文中的值的元素)。每个 XPath 上下文键元素都会导致执行等同于 Context.Add(key,object) 的操作。

<ContextLoaderStep assemblyPath="" 
  typeName="Microsoft.Services.BizTalkApplicationFramework.BizUnit.XmlContextLoader"> 
<XPath contextKey="sourcefilename">
  /*[local-name()='Variables']/*[local-name()='sourcefilename']
</XPath> 
<XPath contextKey="targetfilename">
  /*[local-name()='Variables']/*[local-name()='targetfilename']
</XPath> 
</ContextLoaderStep>

RegExContextLoader

概述

RegExContextLoader 会将正则表达式应用于源数据,并将值添加到上下文中。

示例

以下是此测试步骤的 XML 表示的示例。在此示例中,已使用文件验证步骤验证了文件的存在,并且该文件包含所有上下文变量。

本示例中使用的实际文件包含在源代码中,位于 TestData 文件夹内。文件名是 RegExTestData.txt。文件内容如下所示:

The BizTalk web site is here: http://www.microsoft.com/biztalk, 
you can find out more about the product there.

现在,当我们使用 ContextLoader 时,我们可以使用正确类型的上下文加载器(如 XmlContextLoaderRegExContextLoader)将文件的所有内容加载到上下文中。

这里我们使用 RegExContextLoader 并将各种项添加到上下文中。每个 RegEx 上下文键元素都将导致执行等同于 Context.Add(key,object) 的操作。(例如,名为 HTTP_Url 的上下文键现在将包含 http://www.microsoft.com/biztalk。)

<ContextLoaderStep assemblyPath="" 
   typeName="Microsoft.Services.BizTalkApplicationFramework.BizUnit.RegExContextLoader"> 
<RegEx contextKey="HTTP_Url">/def:html/def:body/def:p[2]/def:form</RegEx> 
<RegEx contextKey="ActionID">/def:html/def:body/def:p[2]/def:form/def:input[3]</RegEx> 
<RegEx contextKey="ActionType">/def:html/def:body/def:p[2]/def:form/def:input[4]</RegEx> 
<RegEx contextKey="HoldEvent">/def:html/def:body/def:p[2]/def:form/def:input[2]</RegEx>
</ContextLoaderStep>

TextContextLoader

概述

TextContextLoader 的工作方式类似于 Substring 和旧的 VB6 Mid$ 函数。它会在源数据中搜索指定的字符串,然后从指定位置和指定长度返回子字符串。

示例

以下是此测试步骤的 XML 表示的示例。在此示例中,已使用文件验证步骤(未显示)验证了文件的存在,并且该文件包含所有上下文变量。本示例中使用的实际文件包含在源代码中,位于 TestData 文件夹内。文件名是 TextContextLoaderDemo.txt。该文件包含以下两行:

source=c:\temp\test.xml"
target=c:\temp\testtargetnew.xml"

在以下代码片段中,我们使用 TextContextLoader 并将各种项添加到上下文中。

<ContextLoaderStep assemblyPath="" 
   typeName="Microsoft.Services.BizTalkApplicationFramework.BizUnit.TextContextLoader"> 
<Item contextKey="sourcefilename" searchString="source" skipNumber="1" stringLength="16" /> 
<Item contextKey="targetfilename" searchString="target" skipNumber="1" stringLength="25" /> 
</ContextLoaderStep>

现在发生的情况是,在设置名为“sourcefilename”的上下文键时,系统会查找模式/搜索字符串“source”,并找到其 IndexOf 值。然后将其加到 skipNumber(即 1)上,从而忽略数据行中的“=”符号。然后它查找接下来的 16 个字符(恰好是完整的路径名),并返回该字符。对于下一个上下文键“targetfilename”,会发生相同的处理,在这种情况下,它会获取 25 个字符。

这一概念可以应用于源文件中的一个大型参数字符串(如果您不想费心创建 XML 文件并找出必要的 XPath 表达式)。

局限性

此步骤确实有一个限制,即返回值的字符串长度需要预先知道,这限制了开发者轻松更改测试数据的能力。可以创建此步骤的未来版本(或另一个自定义步骤),它允许灵活地加载上下文值数组。

ContextManipulatorStep

概述

ContextManipulator 用于操作 BizUnit Context 字段。根据文档,它可用于从一个或多个现有字段创建一个新字段。

示例

在以下示例中,创建了一个名为 newsource 的新上下文键,其值来自现有的上下文键。

<TestStep assemblyPath="" 
   typeName="Microsoft.Services.BizTalkApplicationFramework.BizUnit.ContextManipulatorStep"> 
<ContextItem contextKey="newsource"> 
<ItemTest takeFromCtx="sourcefilename"></ItemTest> 
</ContextItem> 
</TestStep>

Issue

开箱即用地,此步骤似乎不起作用,无论如何尝试。代码似乎并未正确编写。(我们最好编写自己的步骤来处理此问题。)我将很快为此编写一个自定义步骤,并发布在此网站上。

摘要

本文仅对 Context 的工作方式进行了简要概述,希望这能为您提供所需的理解来利用它。在我当前的一个集成项目中,我们编写了一些自定义步骤,并广泛使用 Context 来读取我们的 app.configweb.config 文件,事实证明它在消除冗余声明和硬编码方面非常有价值。如果您有任何问题,请发送电子邮件给我,我会尽快答复。祝您好运(如果您编写了任何自定义步骤或找到了使用 Context 的新技巧,请告知社区的其他成员)。

此步骤提供的代码存在几个 bug

修复 1:删除创建流读取器并读取到数据流末尾的代码,因为这样 XmlDoc 将无法加载数据(因为指针已移到末尾),并且 StreamReader 根本没有在任何地方使用。

修复 2:将 SelectSingleNode 代码更改为以下内容:

contextValue = doc.SelectSingleNode( xpathExp ).InnerText;
© . All rights reserved.