菲兒 發表於 2025-5-22 19:43:00

pytest框架

<p>&nbsp;</p>
<div>pytest 是 python 的第三方单元测试框架,比自带unittest 更简洁和高效,支持315种以上的插件,同时兼容 unittest 框架。</div>
<div>这就使得我们在 unittest 框架迁移到pytest 框架的时候不需要重写代码。接下来我们在文中来对分析下 pytest 有哪些简洁、高效的用法:</div>
<div>&nbsp;</div>
<div>环境搭建</div>
<div>
<div class="cnblogs_Highlighter">
<pre class="brush:python;gutter:true;">#首先使用 pip 安装 pytest<br>pip install pytest
pip install pytest-html    #原生态报告模板<br>pip show pytest         #查看 pytest 是否安装成功</pre>
</div>
</div>
<div>
<div>&nbsp;</div>
<div>使用 pytest 执行测试需要遵行的规则:</div>
<div>
<ul>
<li>必须以test_开头,或,test结尾</li>
<li>测试类必须以Test开头,,并且类中不能有_init_方法</li>
<li>测试方法必须以test开头</li>
<li>断言必须使用assert</li>
</ul>
</div>
<div>
<div>&nbsp;</div>
<div>在pytest中有四种setup和teardown:</div>
<ul>
<li>setup_module 和 teardown_module 在整个测试用例所在的文件中所有的方法运行前和运行后运行,只会运行一次;</li>
<li>setup_class 和 teardown_class 则在整个文件中的一个class中所有用例的前后运行,</li>
<li>setup_method 和 teardown_method 在class内的每个方法运行前后运行,</li>
<li>setup_function、teardown_function 则是在非class下属的每个测试方法的前后运行;</li>
</ul>
</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>
<div>数据驱动:</div>
</div>
<div>举例:</div>
<div>
<div class="cnblogs_code">
<pre>@pytest.mark.parametrize( <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">x,y,z</span><span style="color: rgba(128, 0, 0, 1)">"</span>, [(1,2,3),(2,3,4<span style="color: rgba(0, 0, 0, 1)">)] )  #列表套列表/列表套元组均可
  </span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> test1(x,y,z):
    </span><span style="color: rgba(0, 0, 255, 1)">assert</span> x+y == z</pre>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
