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

BizUnit 4.0 和 BizTalk 2010 - 简单编排

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.85/5 (15投票s)

2011年8月22日

CPOL

9分钟阅读

viewsIcon

66395

downloadIcon

1190

本文将演示如何使用 BizUnit 4.0 对 BizTalk 2010 中的简单编排进行单元测试。

引言

2011 年 5 月,BizUnit 发布了一个新版本。本文旨在演示如何使用 BizUnit 4.0 对 BizTalk 2010 中的简单编排进行单元测试。这将是一系列关于 BizUnit 和 BizTalk 2010 的文章的第一篇。

本文涵盖了一个非常简单的场景,演示了 BizUnit 的一小部分功能。对编排进行单元测试。

背景

单元测试在软件开发中是无价的,对于 BizTalk 来说,它既棘手又至关重要。BizUnit 是一个出色的工具,BizTalk 开发人员应常规使用它来确保他们编写的代码质量。

BizUnit 采用黑盒方法来测试 BizTalk 应用程序。本文中的测试执行以下操作:

  1. 复制一个示例文件并将其放入 BizTalk 的接收位置
  2. 检查目标位置是否正确数量的文件到达
  3. 根据 XSD 验证这些文件
  4. 检查文件内容

必需下载

应从 CodePlex 下载最新版本的 BizUnit(本文使用 4.0 版本)。

所需软件

运行示例代码需要以下软件:

  • Visual Studio 2010
  • Microsoft BizTalk Server 2010

示例 BizTalk 项目

在进行任何测试之前,我们需要创建一个测试项目。为此,我们需要定义三个模式、两个映射和一个编排。这是一个非常非常简单的项目,但足以开始。

现在,众所周知,在 TDD(测试驱动开发)的世界里,我们会先编写测试,然后再让测试通过。在 BizTalk 中,这不能以最纯粹的形式完成。您至少需要输入和输出模式。

请记住,为 BizTalk 解决方案进行强命名,否则将无法部署它。

模式

我们将定义的模式是代表客户订单的输入模式,然后是两个输出模式,一个是简单的订单摘要,另一个是拣货单。这些是简单的模式,并不完全现实,但它们满足了本文的用途。

源模式

源模式代表多行客户订单。一个订单可以有多行,每行都有数量和价格。这是一个简单的模式,但足以满足本文的需求。

Source Schema

用于测试的示例文本是:

<ns0:CustomerOrder xmlns:ns0="http://Timewave.BizTalkUnit.Sample.SourceSchema">
  <Forename>Tycho</Forename>
  <Surname>Lien</Surname>
  <CustomerId>10000001</CustomerId>
  <OrderTotal>1000.00</OrderTotal>
  <PaymentStatus>Paid</PaymentStatus>
  <OrderLines>
    <Line>
      <ItemId>1234</ItemId>
      <ItemQty>1</ItemQty>
      <PriceAtOrder>399.99</PriceAtOrder>
    </Line>
    <Line>
      <ItemId>2345</ItemId>
      <ItemQty>1</ItemQty>
      <PriceAtOrder>100.01</PriceAtOrder>
    </Line>
    <Line>
      <ItemId>3456</ItemId>
      <ItemQty>1</ItemQty>
      <PriceAtOrder>500.00</PriceAtOrder>
    </Line>
  </OrderLines>
</ns0:CustomerOrder>

拣货单模式

拣货单模式将是客户订单(源模式)中包含的物品列表。本文中的测试不使用它。

Pick List Schema

摘要模式

摘要模式将包含客户的详细信息以及订购物品的数量。

Summary Schema

映射

我们将创建两个映射。这些映射会将源消息转换为摘要消息和拣货单消息。

摘要映射

摘要映射将源模式中的值转换为摘要模式。并非源模式中的所有值都会被使用。Forename Surname 元素使用string 连接函数进行连接。记录计数函数用于获取物品的数量。

Summary Map

拣货单映射

拣货单映射只需将客户订单(源模式)文档转换为拣货单模式。使用CustomerId ,并且循环函数可确保为每个订单行创建一个Item

Pick List Map

业务流程

编排再次相对简单。一个符合源模式的文档将从文件位置拾取并传入编排。文件将被转换为摘要模式,然后通过发送端口将其放入相应的目标文件位置。然后,相同的源文档将被转换为拣货单模式,并放入拣货单文件位置。

ProcessOrder.odx

Orchestration

简单,但足以满足本次测试的目的。

BizTalk 部署

我假设您知道如何构建 BizTalk 解决方案并将其部署到 BizTalk,因此在此不作赘述。

只需确保 BizTalk 中的接收和发送位置与后面的测试项目中的位置匹配。

测试项目

一旦 BizTalk 项目启动并运行并部署到 BizTalk,就可以创建测试项目了。在实际应用中,您应该在创建 BizTalk 项目后立即完成此操作。测试应该在构建完模式之后、执行任何其他操作之前创建。

因此,向解决方案添加一个测试项目。

Add Test Project

接下来,我们需要为测试项目添加 BizUnit 引用。您需要浏览到它们,它们位于C:\Program Files\BizUnit\BizUnit 4.0\Bins,假设是标准安装。

