<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>自动化 on 测试开发刚哥</title>
    <link>https://dongfanger.github.io/tags/%E8%87%AA%E5%8A%A8%E5%8C%96/</link>
    <description>Recent content in 自动化 on 测试开发刚哥</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <lastBuildDate>Wed, 07 Jan 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://dongfanger.github.io/tags/%E8%87%AA%E5%8A%A8%E5%8C%96/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Allure测试报告完整学习笔记</title>
      <link>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E8%87%AA%E5%8A%A8%E5%8C%96/000007-allure%E6%B5%8B%E8%AF%95%E6%8A%A5%E5%91%8A%E5%AE%8C%E6%95%B4%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/</link>
      <pubDate>Wed, 07 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E8%87%AA%E5%8A%A8%E5%8C%96/000007-allure%E6%B5%8B%E8%AF%95%E6%8A%A5%E5%91%8A%E5%AE%8C%E6%95%B4%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;本书作者：测试开发刚哥，文章版权归个人所有，未经授权请勿转载。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;目录&#34;&gt;目录&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;简介&lt;/li&gt;
&lt;li&gt;安装Allure&lt;/li&gt;
&lt;li&gt;Allure测试报告的结构&lt;/li&gt;
&lt;li&gt;Java TestNG集成Allure Report&lt;/li&gt;
&lt;li&gt;Python Pytest集成Allure Report&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;简介&#34;&gt;简介&lt;/h1&gt;
&lt;p&gt;假如你想让测试报告变得漂亮一点，那你一定会在搜索引擎中找到Allure测试报告的。Allure官方给出了个在线网站，访问以下链接就能一睹为快：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://demo.qameta.io/allure/&#34;&gt;https://demo.qameta.io/allure/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/12513ca6699c49569b795699f0d97579.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;可以在左下角切换为中文报告：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/0e022a1416a444058f2241cbf2a00d8c.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;如此好看的测试报告，哪个老板不喜欢呢？&lt;/p&gt;
&lt;h1 id=&#34;安装allure&#34;&gt;安装Allure&lt;/h1&gt;
&lt;p&gt;1.在GitHub releases：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/allure-framework/allure2/releases&#34;&gt;https://github.com/allure-framework/allure2/releases&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/97e74735b6524fb687af5c5ec894811c.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;或者Maven Central：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://repo.maven.apache.org/maven2/io/qameta/allure/allure-commandline/&#34;&gt;https://repo.maven.apache.org/maven2/io/qameta/allure/allure-commandline/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/6d5dc013fc9a48bf91c95fbd41be42cb.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;下载安装包并解压。&lt;/p&gt;
&lt;p&gt;2.找到bin目录，Windows使用&lt;code&gt;allure.bat&lt;/code&gt;，Unix使用&lt;code&gt;allure&lt;/code&gt;：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/d3ba1cb635c846ecbd32e9377284c68a.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;3.为了后续方便使用，可以把bin完整路径添加到&lt;strong&gt;系统环境变量PATH&lt;/strong&gt;中，然后在命令行直接输入&lt;strong&gt;allure&lt;/strong&gt;命令。&lt;/p&gt;
&lt;p&gt;官方也给出了通过Linux的ppa、Mac的brew、Windows的scoop的安装方式，不过对于咱们老百姓来说，不如手动下载包来安装实在。&lt;/p&gt;
&lt;p&gt;安装后就可以检查是否安装成功了：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ allure --version
2.17.2
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;因为Allure是用Java写的，所以如果无法运行，那么要检查下有没有安装Java。&lt;/strong&gt;&lt;/p&gt;
&lt;h1 id=&#34;allure测试报告的结构&#34;&gt;Allure测试报告的结构&lt;/h1&gt;
&lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/ce7256011e964d36a061220166d12c1d.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;categories&#34;&gt;Categories&lt;/h2&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/5d641f9211064c399c724b7ca8deb3ee.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;suites&#34;&gt;Suites&lt;/h2&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/fcc7165248104aa5a74a703717652d1e.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/e446c3a5ebcd490fae30080c02c131ab.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;graphs&#34;&gt;Graphs&lt;/h2&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/9a50ab9021a6444d82a66095320feb83.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;timeline&#34;&gt;Timeline&lt;/h2&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/0b7039a102cd4f418955be77a28e33a4.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;behaviors&#34;&gt;Behaviors&lt;/h2&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/bec7ea1565e0460d932a4d68ed82691a.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;packages&#34;&gt;Packages&lt;/h2&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/fb8f324550224cbb848a9546255caaf0.png&#34;&gt;&lt;/p&gt;
&lt;h1 id=&#34;java-testng集成allure-report&#34;&gt;Java TestNG集成Allure Report&lt;/h1&gt;
&lt;h2 id=&#34;集成&#34;&gt;集成&lt;/h2&gt;
&lt;p&gt;在Maven的pom.xml中添加：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;properties&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;aspectj.version&amp;gt;&lt;/span&gt;1.8.10&lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;/aspectj.version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;/properties&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.qameta.allure&lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;allure-testng&lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;LAST_VERSION&lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.maven.plugins&lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-surefire-plugin&lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;2.20&lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;argLine&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    -javaagent:&amp;#34;${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;/argLine&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.aspectj&lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;aspectjweaver&lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${aspectj.version}&lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后执行命令：&lt;/p&gt;</description>
    </item>
    <item>
      <title>老板给我安排了个测试环境治理的活</title>
      <link>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E8%87%AA%E5%8A%A8%E5%8C%96/000006-%E8%80%81%E6%9D%BF%E7%BB%99%E6%88%91%E5%AE%89%E6%8E%92%E4%BA%86%E4%B8%AA%E6%B5%8B%E8%AF%95%E7%8E%AF%E5%A2%83%E6%B2%BB%E7%90%86%E7%9A%84%E6%B4%BB/</link>
      <pubDate>Tue, 06 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E8%87%AA%E5%8A%A8%E5%8C%96/000006-%E8%80%81%E6%9D%BF%E7%BB%99%E6%88%91%E5%AE%89%E6%8E%92%E4%BA%86%E4%B8%AA%E6%B5%8B%E8%AF%95%E7%8E%AF%E5%A2%83%E6%B2%BB%E7%90%86%E7%9A%84%E6%B4%BB/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;本书作者：测试开发刚哥，文章版权归个人所有，未经授权请勿转载。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;测试环境困局&#34;&gt;测试环境困局&lt;/h1&gt;