</div>
<div>
<div>fixture源码详解</div>
<div>fixture(scope='function',params=None,autouse=False,ids=None,name=None):</div>
<ul>
<li>scope:有四个级别参数"function"(默认),"class","module","session"</li>
<li>params:一个可选的参数列表,它将导致多个参数调用fixture功能和所有测试使用它。</li>
<li>autouse:如果True,则为所有测试激活fixture func可以看到它。如果为False则显示需要参考来激活fixture</li>
<li>ids:每个字符串id的列表,每个字符串对应于params这样他们就是测试ID的一部分。如果没有提供ID它们将从params自动生成</li>
<li>name:fixture的名称。这默认为装饰函数的名称。</li>
</ul>
</div>
<div>
<div>fixture的作用范围</div>
<div>  fixture里面有个scope参数可以控制fixture的作用范围:</div>
<div>  session&gt;module&gt;class&gt;function</div>
<ul>
<li>-function:每一个函数或方法都会调用</li>
<li>-class:每一个类调用一次,一个类中可以有多个方法</li>
<li>-module:每一个.py文件调用一次,该文件内又有多个function和class</li>
<li>-session:是多个文件调用一次,可以跨.py文件调用,每个.py文件就是module</li>
</ul>
<div>&nbsp;</div>
<div>
<div>usefixtures与传fixture区别:</div>
<ul>
<li>如果fixture有返回值,那么usefixture就无法获取到返回值,这个是装饰器usefixture与用例直接传fixture参数的区别。</li>
<li>当fixture需要用到return出来的参数时,只能讲参数名称直接当参数传入,不需要用到return出来的参数时,两种方式都可以。</li>
</ul>
<div>fixture自动使用autouse=True</div>
<div>  当用例很多的时候,每次都传这个参数,会很麻烦。</div>
<div>  fixture里面有个参数autouse,默认是False没开启的,可以设置为True开启自动使用fixture功能,这样用例就不用每次都去传参了</div>
<div>  autouse设置为True,自动调用fixture功能</div>
<p>调用fixture的三种方法</p>
</div>
<div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span>   <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">1、函数或类里面方法直接传fixture的函数参数名称</span>
<span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 0, 0, 1)">   @pytest.fixture()
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span>    <span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> test1():
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span>     <span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">\n开始执行function</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span>   
<span style="color: rgba(0, 128, 128, 1)"> 6</span>    <span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> test_a(test1):
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span>      <span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">---用例a执行---</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span>   
<span style="color: rgba(0, 128, 128, 1)"> 9</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">2、使用装饰器@pytest.mark.usefixtures()修饰需要运行的用例</span>
<span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 0, 1)"> @pytest.fixture()
</span><span style="color: rgba(0, 128, 128, 1)">11</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> test1():
</span><span style="color: rgba(0, 128, 128, 1)">12</span>      <span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">\n开始执行function</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">13</span>@pytest.mark.usefixtures(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">test1</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">14</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> test_a():
</span><span style="color: rgba(0, 128, 128, 1)">15</span>      <span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">---用例a执行---</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">16</span>
<span style="color: rgba(0, 128, 128, 1)">17</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">3、叠加usefixtures</span>
<span style="color: rgba(0, 128, 128, 1)">18</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">如果一个方法或者一个class用例想要同时调用多个fixture,可以使用@pytest.mark.usefixture()进行叠加。注意叠加顺序,先执行的放底层,后执行的放上层。</span>
<span style="color: rgba(0, 128, 128, 1)">19</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> pytest
</span><span style="color: rgba(0, 128, 128, 1)">20</span>
<span style="color: rgba(0, 128, 128, 1)">21</span> <span style="color: rgba(0, 0, 0, 1)"> @pytest.fixture()
</span><span style="color: rgba(0, 128, 128, 1)">22</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> test1():
</span><span style="color: rgba(0, 128, 128, 1)">23</span>      <span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">\n开始执行function</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">24</span>
<span style="color: rgba(0, 128, 128, 1)">25</span>@pytest.mark.usefixtures(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">test1</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">26</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> test_a():
</span><span style="color: rgba(0, 128, 128, 1)">27</span>      <span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">---用例a执行---</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">28</span>
<span style="color: rgba(0, 128, 128, 1)">29</span> <span style="color: rgba(0, 0, 0, 1)"> @pytest.fixture()
</span><span style="color: rgba(0, 128, 128, 1)">30</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> test1():
</span><span style="color: rgba(0, 128, 128, 1)">31</span>      <span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">\n开始执行function1</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">32</span>
<span style="color: rgba(0, 128, 128, 1)">33</span> <span style="color: rgba(0, 0, 0, 1)"> @pytest.fixture()
</span><span style="color: rgba(0, 128, 128, 1)">34</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> test2():
</span><span style="color: rgba(0, 128, 128, 1)">35</span>      <span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">\n开始执行function2</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">36</span>
<span style="color: rgba(0, 128, 128, 1)">37</span>@pytest.mark.usefixtures(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">test1</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">38</span>@pytest.mark.usefixtures(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">test2</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">39</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> test_a():
</span><span style="color: rgba(0, 128, 128, 1)">40</span>      <span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">---用例a执行---</span><span style="color: rgba(128, 0, 0, 1)">'</span>)</pre>
</div>
<p>&nbsp;</p>
</div>
<p>#pytest.main()<br>启动Pytest测试运行器,main() 函数如果不带任何参数,会自动查找和执行当前路径及其子目录中所有符合Pytest命名规范的所有测试文件(通常是文件名以 test_ 开头)。<br>  #常用参数:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#示例<br></span></pre>
<div>test_1.py文件</div>
<div>test_2.py文件</div>
<div>&nbsp;</div>
<pre><span style="color: rgba(0, 0, 0, 1)">Login类:<br></span>  登录方法 login<br><span>Shop类: <br></span><span>  列出</span>方法 <span>shop_list<br></span>   更新方法 <span>shop_update</span></pre>
</div>
<ul>
<li>-m   <code>-m &lt;标记&gt;</code>:运行指定标记的用例(需配合<code>@pytest.mark</code>使用)。支持逻辑表达式(如<code>and</code>/<code>or</code>)组合多个标记</li>
</ul>
<p>        如:pytest.main(['-m', 'smoke']) # 执行标记为smoke的用例</p>
<ul>
<li>-<code>-k &lt;表达式&gt;</code>:按名称匹配用例(支持逻辑运算符)  </li>
</ul>
<div>        如:pytest.main( ['-k', 'test_login or test_logout'] )   # 执行名称包含login 或 logout的用例</div>
<ul>
<li>-s      #输出到控制台。</li>
<li>-v     #以详细模式运行测试,显示更多的信息,如每个测试用例的名称、结果和错误信息。</li>
<li>--collect-only   #只收集测试用例但不执行它们,可以用于查看测试集中的所有可用测试。</li>
<li>-ignore     #忽略某个测试模块</li>
<li>-q     #简化打印信息</li>
<li>-x     #出现一条测试用例失败就退出测试。在调试阶段非常有用,当测试用例失败时,应该先调试通过,而不是继续执行测试用例。</li>
</ul>
<div>跳过/条件跳过</div>
<div>  skip   跳过--相当于注释的效果</div>
<div>  skipif  有条件的跳过--</div>
<p>&nbsp;</p>
<div>Allure报告优化</div>
<div>
<table style="height: 453px; width: 608px" border="0" align="left">
<tbody>
<tr>
<td>
<div>使用方法</div>
</td>
<td>
<div>参数值</div>
</td>
<td>参数说明</td>
</tr>
<tr>
<td>
<div>@allure.epic()</div>
</td>
<td>
<div>epic描述</div>
</td>
<td>
<div>敏捷里面的概念,定义史诗,往下是feature</div>
</td>
</tr>
<tr>
<td>
<div>@allure.feature()</div>
</td>
<td>
<div>模块名称</div>
</td>
<td>
<div>功能点的描述,往下是story</div>
</td>
</tr>
<tr>
<td>
<div>@allure.story()</div>
</td>
<td>
<div>用户故事</div>
</td>
<td>
<div>用户故事,往下是title</div>
</td>
</tr>
<tr>
<td>
<div>@allure.title(用例的标题)</div>
</td>
<td>
<div>用例的标题</div>
</td>
<td>
<div>重命名html报告名称</div>
</td>
</tr>
<tr>
<td>
<div>@allure.testcase()</div>
</td>
<td>
<div>测试用例的链接地址</div>
</td>
<td>
<div>对应功能测试用例系统里面的case</div>
</td>
</tr>
<tr>
<td>
<div>@allure.issue()</div>
</td>
<td>缺陷</td>
<td>
<div>对应缺陷管理系统里面的链接</div>
</td>
</tr>
<tr>
<td>
<div>@allure.description()</div>
</td>
<td>
<div>用例描述</div>
</td>
<td>测试用例的描述</td>
</tr>
<tr>
<td>
<div>@allure.step()</div>
</td>
<td>
<div>操作步骤</div>
</td>
<td>测试用例的步骤</td>
</tr>
<tr>
<td>
<div>@allure.severity()</div>
</td>
<td>
<div>用例等级</div>
</td>
<td>
<div>blocker,critical,normal,minor,trivial</div>
</td>
</tr>
<tr>
<td>
<div>@allure.link()</div>
</td>
<td>链接</td>
<td>
<div>定义一个链接,在测试报告展现</div>
</td>
</tr>
<tr>
<td>
<div>@allure.attachment()&nbsp;</div>
</td>
<td>附件</td>
<td>
<p>报告添加附件</p>
</td>
</tr>
</tbody>
</table>
 </div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
<div>&nbsp;</div>
</div>
</div><br><br>
来源:https://www.cnblogs.com/cm21/p/18886312
頁: [1]
查看完整版本: pytest框架