<?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/categories/%E9%A1%B9%E7%9B%AE/</link>
    <description>Recent content in 项目 on 测试开发刚哥</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <lastBuildDate>Mon, 19 Jan 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://dongfanger.github.io/categories/%E9%A1%B9%E7%9B%AE/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Python 处理接口数据，这个函数太香了</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/python%E5%A4%84%E7%90%86%E6%8E%A5%E5%8F%A3%E6%95%B0%E6%8D%AE%E8%BF%99%E4%B8%AA%E5%87%BD%E6%95%B0%E5%A4%AA%E9%A6%99%E4%BA%86/</link>
      <pubDate>Mon, 19 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/python%E5%A4%84%E7%90%86%E6%8E%A5%E5%8F%A3%E6%95%B0%E6%8D%AE%E8%BF%99%E4%B8%AA%E5%87%BD%E6%95%B0%E5%A4%AA%E9%A6%99%E4%BA%86/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;本书作者：测试开发刚哥，文章版权归个人所有，未经授权请勿转载。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;python-处理接口数据&#34;&gt;Python 处理接口数据&lt;/h1&gt;
&lt;p&gt;接口数据通常是 JSON 格式，Python 处理起来并不轻松。&lt;/p&gt;
&lt;p&gt;方法一，json 文件。额外编写代码读取文件，接口参数很多，文件变多，难维护。&lt;/p&gt;
&lt;p&gt;方法二，字典。JSON 可以直接粘贴到代码中，Python 认作字典，但语法有差异，JSON 的语法是 true/false/null，Python 的语法是 True/False/None，不兼容。&lt;/p&gt;
&lt;p&gt;这两种方法都有共同的缺点，需要编写表达式来定位某个节点。&lt;/p&gt;
&lt;p&gt;比如：&lt;code&gt;body[&amp;quot;a&amp;quot;][0][&amp;quot;x&amp;quot;][&amp;quot;m&amp;quot;]&lt;/code&gt;&lt;/p&gt;
&lt;h1 id=&#34;字符串与占位符&#34;&gt;字符串与占位符&lt;/h1&gt;
&lt;p&gt;占位符是一种很常见的文本替换技术，在任何编程语言中都有广泛应用。&lt;/p&gt;
&lt;p&gt;Python 语法有个很特别的字符串，三引号字符串：&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-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;test_json &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&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:#0a3069&#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:#0a3069&#34;&gt; &amp;#34;bool&amp;#34;: true,
&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:#0a3069&#34;&gt;  &amp;#34;x&amp;#34;: null,
&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:#0a3069&#34;&gt;  &amp;#34;customerId&amp;#34;: &amp;#34;123456&amp;#34;,
&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:#0a3069&#34;&gt;  &amp;#34;items&amp;#34;: [
&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:#0a3069&#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:#0a3069&#34;&gt;      &amp;#34;productId&amp;#34;: &amp;#34;987654&amp;#34;,
&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:#0a3069&#34;&gt;      &amp;#34;quantity&amp;#34;: 2,
&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:#0a3069&#34;&gt;      &amp;#34;price&amp;#34;: 199.99
&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:#0a3069&#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:#0a3069&#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:#0a3069&#34;&gt;  &amp;#34;shippingAddress&amp;#34;: {
&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:#0a3069&#34;&gt;    &amp;#34;recipientName&amp;#34;: &amp;#34;张三&amp;#34;,
&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:#0a3069&#34;&gt;    &amp;#34;streetAddress&amp;#34;: &amp;#34;北京市朝阳区某街道123号&amp;#34;,
&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:#0a3069&#34;&gt;    &amp;#34;city&amp;#34;: &amp;#34;北京&amp;#34;,
&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:#0a3069&#34;&gt;    &amp;#34;state&amp;#34;: &amp;#34;北京&amp;#34;,
&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:#0a3069&#34;&gt;    &amp;#34;postalCode&amp;#34;: &amp;#34;100000&amp;#34;,
&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:#0a3069&#34;&gt;    &amp;#34;country&amp;#34;: &amp;#34;中国&amp;#34;
&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:#0a3069&#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:#0a3069&#34;&gt;  &amp;#34;paymentMethod&amp;#34;: {
&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:#0a3069&#34;&gt;    &amp;#34;type&amp;#34;: &amp;#34;CreditCard&amp;#34;,
&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:#0a3069&#34;&gt;    &amp;#34;cardNumber&amp;#34;: &amp;#34;4111111111111111&amp;#34;,
&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:#0a3069&#34;&gt;    &amp;#34;expiryDate&amp;#34;: &amp;#34;12/25&amp;#34;,
&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:#0a3069&#34;&gt;    &amp;#34;cvv&amp;#34;: &amp;#34;123&amp;#34;
&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:#0a3069&#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:#0a3069&#34;&gt;  &amp;#34;orderNotes&amp;#34;: &amp;#34;请尽快发货，谢谢！&amp;#34;
&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:#0a3069&#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:#0a3069&#34;&gt;&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;基本思路是，把 JSON 写在三引号字符串中，这能保留原生 JSON 格式，就像很多测试平台的做法一样，然后再通过占位符，直接替换其中的节点值。占位符不用编写表达式定位节点，在 JSON 字符串标记即可。&lt;/p&gt;</description>
    </item>
    <item>
      <title>年度大版本，tep3 回归纯粹 Python 接口测试框架</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E5%B9%B4%E5%BA%A6%E5%A4%A7%E7%89%88%E6%9C%ACtep3%E5%9B%9E%E5%BD%92%E7%BA%AF%E7%B2%B9python%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95%E6%A1%86%E6%9E%B6/</link>
      <pubDate>Sun, 18 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E5%B9%B4%E5%BA%A6%E5%A4%A7%E7%89%88%E6%9C%ACtep3%E5%9B%9E%E5%BD%92%E7%BA%AF%E7%B2%B9python%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95%E6%A1%86%E6%9E%B6/</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;tep 是基于 pytest 开发的接口测试框架，上个版本从小工具升级为了关键字驱动框架，通过 pystats 发现最近半年仍然有 4000+人次在安装使用 tep。时隔 1 年后，我对 tep 进行了一次大版本改造，抛弃 tep2 的 Java 代码风格，重新回归到 tep1 的纯粹 Python 风格。&lt;/p&gt;
&lt;h1 id=&#34;纯粹-python&#34;&gt;纯粹 Python&lt;/h1&gt;
&lt;p&gt;所谓纯粹 Python，体现在两个方面，一个方面是 tep 源码进行了重写，更加 Pythonic，自动化用例写起来也更加简单易懂；另一方面是抛弃了依赖 Java 的 Allure 和依赖 C++的 loguru，分别使用 Python 技术栈的 pytest-html 和 logging 替代。&lt;/p&gt;
&lt;h1 id=&#34;tep3-版本&#34;&gt;tep3 版本&lt;/h1&gt;
&lt;h2 id=&#34;简介&#34;&gt;简介&lt;/h2&gt;
&lt;p&gt;tep 是 Try Easy Pytest 的首字母缩写，帮你轻松上手 pytest。&lt;/p&gt;
&lt;p&gt;框架特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基于 pytest 封装，成熟、稳定且扩展性强。&lt;/li&gt;
&lt;li&gt;框架完全由 Python 构建，没有混杂其他语言。&lt;/li&gt;
&lt;li&gt;原生 Python 语法，学习 Python，零成本使用框架。&lt;/li&gt;
&lt;li&gt;HAR 包转换 pytest 用例。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;安装&#34;&gt;安装&lt;/h2&gt;
&lt;p&gt;支持 Python3.8 以上版本&lt;/p&gt;</description>
    </item>
    <item>
      <title>tep1.0.0 教程</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/tep1.0.0%E6%95%99%E7%A8%8B/</link>
      <pubDate>Sat, 17 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/tep1.0.0%E6%95%99%E7%A8%8B/</guid>
      <description>正式版教程： &lt;a href=&#34;https://dongfanger.gitee.io/blog/tep.html&#34;&gt;https://dongfanger.gitee.io/blog/tep.html&lt;/a&gt;</description>
    </item>
    <item>
      <title>当 Pytest 遇上 MVC 分层设计自动化用例就该这么写</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E5%BD%93pytest%E9%81%87%E4%B8%8Amvc%E5%88%86%E5%B1%82%E8%AE%BE%E8%AE%A1%E8%87%AA%E5%8A%A8%E5%8C%96%E7%94%A8%E4%BE%8B%E5%B0%B1%E8%AF%A5%E8%BF%99%E4%B9%88%E5%86%99/</link>
      <pubDate>Fri, 16 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E5%BD%93pytest%E9%81%87%E4%B8%8Amvc%E5%88%86%E5%B1%82%E8%AE%BE%E8%AE%A1%E8%87%AA%E5%8A%A8%E5%8C%96%E7%94%A8%E4%BE%8B%E5%B0%B1%E8%AF%A5%E8%BF%99%E4%B9%88%E5%86%99/</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;数据写在代码里，追求快速编写用例，是我设计 tep 的一个特点，这在个人编写时是一种非常良好的体验。但相比于 HttpRunner、JMeter 等来说，总觉得还差点意思。思考良久，总结为三个字：&lt;strong&gt;工程化&lt;/strong&gt;。工程化是我近一年在学习 Java 并参与了 2 个测试平台模块开发，和写了几个小工具后，感受到的一种编程思想。而其中最明显的就是 Spring 的 MVC 分层设计。为了让 tep 更工程化，后续版本将以 MVC 模块编写用例为准，同时会兼容之前的脚本式快速编写。&lt;/p&gt;
&lt;h1 id=&#34;示例&#34;&gt;示例&lt;/h1&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/5487a3073adf417c82931654f233f508.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;test_case：用例主程序；&lt;/p&gt;
&lt;p&gt;steps：测试步骤；&lt;/p&gt;
&lt;p&gt;data：纯粹的 json；&lt;/p&gt;
&lt;h2 id=&#34;测试用例&#34;&gt;测试用例&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;test_case.py&lt;/code&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-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#24292e&#34;&gt;allure&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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:#cf222e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#24292e&#34;&gt;examples.tests.LoginToPayFlow.steps.step_add_cart&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;import&lt;/span&gt; step_add_cart
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#24292e&#34;&gt;examples.tests.LoginToPayFlow.steps.step_order&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;import&lt;/span&gt; step_order
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#24292e&#34;&gt;examples.tests.LoginToPayFlow.steps.step_pay&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;import&lt;/span&gt; step_pay
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#24292e&#34;&gt;examples.tests.LoginToPayFlow.steps.step_search_sku&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;import&lt;/span&gt; step_search_sku
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#24292e&#34;&gt;utils.cache&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;import&lt;/span&gt; TepCache
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#24292e&#34;&gt;utils.step&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;import&lt;/span&gt; Step
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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:#0a3069&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&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:#0a3069&#34;&gt;测试登录到下单流程，需要先运行utils/fastapi_mock.py
&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:#0a3069&#34;&gt;&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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:#0550ae&#34;&gt;@allure.title&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;从登录到下单支付&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#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:#cf222e&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#6639ba&#34;&gt;test&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;login&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; env_vars&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; case_vars&lt;span style=&#34;color:#1f2328&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    case_vars&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;put&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;token&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; login&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;token&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    cache &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; TepCache&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;env_vars&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;env_vars&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; case_vars&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;case_vars&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Step&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;搜索商品&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; step_search_sku&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; cache&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Step&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;添加购物车&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; step_add_cart&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; cache&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Step&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;下单&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; step_order&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; cache&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Step&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;支付&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; step_pay&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; cache&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;TepCache 是“缓存”，包括 global_vars、env_vars、case_vars 三个级别的变量池。&lt;/p&gt;</description>
    </item>
    <item>
      <title>tep 支持 pytest-xdist 分布式执行用例及合并 Allure 报告</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/tep%E6%94%AF%E6%8C%81pytest-xdist%E5%88%86%E5%B8%83%E5%BC%8F%E6%89%A7%E8%A1%8C%E7%94%A8%E4%BE%8B%E5%8F%8A%E5%90%88%E5%B9%B6allure%E6%8A%A5%E5%91%8A/</link>
      <pubDate>Thu, 15 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/tep%E6%94%AF%E6%8C%81pytest-xdist%E5%88%86%E5%B8%83%E5%BC%8F%E6%89%A7%E8%A1%8C%E7%94%A8%E4%BE%8B%E5%8F%8A%E5%90%88%E5%B9%B6allure%E6%8A%A5%E5%91%8A/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;本书作者：测试开发刚哥，文章版权归个人所有，未经授权请勿转载。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;tep 近期更新频率较快，一方面是作者在积极投入到 tep 工具开发中；另一方面是我们聚集了 20 位小伙伴，一起合力打造&lt;strong&gt;EasyPytest 测试平台&lt;/strong&gt;，teprunner 的 FastAPI 升级版本，依托于 tep，&lt;strong&gt;帮你高效管理 pytest 测试用例&lt;/strong&gt;。陆续也会有平台开发日志发布，欢迎持续关注。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;tep0.11.1 版本升级内容：&lt;/p&gt;
