微服务架构下的软件测试实践

Spring 微服务架构下的测试策略:单元、集成到端到端测试 微服务架构下Spring测试策略:从单元到端到端测试 摘要: 随着单体应用向微服务转型,测试策略面临新挑战。本文探讨了Spring微服务架构下的多层次测试方法。单元测试使用JUnit5/Mockito验证独立逻辑;集成测试通过@SpringBootTest等注解验证服务内部协作;端到端测试模拟真实用户场景。Spring生态提供了丰富工具支持,包括Testcontainers和WireMock等,帮助开发者构建健壮的测试体系,确保微服务质量并降低生产风险。测试矩阵覆盖从组件到系统的各个层面,形成完整的质量保障 阅读详情

随着企业开发模式逐渐从传统的整体式(Monolithic)产品交付,向快节奏的微服务架构迁移,软件测试人员也必须相应地调整自己的测试方法和工具,才能多快好省地提高测试覆盖率,尽早发现潜在的缺陷。在快速迭代的背景之下,依然能够满足企业对产品质量的严格要求。

本文将结合 Martin Fowler、Rick Osowski 等行业大师们关于微服务的理论观点,以及我在 DevOps、自动化测试领域所积累的经验,向大家介绍怎样快速地构建起微服务的测试流水线(Pipeline)。本文主要面向的对象为:计划或者已经采用微服务架构的开发团队和测试人员。不敢奢言面面俱到,但求以实践经验的干货为主,避免重复读者们已经熟悉的概念,让大家有所收获或启示。

当我们提到微服务的时候,我们在说什么?

坊间关于微服务的介绍已经连篇累牍,相信读者都或多或少有所了解。那么对于测试人员而言,“微服务”到底有什么特点呢?

enter image description here

(1) 每个服务承担一定的职责:“尽可能小,但是又达到必要的规模。(as small as possible but as big as necessary)” 。

在问答网站 Quora 上,有一个著名的问题:什么是程序员觉得最浪费时间的事情?排名第一的回答中提到:“不必要的微服务。” 这句话揭示了企业在转向微服务架构时经常走入的误区。“微”固然重要,但是首要的是提供“服务”,这才构成“微服务”的价值。盲目地切分功能(Feature),却没有起到解耦合的作用,只是会增加维护、测试的成本。毕竟,多一项服务,就会多出一系列的流水线和测试要求。

(2)微服务之间通常通过 Rest over HTTP 连接。

最常见的连接/交互方式,即通过 POST、GET、PUT、DELETE 这些命令操作 API,通过 JSON 传递参数。这种简易、明确的交互方式为契约测试(Contract Test)提供了基础,本文《契约测试入门》小节将详细介绍。

(3)每种服务不一定提供用户界面。

这意味着每种服务的测试,并不一定能够或者需要从 UI 完成。这对 API 级别的集成化测试提出了要求,详见本文《了解集成测试》小节。

(4)微服务通常还可以划分为更小的模块。

如下图所示,一个典型的微服务可以分为这几个模块:资源、业务逻辑、数据存储接口、外部通信接口等。

enter image description here

微服务架构对于软件测试意味着什么?

综合微服务的上述特点,对于测试提出了什么要求呢?

开发团队采用的任何测试策略,都应当力求为服务内部每个模块的完整性,以及每个模块之间、各个服务之间的交互,提供全面的测试覆盖率,同时还要保持测试的轻便快捷。

以一个常见的开发团队为例,可能同时开发多个功能模块,有不同的开发进度和交付期限,但是整个团队又必须保证在固定的时间节点(譬如每月一次、每个 Sprint 一次,甚至每天一次),持续地为用户提供可以部署、使用的产品。这意味着,过去那种等待产品经理、业务部门提供需求,开发人员进行开发,最后交给测试人员集成测试的方法,已经无法提供足够的测试粒度和足够快的响应速度。

归结起来,与基于整体式架构的传统测试方法相比,微服务架构对测试提出了以下挑战:

  • 服务/模块/层次(layer)之间存在复杂的依赖性:这意味着,如果想单独测试某一个服务,或者服务中的某个模块,就必须剥离它们对于其他环节的依赖关系。这需要通过 mock 等方式来实现,具体请见下文。
  • 不同的服务可能会在不同的环境/设置下运行:特别是一些后端服务,与前端服务的运行环境可能截然不同。这时在考虑对每种服务设立自动化管线时,就必须有针对性的设置相应的环境配置。
  • 涉及多个服务的 UI 端到端测试(End-to-End 测试,简称 E2E 测试)非常容易出错:因为每种服务的开发进度不同,集成不同服务的端到端测试往往会因为某一个服务的微小改动而出错。这种出错是测试人员希望避免的干扰信息。这意味着,对端到端测试的设计,必须采取一定的防干扰、防误报策略,详见本文《端到端测试的优化策略》小节。
  • 测试结果可能取决于网络的稳定性:特别是涉及到数据存储和外部通信的部分,如果在测试中不摆脱这些因素的影响,就可能会得到一些随机性的误报,干扰测试结果。
  • 与交付周期不同的开发团队之间的交流成本:这一点虽然跟技术无关,但是实际上会对测试人员的工作造成很大的困扰。因为开发模式分解为负责不同服务的多个小组,测试人员往往每天要花费大量的时间,了解不同团队的开发进度。如果还需要手动进行回归测试(Regression Test),最终将会不堪重负。所以自动化是必须采取的手段和方向。

