【问题标题】:Mocking WebService consumed by a Biztalk Request-Response port模拟 Biztalk 请求-响应端口使用的 WebService
【发布时间】:2010-09-20 09:23:03
【问题描述】:

我正在使用BizUnit 对我的 Biztalk 编排进行单元测试,但是一些编排使用 WebService,并且测试这些似乎更像是集成测试而不是单元测试。

我熟悉使用模拟框架来模拟生成的代理对象,以便从 Windows 窗体应用程序测试 Web 服务,但我希望能够在请求中以更集成的方式进行-响应端口?

你会如何解决这个问题?

【问题讨论】:

  • 有人必须有一个通用的解决方案!

标签: web-services mocking biztalk


【解决方案1】:

这正是我作为 BizTalk 开发人员的主要烦恼之一 - BizTalk 不适合进行单元测试。从您进入 BizTalk 应用程序的 99% 的接口是基于消息的并且有大量可能的输入这一事实,到编排的不透明性质,BizTalk 没有提供测试功能单元的真正方法......以及......单位。

对于 BizTalk,遗憾的是,集成测试通常是唯一的游戏。

这导致,由于 Kevin Smith 没有过错,BizUnit 被 (IMO) 用词不当。一个更好的名字可能是 BizIntegrationIt。 BizUnit 提供了一系列辅助集成测试的工具,其大部分测试,例如检查文件是否已写入给定目录或向 BizTalk HTTPReceive 位置发送 HTTPRequest 严格来说都是测试集成。

既然我已经吐槽了,你所要求的是我考虑了很长时间的东西,即创建自动化单元测试的能力,让我真正相信我做一个小的改变地图不会突然破坏下游的其他东西,也是一种消除对外部服务依赖的方法。

我从来没有想过这样做的好方法,但下面是一个应该工作的解决方案,我已经单独完成了每个部分的变体,但从未尝试过以这种特定的形式在一起。

因此,鉴于希望模拟对某些外部服务(甚至可能还不存在)的调用,而不需要实际进行任何外部调用并且希望能够设置对该服务的期望调用并指定响应的性质,我能想到的唯一方法是开发一个自定义适配器。

使用自定义适配器模拟网络服务

如果您构建自定义请求-响应适配器,您可以将其插入您的发送端口以代替 SOAP 适配器。然后,您可以为适配器指定属性,使其能够充当 Web 服务的模拟。该适配器在概念上类似于环回适配器,但允许内部模拟逻辑。

您可能希望作为适配器属性包含的内容:

  • 预期的文档(可能是一个磁盘位置,指定了您希望 BizTalk 应用程序发送到 Web 服务的内容示例)。
  • 响应文档 - 适配器将发送回消息传递引擎的文档。
  • 对测试的特定期望,例如文档元素中的查找值。

您还可以让自定义适配器写入磁盘并设置 BizUnit 步骤来验证写出的文件。

构建自定义适配器并非易事,但有可能,您可以从BizTalk Adapter Wizard 开始,还有一篇关于部署自定义适配器here 的文章。

向导生成的代码有bug,需要将new Guid(""),改为new Guid()

还有一些在 BizTalk SDK 中构建自定义适配器的示例。

另一种选择是使用普通的 http 页面和 HTTP 请求响应,如 here 所讨论的那样,您的所有逻辑都在 http 页面中。如果您很高兴有一个 http 调用并设置一个 IIS 端口来监听您的测试,这可能会更简单。

初始化单元测试

您可以使用 .bat 文件将绑定文件导入 BizTalk 应用程序。

如果您为运行的每个测试以及标准应用程序设置创建一个新的绑定文件,那么您可以运行相应的批处理文件以应用正确的绑定。

每个绑定文件都会更改您的 Web 服务发送端口以使用模拟自定义适配器并为该测试设置特定属性。

然后,您甚至可以创建一个自定义 BizUnit 步骤,该步骤(可能)根据测试步骤中的设置生成绑定设置,然后运行 ​​shell 命令来更新绑定。

测试消息内容

您可能要考虑的最后一件事是将所有这些真正联系在一起,是测试消息内容的某种方式。您可以在模拟适配器中执行此操作,但对于大型消息或大量可能的输入消息,这将很快变得乏味。