&lt;p&gt;1、pytest-xdist 分布式执行用例，合并 Allure 报告；&lt;/p&gt;
&lt;p&gt;2、global_vars 全局变量配置；&lt;/p&gt;
&lt;h1 id=&#34;分布式执行用例&#34;&gt;分布式执行用例&lt;/h1&gt;
&lt;p&gt;借助于 pytest-xdist，在命令行执行时添加参数&lt;code&gt;-n auto&lt;/code&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-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pytest &lt;span style=&#34;color:#0550ae&#34;&gt;-&lt;/span&gt;n auto
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;pytest-xdist 会自动根据本地机器硬件配置，设置最优并发，并分发用例，分布式执行。&lt;/p&gt;
&lt;p&gt;测试时先运行 main.py，然后在 case100 目录下执行&lt;code&gt;pytest -n auto --tep-reports&lt;/code&gt;：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/1076643eec9e418685bdef10b49e53a5.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;第一次串行，第二次 xdist 并行：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/55a2c725e31e47ac8b2abebd886a3abe.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;执行时间从 50s 一下降到 5s，性能提升还是非常的明显。&lt;/p&gt;
&lt;h1 id=&#34;合并-allure-报告&#34;&gt;合并 Allure 报告&lt;/h1&gt;
&lt;p&gt;pytest-xdist 分布式执行，只要把 allure 源文件，也就是那一堆 json 文件，存到同一个目录下，报告的数据就是一体的，不需要单独合并。但是有个问题，tep 封装了&lt;code&gt;--tep-reports&lt;/code&gt; 命令行参数一键生成 Allure 报告，背后的逻辑是在 pytest_sessionfinish hook 函数里面实现的，分布式执行时，每个 xdist 的 node 都是一个单独的 session，多个 node 就会生成多份报告：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/8c44989d22914ca68894d80d1aa07d4c.png&#34;&gt;c&lt;/p&gt;</description>
    </item>
    <item>
      <title>tep 时隔 8 个月迎来重大全新升级</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/tep%E6%97%B6%E9%9A%948%E4%B8%AA%E6%9C%88%E8%BF%8E%E6%9D%A5%E9%87%8D%E5%A4%A7%E5%85%A8%E6%96%B0%E5%8D%87%E7%BA%A7/</link>
      <pubDate>Wed, 14 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/tep%E6%97%B6%E9%9A%948%E4%B8%AA%E6%9C%88%E8%BF%8E%E6%9D%A5%E9%87%8D%E5%A4%A7%E5%85%A8%E6%96%B0%E5%8D%87%E7%BA%A7/</guid>
      <description>&lt;strong&gt;tep 此次更新，旨在从“工具”升级为“框架”，为此做了大量的代码整洁工作，重新设计了部分功能，项目脚手架也焕然一新。&lt;/strong&gt;</description>
    </item>
    <item>
      <title>接口自动化项目落地之 HTTPBin 网站</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E6%8E%A5%E5%8F%A3%E8%87%AA%E5%8A%A8%E5%8C%96%E9%A1%B9%E7%9B%AE%E8%90%BD%E5%9C%B0%E4%B9%8Bhttpbin%E7%BD%91%E7%AB%99/</link>
      <pubDate>Tue, 13 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E6%8E%A5%E5%8F%A3%E8%87%AA%E5%8A%A8%E5%8C%96%E9%A1%B9%E7%9B%AE%E8%90%BD%E5%9C%B0%E4%B9%8Bhttpbin%E7%BD%91%E7%AB%99/</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;找个开源网站或开源项目，用&lt;strong&gt;tep&lt;/strong&gt;实现整套&lt;strong&gt;pytest&lt;/strong&gt;接口自动化项目落地，归档到电子书，作为&lt;strong&gt;tep 完整教程&lt;/strong&gt;的&lt;strong&gt;项目篇&lt;/strong&gt;一部分。自从 tep 完整教程发布以后，tep 被越来越多小伙伴了解。教程只是纯理论，是骡子是马，拉出来遛遛才知道。做接口自动化项目落地，一方面是为了让自己脑海中的构想实实在在的呈现出来，现实和理想存在多少差距，不断尝试去弥补和修缮；另一方面也是方便读者朋友们学习使用，借助实际项目来练习，才能在赛道中弯道超车。&lt;/p&gt;
&lt;h1 id=&#34;httpbin-网站&#34;&gt;HTTPBin 网站&lt;/h1&gt;
&lt;p&gt;httpbin.org 是一个简单的在线提供 HTTP 服务的网站：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/216043454b2f43eeb4659ce9ac7b81a8.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/acfb96edb6fe40008c3942d17482d2ee.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;它能够用来对 HTTP 进行在线测试。&lt;/p&gt;
&lt;h1 id=&#34;测试报告&#34;&gt;测试报告&lt;/h1&gt;
&lt;p&gt;HTTPBin 网站的接口自动化项目包含&lt;strong&gt;11 个用例集&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/2b7c958062ed47d89e09e9e40d6abb5c.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;67 条测试用例&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/c63e2d9a06bc4bdd8e7feed8b7ebc349.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;自动化执行正确率 98.5%&lt;/strong&gt;，其中有 1 条错误结果，是我故意为之的，因为想展示下断言失败的效果。&lt;/p&gt;
&lt;h1 id=&#34;环境配置&#34;&gt;环境配置&lt;/h1&gt;
&lt;p&gt;包含 http 和 https 两套环境，因为 HTTPBin 支持 HTTP&amp;amp;HTTPS：&lt;/p&gt;
&lt;p&gt;&lt;em&gt;fixtures/fixture_env_vars.py&lt;/em&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-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57606a&#34;&gt;#!/usr/bin/python&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:#57606a&#34;&gt;## encoding=utf-8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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:#cf222e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#24292e&#34;&gt;tep.fixture&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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:#0550ae&#34;&gt;@pytest.fixture&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;scope&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;session&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#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:#cf222e&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#6639ba&#34;&gt;env_vars&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;config&lt;span style=&#34;color:#1f2328&#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:#cf222e&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;Clazz&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;TepVars&lt;span style=&#34;color:#1f2328&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        env &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; config&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;env&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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:#0a3069&#34;&gt;&amp;#34;&amp;#34;&amp;#34;变量定义开始&amp;#34;&amp;#34;&amp;#34;&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:#57606a&#34;&gt;# 环境变量&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        mapping &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#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:#0a3069&#34;&gt;&amp;#34;http&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;{&lt;/span&gt;  &lt;span style=&#34;color:#57606a&#34;&gt;# http环境&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:#0a3069&#34;&gt;&amp;#34;domain&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;http://httpbin.org&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#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:#1f2328&#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:#0a3069&#34;&gt;&amp;#34;https&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;{&lt;/span&gt;  &lt;span style=&#34;color:#57606a&#34;&gt;# https环境&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:#0a3069&#34;&gt;&amp;#34;domain&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;https://httpbin.org&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#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:#1f2328&#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:#57606a&#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:#1f2328&#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:#57606a&#34;&gt;# 定义类属性，敲代码时会自动补全&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        domain &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; mapping&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;env&lt;span style=&#34;color:#1f2328&#34;&gt;][&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;domain&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#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:#0a3069&#34;&gt;&amp;#34;&amp;#34;&amp;#34;变量定义结束&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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:#cf222e&#34;&gt;return&lt;/span&gt; Clazz&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;配置默认为 http 环境：&lt;/p&gt;</description>
    </item>
    <item>
      <title>民间流转的 pytest 项目结构设计</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E6%B0%91%E9%97%B4%E6%B5%81%E8%BD%AC%E7%9A%84pytest%E9%A1%B9%E7%9B%AE%E7%BB%93%E6%9E%84%E8%AE%BE%E8%AE%A1/</link>
      <pubDate>Mon, 12 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E6%B0%91%E9%97%B4%E6%B5%81%E8%BD%AC%E7%9A%84pytest%E9%A1%B9%E7%9B%AE%E7%BB%93%E6%9E%84%E8%AE%BE%E8%AE%A1/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;本书作者：测试开发刚哥，文章版权归个人所有，未经授权请勿转载。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/d890fa29667248acb99bcd84bb794f0a.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;创建上图的 pytest 项目结构，&lt;strong&gt;只需要一条命令即可&lt;/strong&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-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tep startproject demo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/8ef1c1ae74b04a1295e9a3c91a44aeac.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;前提是安装 tep0.9.8 版本：&lt;/strong&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-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pip install &lt;span style=&#34;color:#953800&#34;&gt;tep&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;==&lt;/span&gt;0.9.8
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;示例代码单独放在了 samples 文件夹下，可以放心将整个目录删除。其中的 db 演示了连接 MySQL 数据库，http 演示了 requests 常见用法和 tep request 的猴子补丁，login_pay 演示了&lt;strong&gt;从登陆到下单该如何编写脚本&lt;/strong&gt;，包括 httprunner、mvc（不推荐）、tep（强烈推荐）三种写法。&lt;/p&gt;
&lt;p&gt;fixtures 从 conftest.py 文件中单独拎了出来。这个设计与 Django 不谋而合，Django 也有个叫做 fixtures 的文件夹，用来存放测试数据。其实 pytest 的 fixture 的本意是可以用来做 setup 和 teardown 的，从这个意义来说，fixtures 就是存放测试数据的，比如封装登录接口为用例提供 token。&lt;/p&gt;
&lt;p&gt;utils 存放了一些工具。比如自带的 fastapi 项目，request 猴子补丁，mitmproxy 抓包自动生成用例。request 猴子补丁可以自定义日志输出格式，在发送请求前后完成任何你想做的操作。&lt;/p&gt;
&lt;p&gt;tep0.9.8 版本正式发布，对项目脚手架进行了精简，是为接下来的**《tep 完整教程帮你突破 pytest》**做好准备。&lt;/p&gt;</description>
    </item>
    <item>
      <title>tep 集成 mitmproxy 录制流量自动生成用例</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/tep%E9%9B%86%E6%88%90mitmproxy%E5%BD%95%E5%88%B6%E6%B5%81%E9%87%8F%E8%87%AA%E5%8A%A8%E7%94%9F%E6%88%90%E7%94%A8%E4%BE%8B/</link>
      <pubDate>Sun, 11 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/tep%E9%9B%86%E6%88%90mitmproxy%E5%BD%95%E5%88%B6%E6%B5%81%E9%87%8F%E8%87%AA%E5%8A%A8%E7%94%9F%E6%88%90%E7%94%A8%E4%BE%8B/</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;操作过程非常简单，流程如下：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/878aab2dbe594c36b9daadf8c46baf8b.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;①&lt;strong&gt;配置过滤域名&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;必须配置，不然会有很多无效流量造成数据冗余。&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/aecdc4689cd145c5b79e049fbc5e18e1.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;②&lt;strong&gt;启动代理&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;「示例」使用了反向代理，tep 自带 FastApi 启动 Mock 服务：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/5477922c30864b6686005cac4c30d1a0.png&#34;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;「&lt;strong&gt;实际&lt;/strong&gt;」使用正向代理，并手动配置代理。命令说明在&lt;code&gt;utils/mitm.py&lt;/code&gt;文件中有：&lt;img loading=&#34;lazy&#34; src=&#34;../assets/4a6bbaf69b9c4321960f445ff9c07b4e.png&#34;&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;③&lt;strong&gt;录制流量&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;「示例」通过 Postman 发起请求：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/e75f4777b1514b22bd450704670603bf.png&#34;&gt;&lt;/p&gt;