如何应对这些挑战,我总结了下面这三个原则:

  • 自动化:测试任务的增加,要求测试人员必须把主要的精力用于将测试自动化,摆脱手动测试带来的沉重负担。当然,自动化测试必须足够稳定、稳健,不能动辄误报,否则反而会导致很高的维护成本。
  • 层次化:这意味着采用分层次的测试方法,粒度由细到粗,范围由小到大。下面这幅度说明了几个主要层次之间的关系:

enter image description here

最底层的是单元测试(Unit Test),粒度最细,速度最快,维护成本也最低。往上是针对每种服务内部的各种模块、业务流程的测试。最上面是基于前端 UI 的测试,这部分的粒度最粗,范围最大(因为会覆盖大多数服务),但是维护成本最高,因为稍微有些细微的变化就可能需要调整脚本。而且,由于基于前端,需要设置很多响应时间和等待时间,所以速度越最慢。

  • 可视化:为了降低交流成本,最好的办法就是让所有的测试结果可视化。这意味着将构建(Build)、测试(Test)、部署(Deploy)所有这些相关任务构建在一个流水线之中,让所有团队成员都可以随时监控项目进度,找到阻碍项目的瓶颈。本文《揭开测试流水线的奥秘》小节将会详细介绍如何建立这样的流水线。

下面将以层次化的方式,逐一介绍在微服务架构中所采用的主要测试方法,如下图所示,它们包括:

  • 单元测试(Unit Test)
  • 集成测试(Integration Test)
  • 组件测试 (Component Test)
  • 端到端测试(End-to-end Test)
  • 探索测试( Exploratory Test,即手动测试)

enter image description here

怎么针对微服务架构做单元测试?

单元测试的目的是执行软件程序中最小的可测试单元,验证其运行结果是否符合预期。

单元测试的工具有很多,例如:

  • C++:Googletest、GMock
  • Java:Junit、TestNG、Mockito、PowerMock
  • JavaScript:Qunit、Jasmine
  • Python:unittest
  • Lua:luaunit

其实现方法主要遵循:构建(Setup)-> 执行(Exercise)-> 验证(Verify)—> 清理(Teardown)这个过程。

定义测试边界是实现高效测试的第一步。测试的目的是为了验证边界里“黑盒”的行为是否符合预期,我们向黑盒输入数据,然后验证输出的正确性。单元测试里,黑盒指的是函数或者类的方法,目的是单独测试特定代码块的行为。但是在微服务架构中,很多时候黑盒的输出需要依赖于其他的功能或者服务,即存在外部依赖。

为了在不依赖于外部条件的情况下制造出各种输入数据,就需要使用 Stub,也叫作 Mock。这个可以使用依赖注入或方法搅拌(Swizzle)来实现。测试框架在运行被测试的函数时可以确保对底层依赖项的调用会被重定向到 Stub 上,这样单元测试就可以在没有外部服务的情况下进行,即保证了速度,又避免了网络条件的影响。创建 Stub 的工具有很多,包括 Node.js/JavaScript框架下的 sinon.js、testdouble.js 等; Python 下的 Mock 等。

重点需要提及的一点是,测试人员应当设法将单元测试的覆盖率作为一个重要的监控指标,记录并可视化。例如,Teamcity 或者 Jenkins 这样的流程化工具,支持用 dotCover 来统计流程中单元测试的覆盖率,并将结果以 TXT 报告或者 HTML 的方式显示在任务页面上。进一步也可以将覆盖率、测试结果的数据,自动输出到 SonarQube 这样的代码质量监控工具之中,以便随时检查出测试没有通过或者测试覆盖率不符合预期的情况。

enter image description here

高覆盖率的单元测试是保障代码质量的第一道也是最重要的关口。从分工上来说,测试人员可能不会参与单元测试的开发与维护,但是测试人员应当协助开发人员确保单元测试的部署和覆盖率,这是确保后续一系列测试手段发挥作用的前提。

了解集成测试

在微服务架构中,集成测试的主要目的是把一些子模块组合到一起,以“子系统”的方式工作,确保它们能够以预期的方式协作,并检查不同模块之间的通信和交互,核实接口上是否存在问题。

最常见的集成测试,是检查微服务对外的模块与外部服务的通信,以及与外部数据库的交互,即下图中用黄色虚线标出的部分。

enter image description here