一种选择是创建一个调用Schematron 的自定义管道来验证它接收到的文件。 Schematron 是一种模式语言,它允许比 xsd 更丰富的文件检查级别,因此您可以检查诸如“如果元素 x 包含此内容,我希望元素 y 存在”之类的内容。

如果您构建了一个将 schematron 模式作为参数的自定义管道,那么您可以为特定的单元测试交换一个测试文件,验证该测试是否适用于该测试,当您调用 Web 服务时,您会得到一个实际匹配的文件你想要什么(不只是匹配 xsd)

【讨论】:

    【解决方案2】:

    作为 BizUnitExtensions (www.codeplex.com/bizunitextensions) 的合著者,我同意 BizUnit 中的“单元”名称可能会造成混淆,但对于 Biztalk,“集成测试”是单元测试。一些 Biztalk 人员已经成功地使用模拟来测试管道组件和其他测试工具(+ BizUnit/Extensions)来测试模式和映射。

    不幸的是,编排是不透明的。但这是有充分理由的。

    (a) 由于消息框中有庞大的订阅系统 - 编排在被激活时使用等,因此无法启动一些“虚拟”进程来托管编排(可以为管道完成。Tomas Restrepo 在这些方面做了一些事情)。

    (b) 另外,这个虚拟进程将如何处理持久性和脱水?我敢打赌,使用 WF 的人在尝试完全测试工作流程时会遇到同样的问题。

    (c) 我们不直接使用 C#,所以我们无法“注入”模拟 接口到编排代码。

    (d) 编排并不是真正的“单元”。它是一个复合元素。这些单元是进出消息框的消息以及通过表达式形状调用的外部组件。因此,即使您可以注入模拟 Web 服务接口,也无法注入模拟消息框和相关集等。

    可以为编排做的一件事(我一直在考虑添加到 BizUnitExtensions 库来执行此操作)是与 OrchestrationProfiler 工具链接,因为该工具提供了所有形状的非常详细的报告,并且不知何故检查各个步骤是否已执行(可能还有执行所需的时间)。这可能会使编排更像是一个白盒。另外考虑到编排调试器显示了很多变量值,当然必须可以通过 API 获取该信息以显示变量的值处于给定实例的给定点。

    回到 Richard 的问题,我之前的开发团队有一个解决方案。基本上我们所做的是编写一个通用的可配置 HttpHandler 来解析传入的服务请求并返回预设的响应。发回的响应可根据 XPath 等条件进行配置。在 BUILD 和 DEV 绑定文件中,webservice 端点是 mock。这在将 BUILD 和 DEV 环境与实际的第三方 Web 服务隔离开来时非常有效。这也有助于采用“合同优先”的方法,我们构建了 mock,orch 开发人员使用它,而 web 服务作者继续构建实际的服务。

    [更新:09 年 2 月 17 日:此工具现在在 codeplex 上:http://www.codeplex.com/mockingbird。 如果这种方法听起来很有趣,请查看并告诉我您对该工具的看法]

    现在,在有人抛出旧的“关于模拟对象框架的内容”栗子之前,让我说上面的实用程序既适用于 Biztalk 的“消费者”,也适用于非 Biztalk 消费者,但我也使用过 NMock2 和发现这是在编写 CLR 消费者时模拟接口和设定期望的绝佳方式。 (我将很快研究 MoQ 和 TypeMock 等)。但是,由于上述原因,它不适用于编排。

    希望这会有所帮助。

    问候,

    本杰

    【讨论】:

    • 很高兴在 StackOverflow Benjy 上见到你 - 我关注你的博客和 BizUnitExtensions 项目已有一段时间了。我不认为你把我的帖子当作侮辱,但以防万一,这根本不是这个意思!感谢您对该主题提出一些好的想法。
    • 还有一个关于单元测试自定义管道的单独评论 - 创建管道使用的所有框架对象的工厂是公共 API,所以正如你所说,使用这些和模拟你可以进行“正确”的单元测试在管道上。我通常为我构建的任何自定义管道编写单元测试。
    【解决方案3】:

    不要。

    不要针对任意接口进行测试,也不要为它们创建模拟。

    大多数人似乎认为开发人员(单元)测试旨在测试非平凡的、单独的功能单元,例如单个类。另一方面,对主要子系统或整个系统进行客户(验收/集成)测试也很重要。

    对于 Web 服务,重要的功能单元隐藏在实际执行有意义服务的类中,位于通信线路后面。这些类应该有单独的开发人员测试类来验证它们的功能,但完全没有任何面向 Web 服务的通信线路。自然地,但可能不是很明显,这意味着您的功能实现必须与布线的实现分开。因此,您的开发人员(单元)测试永远不会看到任何特殊的通信线路;这是集成的一部分,可以(适当地)将其视为“演示”问题而不是“业务逻辑”。

    客户(验收/集成)测试应解决更大规模的功能,但仍不关注“展示”问题。这就是 Facade 模式的普遍使用——暴露一个具有统一的、粗粒度的、可测试的接口的子系统。同样,Web 服务通信集成是无关紧要的,并且是单独实现的。

    但是,实现一组单独的测试非常有用,这些测试实际上确实包括 Web 服务集成。但我强烈建议不要只测试该集成的一方面:端到端测试。这意味着构建作为 Web 服务客户端的测试,就像真正的生产代码一样;他们应该以与实际应用程序完全相同的方式使用 Web 服务,这意味着这些测试可以作为任何必须实现此类应用程序的人的示例(例如,如果您正在销售库,则就像您的客户一样)。

    那么,为什么要这么麻烦呢?

    1. 您的开发人员测试验证您的功能是否可以在小范围内工作,无论它是如何访问的(独立于表示层,因为它都在业务逻辑层内)。

    2. 您的客户测试验证了您的功能在您的业务逻辑层的接口边界处是否可以在大型环境中正常工作,无论它是如何访问的。

    3. 您的集成测试验证您的表示层与您的业务逻辑层一起工作,现在可以管理它,因为您现在可以忽略底层功能(因为您在上面单独测试了它)。换句话说,这些测试的重点是漂亮面孔的薄层(GUI?)和通信接口(Web 服务?)。

    4. 当您添加另一种访问功能的方法时,您只需为新的访问形式(表示层)添加集成测试。您的开发人员和客户测试可确保您的核心功能保持不变且完好无损。

    5. 您不需要任何特殊工具,例如专门用于 Web 服务的测试工具。您使用将在生产代码中使用的工具/组件/库/技术,就像在此类生产代码中使用它们一样。这使您的测试更有意义,因为您不是在测试其他人的工具。它可以为您节省大量时间和金钱,因为您无需购买、部署、开发和维护特殊工具。但是,如果您通过 GUI 进行测试(不要那样做!),您可能需要一个特殊工具来处理该部分(例如,HttpUnit?)。

    所以,让我们具体一点。假设我们想提供一些功能来跟踪自助餐厅的每日菜单(因为我们在一家大型公司工作,大楼里有自己的咖啡馆,就像我的一样)。假设我们的目标是 C#。

    我们为菜单、菜单项和其他细粒度的功能及其相关数据构建了一些 C# 类。我们使用 nAnt 建立了一个自动构建(你这样做,对吗?),它使用 nUnit 执行开发人员测试,我们确认我们可以构建一个每日菜单并通过所有这些小块查看它。

    我们对我们的发展方向有了一定的了解,因此我们通过创建一个单独的类来应用 Facade 模式,该类公开了少数方法,同时隐藏了大部分细粒度的部分。我们添加了一组单独的客户测试,这些测试仅通过该新外观进行操作,就像客户端一样。

    现在我们决定为我们的大型企业知识工作者提供一个网页,以查看今天的自助餐厅菜单。我们编写一个 ASP.NET 页面,让它调用我们的外观类(如果我们使用 MVC,它将成为我们的模型),然后部署它。由于我们已经通过客户测试彻底测试了外观类,并且由于我们的单个网页非常简单,因此我们放弃了针对网页编写自动化测试——使用一些知识工作者的手动测试就可以了。

    稍后,我们开始添加一些主要的新功能,例如能够预订当天的午餐。我们扩展了我们的细粒度类和相应的开发人员测试,因为我们知道我们预先存在的测试可以防止我们破坏现有的功能。同样,我们扩展了外观类,甚至可能随着接口的增长分离出一个新类(例如 MenuFacade 和 OrderFacade),并在我们的客户测试中添加类似的内容。

    现在,也许网站的更改(两个页面就是一个网站,对吗?)使手动测试无法令人满意。因此,我们引入了一个类似于 HttpUnit 的简单工具,它允许 nUnit 测试网页。我们实现了一系列集成/表示测试,但针对的是我们的外观类的模拟版本,因为这里的重点只是网页可以工作——我们已经知道外观类可以工作。测试通过模拟门面推送和拉取数据,只是为了测试数据是否成功到达另一端。仅此而已。

    当然,我们的巨大成功促使 CEO 要求(要求)我们将 Web 应用程序公开给 mega-corp 的黑莓手机。因此,我们实现了一些新页面和一组新的集成测试。我们不必接触开发人员或客户测试,因为我们没有添加新的核心功能。

    最后,CTO 要求(要求)我们将我们的自助餐厅应用程序扩展到 mega-corp 的所有机器人工人——您在过去几天注意到他们了吗?所以,现在我们添加一个通过我们的外观进行通信的 Web 服务层。同样,我们的核心功能、我们的开发人员测试或我们的客户测试没有任何变化。我们通过创建使用等效 Web 服务 API 公开外观的类来应用适配器/包装器模式,并且我们创建客户端类来使用该 API。我们添加了一组新的集成测试,但它们使用普通的 nUnit 创建客户端 API 类,这些类通过 Web 服务连接与服务端 API 类进行通信,服务端 API 类调用模拟外观类,从而确认我们的连接工作。

    请注意,在整个过程中,除了我们的生产平台和代码、我们选择的开发平台、一些用于自动化构建和测试的开源组件以及一些定义明确的测试组之外,我们不需要任何重要的东西。另请注意,我们没有测试任何我们在生产中不使用的东西,也没有测试任何东西两次。

    我们最终得到了一个已经证明自己成熟的功能核心(业务逻辑层)(假设)。我们有三个独立的表示层实现:一个针对台式机的网站、一个针对黑莓手机的网站和一个 Web 服务 API。

    现在,请原谅我的冗长答案——我厌倦了不充分的答案,我不想提供一个。请注意,我实际上已经这样做了(尽管不是为自助餐厅菜单)。

    【讨论】:

    • +1 我完全同意这种观点。我仍然发布了我的答案,因为a)当你发布时我已经打字一半了 :),b)BizTalk 使测试变得非常困难,希望我的一些想法对 OP 和 c)如果有人有比我的解决方案更好的选择我很想听听。
    【解决方案4】:

    这是一个非常有趣的问题,我还没有看到一个好的通用答案。有些人建议使用 SoapUI,但我还没有时间实际测试它。 This page 可能对此很感兴趣。

    另一种方法可能是以某种方式包装 WebDev.WebHost.dll 并使用它...... Phil Hakkck 在this post 中讨论了这一点。

    之前也在 SO here 上讨论过。

    如果您找到其他解决方案,请告诉我们!

    【讨论】:

      【解决方案5】:

      这是这样做的方法:

      回到理查德的问题,我的 以前的开发团队有一个解决方案。 基本上我们所做的就是写一个 通用的可配置 HttpHandler 解析传入的服务请求和 返回预设的响应。这 发回的响应是可配置的 基于XPath等条件

      【讨论】:

        【解决方案6】:

        我已经有一段时间不用这样做了,但是当我测试我的 Biztalk 应用程序时,我总是使用soap ui 或 web service studio。我能够毫不费力地测试不同的输入值。

        【讨论】:

        • 但是如何将 SoapUI 或 Web Service Studi 连接到 BizUnit 并运行自动测试?这就是问题...
        猜你喜欢
        • 1970-01-01
        • 2022-12-03
        • 1970-01-01
        • 2017-04-15
        • 2015-08-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-28
        相关资源
        最近更新 更多