&lt;p&gt;测试环境治理专项是在我入职2个月接手的活，用“烂摊子”来形容一点也不为过。年久失修，需求基本没有在测试环境使用，想用也有很多问题。人员缺乏信心，之前负责测试环境的同学抱怨极多，外部推不动，内部又没有技术能力支撑，负能量已经蔓延到整个团队。当然，我也是其中一员，这事确实难搞。在技术部&lt;strong&gt;测试环境平台化&lt;/strong&gt;的大方向下，需要每个组出一个接口人来牵头，考虑到我以前写过测试平台，乱七八糟的事都整过，老板就指定了我。&lt;/p&gt;
&lt;h1 id=&#34;what测试环境是什么&#34;&gt;What，测试环境是什么？&lt;/h1&gt;
&lt;p&gt;测试环境是一套能够支撑业务系统运行的环境，是相对于预发环境和生产环境来说完全隔离的环境。&lt;strong&gt;测试环境=应用+数据+配置+依赖服务&lt;/strong&gt;。应用包含系统应用和中间件等，数据就是测试物料，配置针对测试环境应该有单独的一套，依赖服务要跟外部联调好以后整个环境才是可用的。测试环境治理就是通过内部搭建和外部联调，保障业务系统能够在完全隔离的环境中运行。&lt;/p&gt;
&lt;h1 id=&#34;why为什么要做测试环境&#34;&gt;Why，为什么要做测试环境？&lt;/h1&gt;
&lt;p&gt;测试环境是为了隔离。如果只有一套生产环境，那么开发、测试、上线等活动，可能会对线上系统稳定性造成影响，可能会污染线上用户数据，可能引起客户投诉甚至资产损失，所以&lt;strong&gt;需要有一套完全隔离的测试环境&lt;/strong&gt;。&lt;/p&gt;
&lt;h1 id=&#34;who谁来负责测试环境&#34;&gt;Who，谁来负责测试环境？&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;每个测试人员&lt;/strong&gt;都需要具备测试环境搭建能力。当然可以推动运维或研发来搭建测试环境，但是测试人员需要具备搭建能力，能够自主编译，构建，部署，遇到问题能够根据日志做初步定位，将问题抛出推动研发或外部依赖方解决。&lt;/p&gt;
&lt;h1 id=&#34;when什么时间做测试环境&#34;&gt;When，什么时间做测试环境？&lt;/h1&gt;
&lt;p&gt;测试环境治理需要&lt;strong&gt;前置到研发自测阶段&lt;/strong&gt;。在实践过程中，测试同学暴露出来最多的问题是，没有时间投入到测试环境搭建中，一方面是缺乏动力，不肯迈出艰难的第一步，另一方面也是跟项目节奏有关，研发就算用测试环境自测，也会在预发联调好以后再提测，到测试手上时，已经有可用的预发环境了，就不会再去用测试环境。“项目时间紧，测试环境不好用，直接用预发测吧”，顺理成章的就成为了很合理的借口。所以需要从提测，前置到，研发自测，做测试环境治理：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/366febbd0a19441881cdffe1a55b1ea4.png&#34;&gt;&lt;/p&gt;
&lt;h1 id=&#34;where从哪里入手测试环境&#34;&gt;Where，从哪里入手测试环境？&lt;/h1&gt;
&lt;p&gt;测试环境治理需要&lt;strong&gt;从上往下&lt;/strong&gt;才能推动，先有文化，才有行动。假如只有某个部门想做测试环境治理，外部依赖基本上是推不动的，一个人呐喊得再愤怒其他人也可能无动于衷。所以得先把测试环境治理这件事，跟老板沟通，从高层入手，把它定义为一项政治任务，从上往下层层递进。&lt;/p&gt;
&lt;h1 id=&#34;how怎么做测试环境&#34;&gt;How，怎么做测试环境？&lt;/h1&gt;
&lt;p&gt;工欲善其事，必先利其器，公司的基建比较完善，给测试人员搭建测试环境降低了很大难度。设想一下，假如只能折腾Docker和K8S，那可能需要专门的运维才能搞得定环境，对测试来说门槛就会比较高了，除了少数技术能力强的，其他同学基本没有什么可操作性。&lt;strong&gt;测试环境平台化就是武器&lt;/strong&gt;。公司有个部署平台叫做JDOS，日常运维都是在这上面操作，没有运维人员，环境全靠开发人员和测试人员自己整。JDOS已经是页面化操作了，但它对测试环境没有特殊的应用场景，是个大而全的平台，所以二级部门开了一个测试环境平台，Env，&amp;ldquo;一款全流程自动化测试环境搭建的利器&amp;rdquo;。&lt;/p&gt;
&lt;p&gt;Env的核心思想是&lt;code&gt;1+N&lt;/code&gt;。&lt;code&gt;1&lt;/code&gt;代表稳定分组（分组≈Pod），搭建稳定分组需要经过创建系统，创建应用，创建集群，申请机器，代码编译构建，部署镜像，修改配置等操作，需要选取master稳定版本，这样才能对外提供稳定服务。&lt;code&gt;N&lt;/code&gt;是克隆&lt;code&gt;1&lt;/code&gt;产生的多个分组，相互隔离，能让开发同学复用测试搭建好的环境，完成冒烟自测等过程；也能在多业务联调测试时，通过平台快速搭建一套全链路测试环境。&lt;/p&gt;
&lt;p&gt;Env提供了环境监控的功能。对于搭建好的稳定环境，它可以每天监控机器是否可用，服务是否正常，镜像是否老旧，等等等，让你及时维护环境，保障稳定性。&lt;/p&gt;
&lt;p&gt;Env提供了一键搭建的功能。新克隆的环境，只要点一下“一键搭建”，就会基于稳定分组，自动化搭建一套新环境，大大节约了时间成本。&lt;/p&gt;
&lt;p&gt;Env提供了拓扑画图的功能。将多个应用拖到一张拓扑图里面，根据依赖关系连线，能够直观了解到应用之间的依赖关系。基于拓扑来克隆新环境，也能批量克隆多个应用。假如多项目需求并行迭代，想要多套联调的测试环境，就可以克隆多套新环境。&lt;/p&gt;
&lt;p&gt;Env还解决了一个资源浪费的问题，以前搭建测试环境比较随意，申请资源也很容易，其实会导致很多机器用过后，一直空置在那里。Env收拢了申请资源入口，基于Env来创建稳定分组，只能有1个，想要更多必须走审批。而对于克隆的新环境，也会有期限，14天以后会自动释放，想要延期也必须走审批。&lt;/p&gt;
&lt;p&gt;我所负责的第一件事，就是用Env来搭建一张拓扑图，把组内所有应用都从JDOS迁移到Env上，&lt;strong&gt;维持稳定环境对外提供支撑对接，克隆环境对内支持多项目并行&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;搭建测试环境只是起步，&lt;strong&gt;测试环境治理的目标是需求能够使用测试环境&lt;/strong&gt;。对于外部依赖少的业务模块来说，这相对容易。对于外部依赖很多的业务模块来说，这就很难了。那么该如何推动这件事呢？&lt;/p&gt;
&lt;p&gt;第1个策略是共建，让研发和测试一起来搭建和维护测试环境。&lt;/p&gt;
&lt;p&gt;第2个策略是做功能验证，梳理出链路用例，跟踪验证结果，识别卡点问题：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/993f842d5d314b23a877f507494f3697.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;对于卡点问题的处理，把干系人单独拉群对，响应超过3天就往上抛，&lt;strong&gt;一定会遇到推不动的问题，那么办法只能找自己的上游负责人，层层向上反馈，让上面的负责人去找对方负责人，然后推动对方的下游同学来协助解决&lt;/strong&gt;。卡点问题记录后需要做问题分类，做好统计，这既是工作量的体现，也是每周进度汇报的依据：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/546328b1b59744b9951e185dea9319fd.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/687bb904572e48f9ad64703e7e3a6f86.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;第3个策略就是制定kpi，强制大家使用测试环境完成绩效。&lt;/p&gt;
&lt;h1 id=&#34;how-much测试环境做到什么程度&#34;&gt;How much，测试环境做到什么程度？&lt;/h1&gt;
&lt;p&gt;测试环境的kpi能反应出测试环境应该做到什么程度，可以使用&lt;strong&gt;需求使用测试环境占比&lt;/strong&gt;和&lt;strong&gt;测试环境bug占比&lt;/strong&gt;。需求使用测试环境占比的计算公式是&lt;code&gt;打标了测试环境的提测卡片数/总的提测卡片数&lt;/code&gt;，测试在点击开始测试时，选择是否使用测试环境进行打标。测试环境bug占比的计算公式是&lt;code&gt;测试环境bug/(测试环境bug+预发环境bug+生产环境bug)&lt;/code&gt;，在提交缺陷时选择环境类型进行打标。测试环境bug占比的意义更大，因为使用测试环境与否，最终的体现还是落在缺陷上面的，比较容易量化，需求使用测试环境占比不是很确定，需求多少功能在测试环境使用了，相对来说不是很好度量，但也可以作为辅助指标进行观察。&lt;/p&gt;
&lt;h1 id=&#34;测试环境破局&#34;&gt;测试环境破局&lt;/h1&gt;
&lt;p&gt;测试环境关联了很多东西，比如物料、自动化、精准、流水线等，都可以围绕测试环境来做文章。测试环境既是团队重点，也是是我个人的大案例，目前已经解决了部分困难，要想做出一鸣惊人的成绩，还需要站在更高的角度去看待整个事情，这也是一个全新的挑战，需要不断刷新自己，突破。&lt;/p&gt;</description>
    </item>
    <item>
      <title>端到端自动化的开源框架</title>
      <link>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E8%87%AA%E5%8A%A8%E5%8C%96/000005-playwright%E7%AB%AF%E5%88%B0%E7%AB%AF%E8%87%AA%E5%8A%A8%E5%8C%96%E7%9A%84%E5%BC%80%E6%BA%90%E6%A1%86%E6%9E%B6/</link>
      <pubDate>Mon, 05 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E8%87%AA%E5%8A%A8%E5%8C%96/000005-playwright%E7%AB%AF%E5%88%B0%E7%AB%AF%E8%87%AA%E5%8A%A8%E5%8C%96%E7%9A%84%E5%BC%80%E6%BA%90%E6%A1%86%E6%9E%B6/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;本书作者：测试开发刚哥，文章版权归个人所有，未经授权请勿转载。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;什么是playwright&#34;&gt;什么是Playwright？&lt;/h1&gt;