&lt;blockquote&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/cf5ebc04eea34b0cbd710dcb35b9d378.png&#34;&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;自动生成用例&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;用例就在&lt;code&gt;tests/mitm&lt;/code&gt;&lt;strong&gt;实时生成&lt;/strong&gt;好了，用例文件名为当前时间：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/423aec3928b24f778066d05885ebd279.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;每录制一个请求，就能在测试用例中看到实时添加了一条测试步骤：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;    # 接口描述
    # 数据
    # 请求
    response = request(
        &amp;#34;{method}&amp;#34;,
        url=&amp;#34;{url}&amp;#34;,
        headers={headers},
        {body_grammar}
    )
    # 数据提取
    # var = response.jmespath(&amp;#34;expression&amp;#34;)
    # 断言
    assert response.status_code &amp;lt; 400
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;录制完成以后，就可以再次编辑测试用例完善它。&lt;/p&gt;
&lt;h1 id=&#34;原理&#34;&gt;原理&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;utils/mitm.py&lt;/code&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-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57606a&#34;&gt;#!/usr/bin/python&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:#57606a&#34;&gt;## encoding=utf-8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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:#57606a&#34;&gt;## mitmproxy录制流量自动生成用例&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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:#cf222e&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#24292e&#34;&gt;os&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:#cf222e&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#24292e&#34;&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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:#cf222e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#24292e&#34;&gt;mitmproxy&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;import&lt;/span&gt; ctx
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;project_dir &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; os&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;path&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;dirname&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;os&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;path&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;dirname&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;os&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;path&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;abspath&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#953800&#34;&gt;__file__&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tests_dir &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; os&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;path&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;join&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;project_dir&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;tests&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#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:#57606a&#34;&gt;## tests/mitm&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mitm_dir &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; os&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;path&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;join&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;tests_dir&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;mitm&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#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:#cf222e&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;not&lt;/span&gt; os&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;path&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;exists&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;mitm_dir&lt;span style=&#34;color:#1f2328&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    os&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;mkdir&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;mitm_dir&lt;span style=&#34;color:#1f2328&#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:#57606a&#34;&gt;## 当前时间作为文件名&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;filename &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; time&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;strftime&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;%Y%m&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;%d&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;_%H_%M_%S&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; time&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;localtime&lt;span style=&#34;color:#1f2328&#34;&gt;())&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;.py&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;case_file &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; os&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;path&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;join&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;mitm_dir&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; filename&lt;span style=&#34;color:#1f2328&#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:#57606a&#34;&gt;## 生成用例文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;template &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;&amp;#34;&amp;#34;from tep.client import request
&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:#0a3069&#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:#0a3069&#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:#0a3069&#34;&gt;def test():
&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:#0a3069&#34;&gt;&amp;#34;&amp;#34;&amp;#34;&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:#cf222e&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;not&lt;/span&gt; os&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;path&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;exists&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;case_file&lt;span style=&#34;color:#1f2328&#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:#cf222e&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#6639ba&#34;&gt;open&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;case_file&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;w&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; encoding&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;utf8&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;as&lt;/span&gt; fw&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        fw&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;write&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;template&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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:#cf222e&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;Record&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#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:#cf222e&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#6639ba&#34;&gt;__init__&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#6a737d&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; domains&lt;span style=&#34;color:#1f2328&#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:#6a737d&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;domains &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; domains
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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:#cf222e&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#6639ba&#34;&gt;response&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#6a737d&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; flow&lt;span style=&#34;color:#1f2328&#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:#cf222e&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#6a737d&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#cf222e&#34;&gt;match&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;flow&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;request&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;url&lt;span style=&#34;color:#1f2328&#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:#57606a&#34;&gt;# method&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            method &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; flow&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;request&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;method&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;lower&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ctx&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;log&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;error&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;method&lt;span style=&#34;color:#1f2328&#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:#57606a&#34;&gt;# url&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            url &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; flow&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;request&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;url
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ctx&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;log&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;error&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;url&lt;span style=&#34;color:#1f2328&#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:#57606a&#34;&gt;# headers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            headers &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#6639ba&#34;&gt;dict&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;flow&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;request&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;headers&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ctx&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;log&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;error&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;headers&lt;span style=&#34;color:#1f2328&#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:#57606a&#34;&gt;# body&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            body &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; flow&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;request&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;text &lt;span style=&#34;color:#0550ae&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ctx&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;log&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;error&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;body&lt;span style=&#34;color:#1f2328&#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:#cf222e&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#6639ba&#34;&gt;open&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;case_file&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; encoding&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;utf8&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;as&lt;/span&gt; fa&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                fa&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;write&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#6a737d&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;step&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;method&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; url&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; headers&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; body&lt;span style=&#34;color:#1f2328&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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:#cf222e&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#6639ba&#34;&gt;match&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#6a737d&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; url&lt;span style=&#34;color:#1f2328&#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:#cf222e&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#6a737d&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;domains&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ctx&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;log&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;error&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;必须配置过滤域名&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            exit&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#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:#cf222e&#34;&gt;for&lt;/span&gt; domain &lt;span style=&#34;color:#0550ae&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#6a737d&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;domains&lt;span style=&#34;color:#1f2328&#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:#cf222e&#34;&gt;if&lt;/span&gt; domain &lt;span style=&#34;color:#0550ae&#34;&gt;in&lt;/span&gt; url&lt;span style=&#34;color:#1f2328&#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:#cf222e&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;True&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:#cf222e&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#cf222e&#34;&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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:#cf222e&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#6639ba&#34;&gt;step&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#6a737d&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; method&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; url&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; headers&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; body&lt;span style=&#34;color:#1f2328&#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:#cf222e&#34;&gt;if&lt;/span&gt; method &lt;span style=&#34;color:#0550ae&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;get&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            body_grammar &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;params=&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;{&lt;/span&gt;body&lt;span style=&#34;color:#0a3069&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;&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:#cf222e&#34;&gt;else&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            body_grammar &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;json=&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;{&lt;/span&gt;body&lt;span style=&#34;color:#0a3069&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;&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:#cf222e&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&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:#0a3069&#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:#0a3069&#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:#0a3069&#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:#0a3069&#34;&gt;    response = request(
&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:#0a3069&#34;&gt;        &amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;{&lt;/span&gt;method&lt;span style=&#34;color:#0a3069&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;,
&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:#0a3069&#34;&gt;        url=&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;{&lt;/span&gt;url&lt;span style=&#34;color:#0a3069&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;,
&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:#0a3069&#34;&gt;        headers=&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;{&lt;/span&gt;headers&lt;span style=&#34;color:#0a3069&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#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:#0a3069&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;{&lt;/span&gt;body_grammar&lt;span style=&#34;color:#0a3069&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#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:#0a3069&#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:#0a3069&#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:#0a3069&#34;&gt;    # var = response.jmespath(&amp;#34;expression&amp;#34;)
&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:#0a3069&#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:#0a3069&#34;&gt;    assert response.status_code &amp;lt; 400
&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:#0a3069&#34;&gt;&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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:#57606a&#34;&gt;## ==================================配置开始==================================&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;addons &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Record&lt;span style=&#34;color:#1f2328&#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:#57606a&#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:#1f2328&#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:#0a3069&#34;&gt;&amp;#34;http://www.httpbin.org&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#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:#0a3069&#34;&gt;&amp;#34;http://127.0.0.1:5000&amp;#34;&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:#1f2328&#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:#1f2328&#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:#1f2328&#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:#57606a&#34;&gt;## ==================================配置结束==================================&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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:#0a3069&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&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:#0a3069&#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:#0a3069&#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:#0a3069&#34;&gt;mitmdump -s mitm.py
&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:#0a3069&#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:#0a3069&#34;&gt;mitmdump -s mitm.py --mode reverse:http://127.0.0.1:5000 --listen-host 127.0.0.1 --listen-port 8000
&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:#0a3069&#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:#0a3069&#34;&gt;&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过 mitmproxy 命令启动代理后，获取当前时间作为文件名在&lt;code&gt;tests/mitm&lt;/code&gt;下生成用例文件，给 addons 添加插件 Record 类，通过 response 钩子捕获请求信息，对请求进行域名过滤，域名匹配成功的请求就使用测试步骤代码模板，填充 method、url、headers、body 数据，追加到测试用例文件中。&lt;/p&gt;</description>
    </item>
    <item>
      <title>teprunner 测试平台入门级部署手册发布啦</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/teprunner%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0%E5%85%A5%E9%97%A8%E7%BA%A7%E9%83%A8%E7%BD%B2%E6%89%8B%E5%86%8C%E5%8F%91%E5%B8%83%E5%95%A6/</link>
      <pubDate>Sun, 11 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/teprunner%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0%E5%85%A5%E9%97%A8%E7%BA%A7%E9%83%A8%E7%BD%B2%E6%89%8B%E5%86%8C%E5%8F%91%E5%B8%83%E5%95%A6/</guid>
      <description>很多朋友是因为 teprunner，也就是这个小众的 pytest 内核测试平台关注的公众号。为了让大家更好的上手 teprunner，我更新了它的 README，希望能让小伙伴们根据这些文档内容，一步一步的在自己本地电脑上把项目跑起来。项目跑起来之后，就可以参考前面一系列的学习教程，自己动手做一遍，在做的过程中和 teprunner 进行对比，不懂的点逐一突破，由点到面，完整实现。**这种学习方式能更快速的掌</description>
    </item>
    <item>
      <title>tep0.9.5 支持自定义扩展 request</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/tep0.9.5%E6%94%AF%E6%8C%81%E8%87%AA%E5%AE%9A%E4%B9%89%E6%89%A9%E5%B1%95request/</link>
      <pubDate>Sat, 10 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/tep0.9.5%E6%94%AF%E6%8C%81%E8%87%AA%E5%AE%9A%E4%B9%89%E6%89%A9%E5%B1%95request/</guid>
      <description>tep0.9.5 更新了以下内容：</description>
    </item>
    <item>
      <title>teprunner 重磅更新 Git 打通 PyCharm 与测试平台</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/teprunner%E9%87%8D%E7%A3%85%E6%9B%B4%E6%96%B0git%E6%89%93%E9%80%9Apycharm%E4%B8%8E%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0/</link>
      <pubDate>Sat, 10 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/teprunner%E9%87%8D%E7%A3%85%E6%9B%B4%E6%96%B0git%E6%89%93%E9%80%9Apycharm%E4%B8%8E%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0/</guid>
      <description>经过 Python 测试交流群的小伙伴群策群力，teprunner 添加了一个重要功能，把 PyCharm 中的代码，通过 Git 同步到测试平台中，生成测试用例。这样，teprunner 就成了一个名副其实的&lt;strong&gt;pytest 脚本在线管理平台&lt;/strong&gt;。</description>
    </item>
    <item>
      <title>tep 支持 MVC 架构实现用例数据分离</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/tep%E6%94%AF%E6%8C%81mvc%E6%9E%B6%E6%9E%84%E5%AE%9E%E7%8E%B0%E7%94%A8%E4%BE%8B%E6%95%B0%E6%8D%AE%E5%88%86%E7%A6%BB/</link>
      <pubDate>Fri, 09 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/tep%E6%94%AF%E6%8C%81mvc%E6%9E%B6%E6%9E%84%E5%AE%9E%E7%8E%B0%E7%94%A8%E4%BE%8B%E6%95%B0%E6%8D%AE%E5%88%86%E7%A6%BB/</guid>
      <description>大家好，我是刚哥。</description>
    </item>
    <item>
      <title>teprunner 测试平台定时任务这次终于稳了</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/teprunner%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1%E8%BF%99%E6%AC%A1%E7%BB%88%E4%BA%8E%E7%A8%B3%E4%BA%86/</link>
      <pubDate>Fri, 09 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/teprunner%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1%E8%BF%99%E6%AC%A1%E7%BB%88%E4%BA%8E%E7%A8%B3%E4%BA%86/</guid>
      <description>teprunner 测试平台已经有一个多月没有更新了，主要原因是定时任务不够稳定，经过反复试错，找到了解决办法，这次终于稳定了。</description>
    </item>
    <item>
      <title>tep 集成 HttpRunner 与 Flask 实现开箱即用</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/tep%E9%9B%86%E6%88%90httprunner%E4%B8%8Eflask%E5%AE%9E%E7%8E%B0%E5%BC%80%E7%AE%B1%E5%8D%B3%E7%94%A8/</link>
      <pubDate>Thu, 08 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/tep%E9%9B%86%E6%88%90httprunner%E4%B8%8Eflask%E5%AE%9E%E7%8E%B0%E5%BC%80%E7%AE%B1%E5%8D%B3%E7%94%A8/</guid>
      <description>大家好，我是刚哥。</description>
    </item>
    <item>
      <title>teprunner 测试平台用例编写等体验响应式升级</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/teprunner%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0%E7%94%A8%E4%BE%8B%E7%BC%96%E5%86%99%E7%AD%89%E4%BD%93%E9%AA%8C%E5%93%8D%E5%BA%94%E5%BC%8F%E5%8D%87%E7%BA%A7/</link>
      <pubDate>Thu, 08 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/teprunner%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0%E7%94%A8%E4%BE%8B%E7%BC%96%E5%86%99%E7%AD%89%E4%BD%93%E9%AA%8C%E5%93%8D%E5%BA%94%E5%BC%8F%E5%8D%87%E7%BA%A7/</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;在免费开源的测试平台中，teprunner 的 UI 界面应该算得上第一梯度了，BUT，美中不足，在不同分辨率显示器（比如 13.3 寸小屏笔记本）下布局大的弹出窗口，表现不尽如人意。而这又是核心功能代码编辑的界面，比如用例编写、fixture 编写，很有必要优化升级。除此之外还有滚动条的问题：竖向双滚动条和横向滚动条，也对体验造成影响。本文将对这些内容进行改造，具体如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;编写用例页面，从弹窗改为子页面。&lt;/li&gt;