在测试与外部的通信时,注意集成测试的目的是检查通信是否通畅,而不是对外部模块做功能上的验收测试,因而只需要检查基本的“核心路径”(Critical Path)即可。这种测试有助于发现任何协议层次的错误,例如丢失 HTTP 报头、SSL 使用错误,以及请求/响应不匹配等情况。

另外,因为大部分集成测试都涉及到网络连接,所以必须确认服务或者模块能够妥善地处理网络故障等情况。如果需要测试模块在外部服务进入特殊状态时的行为,也可以采用上文所述的 Stub,来模拟外部服务的状态,例如响应超时。测试与数据库的链接可以确保微服务所使用的数据模式(Scheme)符合数据库中的定义。

在单元测试通过的基础上,集成测试进一步完善了我们的测试覆盖率,即让我们知道:不仅微服务内的模块可以正常工作(根据单元测试的结果),而且这些模块也可以正常地组合到一起发挥作用,并与外部进行通信和交互。

下一步,我们需要了解单个微服务能否正常工作,这就引出了“组件测试” (Component Test)。

组件测试详解

这里说的组件,是指一个大型系统中,某一个可以独立工作的、包装完整的组成部分。在微服务架构中,组件实际上就代表着微服务本身。

这个测试的实质,就是把一项微服务周边依赖的所有其他服务或者资源全部模拟化,从该服务外部“用户”的角度来检查服务能否提供预期的输出。

为了将这些依赖关系模拟化,通常有两种方式,一种是把所有服务和调用关系都放在一个进程之中,再使用 Inproctester(用于 Java 环境)和 Plasma(用于 .NET 环境)等工具模拟依赖关系。这样做的好处是降低复杂性,缺点是需要更改生产代码。另外一种方法则是将模拟的依赖关系放在微服务进程之外,使用真实的网络连接调用为服务的对外 API。好处是适用于高度复杂的微服务,缺点是依赖关系的模拟难度大大提高。可以选用的工具包括 moco、stubby4j 和 Mountebank 等。

以 Mountebank 为例,它可以模拟出一个虚拟的 API,供微服务调用。例如针对下面这段数据:

    {
      "port": 4545,
      "protocol": "http",
      "stubs": [{
          "responses": [{
            "is": {
              "statusCode": 200,
              "headers": {
                "Content-Type": "application/json"
              },
              "body": ["Australia", "Brazil", "Canada", "Chile", "China", "Ecuador", "Germany", "India", "Italy", "Singapore", "South Africa", "Spain", "Turkey", "UK", "US Central", "US East", "US West"]
            }
          }],
          "predicates": [{
            "equals": {
              "path": "/country",
              "method": "GET"
            }
          }]
        }, {
          "responses": [{
            "is": {
              "statusCode": 400,
              "body": {
                "code": "bad-request",
                "message": "Bad Request"
              }
            }
          }]
        }]
    }

写一个简短的脚本,就能在浏览器中输入地址:http://localhost:2525/country 时返回一个列表。

    #!/bin/sh
    set -e
    RUN_RESULT=$(docker ps | grep hasanozgan/mountebank | wc -l)
    MOUNTEBANK_URI=http://localhost:2525
    BANK_IS_OPEN=1

    if [ "$RUN_RESULT" -eq 0 ]; then
      docker run -p 2525:2525 -p 4545:4545 -d hasanozgan/mountebank
    fi

    curl $MOUNTEBANK_URI/imposters || BANK_IS_OPEN=0
    if [ $BANK_IS_OPEN -eq 1 ]; then
      break
    fi

    curl -X DELETE $MOUNTEBANK_URI/imposters/4545
    curl -X POST -H 'Content-Type: application/json' -d @stubs.json $MOUNTEBANK_URI/imposters

至此,我们完成了对服务本身的各项测试。接下来,我们怎么确保不同的服务之间都能够正常地协作呢?这就要引入契约测试(Contract Test)的概念。

契约测试入门

契约测试 ,通常又被称为消费者驱动的契约测试(Consumer-Driven Contract Test,简称 CDC)。我们可以将服务分为消费者端和生产者端,而 CDC 的核心思想在于是从消费者业务实现的角度出发,由消费者端定义需要的数据格式以及交互细节,生成一份契约文件。然后生产者根据契约文件来实现自己的逻辑,并在持续集成环境中持续验证该实现结果是否正确。

enter image description here

注意,CDC 型契约测试有几个核心原则:

  1. CDC 是以消费者提出接口契约,交由服务提供方实现,并以测试用例对契约进行产生约束,所以服务提供方在满足测试用例的情况下,可以自行更改接口或架构实现而不影响消费者。
  2. CDC 是一种针对外部服务接口进行的测试,它能够验证服务是否满足消费方期待的契约。它的本质是从利益相关者的目标和动机出发,最大限度地满足需求方的业务价值实现。
  3. 契约测试不是组件测试,它们并不需要深入地检查服务的功能,而是只检查服务请求的输入、输出是否包含了必要的数据结构和属性,以及响应延时、速度等是否在预期的范围之内。

