Java 23,Spring Boot 3.3.4:人工智能驱动的测试生成

在应用程序测试中实现全面自动化对于确保云原生应用程序的可靠性和最佳性能至关重要,尤其是在通过持续部署优先考虑快速上市的情况下。

云原生(即微服务)测试自动化策略

该方法包括单元测试、集成测试、契约测试和端到端测试。

来源:幻灯片:《微服务架构系列——测试策略》

  • 单元测试:单元测试用于检验应用程序中最小可测试软件单元的行为是否符合预期。
  • 组件测试:组件测试将所测试软件的范围限制在系统的一部分,通过内部代码接口操作系统,并使用测试替身将被测代码与其他组件隔离开来。
  • 契约测试:借助Pact等工具确保服务遵循约定的API契约。
  • 集成测试:集成契约测试是在外部服务边界进行的测试,用于验证其是否满足使用该服务的消费者所期望的契约。
  • 端到端测试:端到端测试用于验证系统是否满足外部需求并达成其目标,对整个系统进行从头到尾的测试。

GitHub仓库:《微服务测试快速入门》

此外,像用于容器编排的Kubernetes和用于服务网格的Istio等工具可以帮助创建逼真的测试环境,使测试过程更加稳健可靠。

在深入探讨测试自动化的具体细节之前,有必要先了解更广泛的软件开发领域。这将有助于我们理解自动化在整个流程中的位置以及可用的各种自动化类型。

以下图片展示了软件开发生命周期(SDLC)中的规范运维(SpecOps)工作流程,强调了从规范(Specs)到运维(Ops)的过程。

来源:幻灯片:《微服务架构系列——测试策略》

从规范到设计与开发

新建项目

  • 涉及从头开始构建应用程序,重点关注:
  • 领域驱动设计(DDD):围绕核心业务领域构建项目。
  • 事件溯源/命令查询职责分离(CQRS):分别处理状态变更和查询职责。

既有项目

  • 涉及对现有系统进行现代化改造或增强,采用的技术包括:
  • 迁移模式:例如采用“绞杀者模式”等策略逐步替换遗留系统。
  • 变更数据捕获(CDC):实时捕获数据变化以实现无缝迁移。

管道自动化(构建→测试→阶段)

本部分对软件开发生命周期的各个阶段进行自动化,以确保效率和可靠性。

  1. 构建
    侧重于对源代码进行编译、打包并为部署做准备,包括:
  • 源代码:使用Maven、NPM和Docker Hub等工具进行特性代码、配置以及依赖管理。
  1. 测试自动化
    通过多个测试层级确保质量和性能,包括:
  • 单元测试:验证单个组件。
  • 组件测试:测试应用程序中独立的部分。
  • 契约测试:验证微服务之间的API契约。
  • 集成测试:确保各组件协同工作。
  1. 基础设施自动化(基础设施即代码)
    对基础设施的供应和管理进行自动化,涵盖:
  • 容器(例如Docker)。
  • 编排(例如Kubernetes)。
  • 无服务器架构,以实现可扩展且具有成本效益的解决方案。
  • 服务网格(例如Istio):用于可观测性、安全性和流量路由,包括:
  • 流量路由:高效地管理和引导应用程序流量。
  • 安全性:实施双向传输层安全协议(mTLS)以实现安全通信,并使用JSON Web令牌(JWT)进行身份验证。
  • 策略:必须应用网络和安全策略以保持合规性,并构建纵深防御的强大安全架构。
  1. 阶段
    在类似生产环境的环境中为应用程序部署做准备。

运维(Ops)

一旦应用程序部署完成,重点就转移到运维可靠性上,包括:

  • 可观测性:使用日志、指标和追踪来监控性能并识别问题。

最终目标

  • 容错性:确保系统能够从故障中恢复。
  • 可靠性:在各种条件下提供稳定的性能。
  • 可扩展性:能够无缝扩展以应对需求波动。

该工作流程突出了一个持续集成和持续部署(CI/CD)管道,并高度强调自动化,将架构原则与开发、测试和运维实践相结合,以便在云原生环境中交付可扩展、可靠且易于维护的软件。

人工智能驱动的顶级测试自动化工具