&lt;li&gt;编写 fixture 页面，从弹窗改为子页面。&lt;/li&gt;
&lt;li&gt;代码编辑区域高度自适应。&lt;/li&gt;
&lt;li&gt;缩小左侧菜单，移动项目环境和新增按钮同一行，&lt;strong&gt;扩大编辑区面积。&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;消除所有双向滚动条。&lt;/li&gt;
&lt;li&gt;消除所有横向滚动条。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;语法说明添加环境变量和 fixtures 示例代码。&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;其他细节优化。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;响应式是指同一套前端代码在不同浏览器（PC 端、移动端等）都能适配，&lt;strong&gt;Element UI 已经是响应式设计了，本文的响应式体现在代码编辑区行高根据 window.innerHeight 自动计算设定。&lt;/strong&gt;&lt;/p&gt;
&lt;h1 id=&#34;升级效果展示&#34;&gt;升级效果展示&lt;/h1&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/abb289b0c2ad40d0b876edfd0078712a.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;左侧菜单栏变窄；添加环境变量和 fixtures 示例代码。&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/8f2785c1c9bd4d5ead1ab11ab700afe6.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;项目环境和新增按钮同一行显示，扩大有效内容可视面积。&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/21e3c8c2725b414d841f5aa8166eb133.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;fixtures 的新增和编辑从弹窗改为子路由页面，代码编辑区高度自适应，纵向滚动条只出现一个。&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/978e0307dd804de58c101d3f8d908fe0.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;消除横向滚动条；缩小了用例描述列以外其他列宽；替换操作按钮文字为图标。&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/a0ddb7fee2e74834b416755ead80e364.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;用例的新增和编辑从弹窗改为子路由页面，代码编辑区高度自适应，纵向滚动条只出现一个。&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/98b3d62d1d144be595d485264f5f0a11.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;用例运行结果的新增和编辑从弹窗改为子路由页面，代码编辑区高度自适应，纵向滚动条只出现一个。&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/ac3e7fdec3304676a6c32a6815e55d8b.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;测试计划的新增，编辑，运行结果也做了相同调整。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;整体而言，有效信息的可视面积和可操作面积都尽可能扩大了！&lt;/strong&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/4181f693f5a74f7d8e3b474ffc40e44a.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;比较繁琐，&lt;strong&gt;没有新知识&lt;/strong&gt;，这里就不一一讲解了，而是选择用到的关键技术点来进行&lt;strong&gt;知识回顾&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;template 添加&lt;code&gt;&amp;lt;router-view&amp;gt;&amp;lt;/router-view&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;主页面 div 添加&lt;code&gt;v-if=&amp;quot;$route.name === &#39;name&#39;&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;在 router/index.js 中添加 children 子路由&lt;/li&gt;
&lt;li&gt;跳转页面前，存 localStorage&lt;/li&gt;
&lt;li&gt;新页面 create()时，取 localStorage&lt;/li&gt;
&lt;li&gt;&lt;code&gt;this.$router.push&lt;/code&gt;跳转路由&lt;/li&gt;
&lt;li&gt;div 同行显示用&lt;code&gt;float: left&lt;/code&gt;，紧跟的 div 换行用&lt;code&gt;clear: both&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;window.innerHeight 获取屏幕高度&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;小结&#34;&gt;小结&lt;/h1&gt;
&lt;p&gt;本文完成了对 teprunner 测试平台前端 UI 界面的体验升级，&lt;strong&gt;已经适配 13.3 寸到 27 寸显示器&lt;/strong&gt;，如果还在担心不好用的话，那么现在可以好好试试了。定时任务从目前优化效果来看，已经趋于稳定，不久就会和大家见面。&lt;/p&gt;</description>
    </item>
    <item>
      <title>teprunner 测试平台测试计划批量运行用例</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/teprunner%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0%E6%B5%8B%E8%AF%95%E8%AE%A1%E5%88%92%E6%89%B9%E9%87%8F%E8%BF%90%E8%A1%8C%E7%94%A8%E4%BE%8B/</link>
      <pubDate>Wed, 07 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/teprunner%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0%E6%B5%8B%E8%AF%95%E8%AE%A1%E5%88%92%E6%89%B9%E9%87%8F%E8%BF%90%E8%A1%8C%E7%94%A8%E4%BE%8B/</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;上一篇文章已经把 pytest 引入到测试平台中，通过多线程和多进程的方式，运行测试用例。有了这个基础，做批量运行用例的功能就很简单了，只需要前端传入一个 CaseList 即可。本文的后端代码是增删改查和复用 run_case 相关代码做个 run_plan。前端代码将学习如何通过 LocalStorage 在非父子组件之间传递数据。具体开发内容如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;测试计划增删改查&lt;/li&gt;
&lt;li&gt;测试计划动态添加移除测试用例&lt;/li&gt;
&lt;li&gt;运行测试计划，批量运行用例&lt;/li&gt;
&lt;li&gt;计划运行结果、用例运行结果&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;编写后端代码&#34;&gt;编写后端代码&lt;/h1&gt;
&lt;p&gt;编辑 teprunner/urls.py 文件，添加测试计划的路由：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/1c96969043d24bd0b87c84d657795fa5.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;编辑 teprunner/models.py 文件，添加 3 张表的 model：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/fcd47aad64ed43e4a1d72f29dfa16568.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;Plan 存放测试计划，PlanCase 存放计划和用例关联关系，PlanResult 和 CaseResult 类似，这里之所以把单独出来一张结果表，是为了和用例结果 CaseResult 相互独立，防止计划结果覆盖用例结果，毕竟 CaseResult 一般是手工跑出来的，PlanResult 一般是定时任务跑出来的，功能数据解耦后处理起来也更方便。&lt;/p&gt;
&lt;p&gt;编辑 teprunner/serializers.py 文件，添加序列化器：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/b2608ab6d83845e2a7c26f365a6ee6e3.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/49b760af5b804974a9d5d8aa06a87402.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/5992c4f23daf478f9984ca7186da9881.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;为了前端展示需要，这里额外关联了一些字段进行展示。尤其是：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/97d5f6ac98354ce5b2d1a501f45f3d94.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/1fdbb3cd5aef45e89a27b0fc3d3cb3ed.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/9fd4fcda762342339a84b37707c177be.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;caseNum 用例总条数，passedNum 成功条数，failedNum 失败条数，errorNum 错误条数。成功定义为：只有 passed，没有 failed 和 error 的用例。失败定义为：只有 failed，没有 error 的用例。错误定义为：只要有 error 的用例。&lt;/p&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/ebdfaf64af22487994b1f0bf89b93140.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;重写 to_representation 方法，把不需要返回的字段 pop 移出去。这里 output 在计划运行结果不需要，在用例运行结果才需要，为了减少传输数据，就在计划运行结果的接口响应中移出去了。&lt;/p&gt;</description>
    </item>
    <item>
      <title>原创 pytest 辅助工具 tep0.9.1 版本恢复项目初始化文件</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E5%8E%9F%E5%88%9Bpytest%E8%BE%85%E5%8A%A9%E5%B7%A5%E5%85%B7tep0.9.1%E7%89%88%E6%9C%AC%E6%81%A2%E5%A4%8D%E9%A1%B9%E7%9B%AE%E5%88%9D%E5%A7%8B%E5%8C%96%E6%96%87%E4%BB%B6/</link>
      <pubDate>Wed, 07 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E5%8E%9F%E5%88%9Bpytest%E8%BE%85%E5%8A%A9%E5%B7%A5%E5%85%B7tep0.9.1%E7%89%88%E6%9C%AC%E6%81%A2%E5%A4%8D%E9%A1%B9%E7%9B%AE%E5%88%9D%E5%A7%8B%E5%8C%96%E6%96%87%E4%BB%B6/</guid>
      <description>最近几个月时间有些小伙伴问到为什么 tep 项目初始化文件没有了？</description>
    </item>
    <item>
      <title>tep 环境变量、fixtures、用例三者之间的关系</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/tep%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8Ffixtures%E7%94%A8%E4%BE%8B%E4%B8%89%E8%80%85%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB/</link>
      <pubDate>Tue, 06 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/tep%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8Ffixtures%E7%94%A8%E4%BE%8B%E4%B8%89%E8%80%85%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB/</guid>
      <description>tep 是一款测试工具，在 pytest 测试框架基础上集成了第三方包，提供项目脚手架，帮助以写 Python 代码方式，快速实现自动化项目落地。</description>
    </item>
    <item>
      <title>teprunner 测试平台 Django 引入 pytest 完整源码</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/teprunner%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0django%E5%BC%95%E5%85%A5pytest%E5%AE%8C%E6%95%B4%E6%BA%90%E7%A0%81/</link>
      <pubDate>Tue, 06 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/teprunner%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0django%E5%BC%95%E5%85%A5pytest%E5%AE%8C%E6%95%B4%E6%BA%90%E7%A0%81/</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;pytest 登场！本文将在 Django 中引入 pytest，原理是先执行 tep startproject 命令创建 pytest 项目文件，然后从数据库中拉取代码写入文件，最后调用 pytest 命令运行用例。为了提高运行效率，用例运行是并行的，采用了多线程和多进程，两个都有，这在最后有个单独小结进行比较完整的说明。因为用例运行是异步的，所以前端并不知道什么时候执行完才能拿到运行结果，可以发多个 HTTP 请求轮询，但这种方式并不优雅，本文将采用 WebSocket 来实现用例结果查询。具体内容为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cases/&amp;lt;int:pk&amp;gt;/run&lt;/code&gt;运行用例接口&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ws/teprunner/cases/&amp;lt;int:case_id&amp;gt;/result/&lt;/code&gt;用例结果查询接口&lt;/li&gt;