&lt;p&gt;Playwright是一个开源框架，用于对Web应用进行端到端测试。&lt;/p&gt;
&lt;h1 id=&#34;什么是端到端测试&#34;&gt;什么是端到端测试？&lt;/h1&gt;
&lt;p&gt;这里的“端”，不是指A模块或B模块，而是可以理解为从前端到后端。举个例子，对于登录功能来说，如果只测前端，那么测试范围就是前端页面，可能会对后端接口进行mock。如果只测后端，那么测试范围就是后端接口等。而端到端呢，就是前端输入用户名密码，点击登录，与后端交互，查询数据库，鉴权，后端返回登录成功，前端进行页面跳转。端到端测试，可以理解为全流程测试，也可以理解为模拟用户场景测试。&lt;/p&gt;
&lt;h1 id=&#34;playwright框架特点&#34;&gt;Playwright框架特点&lt;/h1&gt;
&lt;p&gt;官方网站首页：&lt;a href=&#34;https://playwright.dev/python/&#34;&gt;https://playwright.dev/python/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;总结下重点，一是跨浏览器、跨平台、跨语言；二是自动等待；三是多用户场景测试；四是只需要一次登录；五是可以录制脚本。&lt;/p&gt;
&lt;h1 id=&#34;快速入门&#34;&gt;快速入门&lt;/h1&gt;
&lt;p&gt;在官网的顶部菜单可以切换不同编程语言的教程：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/24bbbd01c6594bc08a753059ab61356f.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;本文及后续文章均选择Python。&lt;/p&gt;
&lt;h2 id=&#34;安装&#34;&gt;安装&lt;/h2&gt;
&lt;p&gt;安装Python的Playwright，这里结合了pytest：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;pip install pytest-playwright
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;成功后安装浏览器：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;playwright install
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这里也可以不安装浏览器，而是在脚本里面指定现有浏览器路径。&lt;/p&gt;
&lt;h2 id=&#34;示例&#34;&gt;示例&lt;/h2&gt;
&lt;p&gt;test_example.py&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;import re
from playwright.sync_api import Page, expect