让我们重新聚焦于测试自动化,特别是探索人工智能驱动的测试自动化以及这些工具如何增强测试过程。以下是此类工具的一些示例。

1. Diffblue Cover

用途:自动为Java应用程序生成单元测试。
主要特性

  • 借助人工智能生成测试,实现高代码覆盖率。
  • 支持JUnit和TestNG。
  • 与IntelliJ IDEA和Maven集成。
    使用案例:为Spring Boot服务、控制器和存储库自动生成单元测试。

2. Testim

用途:人工智能驱动的用于创建、执行和维护自动化功能测试的工具。
主要特性

  • 具备自我修复测试功能,可适应UI变化。
  • 与CI/CD管道集成。
  • 支持微服务的API测试。
    使用案例:对具有动态用户界面的Spring Boot应用程序进行功能和端到端测试。

3. Mabl

用途:基于云的、人工智能驱动的用于功能测试的测试自动化工具。
主要特性

  • 支持REST API测试,非常适合Spring Boot微服务。
  • 具备人工智能驱动的缺陷检测功能。
  • 与CI/CD工作流无缝集成。
    使用案例:对Spring Boot应用程序中的微服务和API层进行全面测试。

4. Katalon Studio

用途:一个多功能的测试平台,具备人工智能增强功能,可用于Web、API和移动测试。
主要特性

  • 支持使用Groovy编写基于Java的测试脚本。
  • 具备人工智能驱动的对象检测和智能测试建议功能。
  • 内置API测试功能。
    使用案例:对Spring Boot应用程序中的RESTful API测试进行自动化。

5. Functionize

用途:人工智能驱动的用于功能和性能测试的平台。
主要特性

  • 利用自然语言处理创建测试用例。
  • 由人工智能驱动测试执行和维护。
  • 与Jenkins和GitLab等CI/CD工具集成。
    使用案例:对Spring Boot应用程序中的用户界面和API进行功能测试。

6. Applitools

用途:人工智能驱动的视觉测试平台。
主要特性

  • 支持Java和Spring Boot应用程序,并能无缝集成SDK。
  • 利用视觉人工智能检测跨环境的UI变化。
  • 与Selenium、Cypress和TestNG集成。
    使用案例:验证Spring Boot Web应用程序中前端组件的视觉一致性。

7. Tricentis Tosca

用途:人工智能驱动的持续测试平台。
主要特性

  • 支持对Java应用程序进行API和UI测试。
  • 具备自我修复测试和智能测试优化功能。
  • 与CI/CD管道集成。
    使用案例:对Spring Boot应用程序(包括REST API和前端组件)进行端到端测试。

8. Selenium与人工智能插件(Healenium)

用途:通过人工智能功能增强Selenium测试。
主要特性

  • Healenium:具备自我修复测试功能,可解决定位器损坏的问题。
    使用案例:对具有动态界面的Spring Boot应用程序的Web UI测试进行自动化。

9. SmartBear TestComplete

用途:人工智能增强的用于功能和回归测试的测试自动化工具。
主要特性

  • 支持Java应用程序,具备脚本编写和录制回放功能。
  • 利用人工智能驱动对UI元素进行对象识别。
  • 与Jenkins和Git集成。
    使用案例:对Spring Boot前端和后端组件进行功能测试。

10. ReTest

用途:人工智能驱动的回归测试工具。
主要特性

  • 利用人工智能进行智能测试维护。
  • 支持基于Java的应用程序。
  • 自动检测应用程序中的变化。
    使用案例:对不断演进的Spring Boot应用程序进行回归测试。

GitHub仓库——Java 23,Spring Boot 3.3.4测试示例

在深入探讨DiffBlue之前,让我先对GitHub仓库进行概述,并展示跨各种平台和测试自动化库的示例测试用例。

以下图片突出显示了各工具以及每个工具或库可用的测试用例数量。

GitHub仓库:《微服务测试快速入门》

依赖项

  • Java 21及以上版本
  • Spring Boot 3.3.4
  • Jakarta EE 10

测试平台

  • JUnit 5(5.10.2版本)
  • TestNG 7(7.10.2版本)
  • Spring Spock 2(2.4.0版本)