在下面这个例子中,我们会通过契约测试检查消费端和服务提供方之间交互的数据包(通常以 JSON 形式存在)中,是否包含了 ID、name 和 age 这三个条目(Item),以及这三个条目的数据结构是否符合预期。

enter image description here

目前,契约测试最常用的工具是 Pact。 它的工作流程简单来说就是这两步:

  1. 在消费端写一个对接口发送请求的单元测试,在运行这个单元测试的时候,Pact 会将服务提供者自动用一个 MockService 代替,并自动生成契约文件,这个契约文件是 JSON 形式存在。
  2. 在服务供应端做契约验证测试,将供应端服务启动之后,通过 Pact 插件可以运行一个命令,例如如果是用 Maven,就是 mvn pact:verify,然后它会自动按照契约生成接口请求并验证接口响应是否满足契约中的预期。

可以看到这个过程中,在消费端不用启动服务供应端,在服务提供端不用启动消费端,却完成了与集成测试类似的验证,这是 Pack 最强大的地方,此外它还有其他一些特性:

  • 测试解耦,就是服务消费端与提供端之间解耦(Decoupling),甚至可以在没有提供者实现的情况下开始消费端的测试。
  • 一致性,通过测试保证契约与现实是一致性的。
  • 测试前移,可以在开发阶段运行,并作为 CI 的一部分,甚至在开发本地就可以去做,而且可以看到一条命令就可以完成,便于尽早发现问题,降低解决问题的成本。
  • Pact 提供的 Pact Broker 可以自动生成一个服务调用关系图,为团队提供了全局的服务依赖关系图。
  • Pact 提供 Pact Broker 这个工具来完成契约文件管理,使用 Pact Broker 后,契约上传与验证都可以通过命令完成,且契约文件可以制定版本。
  • 使用 Pact 这类框架,能有效帮助团队降低服务间的集成测试成本,尽早验证当提供者接口被修改时,是否破坏了消费端预期的数据格式。
  • Pact 目前仅支持 REST HTTP 通信,但对于 RPC 的通信机制暂不支持。

端到端测试的优化策略

契约测试解决了我们对微服务之间协作的测试。自动化测试的最后一步,就是所谓的端到端测试(End-to-End Test),即验证整个系统的功能能否符合用户的预期。

前面的测试大多是后端或者 API 级别的测试,但是端到端测试应当从 UI 执行,这样才能确保用户看到的界面是符合预期的。但是,正如大家都曾经遇到过的,UI 的测试往往是非常脆弱、不稳定的,往往会因为一点点 UI 的变化而失败。为了确保端到端测试起到弥补其他测试的不足,提高覆盖率,但是又不会经常误报的目的,需要注意以下几点:

  1. 端到端测试应当尽量简洁。“简洁”的意思是说,它应当覆盖用户使用功能的核心路径,但是不需要覆盖太多的分支路径。力求 UI 测试的轻量化,才能降低维护成本。否则,整个测试团队就会陷入更新前端脚本的泥潭之中。
  2. 谨慎地选择测试范围。如果某个特定的外部服务或者界面很容易导致测试随机出错,那么可以考虑将这些不确定性排除到端到端测试之外,再通过其他形式的测试加以弥补。
  3. 通过“自动化部署”(Infrastructure-as-code)来提高测试环境的可重复性。在测试不同版本或者不同分支的产品时,自动化测试往往会因为测试环境的不同给出不同的测试结果。这要求环境必须具备可重复性,解决的途径就是通过脚本进行自动化部署,避免手动部署的影响。
  4. 尽可能摆脱数据对于测试的影响。端到端测试的一个常见难题就是怎么管理测试数据。有些团队选择导入已有数据,以加快测试速度,避免了新建数据的时间,但是随着生产代码的变化,这些预先准备的数据必须要随之变化,否则就可能导致测试失败。为此,笔者比较倾向于在测试过程中新建数据,虽然花些时间,但是这样避免了数据维护的成本,也保证了对用户行为的全面测试。

UI 测试的框架和工具很多,目前对于网页测试,最为常见的是“Protractor + Selenium Server + Jasmine测试框架”这个组合,过程如下图所示。

UI测试流程

揭开测试流水线的奥秘

上面我们已经介绍了对于微服务架构,主要的测试类型。那么,如何选择适合自己的测试策略呢?现在我们再回顾一下这几种测试的特点:

  • 单元测试:对生产代码中最小的可测试片段进行检查,判断其是否符合预期。
  • 集成测试:检查模块的组合能否发挥作用,以及模块和外部服务、资源的通信是否正常。
  • 组件测试:以单个微服务作为对象,通过内部接口和外部模拟,将微服务与外界隔离开,测试其功能。
  • 契约测试:在各个微服务之间的接口上,检查它们的交互是否符合预期标准。
  • 端到端测试:从整个产品/系统的角度,进行端到端的检查,判断是否符合外部要求和达到其目标。