Add BizUnit References

您需要添加对以下内容的引用:

  • BizUnit
  • BizUnit.TestSteps
  • BizUnit.TestSteps.BizTalk

完成后,我们就可以开始创建测试方法了。现在,我正在使用 ReSharper,它可以方便地为我添加“using”语句。如果您没有使用 ReSharper,请确保您有对我们之前添加的引用的“using”语句。

接下来的代码是测试方法的完整代码。我将在之后分解代码的每个部分并进行解释。需要注意的一个重要点是,在最后的RunTest()命令之前,没有任何代码会采取任何操作。BizUnit 的一个特性是测试可以用 XAML(早期版本是 XML)编写脚本。下一篇文章将使用 XAML 脚本展示相同的示例。

[TestMethod]
public void Total_Items_Is_3()
{
var totalItemsTest = new TestCase { Name = "Total Items is 3" };

//Get rid of any files that are already there
DeleteStep deleteStep = new DeleteStep();

var filePathsToDelete = new Collection<string> {@"..\..\..\Pickup\Out\Summary\*.xml"};

deleteStep.FilePathsToDelete = filePathsToDelete;
totalItemsTest.SetupSteps.Add(deleteStep);

//We don't do this as it won't be in the XAML
//deleteStep.Execute(new Context());

//Create the test step
var testStep = new CreateStep();
//Where are we going to create the file
testStep.CreationPath = @"..\..\..\Pickup\In\InboundCorrect.xml";
var dataLoader = new FileDataLoader();
//Where are we getting the file from?
dataLoader.FilePath = @"..\..\..\TestData\InboundCorrect.xml";
testStep.DataSource = dataLoader;

totalItemsTest.ExecutionSteps.Add(testStep);

//Create a validating read step
//We should only have one file in the directory
var validatingFileReadStep = new FileReadMultipleStep
{
DirectoryPath = @"..\..\..\Pickup\Out\Summary",
SearchPattern = "*.xml",
ExpectedNumberOfFiles = 1,
Timeout = 3000,
DeleteFiles = true
};

//Create an XML Validation step
//This will check the result against the XSD for the document
var validation = new XmlValidationStep();
var schemaSummary = new SchemaDefinition
{
XmlSchemaPath =
@"..\..\..\Timewave.BizUnit.Sample\Schemas\SummarySchema.xsd",
XmlSchemaNameSpace =
"http://Timewave.BizTalkUnit.Sample.DestinationSchema"
};
validation.XmlSchemas.Add(schemaSummary);

//Create an XPath Validation. This will check a value in the output.
//The Xpath for the node can be grabbed from the Instance XPath property on the XSD.
var xpathProductId = new XPathDefinition
{
Description = "ItemsOrdered",
XPath =
"/*[local-name()='CustomerSummary' and
namespace-uri()='http://Timewave.BizTalkUnit.Sample.DestinationSchema']/
*[local-name()='ItemsOrdered' and namespace-uri()='']",
Value = "3"
};
validation.XPathValidations.Add(xpathProductId);

validatingFileReadStep.SubSteps.Add(validation);

totalItemsTest.ExecutionSteps.Add(validatingFileReadStep);

var bizUnit = new BizUnit.BizUnit(totalItemsTest);
bizUnit.RunTest();
}

代码的第一部分可能会引起争议。我个人认为这是一个风格问题,而不是一个大问题。我在每个测试中做的第一件事就是确保我将要检查结果的位置是空的。一些关于 BizUnit 的文章建议这应该是最后一步,让系统恢复原状,我同意这一点,但我喜欢假设最坏的情况,即之前的测试留下了一个文件,这会导致误报,所以我会在开始时清空该位置。您是否在开始时、结束时或两者都执行此操作,则取决于您!