测试套件

  • Mockito(5.12.0版本)
  • Cucumber(7.18.0版本)
  • Selenium(4.12.0版本)
  • Rest Assured(5.4.0版本)
  • WireMock(3.6.0版本)
  • Pact(4.0.10版本)

设置测试平台和测试套件

测试套件版本——pom.xml

<junit.jupiter.version>5.10.2</junit.jupiter.version>
<testng.version>7.10.2</testng.version>
<spock.version>2.4-M1-groovy-4.0</spock.version>

<hamcrest.version>2.2</hamcrest.version>
<truth.version>1.0.1</truth.version>
<mockito.version>5.12.0</mockito.version>
<wiremock.version>3.6.0</wiremock.version>
<cucumber.version>7.18.0</cucumber.version>
<selenium.version>4.12.0</selenium.version>
<restassured.version>5.4.0</restassured.version>
<pact.version>4.0.10</pact.version>
<assertj.version>3.26.3</assertj.version>

依赖项

io.rest-assured rest-assured ${restassured.version} test com.github.scribejava scribejava-apis 8.3.3 org.junit.jupiter junit-jupiter ${junit.jupiter.version} test org.junit.jupiter junit-jupiter-api ${junit.jupiter.version} test org.junit.jupiter junit-jupiter-engine ${junit.jupiter.version} test org.junit.vintage junit-vintage-engine ${junit.jupiter.version} test org.junit.jupiter junit-jupiter-migrationsupport ${junit.jupiter.version} test org.junit.jupiter junit-jupiter-params ${junit.jupiter.version} test org.hamcrest hamcrest-core ${hamcrest.version} test com.google.truth truth ${truth.version} test org.assertj assertj-core ${assertj.version} test
    <!-- Cucumber框架 -->
io.cucumber cucumber-java ${cucumber.version} io.cucumber cucumber-junit ${cucumber.version} io.cucumber cucumber-core ${cucumber.version} io.cucumber cucumber-java8 ${cucumber.version}
   <dependency>
        <groupId>io.cucumber</groupId>
        <artifactId>cucumber-junit-platform-engine</artifactId>
        <version>${cucumber.version}</version>
        <scope>test</scope>
    </dependency> 
io.cucumber cucumber-picocontainer ${cucumber.version} test io.cucumber cucumber-testng ${cucumber.version} test
    <!-- ================================================================= -->
    <!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
org.seleniumhq.selenium selenium-java ${selenium.version} org.seleniumhq.selenium selenium-api ${selenium.version} org.seleniumhq.selenium selenium-support ${selenium.version}
    <!-- Mockito框架 -->
    <!-- https://mvnrepository.com/artifact/org.mockito/mockito-core -->
org.mockito mockito-core ${mockito.version} test org.mockito mockito-junit-jupiter ${mockito.version} test org.springframework.boot spring-boot-starter-test ${spring.boot.version} test junit junit
    <!-- WireMock框架 -->
org.wiremock wiremock ${wiremock.version} test au.com.dius pact-jvm-provider-junit5 ${pact.version} test au.com.dius pact-jvm-consumer-junit5 ${pact.version} au.com.dius pact-jvm-provider ${pact.version} au.com.dius pact-jvm-consumer-junit ${pact.version} au.com.dius pact-jvm-consumer ${pact.version}

Diffblue Cover

Diffblue Cover是一款人工智能驱动的工具,旨在自动为Java应用程序(包括使用Spring Boot框架构建的应用程序)生成单元测试。

通过利用强化学习,它能生成可靠、可维护且能正确编译和运行的单元测试,有助于提高代码质量并加快开发周期。来源:Diffblue.com

Diffblue Cover的主要特性:

  • 自动测试生成:Diffblue Cover会自动为Java代码编写全面的单元测试,有效减少了通常在测试创建过程中所需的人工工作量。
  • 与开发环境集成:它为IntelliJ IDEA提供了一个插件,使开发人员能够在其集成开发环境(IDE)中直接生成单元测试。这种集成简化了测试流程,允许在编写或修改代码时立即创建测试。
  • 对Spring Boot应用程序的支持:Diffblue Cover与Spring Boot应用程序兼容,能够为诸如控制器和服务等各种组件生成单元测试。它利用Mockito等模拟框架来处理依赖关系,确保测试是独立的,并专注于被测试的单元。
  • 提高开发人员生产力:通过自动生成单元测试,Diffblue Cover使开发人员能够将更多精力放在编写应用程序代码上,从而提高整体生产力,并能更快地交付高质量软件。

