【问题标题】:End to End testing of WebservicesWeb服务的端到端测试
【发布时间】:2010-10-23 04:45:01
【问题描述】:

第一次海报和 TDD 采用者。 :-) 我会有点冗长,所以请多多包涵。

我最近开始使用 Apache CXF 框架、Spring 和 Commons Chain 开发基于 SOAP 的 Web 服务,以实现业务流程。我在这里面临的问题是测试 Web 服务——在单元测试和功能测试中进行测试。

我的第一次单元测试尝试完全失败。为了保持单元测试的灵活性,我使用了一个 Spring XML 文件来保存我的测试数据。此外,我没有创建要测试的“组件”实例,而是从我的 Spring 应用程序上下文中检索它们。包含数据的 XML 文件很快就失控了;在 XML 中创建对象图被证明是一场噩梦。由于要测试的“组件”是从 Spring 应用程序上下文中挑选出来的,因此每次测试运行都会加载 所有 我的应用程序中涉及的组件、使用的 DAO 对象等。此外,与单元的概念相反测试用例集中或集中在仅测试组件上,我的单​​元测试开始访问数据库,与邮件服务器通信等。糟糕,非常糟糕。

我知道我做错了什么,并开始想办法纠正它。根据这个板上的一篇帖子的建议,我查找了 Mockito,这是一个 Java 模拟框架,这样我就可以不用使用真正的 DAO 类和邮件服务器,而只是模拟功能。

随着单元测试的控制,这给我带来了第二个问题;对数据的依赖。我一直在开发的 Web 服务几乎没有逻辑,但严重依赖数据。例如,考虑我的一个组件:

public class PaymentScheduleRetrievalComponent implements Command {
  public boolean execute(Context ctx) {
    Policy policy = (Policy)ctx.get("POLICY");
    List<PaymentSchedule> list = billingDAO.getPaymentStatementForPolicy(policy);
    ctx.put("PAYMENT_SCHEDULE_LIST", list);
    return false;
  }
}

我的大部分组件都遵循相同的路线——从上下文中选择一个域对象,点击 DAO [我们在这里使用 iBatis 作为 SQL 映射器]并检索结果。

那么,现在的问题是:
- 当单个插入或更新可能使数据库处于“不稳定”状态[假设 3 次插入不同表实际上形成单个事务] 时,如何测试 DAO 类?
- 移动大量数据的功能测试 Web 服务的实际标准是什么,即从数据存储中进行无意识的插入/检索?

您的个人经历/cmets 将不胜感激。如果我在解释手头的问题时遗漏了一些细节,请告诉我。

-佐助