&lt;li&gt;&lt;code&gt;projects/&amp;lt;int:pk&amp;gt;/export&lt;/code&gt;下载项目环境接口&lt;/li&gt;
&lt;li&gt;前端添加 WebSocket 请求&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;知识点涉及有点多：tep、pytest、同步、异步、多线程、多进程、回调函数、WebSocket、长连接、全双工、ASGI、WSGI、打 ZIP 包、文件字节流传输。&lt;/p&gt;
&lt;h1 id=&#34;编写后端代码&#34;&gt;编写后端代码&lt;/h1&gt;
&lt;p&gt;编辑 requirements.txt，添加 tep 和 channels：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;tep==0.6.9
channels==3.0.3
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;tep 是用来创建 pytest 项目的，channels 是用来实现 WebSocket 的。&lt;/p&gt;
&lt;p&gt;编辑 teprunner/urls.py 文件，添加 HTTP 路由：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/71e7cccd40254bb886c396048dadf6af.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;首先实现 run 接口，新建 teprunner/views/run.py 文件：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/1482f5173eb94926b01b3ad07a6385d0.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;这是运行用例的主体流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;第一步从请求中获取用例 id、运行环境、运行人，这里演示了获取 user 数据的两种方式：接口传参和从 token 中解析。然后根据 project_id，run_env，user_id 定义了 pytest 项目的路径。&lt;/li&gt;
&lt;li&gt;第二步使用 tep startproject 创建项目文件，清空 fixtures 和 tests 目录，目的有两个：一是清掉 tep 默认 fixtures 和示例 cases，防止对平台产生干扰；二是保证每次运行目录都是干净的，就不用单独去处理前端手动删掉 fixture/case 后，文件残留的问题。然后从数据库中拉取环境变量、fixtures 等数据更新文件。&lt;/li&gt;
&lt;li&gt;起多个线程，分别执行用例，执行前先拉取用例代码写入文件，这里是单条用例运行，之所以要用 for 循环，是因为用例迟早是要批量执行，在设计时就考虑到，避免后面走弯路。然后删掉数据库运行结果，通过 subprocess 起子进程调用 pytest 命令，最后在线程的回调函数中根据 pytest_result 保存用例结果到数据库中。&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;注意！run_case 接口不会直接返回结果，前端是用 WebSocket 来查询结果的。&lt;/p&gt;
&lt;/blockquote&gt;</description>
    </item>
    <item>
      <title>tep0.6.0 更新聊聊 pytest 变量接口用例 3 个级别复用</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/tep0.6.0%E6%9B%B4%E6%96%B0%E8%81%8A%E8%81%8Apytest%E5%8F%98%E9%87%8F%E6%8E%A5%E5%8F%A3%E7%94%A8%E4%BE%8B3%E4%B8%AA%E7%BA%A7%E5%88%AB%E5%A4%8D%E7%94%A8/</link>
      <pubDate>Mon, 05 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/tep0.6.0%E6%9B%B4%E6%96%B0%E8%81%8A%E8%81%8Apytest%E5%8F%98%E9%87%8F%E6%8E%A5%E5%8F%A3%E7%94%A8%E4%BE%8B3%E4%B8%AA%E7%BA%A7%E5%88%AB%E5%A4%8D%E7%94%A8/</guid>
      <description>tep 是一款测试工具，在 pytest 测试框架基础上集成了第三方包，提供项目脚手架，帮助以写 Python 代码方式，快速实现自动化项目落地。fixture 是 pytest 核心技术，本文聊聊如何使用 fixture 完成变量、接口、用例 3 个级别复用。</description>
    </item>
    <item>
      <title>teprunner 测试平台开发用例管理不只有增删改查</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/teprunner%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0%E5%BC%80%E5%8F%91%E7%94%A8%E4%BE%8B%E7%AE%A1%E7%90%86%E4%B8%8D%E5%8F%AA%E6%9C%89%E5%A2%9E%E5%88%A0%E6%94%B9%E6%9F%A5/</link>
      <pubDate>Mon, 05 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/teprunner%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0%E5%BC%80%E5%8F%91%E7%94%A8%E4%BE%8B%E7%AE%A1%E7%90%86%E4%B8%8D%E5%8F%AA%E6%9C%89%E5%A2%9E%E5%88%A0%E6%94%B9%E6%9F%A5/</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;用例管理是对用例进行增删改查，按照前面文章的思路，把它做出来应该不难，如果你已经自己写好了，那么可以和本文提交的代码比较下看看。除了增删改查，用例管理还需要提供运行用例的入口，在操作列添加一个运行按钮，单条用例运行，并弹窗展示运行结果。用例列表需要能看到每条用例执行情况，添加表格列用于展示，其中“运行结果”列要有超链接，点击查看上次运行结果。为了避免修改别人用例出错，还需要有个复制用例功能。除了在线编辑，平台应支持下载项目环境到本地，无缝切换到 PyCharm，让新用户快速上手。综上所述，本文开发内容如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用例增删改查。&lt;/li&gt;
&lt;li&gt;运行按钮，点击后弹出“运行用例结果”。&lt;/li&gt;
&lt;li&gt;添加表格展示列，其中“运行结果”用颜色区分不同结果状态：passed，failed，error，点击超链接后弹出“查看用例结果”。&lt;/li&gt;
&lt;li&gt;复制按钮，点击后生成一条复制的新用例。&lt;/li&gt;
&lt;li&gt;新增/编辑页面，添加运行按钮。&lt;/li&gt;
&lt;li&gt;运行/查看页面，添加编辑按钮。&lt;/li&gt;
&lt;li&gt;下载环境到本地。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;工作量主要在前端，后端先做一部分。&lt;/p&gt;
&lt;h1 id=&#34;编写后端代码&#34;&gt;编写后端代码&lt;/h1&gt;
&lt;p&gt;编辑 teprunner/urls.py，添加路由：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/212bda04278c4eea864f64edbe8e6c2b.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;除了增删改查，还添加了 2 个接口，一个用于获取用例运行的结果，一个用于复制测试用例。&lt;/p&gt;
&lt;p&gt;编辑 teprunner/models.py，添加模型：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/ebbca98ae0734477b8b8ee8a2b2713bd.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;第一个 Model 是 Case，没有定义 name 字段，实际上用例 ID 和用例描述已经够用了，name 不知道填什么，有点多余。第二个 Model 是 CaseResult，会记录运行结果，这个运行结果是从 pytest 执行日志最后一行的 Summary 截取出来的，比如 1 passed，1 failed，耗时也是从 Summary 截取出来的。output 存放代码运行后打到控制台的输出日志。最后三个字段记录运行环境、运行人和运行时间，运行时间取的数据库记录被添加/更新的时间。添加好以后迁移到数据库中：&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-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;python manage.py makemigrations
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;python manage.py migrate
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编辑 teprunner/serializers.py，添加序列化器，第一个序列化器是 CaseSerializer：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/fd7c0235d6684a7aae21827c39a2af96.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;只关联了 Case 模型的字段。&lt;/p&gt;
&lt;p&gt;第二个序列化器是 CaseListSerializer：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/096c709c347f463d9d4c9d1f946d7947.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;它主要用来返回用例列表的数据，除了用例本身，还需要用例结果。serializers.SerializerMethodField 用于自定义序列化字段，定义好字段后，在下面添加&lt;code&gt;get_前缀+字段名&lt;/code&gt;的方法，这是 Django 的规则，然后在方法内部添加取值代码，比如 get_result()，instance 是指 Meta.model 定义的模型，这里就等同于 Case，通过 instance.id 获取到 Case.id 并赋值给 case_id 变量，从 CaseResult 的对象中过滤 case_id 匹配的用例结果，按运行时间倒序，取最新 1 条结果的 result 字段的值。其他字段的处理是类似的，runTime 这里做了下日期格式化：&lt;/p&gt;</description>
    </item>
    <item>
      <title>teprunner 测试平台用例前置模块开发</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/teprunner%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0%E7%94%A8%E4%BE%8B%E5%89%8D%E7%BD%AE%E6%A8%A1%E5%9D%97%E5%BC%80%E5%8F%91/</link>
      <pubDate>Sun, 04 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/teprunner%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0%E7%94%A8%E4%BE%8B%E5%89%8D%E7%BD%AE%E6%A8%A1%E5%9D%97%E5%BC%80%E5%8F%91/</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;现在正式进入测试相关功能开发。teprunner 测试平台底层是 pytest，中间层是 tep，还没了解的朋友可以先看看 tep 的文章，整个平台的设计思路和后面用例的执行都会基于这个工具。tep 的测试用例是放在.py 文件里面的，全局变量或者说环境变量是引用的 env_vars，公共函数和复用接口是引用的 fixtures，在做成平台后，需要把这两个部分独立为两个功能模块。多个项目的接口自动化数据需要隔离开来，要有个项目管理功能。本文将开发四个用例前置模块：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;后台管理&amp;ndash;项目管理&lt;/li&gt;
&lt;li&gt;接口自动化&amp;ndash;语法说明&lt;/li&gt;
&lt;li&gt;接口自动化&amp;ndash;环境变量&lt;/li&gt;
&lt;li&gt;接口自动化&amp;ndash;fixtures&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;语法说明给出了环境变量、fixtures、用例示例（单个接口、多个接口&amp;ndash;增删改查）、请求方法（get、post、put、delete）的使用方法。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;编写后端代码&#34;&gt;编写后端代码&lt;/h1&gt;
&lt;p&gt;先创建名为 teprunner 的 app：&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-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;django-admin startapp teprunner
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在 settings 的 INSTALLED_APPS 中添加配置让 app 生效：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/67d966cf73d6483297dd107366706b05.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;并在 urls.py 添加路由：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/f3bd4250cbe84c6a89367a48fa40ff3f.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;编辑 user/fixtures/user.json，添加一个接口自动化的菜单：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/9322e66b340042d9b8304e1c9fd9bc67.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;截图只截了管理员，测试和开发角色，也需要添加上。access 均为 true，这三个角色都可以访问。添加后把数据同步到数据库：&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-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;python manage.py loaddata user
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编辑 teprunner/models.py，新增模型：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/d6cffae9dd7a4a0b877eb1d08f9e07e1.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;包括了项目、环境变量和 fixture 三张表。Project.env_config 用于给项目配置多个环境。不同项目不同环境的环境变量不一样，在 EnvVar 中添加了 project_id 和 env_name，并按(&amp;ldquo;project_id&amp;rdquo;, &amp;ldquo;env_name&amp;rdquo;, &amp;ldquo;name&amp;rdquo;)作为唯一键，不允许重复。不同项目的 fixtures 不同，不关心环境，在 Fixture 中只添加了 project_id。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Fixture.code 用于存放代码，字段类型为 models.TextField，容纳更多字符。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;models 编写好后，迁移到数据库：&lt;/p&gt;</description>
    </item>
    <item>
      <title>如何用 tep 完成增删改查接口自动化</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E5%A6%82%E4%BD%95%E7%94%A8tep%E5%AE%8C%E6%88%90%E5%A2%9E%E5%88%A0%E6%94%B9%E6%9F%A5%E6%8E%A5%E5%8F%A3%E8%87%AA%E5%8A%A8%E5%8C%96/</link>
      <pubDate>Sun, 04 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E5%A6%82%E4%BD%95%E7%94%A8tep%E5%AE%8C%E6%88%90%E5%A2%9E%E5%88%A0%E6%94%B9%E6%9F%A5%E6%8E%A5%E5%8F%A3%E8%87%AA%E5%8A%A8%E5%8C%96/</guid>
      <description>tep 的设计理念是让人人都可以用 Python 写自动化，本文就来介绍如何用 tep 完成增删改查接口自动化。</description>
    </item>
    <item>
      <title>pytestx 容器化执行引擎</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/pytestx%E5%AE%B9%E5%99%A8%E5%8C%96%E6%89%A7%E8%A1%8C%E5%BC%95%E6%93%8E/</link>
      <pubDate>Sat, 03 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/pytestx%E5%AE%B9%E5%99%A8%E5%8C%96%E6%89%A7%E8%A1%8C%E5%BC%95%E6%93%8E/</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;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/5a917ce9454040089ddd36f52930b7b6.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;前端、后端、pytest 均以&lt;strong&gt;Docker&lt;/strong&gt;容器运行服务，单独的容器化执行引擎，项目环境隔离，即用即取，用完即弃，简单，高效。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;前端容器：页面交互，请求后端，展示 HTML 报告&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;后端容器：接收前端请求，启动任务，构建镜像，触发运行 pytest，挂载 HTML 报告&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;pytest 容器：拉取项目代码，指定目录执行，生成 HTML 报告&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;说明：构建镜像目前是在宿主机启动后端服务来执行 docker 命令的，暂未支持 Kubernetes 编排。宿主机安装了 Docker，启动服务后，可以执行 docker 命令。如果采用容器部署后端，容器里面不包含 Docker，无法构建，个人想法是可以借助 K8S 来编排，当前版本还未实现&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;系统流程&#34;&gt;系统流程&lt;/h1&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/f3705e59f74a44b3b1c49d38776cf513.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;支持 2 种运行模式配置：容器和本地。&lt;/p&gt;