在IntelliJ IDE中设置Diffblue Cover

  1. 打开IntelliJ IDEA。
  2. 导航至“文件”菜单→“设置”(在macOS上为“IntelliJ IDEA”→“设置”)。
  3. 在设置窗口中,从左侧菜单中选择“插件”。
  4. 在“市场”选项卡中,搜索Diffblue Cover。
  5. 点击Diffblue Cover插件旁边的“安装”按钮。
  6. 重启IntelliJ IDEA以完成安装。

自动生成测试用例

  1. 订单服务

@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderRepository orderRepo;
@Autowired
private PaymentService paymentService;
/**
- 用于将服务与订单仓库和支付服务进行自动装配
- @param _orderRepo
- @param _paymentService
/
public OrderServiceImpl(OrderRepository _orderRepo, PaymentService _paymentService) {
orderRepo = _orderRepo;
paymentService = _paymentService;
}
// 这仅用于PACT演示
@Autowired
private ExternalGateWay externalGateWay;
@Override
public OrderEntity getOrderById(String _id) {
// return orderRepo.getOrderById(_id);
return mockGetOrderById(_id);
}
/
*
- 这仅用于PACT演示
- @param _order
- @return
*/
public OrderEntity saveOrderExternal(OrderEntity _order) {
return externalGateWay.saveOrder(_order);
}
@Override
public OrderEntity processOrder(OrderEntity _order) {
// 保存订单
OrderEntity order = orderRepo.saveOrder(_order);
if (order!= null) {
// 进行支付
PaymentStatus payStatus = paymentService.processPayments(
order.getPaymentDetails());
// 更新支付状态
order.setPaymentStatus(payStatus);
}
return order;
}

//...

/**
- 更新订单状态
*/
public OrderEntity updateOrderStatus(String _id, String _status) {
    // 根据订单ID获取订单
    // OrderEntity order = orderRepo.getOrderById(_id);
    OrderEntity order = mockGetOrderById(_id);
    // 检查订单状态并在订单中设置状态
    if (_status.equalsIgnoreCase(OrderStatus.READY_FOR_SHIPMENT.name())) {
        order.orderReadyForShipment();
    } else if (_status.equalsIgnoreCase(OrderStatus.PAYMENT_EXPECTED.name())) {
        order.orderWaitingForPayment();
    }
    return orderRepo.saveOrder(order);
}
/**
- 添加一个新方法来测试DiffBlue Cover
- 发货订单
- @param _id
- @return
*/
public OrderEntity shipOrder(String _id) {
    // 根据订单ID获取订单
    OrderEntity order = mockGetOrderById(_id);
    order.orderReadyForShipment();
    return order;
}
@Override
public PaymentStatus processPayments(PaymentDetails _paymentDetails) {
    return paymentService.processPayments(_paymentDetails);
}
//... 仅展示相关代码...

}

  1. 右键单击代码(控制器/服务)以生成测试用例

点击“编写测试”或“编写框架测试”。

  1. 测试用例生成进行中

  2. 测试用例生成完成

  3. 测试自动生成的订单服务测试代码

Diffblue Cover主要是一个单元测试生成工具,它通常依赖Mockito(或类似的模拟框架)来隔离依赖关系。

以下是由Diffblue为OrderService自动生成的代码。虽然它可能并不完美,但它提供了一个坚实的起点,让您可以在此基础上快速构建。您可以通过添加任何缺失的部分来完善功能,轻松增强生成的代码。这种方法大大减少了编写测试用例所需的时间。

当我尝试为REST控制器生成代码时,结果并不理想。然而,对于存储库和服务,Diffblue的表现非常出色,生成了一个包含所有关键元素的可用代码库。

只需再花20 - 30%的精力来完善和最终确定测试用例,您就能有效地实现全面覆盖。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