总而言之,从上到下,测试的粒度由细到粗。一种测试的粒度越粗,涉及的部分就越多,也就越脆弱(容易误报),执行和维护的成本就越高。

选择了测试策略以后,就可以使用 TeamCity 或者 Jenkins 这样的调度工具来建立持续集成/持续交付的流水线。一个常见的流水线可以表现为:

enter image description here

只有上一步成功通过,才会触发下一步操作。在单个微服务的测试完成之后,再会触发下一步、结合多个微服务的端到端测试。

上面介绍完了微服务自动化测试的各个阶段工作,最后一步是手动测试。如果有了完善的自动测试,手动确认的工作实际上可以非常简单。这一步的关键是要引入业务知识专家(Domain Expert),从用户的角度来探索产品的功能。可以借助微软 Azure 的 ApplicationInsight,或者谷歌云的 Analytics 等工具,记录下这些专家的行为,作为以后自动化测试的用例参考。

云端测试与本地测试的不同

大部分开发团队在开发阶段,都会先把产品部署在本地环境中,进行各种测试。但是在最终部署到生产环境时,现在很多产品都需要发布到云端,不管是微软 Azure、谷歌云、亚马逊 AWS 还是国内的阿里云等。那么,在本地执行的测试流程、代码,能否平稳地覆盖部署到云端的产品呢?

根据我的经验,这两种测试环境的主要区别包括以下两点:

  • 登录机制:在本地环境中,因为大部分都是位于企业网络内部,所以登录机制可能较为简单。但是在公共云环境中,处于安全考虑,云服务供应商都提供了一系列的登录机制,这可能会使得本地的测试代码失效。针对这种方式的不同,就需要开发人员在开发阶段就考虑到云端测试的需要,提供一定的 API 级访问方式。如果是前端的 UI 测试,一般可以直接通过鼠标点击、输入账号的方式直接进入程序界面,但是这面临着是否需要在测试代码中写入登录密码的安全问题。
  • 网络状态:在本地企业网络中,网络条件是非常可以预期的,但是在公有云中,网络和虚拟机的配置往往是存在一定不确定性的。这意味着测试可能会因为一些未知因素而失败。这意味着在本地进行测试时,也要模拟出一定的网络故障、配置错误,检查生产程序对于这些情况的处理。

当然,云端测试也提供了很多有用的功能,譬如云服务供应商一般都提供了全面的监控、诊断工具,便于测试人员、维护人员分析运行状态和查找日志。

性能测试/容量测试的工具选择

性能/容量测试也是微服务测试的一个不可获取的组成部分,特别是对于网页端程序,在流量极具增加时还能否保持稳定运行,是每个产品经理都需要了解的信息。

性能测试包括负荷测试、压力测试、尖峰测试、持久性测试、可扩展性测试等,它可以证明系统能否符合预期的性能指标(SLA),也可以找出系统中导致性能下降的部分。

它的总体流程包括:

  • 确定测试环境
  • 确定性能验收标准(SLA)
  • 计划和设计测试方案
  • 配置测试环境
  • 部署测试方案
  • 执行测试
  • 分析测试结果

目前可供选择的主要工具包括:

  • Microsoft Visual Studio Load Testing
  • HP LoadRunner
  • Neo Load
  • Apache JMeter
  • Rational Performance Monitor
  • Silk Performer
  • Gatling

其中,我用的最多的是 Microsoft Visual Studio Load Tester。它完全基于 HTTP 协议,所以不需要使用浏览器。换句话说,就是和前端的所有 JS 方法都无关,它只记录 HTTP 的请求。除此之外,它和 UI 的端到端测试很接近,都是基于请求响应,从返回结果中提取验证规则,判断是否成功。它的参数化、数据源管理功能都很全面,自定义的验证规则(Validation Rule)也可以应付大多数的情况。另外,它所记录下来的脚本还可以用做手动的测试代码,这是一个额外的好处。

测试人员在新时代的角色演变

最后,我想谈一下我对 QA(测试人员)这个角色在新型开发架构下的演变。下面这张图显示的是开发、测试和运维之间的关系。其中的 DevOps 是目前一个很热门的概念,而 QA+Ops 构成的 TestOps,在我眼里是未来的发展方向。原因是,随着自动化的深化,产品发布频率的提升,单纯拿到产品进行手动或者自动化测试的测试人员已经无法满足企业的需要。

enter image description here

在传统的工作模式中,开发人员发布代码,测试人员进行测试,运维人员推广产品。这种模式的缺点是每个团队之间存在着很高的沟通成本,如下图所示。

enter image description here

而在未来的 TestOps 模式下,TestOps 人员要承担起测试、持续集成/交付和最终推广的职责。

enter image description here

这种模式对测试人员的技术水平提出了更高的要求,但是好处是非常明显的。