&lt;p&gt;容器模式：判断是否支持 docker，如果支持，构建 pytest 镜像，在构建时，通过 git 拉取项目代码，再运行容器，按照指定目录执行 pytest，生成测试报告，并将报告文件挂载到后端。如果不支持，降级为本地运行。&lt;/p&gt;
&lt;p&gt;本地模式：模拟容器行为，在本地目录拉取代码，执行 pytest，生成测试报告。&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/3160ec51a9094badbf1543a35568a028.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;容器模式：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/8cea72d575a34a86a29e6d21f9d792e4.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;本地模式：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/1d2d7ccffec842b58332cf3a5ce6ffc8.png&#34;&gt;&lt;/p&gt;
&lt;h1 id=&#34;平台大改造&#34;&gt;平台大改造&lt;/h1&gt;
&lt;p&gt;pytestx 平台更轻、更薄，移除了用例管理、任务关联用例相关功能代码，只保留真正的任务调度功能，backend 的 requirements.txt 解耦，只保留后端依赖，pytest 相关依赖转移到 tep-project。&lt;/p&gt;
&lt;p&gt;那如何管理用例呢？约定大于配置，&lt;strong&gt;我们约定 pytest 项目已经通过目录维护好了一个稳定的自动化用例集&lt;/strong&gt;，也就是说需要通过平台任务调度的用例，都统一存放在目录 X 下，这些用例基本不需要维护，可以每日稳定执行，然后将目录 X 配置到平台任务信息中，按指定目录执行用例集。对于那些不够稳定的用例，就不能放到目录 X 下，需要调试好以后再纳入。&lt;/p&gt;
&lt;p&gt;为什么不用 marker？pytest 的 marker 确实可以给测试用例打标记，也有人是手动建立任务和用例进行映射，这些方式都不如维护一个稳定的自动化用例集方便，在我们公司平台上，也是维护用例集，作为基础用例集。使用 pytest 项目同理。&lt;/p&gt;</description>
    </item>
    <item>
      <title>teprunner 测试平台部署到 Linux 系统 Docker</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/teprunner%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0%E9%83%A8%E7%BD%B2%E5%88%B0linux%E7%B3%BB%E7%BB%9Fdocker/</link>
      <pubDate>Sat, 03 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/teprunner%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0%E9%83%A8%E7%BD%B2%E5%88%B0linux%E7%B3%BB%E7%BB%9Fdocker/</guid>
      <description>本文是一篇过渡，在进行用例管理模块开发之前，有必要把入门篇开发完成的代码部署到 Linux 系统 Docker 中，把部署流程走一遍，这个过程对后端设计有决定性影响。</description>
    </item>
    <item>
      <title>开源测试平台开发期待你的加入</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E5%BC%80%E6%BA%90%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0%E5%BC%80%E5%8F%91%E6%9C%9F%E5%BE%85%E4%BD%A0%E7%9A%84%E5%8A%A0%E5%85%A5/</link>
      <pubDate>Sat, 03 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E5%BC%80%E6%BA%90%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0%E5%BC%80%E5%8F%91%E6%9C%9F%E5%BE%85%E4%BD%A0%E7%9A%84%E5%8A%A0%E5%85%A5/</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;在 2022 年 7 月 6 日我曾组织过一次开源测试平台开发报名，有 50+人报名，到 2023 年 1 月 28 日项目暂停，如大家在 Gittee 看到的，除我以外，只有 1 个人真正提交了代码：奉孝。&lt;/p&gt;
&lt;p&gt;原因如其中一位同学所说：“感觉我们大部份还是缺少从 0 到 1 的经验，负责的内容有时候不要知道从哪下手，又少了点积极性”。描述得很贴切，可能刚开始动力很足，但因为缺少经验，不够积极，最后实践不了。说的很好，就是做不到。也很无奈。&lt;/p&gt;
&lt;p&gt;二次启动，分为 2 个阶段，第一个阶段是学习阶段，我带着大家一起把 teprunner 平台从 0 到 1 开发一遍，把需要掌握的知识先学一遍，保证有一定基础，挑战能够独立完成模块开发。第二个阶段是开发阶段，共同完成 EasyPytest 测试平台开发，学以致用，加深对前后端分离项目开发的理解，具有真实的平台开发实践。&lt;/p&gt;
&lt;h1 id=&#34;学习阶段&#34;&gt;学习阶段&lt;/h1&gt;
&lt;p&gt;你都不维护了，我为什么还要学 teprunner？Django 没意思？我想学 FastAPI？&lt;/p&gt;
&lt;p&gt;teprunner 有一套完整教程，包括前后端源码、11 篇电子书教程、2 小时视频讲解，虽然我因为工作原因没有继续维护 teprunner，但是它仍然非常适合初学者入门学习测试开发，掌握里面的知识，对于后续学习其他技术，都有很大帮助。我的技术提升除了二刷《流畅的 Python》和编写了 tep 开源工具，最大的提升就是完成了 teprunner 测试平台开发，如果你也能自己动手完成一遍，一定有极大提升。&lt;/p&gt;
&lt;p&gt;Django、Flask、FastAPI、SpringBoot，我认为从入门者角度来说，Django 是最适合的，它属于开箱即用的框架，很多东西都给你准备好了，你用就行，避免刚开始就陷入环境搭建，三方库拼装、数据库维护的麻烦中，降低理解门槛和操作难度。学会了 Django，再学其他的，也很简单，一通百通。刚开始学习，学哪个不是最重要的，最重要的是先学会一个，迈出第一步。以我的经验来说，学习成熟框架 Django 是个正确选择。&lt;/p&gt;
&lt;h1 id=&#34;开发阶段&#34;&gt;开发阶段&lt;/h1&gt;
&lt;p&gt;EasyPytest 的后端把 Django 切换为了 FastAPI，掌握了 Django，再对比 FastAPI，就能对后端开发框架有更深入的理解。就像我学 Python 和 Java 一样，只学一门百思不得其解，对比一看，豁然开朗。目前已经完成了登录、首页、用户管理的开发，Gitee 也有相应源码。未来的规划，是做 teprunner 的升级版，实现 pytest 平台化，80%工作本地开发脚本，20%工作交给平台编排运行。&lt;/p&gt;</description>
    </item>
    <item>
      <title>框架 V2.0.0 开发指南</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E6%A1%86%E6%9E%B6v2.0.0%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/</link>
      <pubDate>Sat, 03 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E6%A1%86%E6%9E%B6v2.0.0%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/</guid>
      <description>&lt;strong&gt;温馨提示：开发指南，根据 V2.0.0 编写，不随版本更新维护，仅供入门参考。最新实现请结合教程和源码阅读，教程会在版本发布后维护。&lt;/strong&gt;</description>
    </item>
    <item>
      <title>一次全量数据对比工具发现问题的过程与思考</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E4%B8%80%E6%AC%A1%E5%85%A8%E9%87%8F%E6%95%B0%E6%8D%AE%E5%AF%B9%E6%AF%94%E5%B7%A5%E5%85%B7%E5%8F%91%E7%8E%B0%E9%97%AE%E9%A2%98%E7%9A%84%E8%BF%87%E7%A8%8B%E4%B8%8E%E6%80%9D%E8%80%83/</link>
      <pubDate>Sat, 03 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E4%B8%80%E6%AC%A1%E5%85%A8%E9%87%8F%E6%95%B0%E6%8D%AE%E5%AF%B9%E6%AF%94%E5%B7%A5%E5%85%B7%E5%8F%91%E7%8E%B0%E9%97%AE%E9%A2%98%E7%9A%84%E8%BF%87%E7%A8%8B%E4%B8%8E%E6%80%9D%E8%80%83/</guid>
      <description>如果没有这次全量数据对比工具，那么也许这个历史问题会继续隐藏着，直到发生线上事故才暴露出来，毕竟人工抽样验证发现的概率只有&lt;strong&gt;5.8%&lt;/strong&gt;。</description>
    </item>
    <item>
      <title>pytestx 重新定义接口框架设计</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/pytestx%E9%87%8D%E6%96%B0%E5%AE%9A%E4%B9%89%E6%8E%A5%E5%8F%A3%E6%A1%86%E6%9E%B6%E8%AE%BE%E8%AE%A1/</link>
      <pubDate>Fri, 02 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/pytestx%E9%87%8D%E6%96%B0%E5%AE%9A%E4%B9%89%E6%8E%A5%E5%8F%A3%E6%A1%86%E6%9E%B6%E8%AE%BE%E8%AE%A1/</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;脚手架：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/aefec433fde14d39abde74206ab83341.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;目录：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/d271b2542dab494595723669cc50dd81.png&#34;&gt;&lt;/p&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-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&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:#0a3069&#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:#0a3069&#34;&gt;&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;test_data &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#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:#0a3069&#34;&gt;&amp;#34;查询SKU&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#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:#0a3069&#34;&gt;&amp;#34;skuName&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;电子书&amp;#34;&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:#1f2328&#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:#0a3069&#34;&gt;&amp;#34;添加购物车&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#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:#0a3069&#34;&gt;&amp;#34;skuId&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;123&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#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:#0a3069&#34;&gt;&amp;#34;skuNum&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;2&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:#1f2328&#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:#0a3069&#34;&gt;&amp;#34;下单&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#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:#0a3069&#34;&gt;&amp;#34;orderId&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;222&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#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:#0a3069&#34;&gt;&amp;#34;payAmount&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;0.2&amp;#34;&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:#1f2328&#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:#0a3069&#34;&gt;&amp;#34;支付&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#1f2328&#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:#0a3069&#34;&gt;&amp;#34;skuId&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;123&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#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:#0a3069&#34;&gt;&amp;#34;price&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;0.1&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#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:#0a3069&#34;&gt;&amp;#34;skuNum&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#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:#0a3069&#34;&gt;&amp;#34;totalPrice&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;0.2&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:#1f2328&#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:#1f2328&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;case_vars &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#6639ba&#34;&gt;dict&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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:#cf222e&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#6639ba&#34;&gt;test&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;http&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; login_headers&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; file_data&lt;span style=&#34;color:#1f2328&#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:#57606a&#34;&gt;# 搜索商品&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    url &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; file_data&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;domain&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;/api/tasks/mock/searchSku&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    body &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; test_data&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;查询SKU&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    response &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; http&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;get&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; url&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;url&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; headers&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;login_headers&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; params&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;body&lt;span style=&#34;color:#1f2328&#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:#cf222e&#34;&gt;assert&lt;/span&gt; response&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;status_code &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;400&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    case_vars&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;skuId&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; response&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;jsonpath&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;$.skuId&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    case_vars&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;skuPrice&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; response&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;jsonpath&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;$.price&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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:#57606a&#34;&gt;# 添加购物车&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    url &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; file_data&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;domain&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;/api/tasks/mock/addCart&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    body &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; test_data&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;添加购物车&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    body&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;skuId&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; case_vars&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;skuId&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    response &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; http&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;post&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; url&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;url&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; headers&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;login_headers&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; json&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;body&lt;span style=&#34;color:#1f2328&#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:#cf222e&#34;&gt;assert&lt;/span&gt; response&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;status_code &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;400&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    case_vars&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;skuNum&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; response&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;jsonpath&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;$.skuNum&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    case_vars&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;totalPrice&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; response&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;jsonpath&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;$.totalPrice&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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:#57606a&#34;&gt;# 下单&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    url &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; file_data&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;domain&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;/api/tasks/mock/order&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    body &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; test_data&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;下单&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    body&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;skuId&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; case_vars&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;skuId&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    body&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;price&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; case_vars&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;skuPrice&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    body&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;skuNum&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; case_vars&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;skuNum&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    body&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;totalPrice&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; case_vars&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;totalPrice&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    response &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; http&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;post&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; url&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;url&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; headers&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;login_headers&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; json&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;body&lt;span style=&#34;color:#1f2328&#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:#cf222e&#34;&gt;assert&lt;/span&gt; response&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;status_code &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;400&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    case_vars&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;orderId&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; response&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;jsonpath&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;$.orderId&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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:#57606a&#34;&gt;# 支付&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    url &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; file_data&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;domain&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;/api/tasks/mock/pay&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    body &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; test_data&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;支付&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    body&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;orderId&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; case_vars&lt;span style=&#34;color:#1f2328&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;orderId&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    response &lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt; http&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;post&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; url&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;url&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; headers&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;login_headers&lt;span style=&#34;color:#1f2328&#34;&gt;,&lt;/span&gt; json&lt;span style=&#34;color:#0550ae&#34;&gt;=&lt;/span&gt;body&lt;span style=&#34;color:#1f2328&#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:#cf222e&#34;&gt;assert&lt;/span&gt; response&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;status_code &lt;span style=&#34;color:#0550ae&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;400&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:#cf222e&#34;&gt;assert&lt;/span&gt; response&lt;span style=&#34;color:#0550ae&#34;&gt;.&lt;/span&gt;jsonpath&lt;span style=&#34;color:#1f2328&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;$.success&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#1f2328&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#0550ae&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#0a3069&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;页面下载脚手架&#34;&gt;页面下载脚手架&lt;/h1&gt;