【问题讨论】:

    标签: java testing service


    【解决方案1】:

    如果我是你,我会远离“上下文作为全局哈希映射”“模式”。

    看起来你正在测试你的持久性映射...

    您可能想看看:testing persistent objects without spring

    【讨论】:

      【解决方案2】:

      我建议使用内存数据库来运行您的单元测试,例如 HSQL。您可以使用它来动态创建架构(例如,如果您使用 Hibernate,则可以使用 XML 映射文件),然后在单元测试结束时销毁数据库之前根据需要插入/更新/删除。您的测试绝不会干扰您的实际数据库。

      对于第二个问题(Web 服务的端到端测试),我过去已经成功地对基于 CXF 的服务进行了单元测试。诀窍是在测试开始时使用轻量级 Web 服务器发布您的 Web 服务(Jetty 是理想的),然后使用 CXF 将客户端指向您的 Web 服务端点,运行您的调用,最后关闭 Jetty完成单元测试后托管您的 Web 服务的实例。

      要实现这一点,您可以使用 CXF 提供的 JaxWsServerFactoryBean(服务器端)和 JaxWsProxyFactoryBean(客户端)类,请参阅此页面以获取示例代码:

      http://cwiki.apache.org/CXF20DOC/a-simple-jax-ws-service.html#AsimpleJAX-WSservice-Publishingyourservice

      我也非常赞成 SOAP UI 对您的 Web 服务进行功能测试。 JMeter 对于 Web 服务的压力测试也非常有用,这对于那些进行数据库查找的服务来说尤其重要。

      【讨论】:

      【解决方案3】:

      首先:您是否有理由必须从 Spring 应用程序上下文中检索被测主题 (SUT)?为了进行高效的单元测试,您应该能够在没有上下文的情况下创建 SUT。听起来您在某处有一些隐藏的依赖项。这可能是你头痛的根源。

      DAO 类是如何测试的,尤其是当一个 单次插入或更新可能 让数据库处于“不稳定”状态 状态[在假设3的情况下 插入不同的表 实际上形成一个单一的交易]?

      运行测试后,您似乎担心数据库的一致性。如果可能的话,使用自己的数据库进行测试,您不需要关心它。如果您有这样的沙箱数据库,您可以根据需要删除数据。在这种情况下,我会执行以下操作:

      1. 使用一些通用标识符标记所有虚假数据,例如为字段添加特殊前缀。
      2. 在运行测试之前删除删除语句,删除标记的数据。如果没有,那么就没有什么不好的事情发生。
      3. 运行您的单个 DAO 测试。之后重复步骤 2. 进行下一次测试。

      什么是事实上的标准 功能测试 Web 服务 移动大量数据,即 无意识的插入/检索 数据存储?

      我不知道。根据您提出的问题,我可以推断您一方面拥有 Web 服务,另一方面拥有数据库。分清责任。每边都有单独的测试套件。一方面只是测试数据库访问(如上所述)。另一方面,只是测试 Web 服务请求和响应。在这种情况下,它支付存根/伪造/模拟与网络对话的层。或者考虑https://wsunit.dev.java.net/。

      如果程序只是将数据推入和推出,我认为没有太多行为。如果是这种情况,那么最难的工作就是对数据库端和 Web 服务端进行单元测试。关键是您可以在不需要“真实”数据的情况下进行单元测试。对于功能测试,您将需要接近现实的手动数据。这可能很麻烦,但如果您已经对数据库和 Web 服务部分进行了密集的单元测试,这应该会大大减少对“现实”测试用例的需求。

      【讨论】:

        【解决方案4】:

        首先,把事情说清楚。

        在理想情况下,您正在构建的软件的生命周期是这样的: - sy 与客户进行报告,因此您获得了一个用户故事,其中包含有关应用程序应如何工作的示例 - 你概括了用户故事,所以你得到了规则,你称之为用例 - 你开始编写一个功能性(端到端)测试,但它失败了...... - 之后你构建了用户界面并模拟了服务,所以你得到了一个绿色的功能测试和一个关于你的服务应该如何工作的规范...... - 你的工作是保持功能测试绿色,并逐步实现服务编写集成测试,并用相同的方法模拟依赖关系,直到你达到单元测试的水平 - 之后,您对用例进行下一次迭代,编写下一个功能测试,依此类推,直到项目结束 - 之后,您与接受产品并支付大量费用的客户进行验收测试

        那么我们从中学到了什么:

        • 测试有多种类型(不要相互混淆)
          • 功能测试 - 用于测试用例(什么都不做)
          • 集成测试 - 用于测试应用程序、组件、模块、类交互(模拟不相关的组件)
          • 单元测试 - 用于测试与环境隔离的单个类(模拟所有内容)
          • 用户验收测试 - 客户确保她接受产品(手动功能测试,或通过工作中的自动功能测试进行的演示)
        • 您不需要通过功能测试和集成测试来测试所有内容,因为这是不可能的。通过功能和集成测试仅测试相关部分,并通过单元测试测试所有内容!熟悉testing pyramid。
        • 使用 TDD,让生活更轻松!
        • 如何测试 DAO 类,尤其是当单次插入或更新可能会使数据库处于“不稳定”状态时 [如果让我们 说 3 次插入不同的表实际上形成了一个 交易]?

        您不必测试您的数据库事务。假设它们运行良好,因为数据库开发人员已经对它们进行了测试,并且我确定您不想编写并发测试…… Db 是一个外部组件,因此您不必自己进行测试。您可以编写数据访问层以使数据存储适应您的系统,并仅为这些适配器编写集成测试。在数据库迁移的情况下,这些测试也将由新数据库的适配器工作,因为您编写它们以实现特定接口......通过任何其他测试(功能测试除外),您可以模拟您的数据访问层。对所有其他外部组件也这样做,编写适配器并模拟它们。将这些类型的集成测试放在与其他测试不同的测试套件中,因为它们会因为数据库访问、文件系统访问等而变慢......

        • 什么是功能测试 Web 服务的事实标准,它围绕大量数据移动,即无意识的插入/检索 来自数据存储?

        您可以使用内存数据库模拟您的数据存储,该数据库实现相同的存储适配器,直到您实现除数据库之外的所有其他内容。之后,您实现数据库的数据访问层并使用功能测试对其进行测试。它会很慢,但它只能运行一次,例如每个新版本...如果您需要通过开发进行功能测试,您可以再次使用内存解决方案对其进行模拟...另一种仅运行的方法受影响的功能测试通过开发,或者修改测试数据库的设置来让事情变得更快,等等……我相信有很多测试优化解决方案……

        【讨论】:

          【解决方案5】:

          我必须说我真的不明白 你的确切问题。是问题 你的数据库留在一个 运行后更改状态 测试?

          是的,这里实际上有两个问题。第一个是运行测试用例后数据库处于不一致状态的问题。第二个是我正在寻找一种优雅的解决方案,用于 Web 服务的端到端测试。

          为了进行高效的单元测试,您应该 能够在没有 语境。听起来你有一些 隐藏在某处的依赖项。那 可能是你的一些根源 头痛。

          这确实是我头痛的根本原因,我现在将借助一个模拟框架来解决这个问题。

          看来你很担心 拥有后数据库的一致性 运行测试。如果可能的话,使用 自己的数据库进行测试,你在哪里 不需要关心它。如果你有 这样的沙盒数据库你可以删除 数据随心所欲。

          这确实是我在上一篇文章中提到的问题的解决方案之一,但这可能不适用于所有情况,尤其是在与数据库/数据不受您控制的遗留系统集成时,以及在某些情况下当某些 DAO 方法要求某些数据已经存在于给定的一组表中时。我应该研究像 DBUnit 这样的数据库单元测试框架吗?

          在这种情况下,它支付 存根/伪造/模拟与之交谈的层 网络。或者考虑 https://wsunit.dev.java.net/.

          啊,看起来很有趣。我还听说过诸如 SOAPUI 之类的可用于功能测试的工具。这里有没有人使用这些工具取得过任何成功?

          感谢所有的回答和对含糊不清的解释表示歉意;英语不是我的母语。

          -佐助

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-06-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多