def test_has_title(page: Page):
    page.goto(&amp;#34;https://playwright.dev/&amp;#34;)

    # Expect a title &amp;#34;to contain&amp;#34; a substring.
    expect(page).to_have_title(re.compile(&amp;#34;Playwright&amp;#34;))

def test_get_started_link(page: Page):
    page.goto(&amp;#34;https://playwright.dev/&amp;#34;)

    # Click the get started link.
    page.get_by_role(&amp;#34;link&amp;#34;, name=&amp;#34;Get started&amp;#34;).click()

    # Expects page to have a heading with the name of Installation.
    expect(page.get_by_role(&amp;#34;heading&amp;#34;, name=&amp;#34;Installation&amp;#34;)).to_be_visible()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;执行pytest后默认会选择chrome在headless模式下运行，可以通过日志观察运行过程。&lt;/p&gt;
&lt;p&gt;更新命令：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;pip install pytest-playwright playwright -U
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;编写测试&#34;&gt;编写测试&lt;/h2&gt;
&lt;p&gt;访问url：&lt;/p&gt;</description>
    </item>
    <item>
      <title>send_keys报错element_not_interactable</title>
      <link>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E8%87%AA%E5%8A%A8%E5%8C%96/000004-ui%E8%87%AA%E5%8A%A8%E5%8C%96send_keys%E6%8A%A5%E9%94%99element_not_interactable/</link>
      <pubDate>Sun, 04 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E8%87%AA%E5%8A%A8%E5%8C%96/000004-ui%E8%87%AA%E5%8A%A8%E5%8C%96send_keys%E6%8A%A5%E9%94%99element_not_interactable/</guid>
      <description>这两天要在阿里云日志中操作UI，以输入关键字搜索日志。</description>
    </item>
    <item>
      <title>webdriver使用已打开过的chrome</title>
      <link>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E8%87%AA%E5%8A%A8%E5%8C%96/000003-ui%E8%87%AA%E5%8A%A8%E5%8C%96webdriver%E4%BD%BF%E7%94%A8%E5%B7%B2%E6%89%93%E5%BC%80%E8%BF%87%E7%9A%84chrome/</link>
      <pubDate>Sat, 03 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E8%87%AA%E5%8A%A8%E5%8C%96/000003-ui%E8%87%AA%E5%8A%A8%E5%8C%96webdriver%E4%BD%BF%E7%94%A8%E5%B7%B2%E6%89%93%E5%BC%80%E8%BF%87%E7%9A%84chrome/</guid>
      <description>基本功能：</description>
    </item>
    <item>
      <title>理想中的接口自动化项目</title>
      <link>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E8%87%AA%E5%8A%A8%E5%8C%96/000002-%E7%90%86%E6%83%B3%E4%B8%AD%E7%9A%84%E6%8E%A5%E5%8F%A3%E8%87%AA%E5%8A%A8%E5%8C%96%E9%A1%B9%E7%9B%AE/</link>
      <pubDate>Fri, 02 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E8%87%AA%E5%8A%A8%E5%8C%96/000002-%E7%90%86%E6%83%B3%E4%B8%AD%E7%9A%84%E6%8E%A5%E5%8F%A3%E8%87%AA%E5%8A%A8%E5%8C%96%E9%A1%B9%E7%9B%AE/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;本书作者：测试开发刚哥，文章版权归个人所有，未经授权请勿转载。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;如何评价接口自动化项目&#34;&gt;如何评价接口自动化项目&lt;/h1&gt;
&lt;p&gt;我理想中的接口自动化项目，是有一套脚本，能够100%覆盖核心业务场景，能够回归线上频繁出现的问题，能够支持手工无法验证的场景，能够抛出偶现问题，能够包含容易遗漏的边界场景、异常场景，每天都能定时运行，出具报告，给予反馈。&lt;/p&gt;
&lt;p&gt;用实际的&lt;strong&gt;指标量化&lt;/strong&gt;下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;功能测试自动化率 = 自动化测试用例数/总测试用例数&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;自动化发现bug占比 = 自动化发现的bug/总bug数&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;自动化发现bug有效性 = 自动化发现的有效bug/自动化提交的bug总数&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;自动化执行成功率 = 自动化执行成功的次数/自动化执行总次数&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;周活跃自动化用例占比 = (∑每周执行过的自动化测试用例)/(∑周维度自动化测试用例)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;应用维度自动化代码覆盖率 = 自动化用例覆盖代码行数/应用维度代码总行数&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;现状是什么situation&#34;&gt;现状是什么(Situation)&lt;/h1&gt;
&lt;p&gt;我负责的业务是发票中台，数据流简化后如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/b337c73fa45a4a5b80cc91b13305c987.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;发票中台对调用方提供RPC服务，底层有读写MySQL、同步ES、消息队列、异步任务等服务，上游是用户和订单，需要账号、增票资质、订单等物料；下游是财务，推送申请单给财务开具发票等。&lt;/p&gt;
&lt;p&gt;发票的接口自动化在多年前是写了的，用Java+TestNG+RPC本地化了一套框架来实现，因为人员离职和业务变更，这套自动化到我手上的时候，已经不能用了，本地化的接口自动化项目也无法做数据度量，只有接口测试平台写的自动化用例才会被统计到。&lt;/p&gt;
&lt;h1 id=&#34;任务是什么task&#34;&gt;任务是什么(Task)&lt;/h1&gt;
&lt;p&gt;我给自己定的绩效是在Q2完成95条自动化用例，按照一个标准化的自动化项目来实现发票的接口自动化，结合测试环境、测试物料、流水线、精准分析，打造一个个人的稳定的沉淀物，无论是晋升还是求职，都能拿来讲点故事。&lt;/p&gt;
&lt;h1 id=&#34;行动是什么action&#34;&gt;行动是什么(Action)&lt;/h1&gt;
&lt;h2 id=&#34;编写自动化用例的方式&#34;&gt;&lt;strong&gt;编写自动化用例的方式&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;1、最理想的方式，是能够录制线上流量直接转换为自动化用例，修修改改即可。虽然我们有流量录制回放平台，但是它跟接口自动化平台并没有打通，很可惜不能采取这种方式。&lt;/p&gt;
&lt;p&gt;2、参考线上流量日志，抓取接口、入参，人工转化为自动化用例。&lt;/p&gt;
&lt;p&gt;3、参考接口的代码设计，比如controller/provider/sdk都定义了应用接口，能知道哪些覆盖到了，哪些还需要补充。&lt;/p&gt;
&lt;p&gt;4、根据入参模板自行构造参数。参数个数太多的话造起来很麻烦。&lt;/p&gt;
&lt;p&gt;我主要采用第2种和第3种方式结合来编写自动化用例。&lt;/p&gt;
&lt;h2 id=&#34;典型自动化用例&#34;&gt;&lt;strong&gt;典型自动化用例&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/5f98cecbf9624b92b0947b266bf882e3.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;前置步骤：初始化数据，将订单发票类型更新为3。&lt;/p&gt;
&lt;p&gt;预设变量：提供参数化数据。&lt;/p&gt;
&lt;p&gt;执行步骤：调用修改订单发票类型接口，将发票类型3改为2，入参引用预设变量。&lt;/p&gt;
&lt;p&gt;财务接口：依赖测试物料无法满足，通过Mock来返回模板数据，让接口继续往下走。&lt;/p&gt;
&lt;p&gt;基础断言：接口响应状态码200。&lt;/p&gt;
&lt;p&gt;业务断言：调用订单列表查询接口，用JSONPath提取响应中的发票类型，断言已经改成了2。&lt;/p&gt;
&lt;h2 id=&#34;场景用例&#34;&gt;场景用例&lt;/h2&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/97835629bcf84376b1b076ecc2efe71f.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;数据准备：通过物料工具造订单数据，写入MySQL数据库中。&lt;/p&gt;
&lt;p&gt;更新MySQL数据：更新订单的部分字段数据，触发binlake，将数据同步至ES，因为提交开票申请是读取的ES数据；从预设变量获取orderId。&lt;/p&gt;
&lt;p&gt;提交开票申请：从ES读取订单数据，提交开票申请；从预设变量获取orderId和userId。&lt;/p&gt;
&lt;p&gt;查询申请单号：根据订单号查询申请单号；从预设变量获取orderId和userId。用JSONPath提取申请单号，存入动态变量中。&lt;/p&gt;
&lt;p&gt;推送财务：把申请单号推送给财务；从动态变量获取applyId。&lt;/p&gt;
&lt;h2 id=&#34;覆盖更多代码&#34;&gt;覆盖更多代码&lt;/h2&gt;
&lt;p&gt;①看代码：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/9044fdece03b49cabe47430cce991cc4.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;在Java工程里面的Controller/Provider找到所有接口，分析可以用来做自动化的接口，设计自动化用例进行覆盖。&lt;/p&gt;
&lt;p&gt;②代码覆盖率：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/7e8be8a6cb654d5cb6b90ba93382873f.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;借助于jacoco，在执行自动化用例后，把代码覆盖率跑出来，分析没覆盖的代码，补充更多&lt;strong&gt;正常/异常/边界&lt;/strong&gt;的自动化用例。也就是精准测试。&lt;/p&gt;
&lt;h2 id=&#34;自动化巡检&#34;&gt;自动化巡检&lt;/h2&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/bb44fe887eb3478685555b893a1b483c.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;每天早上8点，定时任务执行用例集；发送邮件，抄送测试组、开发组、领导，让测试、开发和领导都知道自动化建设情况；如果出现问题，一定要在当天解决，并邮件回复问题原因；确保当天的自动化用例结果都是正确的；第二天接着继续巡检。&lt;/p&gt;
&lt;h2 id=&#34;流水线&#34;&gt;流水线&lt;/h2&gt;
&lt;p&gt;在持续集成中，引入自动化用例环节，把自动化用例跑通作为提测卡点，不通过可以驳回。&lt;/p&gt;
&lt;h1 id=&#34;产出是什么result&#34;&gt;产出是什么(Result)&lt;/h1&gt;
&lt;p&gt;定性来看：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;结合测试环境、测试物料、自动化、流水线、精准测试，完成了一个能对环境和业务进行稳定性巡检，能对研发提测进行质量门禁，能对应用进行代码覆盖率分析的接口自动化项目。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;定量来看：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;功能测试自动化率 = 自动化测试用例数/总测试用例数 &lt;strong&gt;95/100=95%&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;自动化发现bug占比 = 自动化发现的bug/总bug数 &lt;strong&gt;2/53=3.7%&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;自动化发现bug有效性 = 自动化发现的有效bug/自动化提交的bug总数 &lt;strong&gt;2/2=100%&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;自动化执行成功率 = 自动化执行成功的次数/自动化执行总次数 &lt;strong&gt;5396/5621=96%&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;周活跃自动化用例占比 = (∑每周执行过的自动化测试用例)/(∑周维度自动化测试用例) &lt;strong&gt;77%&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;应用维度自动化代码覆盖率 = 自动化用例覆盖代码行数/应用维度代码总行数 &lt;strong&gt;39%&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这个Q主要完成了核心流程和重要接口的自动化用例，还需要持续补充场景用例和异常/边界的自动化用例。&lt;/p&gt;</description>
    </item>
    <item>
      <title>中台RPC接口自动化怎么做</title>
      <link>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E8%87%AA%E5%8A%A8%E5%8C%96/000001-%E4%B8%AD%E5%8F%B0rpc%E6%8E%A5%E5%8F%A3%E8%87%AA%E5%8A%A8%E5%8C%96%E6%80%8E%E4%B9%88%E5%81%9A/</link>
      <pubDate>Thu, 01 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E6%B5%8B%E8%AF%95%E4%B8%93%E9%A2%98/%E8%87%AA%E5%8A%A8%E5%8C%96/000001-%E4%B8%AD%E5%8F%B0rpc%E6%8E%A5%E5%8F%A3%E8%87%AA%E5%8A%A8%E5%8C%96%E6%80%8E%E4%B9%88%E5%81%9A/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;本书作者：测试开发刚哥，文章版权归个人所有，未经授权请勿转载。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;rpc接口&#34;&gt;RPC接口&lt;/h1&gt;
&lt;p&gt;我所在的部门是技术中台，主要负责toB业务，上游是业务条线，包括PC、APP、小程序等终端，这些端的后台是HTTP接口层，而在HTTP接口层之下，就是技术中台的RPC接口层。&lt;/p&gt;
&lt;p&gt;HTTP是一种超文本传输协议，基于TCP/IP来传输文本、图片、音频、视频等数据。数据包的传输能力不是HTTP提供的，而是TCP/IP干的。&lt;strong&gt;HTTP的本质是客户端和服务端约定好的一种通信格式，是一种全世界认可的通用范本。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;RPC是一种远程调用，也就是进程间通信，既可以用HTTP协议，也可以用自定义协议。&lt;strong&gt;RPC的好处是没有HTTP那么多约束，简化了写法，可以根据公司自定义规范，内部统一即可。&lt;/strong&gt; 所以在公司内部特别流行，比如阿里的Dubbo接口就是一种RPC接口，我们公司用的JSF接口，自研的服务框架，简称杰夫。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;谈谈京东的服务框架 &lt;a href=&#34;https://juejin.cn/post/6948351920088186888&#34;&gt;https://juejin.cn/post/6948351920088186888&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;举个例子，本地调用，是调用的本地方法：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;public&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;User&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#6639ba&#34;&gt;getUserById&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;Long&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;id&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;       &lt;/span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;return&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;userDao&lt;span style=&#34;color:#1f2328&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;getUserById&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;id&lt;span style=&#34;color:#1f2328&#34;&gt;);&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#57606a&#34;&gt;// 这叫本地调用&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;而RPC远程调用，调用的是另外一个服务的方法：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f7f7f7;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;public&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;User&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#6639ba&#34;&gt;getUserById&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;Long&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;id&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;       &lt;/span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;return&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;userConsumer&lt;span style=&#34;color:#1f2328&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;getUserById&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;id&lt;span style=&#34;color:#1f2328&#34;&gt;);&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#57606a&#34;&gt;// 这是远程调用，逻辑是用户小组的服务实现的。&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#fff&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#fff&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;本地调用和远程调用的比较如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/e0c812e4fc6b43eda732c1edfba24398.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;左边的本地调用，只在应用内部调用。右边的远程调用，会跨应用在应用之间调用。&lt;/p&gt;
&lt;h1 id=&#34;rpc和http用法区别&#34;&gt;RPC和HTTP用法区别&lt;/h1&gt;
&lt;p&gt;HTTP接口在调用时，输入URL，Method，Headers，Body等等等就可以发送请求了。&lt;/p&gt;
&lt;p&gt;RPC接口的调用大同小异，输入：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;JSF地址&lt;/strong&gt;：方法引用路径，比如&lt;code&gt;com.dongfanger.api.service.ShopProvider&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;方法名&lt;/strong&gt;：方法名称，比如&lt;code&gt;queryShopList&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;别名&lt;/strong&gt;：既可以是分组别名，也可以直连IP地址。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;方法入参&lt;/strong&gt;：JSON串。&lt;/p&gt;
&lt;p&gt;等等等，就可以发起请求了。&lt;/p&gt;
&lt;p&gt;从用法能看出来，&lt;strong&gt;RPC和HTTP接口的结构体是差不多的，但是RPC不需要Method和Headers&lt;/strong&gt;，精简了许多。&lt;/p&gt;
&lt;h1 id=&#34;接口自动化&#34;&gt;接口自动化&lt;/h1&gt;
&lt;p&gt;首先需要考虑的是&lt;strong&gt;目录结构设计&lt;/strong&gt;，HTTP可以模块菜单创建用例目录，比如：&lt;/p&gt;
&lt;p&gt;一级目录：管理端&lt;/p&gt;
&lt;p&gt;二级目录：发票管理&lt;/p&gt;
&lt;p&gt;三级目录：发票查询&lt;/p&gt;
&lt;p&gt;而RPC是无页面的，一般存在很多业务线，所以可以按照功能域和业务线来组织目录，比如：&lt;/p&gt;
&lt;p&gt;一级目录：发票&lt;/p&gt;
&lt;p&gt;二级目录：提交申请&lt;/p&gt;
&lt;p&gt;三级目录：分销&lt;/p&gt;
&lt;p&gt;其次就得考虑&lt;strong&gt;技术实现&lt;/strong&gt;了，公司基建比较完善，无论是HTTP还是JSF接口，都能在接口测试平台上编写自动化用例。虽然是Web平台写用例，但是得益于测试平台的优秀设计和使用体验，用起来很方便，效率也很高。交互方式跟JMeter大同小异，只是在细节上做了很多打磨。&lt;/p&gt;
&lt;p&gt;然后就是&lt;strong&gt;参数构造&lt;/strong&gt;了，建议是用流量回放的方式来做，省去手工编写参数的崩溃感。流量用例创建好以后，需要做一些参数化处理和接口关联。这样才能够把多个接口串起来。&lt;/p&gt;
&lt;p&gt;对于&lt;strong&gt;测试数据&lt;/strong&gt;，通过预设变量来统一管理，自动化用例也尽可能设计成闭环，增加，修改，查询，删除，用例跑完后产生的数据也跟着清理掉。&lt;/p&gt;
&lt;p&gt;最后就是&lt;strong&gt;断言了&lt;/strong&gt;。没有断言的自动化用例，不叫做自动化用例。断言一定要加上，否则定时任务跑出结果后，无法判断到底有没有问题。而断言内容不能只是简单的code200，需要加上业务校验。&lt;/p&gt;
&lt;p&gt;中台RPC接口自动化最难处理的是接口依赖问题，链路特别长，依赖特别多。我一般通过Mock来解决这个问题，公司的测试平台也提供了这个功能。&lt;/p&gt;
&lt;p&gt;需要注意的是，核心用例定时运行监控起来，而一次性用例要及时维护或清理，防止变成僵尸用例。&lt;/p&gt;
&lt;p&gt;最后，我准备基于Vue+FastAPI开发一套新的pytest脚本管理平台，集成流量录制创建用例和Mock等功能，并借鉴公司测试平台的设计，感兴趣的同学可以添加微信&lt;strong&gt;cekaigang&lt;/strong&gt;加群讨论哟。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;参考资料：&lt;/p&gt;
&lt;p&gt;HTTP 的本质？HTTP 和 RPC 的区别？ &lt;a href=&#34;https://www.jianshu.com/p/fe5ccfc5d7bd&#34;&gt;https://www.jianshu.com/p/fe5ccfc5d7bd&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;谈谈京东的服务框架 &lt;a href=&#34;https://juejin.cn/post/6948351920088186888&#34;&gt;https://juejin.cn/post/6948351920088186888&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;</description>
    </item>
  </channel>
</rss>