&lt;p&gt;启动平台前后端服务后，从页面下载脚手架，平台会拉取开源项目 tep-project 最新代码，打成压缩包，生成下载文件，弹窗下载。&lt;/p&gt;</description>
    </item>
    <item>
      <title>tep 用户手册帮你从 unittest 过渡到 pytest</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/tep%E7%94%A8%E6%88%B7%E6%89%8B%E5%86%8C%E5%B8%AE%E4%BD%A0%E4%BB%8Eunittest%E8%BF%87%E6%B8%A1%E5%88%B0pytest/</link>
      <pubDate>Fri, 02 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/tep%E7%94%A8%E6%88%B7%E6%89%8B%E5%86%8C%E5%B8%AE%E4%BD%A0%E4%BB%8Eunittest%E8%BF%87%E6%B8%A1%E5%88%B0pytest/</guid>
      <description>unittest 和 pytest 是 Python 的 2 个强大的测试框架，经常用来做 UI 自动化或接口自动化。unittest 是 PyCharm 的默认集成工具，也是我们大多数人入门自动化的首选框架。pytest 提供了更丰富的功能，相对的上手难度也要高一点。如果学了 pytest 后，想快速用 pytest 写项目，用于工作实践，那么可以试试我写的这款测试工具：&lt;code&gt;tep&lt;/code&gt;，try easy pytest。</description>
    </item>
    <item>
      <title>功能测试用例自动生成算法 Pairwise 工具</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E5%8A%9F%E8%83%BD%E6%B5%8B%E8%AF%95%E7%94%A8%E4%BE%8B%E8%87%AA%E5%8A%A8%E7%94%9F%E6%88%90%E7%AE%97%E6%B3%95pairwise%E5%B7%A5%E5%85%B7/</link>
      <pubDate>Fri, 02 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E5%8A%9F%E8%83%BD%E6%B5%8B%E8%AF%95%E7%94%A8%E4%BE%8B%E8%87%AA%E5%8A%A8%E7%94%9F%E6%88%90%E7%AE%97%E6%B3%95pairwise%E5%B7%A5%E5%85%B7/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;本书作者：测试开发刚哥，文章版权归个人所有，未经授权请勿转载。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;pairwise-算法是什么&#34;&gt;Pairwise 算法是什么&lt;/h2&gt;
&lt;p&gt;对于以下测试场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;浏览器：M，O，P&lt;/li&gt;
&lt;li&gt;操作平台：W（windows），L（linux），i（ios）&lt;/li&gt;
&lt;li&gt;语言：C（chinese），E（english）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;该如何设计功能测试用例呢？&lt;/p&gt;
&lt;p&gt;根据数学统计分析，73%的缺陷（单因子是 35%，双因子是 38%）是由单因子或 2 个因子相互作用产生的。19%的缺陷是由 3 个因子相互作用产生的。也就是说，&lt;strong&gt;大多数的 bug 都是条件的两两组合造成的&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;Pairwise 算法是 L. L. Thurstone 在 1927 年首先提出来的，他是美国的一位心理统计学家。Pairwise 算法基于两两组合，过滤出性价比高的用例集。它的思路是：&lt;strong&gt;如果某一组用例的两两组合结果，在其他组合中均出现，就删除该组用例，从而精简用例&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;对于上述测试场景，可以通过笛卡尔积设计 18 条两两组合的测试用例：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;1，M W C
2，M W E
3，M L C
4，M L E
5，M I C
6，M I E
7，O W C
8，O W E
9，O L C
10，O L E
11，O I C
12，O I E
13，P W C
14，P W E
15，P L C
16，P L E
17，P I C
18，P I E
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;对于第 18 条用例&lt;code&gt;P I E&lt;/code&gt;来说，两两组合是&lt;code&gt;PI ，PE ，IE&lt;/code&gt;，&lt;code&gt;PI&lt;/code&gt;在 17 号，&lt;code&gt;PE&lt;/code&gt;在 16 号，&lt;code&gt;IE&lt;/code&gt;在 12 号出现过，所以第 18 条用例可以过滤掉。按照这个算法继续过滤，最终剩下 9 条用例：&lt;/p&gt;</description>
    </item>
    <item>
      <title>坚持开发原创测试平台</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E5%9D%9A%E6%8C%81%E5%BC%80%E5%8F%91%E5%8E%9F%E5%88%9B%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0/</link>
      <pubDate>Fri, 02 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E5%9D%9A%E6%8C%81%E5%BC%80%E5%8F%91%E5%8E%9F%E5%88%9B%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0/</guid>
      <description>&lt;strong&gt;不管测试平台有没有实际用处，具备测试平台开发能力，是测试开发工程师的必备技能之一。&lt;/strong&gt; 测试平台的实际收益有多少，仁者见仁智者见智，这是一个辩证问题。测试平台开发能力是否具备，一清二楚，这是一个现实问题。我们能做的只有提高自己，解决现实问题。</description>
    </item>
    <item>
      <title>免费搭建你的电子书网站（附源码）</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E5%85%8D%E8%B4%B9%E6%90%AD%E5%BB%BA%E4%BD%A0%E7%9A%84%E7%94%B5%E5%AD%90%E4%B9%A6%E7%BD%91%E7%AB%99%E9%99%84%E6%BA%90%E7%A0%81/</link>
      <pubDate>Fri, 02 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E5%85%8D%E8%B4%B9%E6%90%AD%E5%BB%BA%E4%BD%A0%E7%9A%84%E7%94%B5%E5%AD%90%E4%B9%A6%E7%BD%91%E7%AB%99%E9%99%84%E6%BA%90%E7%A0%81/</guid>
      <description>电子书网站由 AI 实现，Claude Code+DeepSeek-V4-Pro。技术栈 Python+MkDocs，主题 Read the Docs，静态托管 GitHub Pages。具有中文搜索功能。</description>
    </item>
    <item>
      <title>学习版 pytest 内核测试平台开发万字长文入门篇</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E5%AD%A6%E4%B9%A0%E7%89%88pytest%E5%86%85%E6%A0%B8%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0%E5%BC%80%E5%8F%91%E4%B8%87%E5%AD%97%E9%95%BF%E6%96%87%E5%85%A5%E9%97%A8%E7%AF%87/</link>
      <pubDate>Fri, 02 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E5%AD%A6%E4%B9%A0%E7%89%88pytest%E5%86%85%E6%A0%B8%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0%E5%BC%80%E5%8F%91%E4%B8%87%E5%AD%97%E9%95%BF%E6%96%87%E5%85%A5%E9%97%A8%E7%AF%87/</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;2021 年，测试平台如雨后春笋般冒了出来，我就是其中一员，写了一款 pytest 内核测试平台，在公司落地。分享出来后，有同学觉得挺不错，希望能开源，本着“公司代码不要传到网上去，以免引起不必要麻烦”的原则，只能在家从头写一个，边重新梳理代码边温习巩固知识点，以学习交流为目的，定义为“学习版”。&lt;/p&gt;
&lt;h1 id=&#34;功能展示&#34;&gt;功能展示&lt;/h1&gt;
&lt;h2 id=&#34;登录&#34;&gt;登录&lt;/h2&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/a3424569c09d42aca658cf3b885278e3.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;接口自动化&#34;&gt;接口自动化&lt;/h2&gt;
&lt;p&gt;接口自动化&amp;ndash;Dashboard：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/41db611e68aa42019522249b82b90997.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;接口自动化&amp;ndash;环境变量：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/896567b6022149c896fe3ee25a085775.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;接口自动化&amp;ndash;fixtures：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/e78af47ce1b246888d8efec56167a2d2.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;接口自动化&amp;ndash;用例管理：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/562b086acf334c8c9d716b09f40ee67e.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;接口自动化&amp;ndash;用例管理&amp;ndash;编辑用例：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/d9ff4d3f91374aadb002a9feac0acab9.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;接口自动化&amp;ndash;测试计划：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/bac839ba20b642c484b6c61c8487711b.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;接口自动化&amp;ndash;语法说明：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/e6f5f342fe4c4ca7a94aa1425116e772.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;小工具&#34;&gt;小工具&lt;/h2&gt;
&lt;p&gt;小工具&amp;ndash;共享脚本：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/8d2d8773432847dabd769a1e23358c85.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;小工具&amp;ndash;HTTP 状态查询：&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/6abb077760834ea3b36d856bcc0dd4f8.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;后台管理&#34;&gt;后台管理&lt;/h2&gt;
&lt;p&gt;后台管理&amp;ndash;用户管理&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/82bdce6ce2b14a3694103b41159881df.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;后台管理&amp;ndash;项目管理&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/dcf99d0331e34d3ab08a233d42735b7d.png&#34;&gt;&lt;/p&gt;
&lt;h1 id=&#34;本文开发内容&#34;&gt;本文开发内容&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;登录，登出&lt;/li&gt;
&lt;li&gt;首页，修改密码，个人信息&lt;/li&gt;
&lt;li&gt;后台管理，用户管理&lt;/li&gt;
&lt;li&gt;JWT 认证&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本文先打个基础，既是测试平台基本结构，也可以作为 CMS 基础框架，定制开发各种小型项目。&lt;/p&gt;
&lt;h1 id=&#34;技术栈&#34;&gt;技术栈&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Node.js 12.16.3&lt;/li&gt;
&lt;li&gt;Vue 4.5.11&lt;/li&gt;
&lt;li&gt;Python 3.8&lt;/li&gt;
&lt;li&gt;Django 3.1.3&lt;/li&gt;
&lt;li&gt;Django REST framework 3.12.2&lt;/li&gt;
&lt;li&gt;SQLite 3&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;IDE 编辑器推荐 PyCharm 旗舰版，既能写 Django 也能写 Vue 项目。数据库使用 Django 自带 SQLite ，省去安装 MySQL 和 Navicat/Workbench 麻烦，轻量级开发。SQLiteStudio 为 SQLite 数据库可视化工具，只需要下载即可，无需安装，解压就用：：&lt;/p&gt;</description>
    </item>
    <item>
      <title>EasyPytest 测试平台开发日志之系统设计</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/easypytest%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0%E5%BC%80%E5%8F%91%E6%97%A5%E5%BF%97%E4%B9%8B%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1/</link>
      <pubDate>Thu, 01 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/easypytest%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0%E5%BC%80%E5%8F%91%E6%97%A5%E5%BF%97%E4%B9%8B%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1/</guid>
      <description>&lt;strong&gt;EasyPytest 测试平台，帮你高效管理 Pytest 测试用例。&lt;/strong&gt;</description>
    </item>
    <item>
      <title>japi 项目需求分析阶段</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/japi%E9%A1%B9%E7%9B%AE%E9%9C%80%E6%B1%82%E5%88%86%E6%9E%90%E9%98%B6%E6%AE%B5/</link>
      <pubDate>Thu, 01 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/japi%E9%A1%B9%E7%9B%AE%E9%9C%80%E6%B1%82%E5%88%86%E6%9E%90%E9%98%B6%E6%AE%B5/</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;&lt;strong&gt;japi&lt;/strong&gt;项目，是一个接口自动化平台开发项目，由【交流群】招人共建，基于 JMeter，参考 MeterSphere，以学习为目的，完成一个 SpringBoot+Vue 技术栈的纯粹的接口自动化平台开发。&lt;/p&gt;
