Java 如何管理功能测试的应用程序数据?

Java 如何管理功能测试的应用程序数据?,java,spring,grails,testing,functional-testing,Java,Spring,Grails,Testing,Functional Testing,我们目前正在通过引入功能测试来提高一组数据库支持的应用程序(或“服务”)的测试覆盖率。对我来说,功能测试将被测系统(SUT)视为一个黑匣子,并通过其公共界面对其进行测试(无论是Web界面、REST还是我们使用AMQP进入消息传递领域的潜在冒险) 为此,测试用例要么A)引导应用程序的实例,要么B)使用已经运行的实例 版本允许测试用例通过构建工具的测试阶段或在CI作业中轻松测试系统的当前版本。这就是我们的目的。或者去做这个 B版本要求系统已经运行,但系统可能位于(或至少更接近)生产环境中。Grail

我们目前正在通过引入功能测试来提高一组数据库支持的应用程序(或“服务”)的测试覆盖率。对我来说,功能测试将被测系统(SUT)视为一个黑匣子,并通过其公共界面对其进行测试(无论是Web界面、REST还是我们使用AMQP进入消息传递领域的潜在冒险)

为此,测试用例要么A)引导应用程序的实例,要么B)使用已经运行的实例

版本允许测试用例通过构建工具的测试阶段或在CI作业中轻松测试系统的当前版本。这就是我们的目的。或者去做这个

B版本要求系统已经运行,但系统可能位于(或至少更接近)生产环境中。Grails可以在执行功能测试时通过
-baseUrl
选项实现这一点

现在困扰我的是如何在执行每个测试用例之前实现所需的服务状态?

例如,如果我想测试执行基本CRUD的REST接口,我如何在数据库中创建一个实体,以便测试HTTP GET

我看到了不同的可能性:

  • 使用相同的API(例如HTTP POST)创建实体。缺点:更改创建方法会破坏两个测试用例。此外,可能没有针对所有API的创建方法
  • 为测试添加一个额外的CRUD API,并且仅在非生产环境中激活该API。然后使用该API进行测试。缺点:在生产系统中添加额外的代码,API逻辑可能并不简单,例如,创建复杂的实体图(通过聚合/组合),我们需要确保API未被激活用于生产
  • Grails远程控制插件遵循基本相同的方法。它允许您“抓取应用程序”并通过序列化调用任意代码。缺点:感觉“脆弱”。不同的语言/框架可能有类似的机制(这个问题不是Grails特有的)
  • 直接访问关系数据库并创建/删除内容,例如使用DbUnit或仅通过JDBC手动创建实体。缺点:在测试用例中复制创建/删除逻辑和/或ORM。重构DB会破坏测试用例,尽管SUT仍然有效
  • 除了这些可能性之外,Grails在使用(
    -inline
    )选项进行功能测试时允许访问Spring服务(因为应用程序实例与测试用例在同一JVM中运行)。同样的情况也适用于。但是我无法对已经运行的应用程序版本(如上面的选项B所述)运行测试

    那你是怎么做到的呢?我是否错过了任何选项?

    另外,您如何保证每个测试用例在自身之后正确地清理,以便下一个测试用例看到处于相同状态的SUT?

    • 与单元测试一样,在运行功能测试之前,您希望有一个“干净”的数据库。您将需要一些设置/拆卸功能,以使数据库进入定义状态

    • 清理数据库最简单/最快的解决方案是使用sql脚本删除所有内容。(对于调试,在测试设置中运行此命令也很有用,以在测试失败后保持数据库的状态。)可以手动维护此命令(它只包含
      delete
      语句)。如果数据库经常更改,您可以尝试生成干净的脚本(禁用外键(以避免排序问题),删除表)

    • 要生成测试数据,您也可以使用sql脚本,但这将很难维护,或者通过代码创建。代码可以放在普通服务中。如果您不需要实际的生产数据,那么该插件在简化测试数据创建方面会有很大帮助。如果您在代码方面,那么重用生产代码来创建测试数据以避免重复也是有意义的

    • 要调用测试数据设置,只需使用远程控制。我不认为它比所有的http&ajax东西更脆弱;-)。因为我们现在在一个服务中有了所有的创建代码,所以使用远程控制只需要调用创建数据的服务。它不必比远程{ctx.testDataService.setupDataForXyz()}更复杂。如果这么简单,你甚至可以放下遥控器,用控制器/动作来运行它

    • 不要通过功能测试来测试太多细节,以使其不再像以前那样复杂。:)


    IMHO,你的第2点有问题。数据库中的干净(=无数据)状态可能不是我们想要的,因为应用程序需要一些数据才能运行(例如,安全角色…)。如果您在测试设置中创建此数据,这将使我们了解上面的第4点。第4点:哪种AJAX技术?您是对的,远程控制可能比创建CRUD服务要简单。我喜欢在生产代码中有一个
    testDataService的想法。如果您拥有只读主数据,则可以保留它。“全部清除”方法比为每个测试维护不同的清理逻辑容易/快得多。我还从一个服务运行它,因此它很容易集成到设置中。Ajax只是一个关于脆弱性和远程控制的一般评论。与您的问题没有具体关系:)