[TestMethod]
public void Total_Items_Is_3()
{
var totalItemsTest = new TestCase { Name = "Total Items is 3" };

//Get rid of any files that are already there
DeleteStep deleteStep = new DeleteStep();

var filePathsToDelete = new Collection<string> {@"..\..\..\Pickup\Out\Summary\*.xml"};

deleteStep.FilePathsToDelete = filePathsToDelete;
totalItemsTest.SetupSteps.Add(deleteStep);

//We don't do this as it won't be in the XAML
//deleteStep.Execute(new Context());

这都比较直接,有一点需要注意。您不能执行

deleteStep.FilePathsToDelete.Add(filename);

原因是 BizUnit 4.0(当前)在类构造函数中不初始化集合,因此会导致“Object reference not set”错误。

totalItemsTest.SetupSteps.Add(deleteStep) 将把删除步骤添加到测试执行时将发生的步骤中。

可以将totalItemsTest.SetupSteps.Add(deleteStep) 替换为deleteStep.Execute(new Context())。这将立即执行删除步骤。但是,如果测试被序列化为 XAML,则该步骤将不被包含。

下一项任务是创建测试步骤本身。

 //Create the test step
var testStep = new CreateStep();
//Where are we going to create the file
testStep.CreationPath = @"..\..\..\Pickup\In\InboundCorrect.xml";
var dataLoader = new FileDataLoader();
//Where are we getting the file from?
dataLoader.FilePath = @"..\..\..\TestData\InboundCorrect.xml";
testStep.DataSource = dataLoader;

totalItemsTest.ExecutionSteps.Add(testStep);

CreationPath 是 BizTalk 应该使用接收端口监视的路径(目录和文件名)。这是文件将到达 BizTalk 以便 BizTalk 拾取的地方。它不是 BizTalk 创建响应的路径。

FilePath 是 BizUnit 将去获取示例的位置。在实际解决方案中,该目录将包含您所有的测试文档。

接下来,我们创建在测试触发后将执行的步骤。我们将进行 3 种不同的检查。我们将

  1. 检查是否生成了一个文档
  2. 检查文档是否根据 XSD 有效
  3. 检查文档中的计算值是否正确

为了检查文件是否已创建,我们创建了一个FileReadMultipleStep。它将检查特定目录中符合特定模式的文件。我使用了*.xml,但如果您的端口使用文件名来区分输出文件,则也可以轻松地使用PO*.xml

//Create a validating read step
//We should only have one file in the directory
var validatingFileReadStep = new FileReadMultipleStep
{
DirectoryPath = @"..\..\..\Pickup\Out\Summary",
SearchPattern = "*.xml",
ExpectedNumberOfFiles = 1,
Timeout = 3000,
DeleteFiles = true
};

因此,这里的值都比较明显,我们有要检查的目录、我们要查找的文件模式、预期的文件数量和超时时间。我们还有一个标志,告诉 BizUnit 在完成后是否应该删除文件。

Timeout 很重要。如果您有一个复杂的编排,可能需要一些时间才能运行,那么您需要设置此超时。您的测试完全不知道是什么在创建它正在查找的文件。它无法检查 BizTalk 是否已完成,或者服务器上是否有延迟,或者 Web 服务是否正在启动。您需要运用自己的判断将其设置为一个合理的超时。在本例中,3 秒(3000 毫秒)就足够了。

DeleteFiles 将使此步骤在完成后删除文件。在完成后进行清理是个好习惯!如果要查看生成的文件,请删除此项。

接下来,我们检查 XML 是否有效。

//Create an XML Validation step
//This will check the result against the XSD for the document
var validation = new XmlValidationStep();
var schemaSummary = new SchemaDefinition
{
XmlSchemaPath =
@"..\..\..\Timewave.BizUnit.Sample\Schemas\SummarySchema.xsd",
XmlSchemaNameSpace =
"http://Timewave.BizTalkUnit.Sample.DestinationSchema"
};
validation.XmlSchemas.Add(schemaSummary);

同样,这也很简单。请确保您正确获取XmlSchemaNameSpace,因为如果它错误,将导致失败。

接下来,我们创建一个 XPath 验证。它将检查输出文档中是否包含预期的值。

//Create an XPath Validation. This will check a value in the output.
//The Xpath for the node can be grabbed from the Instance XPath property on the XSD.
var xpathProductId = new XPathDefinition
{
Description = "ItemsOrdered",
XPath =
"/*[local-name()='CustomerSummary' and namespace-uri()=
'http://Timewave.BizTalkUnit.Sample.DestinationSchema']/
*[local-name()='ItemsOrdered' and namespace-uri()='']",
Value = "3"
};
validation.XPathValidations.Add(xpathProductId);

用于构造XPathDefinition 的三个参数是描述、要检查的元素的 XPath(从 BizTalk XSD 编辑器中的 XSD 复制并粘贴)以及您期望的值。

代码的最后部分将我们刚刚创建的验证添加到测试中,然后运行测试。

 validatingFileReadStep.SubSteps.Add(validation);

totalItemsTest.ExecutionSteps.Add(validatingFileReadStep);

var bizUnit = new BizUnit.BizUnit(totalItemsTest);
bizUnit.RunTest();

Using the Code

要运行测试,您需要将解决方案部署到 BizTalk 并配置端口。

Test Results

然后,右键单击测试并选择“运行测试”。测试运行后,您将看到“通过”或“失败”。如果显示失败,请右键单击结果并选择“查看测试结果详细信息”。然后,您可以使用详细信息来找出问题所在。请记住下一部分中的注意事项。

如果您的测试失败

与通常的单元测试不同,BizUnit 测试可能会因为代码未损坏以外的原因而失败。在调查失败的测试时,请牢记以下几点。样本中的测试可能因 3 种不同的原因而失败。它们是:

  • 指定目录中没有文件
  • 指定目录中的文件过多(如果发生这种情况,则删除失败)
  • XPath 匹配失败

现在,在正常情况下,您会深入代码以查找引入的错误。在执行此操作之前,请仔细检查以下几点:

  • BizTalk 应用程序正在运行
  • 您的接收适配器已启用
  • 您的发送端口已启用
  • 编排已注册
  • 主机实例正在运行
  • 如果您的进程很复杂,代码中的超时时间足够长

后续步骤

下一篇文章将展示如何使用 XAML 而不是代码来执行本文档中的相同测试。

历史

  • 初始版本 - 2011-08-20
© . All rights reserved.