对于团队:

  • 促进了合作,降低了交流成本;
  • 更加有效地控制持续交付生命周期;
  • 高质量的持续集成。

对于测试人员自己:

  • 可以掌握运维的技能;
  • 必须利用自动化测试来实现持续交付;
  • 主动控制开发生命周期,在整个团队中有很大的发言权。

以上,是我目前对测试工作和测试人员职业发展的一些小想法,仅供参考。

欢迎大家随时扫描下方二维码,向我提问关于自动化测试、微服务架构和DevOps的问题。

参考文献

  1. Martin Fowler: Microservice Architecture.
微服务自动化测试平台实践-张海涛 微服务自动化测试平台实践-张海涛。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 立即下载

相关推荐

Win11系统下Abaqus2022与VS2022+oneAPI2023环境配置全攻略(附VUMAT子程序避坑指南)

本文详细指导在Windows 11系统下,为Abaqus 2022配置Visual Studio 2022与Intel oneAPI 2023的Fortran编译环境,以支持VUMAT等用户子程序开发。内容涵盖软件安装顺序、环境变量关联、快捷方式修改及关键验证步骤,并提供了首个VUMAT子程序的实战编写与模型验证方法,帮助用户高效搭建稳定可靠的仿真开发平台。

pytorch8learner的博客 319

第06节:契约测试入门

在前面几篇文章中,我们学习了怎么对一个微服务,实施从单元到整体的全部测试。下一步,我们就需要考虑怎么测试不同微服务之间的协同、交互。如果采用传统的总体测试方法,对服务之间的协作进行验证,那么随着服务数量和调用关系复杂度的增加,必须面临成本呈现指数级增长的挑战,这表现在: 验证成本高:为了验证多个服务协作后的功能正确与否,需要为每个服务搭建基础设施(包括其依赖的数据库、缓存等),并执行部署、配...

weixin_41918841的博客 1408

一篇教你杰理63系列蓝牙双设备主从连接传输数据过程及配置

首先打开632sdk的app_config.h文件,将宏CONFIG_APP_SPP_LE写0,将宏CONFIG_APP_MULTI写1,对应的CONFIG_BT_GATT_CLIENT_NUM写1代表我只连接一个主机设备。属性都可以修改为自己想要的属性,然后关掉文件,双击gatt_inc_generator.exe文件运行,就会自动弹出生成/更新后的gatt_profile_cfg.h文件,然后里面就是我们代码里面所需要的配置,都是十六进制表示,找到我们刚刚添加的服务属性配置,复制到代码里面去。

xiaolizaixian的博客 1379

从零开始掌握微服务软件测试

课程介绍 随着行业主流开发方式从传统的整体式产品交付,向快节奏的微服务架构迁移,软件测试人员也要相应地调整自己的测试方法和工具,才能多快好省地提高测试覆盖率,尽早发现潜在的缺陷,在快速迭代的背景之下,确保所有微服务满足企业的质量要求。 目前有很多关于微服务架构测试方法的文章,但都是从某个角度切入,缺乏从零开始逐步深入讲解的系统化课程。本达人课共计10篇文章,结合作者的生产实战经验,由浅入深,层层剖...

GitChat 9321

高通量测序数据分析:RNA-seq

深度测序相关数据库与数据格式 SRA toolkit 一、NCBI 和EBI、DDBJ组成INSDC,数据内容相同所以找NCBI就行。 (一)NCBI常用数据库 GenBank:遗传序列数据库,收集了所有公开的DNA序列及其注释 GEO (Gene Expression Omnibus) :收集整理各种表达芯片数据,后来加入了甲基化、lncRNA、miRNA、CNV等其他芯片,还有高通量测序数据...

qq_41134363的博客 3万+

minist手写数字的识别代码复现(pytorch 版本)

电脑系统:Windows 10语言环境:Python 3.8.18编译器:jupyter notebook深度学习环境:torch == 1.13.1+cu116显卡及显存: Tesla V100-PCIE-32GB卷积神经网络(Convolutional Neural Network,CNN或ConvNet)是一种 具有局部连接、权重共享等特性的深层前馈神经网络. 目前的卷积神经网络一般是由卷积层、汇聚层和全连接层交叉堆叠而成的 前馈神经网络。

2202_75521293的博客 2620

【自动化测试】Python - unittest单元测试框架

一、测试模型 下面这部分来自于某书籍资料,拿过来,按需参考一下: 测试模型(1)线性测试1、概念:通过录制或编写对应应用程序的操作步骤产生的线性脚本。单纯的来模拟用户完整的操作场景。(操作,重复操作,数据)都混合在一起。2、优点:每个脚本相对独立,且不产生其他依赖和调用。任何一个测试用例脚本拿出来都可以单独执行。3、缺点:开发成本高,...

weixin_34352005的博客 250

【通信原理 入坑之路】—— 详解IQ调制以及星座图原理