&lt;h1 id=&#34;项目成员&#34;&gt;项目成员&lt;/h1&gt;
&lt;p&gt;经过&amp;quot;填写人员分工表&amp;quot;以后，最终有 38 人参与了本次项目：&lt;/p&gt;
&lt;p&gt;刚哥、布鲁、嘉宥、守正、大刚、风雨、奉孝、大姚、畅月、渔夫、小禹、钰琪、天湖、迷龙、肥涵、胖子、局长、呼呼、明亮、安宁、木棉、番茄、玥玥、哈瑞、虚竹、十五、阿新、卡罗、大白、库昊、左右、小涌、古风、玉洁、小韩、小卷、千凝、昆明。&lt;/p&gt;
&lt;p&gt;随着项目进行，后续“提交学习总结”等环节层层递进，真正留下来的项目成员，会在 GitHub 的 README 中署名。&lt;/p&gt;
&lt;p&gt;在填表时收集了大家的历史经验，这里汇总整理了一下，供参考：&lt;/p&gt;
&lt;p&gt;“Vue+Django 写过测试平台；SpringBoot 写过后端应用；Python 小工具开发；Python+Pytest+Requests 搭建接口自动化框架；Python+Unittest 或 Pytest 自动化测试框架搭建及脚本开发；各类开源自动化测试平台搭建，如：HttpRunnerManager、流马、Yapi、Sonic 等；js+Django2 实现 UI 自动化测试平台；使 Testng 框架进行接口测试；Vue+fastapi 写过测试平台；python+selenium UI 自动化；python+httprunner，接口文档解析自动生成字段校验用例；python+RobotFramework 做过 UI；Java 做过单元测试，熟悉基础语法；学过 JavaSE，JavaEE，实战经验不多；Python Pyqt GUI 工具开发；Python 接口自动化、APP 自动化框架设计及编码；独立负责主导 Python+Locust 性能测试；三方库和标准库：unittest、pytest、appium、selenium、request、httprunner；画过简单的 html、css；App UI 自动化框架搭建：pytest+appium+allure+jenkins 接口自动化框架搭建：pytest+request+allure+jenkins 二次开发及维护过 flask+vue 接口测试平台；二次开发及维护过 springboot+angularUI 测试平台；Pytest+Playwright UI 自动化脚本编写；”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我总结了几个关键字：Vue、Django、SpringBoot、Flask、FastAPI、ElementUI、RobotFramework、脚本开发、工具开发、平台开发、接口自动化、UI 自动化、APP 自动化。&lt;/strong&gt;&lt;/p&gt;
&lt;h1 id=&#34;项目计划&#34;&gt;项目计划&lt;/h1&gt;
&lt;p&gt;招募，人员分工，需求分析，设计，编码，测试，上线。&lt;/p&gt;
&lt;p&gt;由于是以学习为目的，加上都是业余时间投入，也有其他事情要忙，所以该项目不会像真正项目那样，设置里程碑和交付节点，会给足够的学习时间，战线拉得比较长，过程大于结果。&lt;/p&gt;
&lt;h1 id=&#34;需求分析&#34;&gt;需求分析&lt;/h1&gt;
&lt;p&gt;MeterSphere 官方给出的功能列表，接口自动化相关的模块有接口定义和接口自动化。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;接口定义包括以下功能：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在线添加并编辑接口定义;
以树状形式展示项目的模块及对应接口;
支持 HTTP、Dubbo、SQL、TCP 类型接口请求;
支持通过 MeterSphere Json、Postman、Swagger 等多种格式文件快速导入接口，Swagger 可通过 URL 定时同步;
支持接口快捷调试;
根据接口定义快速配置 HTTP、TCP 协议 Mock 服务;
API 列表、CASE 列表、文档模式多种模式灵活切换;
接口页面 API、TEST、CASE、MOCK 多种操作灵活切换;
测试环境信息管理功能;
单接口用例支持引用环境;
支持正则匹配、jsonpath、xpath 等多种类型的断言规则;
支持正则匹配、jsonpath、xpath 等多种类型的参数提取;
支持 BeanShell、Python、Groovy、JavaScript 等多种语言的前后置脚本;
支持前置 SQL、后置 SQL;
支持上传并引用自定义 Jar 包;
支持查看接口及用例变更历史;
手动执行、定时任务、Jenkins 插件触发等多种执行方式;
API、CASE 一键复制;
CASE 一键创建性能测试;
接口定义依赖关系设置;&lt;/p&gt;</description>
    </item>
    <item>
      <title>JSON 转 SQL 小工具源码分享</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/json%E8%BD%ACsql%E5%B0%8F%E5%B7%A5%E5%85%B7%E6%BA%90%E7%A0%81%E5%88%86%E4%BA%AB/</link>
      <pubDate>Thu, 01 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/json%E8%BD%ACsql%E5%B0%8F%E5%B7%A5%E5%85%B7%E6%BA%90%E7%A0%81%E5%88%86%E4%BA%AB/</guid>
      <description>将 key-value 的 JSON 数据，转换为 insert 的 SQL 语句，进而实现网页数据存储到数据库。</description>
    </item>
    <item>
      <title>pytest 内核测试平台落地初体验</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/pytest%E5%86%85%E6%A0%B8%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0%E8%90%BD%E5%9C%B0%E5%88%9D%E4%BD%93%E9%AA%8C/</link>
      <pubDate>Thu, 01 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/pytest%E5%86%85%E6%A0%B8%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0%E8%90%BD%E5%9C%B0%E5%88%9D%E4%BD%93%E9%AA%8C/</guid>
      <description>测试平台，有人说它鸡肋，有人说它有用，有人说它轮子，众说纷纭，不如从自身出发，考虑是否要做测试平台：</description>
    </item>
    <item>
      <title>tep 首次开源 V0.2.3 介绍</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/tep%E9%A6%96%E6%AC%A1%E5%BC%80%E6%BA%90v0.2.3%E4%BB%8B%E7%BB%8D/</link>
      <pubDate>Thu, 01 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/tep%E9%A6%96%E6%AC%A1%E5%BC%80%E6%BA%90v0.2.3%E4%BB%8B%E7%BB%8D/</guid>
      <description>『  tep is a testing tool to help you write pytest more easily. Try Easy Pytest!  』</description>
    </item>
    <item>
      <title>聚焦于任务调度的测试平台 pytestx</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E8%81%9A%E7%84%A6%E4%BA%8E%E4%BB%BB%E5%8A%A1%E8%B0%83%E5%BA%A6%E7%9A%84%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0pytestx/</link>
      <pubDate>Thu, 01 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E8%81%9A%E7%84%A6%E4%BA%8E%E4%BB%BB%E5%8A%A1%E8%B0%83%E5%BA%A6%E7%9A%84%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0pytestx/</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;&lt;strong&gt;聚焦于任务调度&lt;/strong&gt;，接口自动化 80%本地编写，20%交由平台管理。&lt;/p&gt;
&lt;p&gt;如果使用 pytest 做接口自动化，那么个人认为最好的编写工具是 PyCharm，任何低代码测试平台都无法取代。当然不会代码，或者不使用 pytest，那低代码测试平台，或者 yaml，甚至 excel 写自动化用例，都是可以接受的。而在使用 pytest 这个特定场景里面，要做平台化，平台的功能就需要仔细斟酌。既然编写用例最好使用 PyCharm，平台也就只能专注于用例编排和任务调度，即创建任务，关联用例，批量运行，以及定时，并行，通知等。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;pytestx&lt;/strong&gt;正是基于此理念设计的一款纯粹的任务调度平台。&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/883d930149b2437da1b3f410b1835ffa.png&#34;&gt;&lt;/p&gt;
&lt;h1 id=&#34;平台架构&#34;&gt;平台架构&lt;/h1&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;../assets/82056831880343ad8a090709ee6abd26.png&#34;&gt;&lt;/p&gt;
&lt;h1 id=&#34;tep100-的延续&#34;&gt;tep1.0.0 的延续&lt;/h1&gt;
&lt;p&gt;tep1.0.0 版本已经封版，在 pytestx 中对它进行了延续。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;从 pypi 到 git&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;tep 是上传到 pypi 的，通过 pip 命令安装，使用 tep startproject 命令创建项目脚手架，代码结构分为项目代码和 tep 代码。改造后的 tep 只有项目代码，存放在：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://gitee.com/dongfanger/tep-project.git&#34;&gt;https://gitee.com/dongfanger/tep-project.git&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;也就是说，在这个项目中，能看到整个 tep 全貌。之前的 tep 内核代码，比如 fixtures 自动寻找、内置 fixture、环境变量等，全部迁移到了项目代码里面，尤其是 conftest.py 的文件内容。pip install tep 顺带安装的依赖包，也整理到了 requirements.txt，按照说明安装即可。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;pytest-html 替换 allure&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;由重到轻，化繁为简，pytest-html 能够满足数据+日志的报告需要，最新的 V3.2.0 版本的界面尚可。诚然 allure 漂亮，但安装 Java、下载 Allure、配置环境变量、安装 pytest-allure、添加 pytest hook 还是相对麻烦。更重要的是，要支持平台在线查看报告，减少存储占用，pytest-html 无疑是更好的选择。&lt;/p&gt;</description>
    </item>
    <item>
      <title>原创电子书全新重磅升级</title>
      <link>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E5%8E%9F%E5%88%9B%E7%94%B5%E5%AD%90%E4%B9%A6%E5%85%A8%E6%96%B0%E9%87%8D%E7%A3%85%E5%8D%87%E7%BA%A7/</link>
      <pubDate>Thu, 01 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://dongfanger.github.io/posts/%E9%A1%B9%E7%9B%AE/%E5%8E%9F%E5%88%9B%E7%94%B5%E5%AD%90%E4%B9%A6%E5%85%A8%E6%96%B0%E9%87%8D%E7%A3%85%E5%8D%87%E7%BA%A7/</guid>
      <description>电子书，简洁专注的阅读体验。对于技术文章来说，电脑端比手机端更适合阅读，尤其是代码。电子书的左侧目录能快速找到文章，虽然公众号也有文章分类功能，但是不能像目录树一样有“位置感”。电子书还能支持搜索。所以把个人网站做成了电子书。</description>
    </item>
  </channel>
</rss>