文章目录一. IQ调制与解调的原理与过程二.PSK(相移键控)和IQ调制的关系:2.1 用IQ调制实现QPSK调制 一. IQ调制与解调的原理与过程 IQ调制的定义是:“IQ调制就是数据分为两路,分别进行载波调制,两路载波相互正交。I是in-phase(同相), q是 quadrature(正交)” 我们通过下面的示意图介绍IQ调制的过程: 首先,信号分成两路:I路和Q路(为了方便理解我们把这两...

凝望,划过星空的博客 11万+

面向微服务的自动化测试框架

     如果你是一名测试工程师,你可能在过去一年左右听到了更多关于微服务的信息。这并不奇怪,因为许多软件公司也正在转向更“微服务”的创建软件的方式。这不可避免地带来了很多挑战,特别是如何在微服务世界中实现自动化测试。      “微服务”是软件架构中增加的另一个术语。微服务架构风格涉及开发单个应用程序,这些应用程序可以作为一套小型服务一起工作,每个应用程序都运行在其单个进程中,并与轻量级机...

良月柒 2711

Python爬虫实战:公共资源交易平台招标数据采集实战 - 从零构建企业情报系统(附CSV导出 + SQLite持久化存储)!

我长期专注 Python 爬虫工程化实战,主理专栏 👉 《Python爬虫实战》:从采集策略到反爬对抗,从数据清洗到分布式调度,持续输出可复用的方法论与可落地案例。内容主打一个“能跑、能用、能扩展”,让数据价值真正做到——抓得到、洗得净、用得上。

喵手的博客 1288

Open3D点云数据处理(五):点云、mesh可视化(draw_geometries方法)

本文介绍了Open3D中的draw_geometries可视化方法,可以用于可视化点云和mesh。详细讲述了该方法的各个参数的作用,给出了代码示例。

孙悟空 3140

在《我的世界》里,我重建了公司的微服务架构:软件测试从业者的创新实践指南

摘要:本文探讨了利用《我的世界》游戏机制创新微服务测试的方法。通过将微服务映射为游戏方块实体(城堡大门=认证服务)、红石电路模拟API通信、村民NPC生成流量,实现了架构可视化(效率提升700%)和自动化测试(用例覆盖率提升41%)。关键突破包括:用僵尸围攻模拟DDoS攻击、窄桥僵持暴露死锁问题、岩浆流验证熔断机制。实践表明,这种游戏化测试使故障复现率提升133%,新人上手周期缩短600%,同时让系统脆弱性显性化(如末影龙喷火模拟机房火灾)。该方法为复杂分布式系统测试提供了创新思路,实现了工程严谨性与游戏创

2501_94480392的博客 48

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

软件测试/测试开发/全日制 |Python全栈开发:实践容器化部署与微服务架构

Python全栈开发中,容器化部署与微服务架构是现代应用开发中越来越流行的技术选择。容器化部署使用容器技术,如Docker,将应用程序及其所有依赖项打包到一个可移植的容器中,使得应用在不同环境中都能够一致运行。微服务架构则是一种将应用程序拆分为小型、自治的服务的方法,这些服务可以独立开发、部署和扩展。

慕漓的博客 832

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

微服务架构下的测试策略革新

微服务架构下的测试策略革新面临三大核心挑战:分布式系统带来的复杂性剧增、环境依赖与测试数据管理困境,以及持续交付对测试效率的高要求。为此需要重构测试金字塔为四层结构(服务内测试、契约/集成测试、组件测试、端到端测试),推行测试左移和持续测试实践,并引入混沌工程验证系统可靠性。实施路径包括组织文化变革、工具链优化和度量体系建设,最终构建适应微服务架构的现代化质量保障体系。

2501_94480392的博客 1429

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

软件测试框架与应用方法

​ 随着互联网的不断发展,越来越多的程序员都在学习软件测试技术,而今天我们就一起来了解一下,软件测试框架与应用方法。 ​

自动化软件测试 901

微服务可靠性测试_一文搞定微服务测试本质

最近几年,微服务架构越来越火爆,逐渐被企业所采用。随着软件架构的变化,对应的软件测试策略需要作何调整呢?在这里我来先介绍一下微服务的相关概念以及微服务的主流框架SpringCloud,让大家对微服务有一个整体的认识,然后我在对如何进行微服务测试进行概要讲解。相信大家认真阅读本文后,对服微务一定会有从0到1的突破!微服务概念微服务英文名称Microservice,微服务架构模式就是将整个Web应用组...

weixin_39956022的博客 274

微服务测试的思考与实践

最近几年,微服务架构越来越火爆,逐渐被企业所采用。随着软件架构的变化,对应的软件测试策略需要作何调整呢?本文将介绍微服务架构下的测试策略,并结合分享在业务和架构演变过程中,一个历经九年的项目测试策略的演进。 关于微服务 微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,每个服务运行在其独立的进程中,服务间采用轻量级通信机制互相沟通(通常是基于HTTP协议的RESTful API)。每个服务都围绕着具体的业务进行构建,并且能够被独立部署到生产环境、预生产环境。 从微服务的概念可以看出它有

ludongguoa的博客 258

架构师技术要求

有这样一句话,Redis搞定,架构师就搞定了一半。作为架构师,有两大工具必不可少,一个叫Redis,一个叫Nginx。但是他们都不简单,源码都是c编写的。 下面我们就简单讲一讲架构师的基本技术要求。

帝上无天的博客 1127

软件测试实训室解决方案(2025年最新版)

系统具有高内聚、松耦合、单一职责等特点,支持高性能、高并发、跨平台、跨语言的业务需求,确保了平台的稳定性和可扩展性。为确保系统可靠性,方案特别设计了交叉测试、数据完整性测试、正确性测试和接口测试等专项测试环节,重点验证系统在复杂场景下的数据交互准确性。同时,通过性能测试和错误处理测试,评估系统的负载能力和异常恢复机制,确保系统具备良好的健壮性。通过系统的实训培养,学生将具备扎实的专业基础、突出的实践能力和良好的职业发展潜力,能够胜任软件和信息技术服务领域的各类技术岗位,为行业发展提供人才支撑。

whwzzc的博客 1038

当质量保障遇上工程革命:软件测试的十字路口

《软件测试的范式革命:工程3.0时代的质量保障体系重构》 文章揭示了在云原生和AI驱动的软件工程3.0时代,传统测试体系面临的深刻变革。核心观点包括:1)测试角色从"守护者"转向"赋能者",需构建AI可信度评估框架;2)云原生环境下,测试需建立全链路可观测性体系,实现实时质量感知;3)持续交付要求质量保障内嵌至开发全流程;4)测试工程师需进化代码素养、数据智能、工程思维和协作模式四大核心能力。文章提出了从基础建设到智能赋能,最终实现质量体系自治的三阶段实践路径,强调质

2501_94456679的博客 885

《Google软件测试之道》 - 关于人和组织结构

Google的测试理念有什么与众不同?Google的快速开发、快速发布的秘密又是什么?最近在读《Google软件测试之道》,了解了Google的测试理念、自动化测试技术、测试团队的组成。如果你关注团队的效率,有很多理念值得借鉴,很多实践值得尝试。 质量不等于测试 质量不是被测试出来的。传统的开发方式是: 开发人员开发新功能,测试人员编写测试计划。功能开发和测试隔离对立。如何保证软件具有很高的质...

348

2026年江苏省职业院校技能大赛“软件测试”项目竞赛规程

【2026年江苏软件测试赛项培训服务】 📌 核心技能全覆盖 · 精准对标评分标准 ✅ 测试需求分析与用例设计(覆盖全模块功能测试) ✅ 自动化测试省赛正式环境训练(Selenium +unittest + PO设计模式) ✅ 满分缺陷管理与报告撰写(覆盖全模块功能Bug与计划总结定位与编写) ✅ 性能压测与瓶颈定位(JMeter +LoadRunner工具覆盖所有省赛真题训练) ✅ 展示讲解部分团队协作与答辩技巧模拟(还原真实赛场节奏) 🏆 为什么选择我们? → 公司团队曾指导

我是网络安全兼技能大赛工程师,专注网络安全技术学习与技能大赛实战!持续分享最新的技术文章,帮你少走弯路,一起在技术赛道上进步~ 1525

软件测试金字塔模型在实践中的实施难点

软件测试金字塔模型由Mike Cohn提出,将测试分为单元测试、集成测试和UI测试三个层次,强调底层测试应占更大比例。例如,单元测试需要Mock技术,而集成测试涉及环境依赖,UI测试则易受界面变动影响。团队若缺乏自动化经验,往往陷入“写脚本耗时,维护更耗时”的困境,最终回归手动测试。相反,UI测试因直观易上手,常被过度依赖,导致测试效率低下。集成测试和UI测试依赖稳定的测试环境和数据,但现实中环境配置复杂、数据难以隔离,导致测试结果不可靠。缺乏高效的环境治理方案,金字塔模型的高层测试难以有效执行。

uicdkn_673的博客 313

Nano-Banana在软件测试中的应用:系统架构依赖分析

本文介绍了如何在星图GPU平台上自动化部署🖥️Nano-Banana: 结构拆解实验室镜像,用于软件测试中的系统架构依赖分析。该镜像可将文本描述的业务流程自动解析为可视化依赖图,帮助测试工程师精准识别隐性调用链、定位薄弱环节,显著提升集成测试覆盖率与故障预防能力。

weixin_42588555的博客 84
下一篇: 面对区块链,普通人应该做什么?
Wei_Cui_csdn
Wei_Cui_csdn 领域专家: 网络协议与安全技术领域 领域专家: 网络协议与安全技术领域
博客等级 码龄9年 89粉丝 23原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wei_Cui_csdn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值