<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Tutorials on 重定向学院</title><link>https://itest2025.pages.dev/tutorials/</link><description>Recent content in Tutorials on 重定向学院</description><generator>Hugo</generator><language>zh-CN</language><lastBuildDate>Tue, 17 Jun 2025 17:29:15 +0800</lastBuildDate><atom:link href="https://itest2025.pages.dev/tutorials/index.xml" rel="self" type="application/rss+xml"/><item><title>软件测试实质</title><link>https://itest2025.pages.dev/tutorials/13-001-%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E5%AE%9E%E8%B4%A8/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/13-001-%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E5%AE%9E%E8%B4%A8/</guid><description>&lt;p>Ron Patton所著的《软件测试》2002年的中文版，已经十五年了，但它对“软件的实质”的解释仍然是经典，这里摘录与大家分享。&lt;/p>
&lt;p>&lt;strong>实质&lt;/strong>，哲学中的本质，又称为“实质”是指某一对象或事物本身所必然固有的。说的通俗点也就是说软件测试的本来的面目。&lt;/p>
&lt;br>
#### 软件缺陷的定义 
&lt;p>来看一下Ron Patton 为我们的软件缺陷所下的定义。&lt;/p>
&lt;p>&lt;strong>1、软件没有实现产品的说明书所描述的功能。&lt;/strong>&lt;/p>
&lt;p>&lt;strong>2、软件实现了产品说明书描述不应有的功能。&lt;/strong>&lt;/p>
&lt;p>&lt;strong>3、软件执行了产品说明书没讲的操作。&lt;/strong>&lt;/p>
&lt;p>&lt;strong>4、软件没有实现产品说明书没讲但应该实现的功能。&lt;/strong>&lt;/p>
&lt;p>&lt;strong>5、从软件测试员的角度来看，软件难以理解、不易使用、运行缓慢，或者最终用户认为不对。&lt;/strong>&lt;/p>
&lt;p>为什么一个定义要这么多条来描述？这个“缺陷”的定义有这么复杂么？不，它其实并不复杂，作者只是想更加全面的来给“缺陷”下定义。&lt;/p>
&lt;p>下面我们来以建一栋房子为例，来说明一下每一条定义的意思。需要说明的是没有十分完美而且一成不变的产品说明说，而且在实际项目中，它可能非常简陋，模棱两可，甚至经常变动。&lt;/p>
&lt;p>&lt;strong>1、&lt;/strong> 软件没有实现产品说明书的描述的功能。房子的主人希望有一个落地的大窗户，让阳光更好的照进屋子里，而且他特意在房子的设计图纸中画出来，并且还加以说明。结果，他看到的是四面全是墙壁，只有一个小门的房子。那么对于测试人员来说，他就是一个缺陷。&lt;/p>
&lt;p>&lt;strong>2、&lt;/strong> 软件实现了产品说明书中描述的不应有的功能。由于房子的主人生活在南方，天气温暖，而请来的泥瓦匠是北方的，结果给主人建造的房子具然有一个大大的取暖的烟筒，而且主人特意在房子的设计图纸中说明，自己的房子不要烟筒。那么对于测试人员来说，这也是个缺陷。&lt;/p>
&lt;p>&lt;strong>3、&lt;/strong> 软件执行了产品说明书没讲的操作。与第二条类似，不同的是第二条是主人已经明确说了自己不要烟筒，而这一条强调的是在主人没说的情况下。泥瓦匠自作聪明的加了一个烟筒上去。对于测试人员来说，画蛇添足的功能同样被视为缺陷。&lt;/p>
&lt;p>&lt;strong>4、&lt;/strong> 软件没有实现产品说明书没讲但应该实现的功能。房子的主要对屋子的高度、格局，材料，颜色描述的非常清楚。泥瓦匠在建造房子的时候发现，主人没有提地基这回事，为了使房子牢固，所以，所有的房子都是必须要先打地基的，虽然主人没有说，但地基的功能必须要做。如果因为没有描述没有去做，但这又一件必须去做的事。对于测试人员来说，也可以视其这缺陷。&lt;/p>
&lt;p>&lt;strong>5、&lt;/strong> 从软件测试员的角度看，软件难以理解、不易使用、运行缓慢，或者最终用户认为不对。软件测试员是软件除了测试软件运行的缺陷，同样是作为一个用户在再对软件进行使用。如果感觉自己都很难使用，或软件效率非常低且界面丑陋等情况，也可以认为其存在缺陷。或者是最终用户拿到产品时发现这根本不是自己想要的东西，也可以现其为缺陷。当然，用户说不是自己想要的东西，也不能凭借一面之词，可以拿合约，产品说明书来评估。&lt;/p>
&lt;br>
#### 完全测试程序的可能性 
&lt;p>初做软件测试者可能认为拿到软件后就可以进行完全测试了，找出所有软件缺陷，并使软件完美。遗憾的是这是不可能的，我们无法对一个软件进行完全测试，即使最简单的程序也不行。主要原因如下：&lt;/p>
&lt;ul>
&lt;li>输入量太大&lt;/li>
&lt;li>输出结果太多&lt;/li>
&lt;li>软件实现的途径太多&lt;/li>
&lt;li>软件说明书没有客观标准。从不同的角度看，软件缺陷的标准不同&lt;/li>
&lt;/ul>
&lt;p>以上的“太多”的可能性加在一起，致使测试条件难以确定。&lt;/p>
&lt;p>以126邮箱为登录测试为例，其用户长度为50个字符，密码确实不太好计算（因为都是*号），所以这里也按50个字符来计算。&lt;/p>
&lt;p>在输入正确用户名的情况下：&lt;/p>
&lt;pre tabindex="0">&lt;code>1、输入正确的密码名是还否可以登录，

2、那么错误输入0 呢？1呢？2呢？......直到

99999999999999999999999999999999999999999999999999 ，

3、如果密码不是数字，而是字符呢，a 、b、c ... aa、bb 、cc .....

4、如果是大写呢 A 、B、C.... AA 、BB、CC.....

5、如果是大小写呢 Aa、Ab ....

6、如果是小写+数字呢 1a 、1b 、1c ....2a 、2b 、2c.....

7、如果是大写+数字呢 1A 、1B 、1Cc....2A 、2A 、2A.....

8、如果是大写+小写+数字呢 1Aa 、1Bb 、1Cc ....1Aa 、1Bb 、1Cc.....

9、如果有特殊字符呢 @#￥%……&amp;amp;*

10、如果输入字符有空格呢 a b、adbc ee......

11、如果是其它字符+大小写字母+数字呢+空格呢 ！@#&amp;amp;+123AIBKIkklzcb ......

......

12、再换正确的密码，错误的文件名再来一次。

13、用错误的用户名和密码再把上面的情况验证一次。（这样会匹配到所有的用户名密码）

14、什么都不输，直接点击登录
&lt;/code>&lt;/pre>&lt;p>这样穷举下去，就算是计算机也可能需要运行很久。&lt;strong>如果觉得某些测试条件是重复的或者是无必要的，而将其剔除，那么就不能称为完全测试。&lt;/strong>&lt;/p></description></item><item><title>wrk系列教程(1)安装</title><link>https://itest2025.pages.dev/tutorials/15-001-wrk%E7%B3%BB%E5%88%97%E6%95%99%E7%A8%8B1%E5%AE%89%E8%A3%85/</link><pubDate>Fri, 01 Mar 2019 02:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/15-001-wrk%E7%B3%BB%E5%88%97%E6%95%99%E7%A8%8B1%E5%AE%89%E8%A3%85/</guid><description>&lt;p>&lt;a href="https://github.com/wg/wrk" target="_blank" rel="noopener noreffer ">wrk&lt;/a>是一个高性能的性能测试工具，具有非常强的并发能力，很适合做benchmark。&lt;/p>
&lt;p>wrk适合做一些简单的单接口性能压测，具有一定的扩展能力，不太适合做全链路的带业务压测。&lt;/p>
&lt;h3 id="下载源码">下载源码&lt;/h3>
&lt;p>首先你需要1台linux虚拟机或者mac机器。&lt;/p>
&lt;p>如果你用使用git，可以使用下面命令来下载源码&lt;/p>
&lt;pre tabindex="0">&lt;code>git clone https://github.com/wg/wrk.git
&lt;/code>&lt;/pre>&lt;p>或者你可以使用wget来下载源码的压缩包，&lt;strong>并自行解压&lt;/strong>&lt;/p>
&lt;pre tabindex="0">&lt;code>wget https://github.com/wg/wrk/archive/master.zip
&lt;/code>&lt;/pre>&lt;h3 id="安装wrk">安装wrk&lt;/h3>
&lt;p>cd到wrk源码所在目录，运行&lt;/p>
&lt;pre tabindex="0">&lt;code>make
&lt;/code>&lt;/pre>&lt;p>如果一切正常，一段时间后wrk会自动编译完成。我们可以将编译出的wrk可执行文件拷贝到&lt;code>/usr/local/bin&lt;/code>中，这样调用起来会比较方便。&lt;/p>
&lt;p>如果需要定制化安装，你可以参考&lt;a href="https://github.com/wg/wrk/blob/master/INSTALL" target="_blank" rel="noopener noreffer ">这里&lt;/a>&lt;/p>
&lt;h3 id="验证安装">验证安装&lt;/h3>
&lt;p>运行wrk可执行程序，你应该看到下面的结果&lt;/p>
&lt;pre tabindex="0">&lt;code>Usage: wrk &amp;lt;options&amp;gt; &amp;lt;url&amp;gt;
 Options:
 -c, --connections &amp;lt;N&amp;gt; Connections to keep open
 -d, --duration &amp;lt;T&amp;gt; Duration of test
 -t, --threads &amp;lt;N&amp;gt; Number of threads to use

 -s, --script &amp;lt;S&amp;gt; Load Lua script file
 -H, --header &amp;lt;H&amp;gt; Add header to request
 --latency Print latency statistics
 --timeout &amp;lt;T&amp;gt; Socket/request timeout
 -v, --version Print version details

 Numeric arguments may include a SI unit (1k, 1M, 1G)
 Time arguments may include a time unit (2s, 2m, 2h)
&lt;/code>&lt;/pre>&lt;p>原始封面&lt;/p></description></item><item><title>python简明教程: 1. 基本数据类型及操作</title><link>https://itest2025.pages.dev/tutorials/39-001-python%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B-1-%E5%9F%BA%E6%9C%AC%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E5%8F%8A%E6%93%8D%E4%BD%9C/</link><pubDate>Thu, 22 Nov 2018 03:23:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/39-001-python%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B-1-%E5%9F%BA%E6%9C%AC%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E5%8F%8A%E6%93%8D%E4%BD%9C/</guid><description>&lt;p>本文内容基本上翻译自&lt;a href="http://cheat.sh/python/:learn" target="_blank" rel="noopener noreffer ">http://cheat.sh/python/:learn)&lt;/a>&lt;/p>
&lt;p>&lt;strong>非原创, 非原创, 非原创!!!&lt;/strong>&lt;/p>
&lt;p>感谢原文社区作者&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 以```#```开头进行单行注释&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34; 使用3个双引号
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 来定义多行文本
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 多行文本一般被用来
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 做注释用了
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 这是数字&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">3&lt;/span> &lt;span class="c1"># =&amp;gt; 3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 这是做简单的算术&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">1&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="c1"># =&amp;gt; 2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">8&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="c1"># =&amp;gt; 7&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">10&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="c1"># =&amp;gt; 20&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">35&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="mi">5&lt;/span> &lt;span class="c1"># =&amp;gt; 7&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 除法有点不太一样，除法默认是做整数除法，比如&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">5&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="c1"># =&amp;gt; 2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 我们一般所认知的除法在python里其实就是浮点数除法，嗯，首先要了解什么是浮点数(floats)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mf">2.0&lt;/span> &lt;span class="c1"># 这就是浮点数了&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mf">11.0&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="mf">4.0&lt;/span> &lt;span class="c1"># =&amp;gt; 2.75 嗯...好多了&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 可以强制返回整数，正数负数都可以了&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">5&lt;/span> &lt;span class="o">//&lt;/span> &lt;span class="mi">3&lt;/span> &lt;span class="c1"># =&amp;gt; 1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mf">5.0&lt;/span> &lt;span class="o">//&lt;/span> &lt;span class="mf">3.0&lt;/span> &lt;span class="c1"># =&amp;gt; 1.0 # 浮点数也行&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">-&lt;/span>&lt;span class="mi">5&lt;/span> &lt;span class="o">//&lt;/span> &lt;span class="mi">3&lt;/span> &lt;span class="c1"># =&amp;gt; -2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">-&lt;/span>&lt;span class="mf">5.0&lt;/span> &lt;span class="o">//&lt;/span> &lt;span class="mf">3.0&lt;/span> &lt;span class="c1"># =&amp;gt; -2.0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 注意，我们可以可以import division 模块(关于import教程第6节会有涉及)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 这样 &amp;#39;/&amp;#39; 就可以实现普通的我们所熟悉的除法功能了&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 貌似python3里面&amp;#39;/&amp;#39;默认就是普通除法模式&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">__future__&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">division&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">11&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="mi">4&lt;/span> &lt;span class="c1"># =&amp;gt; 2.75 ...普通除法&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">11&lt;/span> &lt;span class="o">//&lt;/span> &lt;span class="mi">4&lt;/span> &lt;span class="c1"># =&amp;gt; 2 ...取整除法&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 模/取余操作&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">7&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">3&lt;/span> &lt;span class="c1"># =&amp;gt; 1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 乘方 (x 的 y 次方)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">2&lt;/span> &lt;span class="o">**&lt;/span> &lt;span class="mi">4&lt;/span> &lt;span class="c1"># =&amp;gt; 16&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 用括号强制改变算术的结合律&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="c1"># =&amp;gt; 8&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 布尔值的操作或者叫逻辑运算&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 注意 &amp;#34;and&amp;#34; 和 &amp;#34;or&amp;#34; 是区分大小写的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kc">True&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="kc">False&lt;/span> &lt;span class="c1"># =&amp;gt; False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kc">False&lt;/span> &lt;span class="ow">or&lt;/span> &lt;span class="kc">True&lt;/span> &lt;span class="c1"># =&amp;gt; True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 注意布尔操作跟整数搅在一起的时候&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">0&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="c1"># =&amp;gt; 0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">-&lt;/span>&lt;span class="mi">5&lt;/span> &lt;span class="ow">or&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="c1"># =&amp;gt; -5&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">0&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="kc">False&lt;/span> &lt;span class="c1"># =&amp;gt; True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="kc">True&lt;/span> &lt;span class="c1"># =&amp;gt; False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">1&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="kc">True&lt;/span> &lt;span class="c1"># =&amp;gt; True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 用not来逻辑取反&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="ow">not&lt;/span> &lt;span class="kc">True&lt;/span> &lt;span class="c1"># =&amp;gt; False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="ow">not&lt;/span> &lt;span class="kc">False&lt;/span> &lt;span class="c1"># =&amp;gt; True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 相等判断用 ==&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">1&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="c1"># =&amp;gt; True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="c1"># =&amp;gt; False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 不等用 !=&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">1&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="c1"># =&amp;gt; False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">2&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="c1"># =&amp;gt; True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 更多的比较&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">1&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">10&lt;/span> &lt;span class="c1"># =&amp;gt; True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">1&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">10&lt;/span> &lt;span class="c1"># =&amp;gt; False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">2&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="c1"># =&amp;gt; True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">2&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="c1"># =&amp;gt; True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 比较可以串起来&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">1&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">3&lt;/span> &lt;span class="c1"># =&amp;gt; True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">2&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">3&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="c1"># =&amp;gt; False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 用 &amp;#34; 或 &amp;#39; 来创建字符串&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;This is a string.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1">&amp;#39;This is also a string.&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 字符串也是可以相加的!&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;Hello &amp;#34;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="s2">&amp;#34;world!&amp;#34;&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;Hello world!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 不用 &amp;#39;+&amp;#39; 号也能加&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;Hello &amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;world!&amp;#34;&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;Hello world!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ... 甚至可以相乘&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;Hello&amp;#34;&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">3&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;HelloHelloHello&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 字符串可以当成是字符组成的列表&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;This is a string&amp;#34;&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#39;T&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 可以拿到字符串的长度&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;This is a string&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; 16&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 可以用 % 来格式化字符串&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Even though the % string operator will be deprecated on Python 3.1 and removed&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 即使 % 操作在Python 3.1以后会被废弃和移除&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 不过知道这些代码是如何工作的总不是坏事&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;apple&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;lemon&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">z&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;The items in the basket are &lt;/span>&lt;span class="si">%s&lt;/span>&lt;span class="s2"> and &lt;/span>&lt;span class="si">%s&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 新一点的格式化字符串的方式是使用format方法&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 这个方法更好一些&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2"> is a &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;This&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;placeholder&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{0}&lt;/span>&lt;span class="s2"> can be &lt;/span>&lt;span class="si">{1}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;strings&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;formatted&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 如果你不想数数的话，你还可以使用关键字&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{name}&lt;/span>&lt;span class="s2"> wants to eat &lt;/span>&lt;span class="si">{food}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;Bob&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">food&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;lasagna&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># None是一个对象&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 所以你是有对象的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kc">None&lt;/span> &lt;span class="c1"># =&amp;gt; None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 不要使用 &amp;#34;==&amp;#34; 符号进行对象和None的比较&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 要使用 &amp;#34;is&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;etc&amp;#34;&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="kc">None&lt;/span> &lt;span class="c1"># =&amp;gt; False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kc">None&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="kc">None&lt;/span> &lt;span class="c1"># =&amp;gt; True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># &amp;#39;is&amp;#39;符号用来测试对象的之间的相当性&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 在比较基本类型的时候可能用处不大&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 不过用在对象的比较方面却是很有用的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Any object can be used in a Boolean context.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 任何的对象都可以在布尔值的上下文中使用&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 下面的值会被认为是false的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># - None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># - zero of any numeric type (e.g., 0, 0L, 0.0, 0j)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># - 任何数字类型的0 (比如, 0, 0L, 0.0, 0j)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># - 空序列 (比如, &amp;#39;&amp;#39;, (), [])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># - 空的容器类型 (比如, {}, set())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># - 某些情况下用户自定义的类的实例&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 见: https://docs.python.org/2/reference/datamodel.html#object.__nonzero__&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">#&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 其他的值都被认为是true(使用bool()测试这些值的时候会返回True).&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">bool&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">bool&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; False&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p></description></item><item><title>（一）Docker介绍</title><link>https://itest2025.pages.dev/tutorials/30-001-%E4%B8%80docker%E4%BB%8B%E7%BB%8D/</link><pubDate>Mon, 22 Jan 2018 14:55:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/30-001-%E4%B8%80docker%E4%BB%8B%E7%BB%8D/</guid><description>&lt;h4 id="什么就docker">什么就Docker?&lt;/h4>
&lt;hr>
&lt;p>Docker是一个开源项目， 诞生于2013年初，最初是dotCloud公司内部的一个业余项目。它基于Google公司推出的Go语言实现。项目后来加入了Linux基金会，遵从了Apache 2.0协议，项目代码在&lt;a href="https://github.com/docker" target="_blank" rel="noopener noreffer ">GitHub&lt;/a> 上进行维护。&lt;/p>
&lt;p>Docker项目的目标是实现轻量级的操作系统虚拟化解决方案。Docker的基础是Linux容器（LXC）等技术。在LXC的基础上Docker进行了进一步的封装，让用户不需要去关心容器的管理，使得操作更为简便。用户操作Docker的容器就像操作一个快速轻量级的虚拟机一样简单。&lt;/p>
&lt;h4 id="为什么要使用docker">为什么要使用Docker?&lt;/h4>
&lt;hr>
&lt;p>Docker 相比传统虚拟机有诸多优势。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>启动速度更快：&lt;/strong> 秒级启动。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>快速的部署和交付：&lt;/strong> 开发者可以使用一个标准的镜像来构建一套开发容器，开发完成之后， 运维人员可以直接使用这个容器来部署代码。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>更高效的虚拟化：&lt;/strong> 它是内核级的虚拟化，因此可以实现更高的性能和效率。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>高效的迁移：&lt;/strong> Docker可以运行在不同的平台，用户可以轻松的将一个应用从一个平台迁移到另一个平台。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>节省开支：&lt;/strong> Docker容器除了运行其中应用外，基本不消耗额外的系统资源，一台设备可以运行上千个容器。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h4 id="docker基本概念">Docker基本概念&lt;/h4>
&lt;hr>
&lt;p>Docker包括三个基本概念&lt;/p>
&lt;ul>
&lt;li>镜像（Image）&lt;/li>
&lt;/ul>
&lt;p>Docker提供了一个很简单的机制来创建镜像或者更新现有的镜像，用户甚至可以直接从其他人那里下载一个已经做好的镜像来直接使用。镜像可以用来创建Docker容器。&lt;/p>
&lt;ul>
&lt;li>容器（Container）&lt;/li>
&lt;/ul>
&lt;p>容器是从镜像创建的运行实例。它可以被启动、开始、停止、 删除。每个容器都是相互隔离的、保证安全的平台。&lt;/p>
&lt;ul>
&lt;li>仓库（Repository）&lt;/li>
&lt;/ul>
&lt;p>仓库是集中存放镜像文件的场所。仓库分为公开仓库（Public）和私有仓库（Private） 两种形式。&lt;/p>
&lt;p>最大的公开仓库是 &lt;a href="https://hub.docker.com" target="_blank" rel="noopener noreffer ">Docker	Hub&lt;/a>，存放了数量庞大的镜像供用户下载。 &lt;a href="https://www.docker-cn.com/registry-mirror" target="_blank" rel="noopener noreffer ">中国官方镜像加速&lt;/a>&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1606256485258-ae784908699f?w=300"
 data-srcset="https://images.unsplash.com/photo-1606256485258-ae784908699f?w=300, https://images.unsplash.com/photo-1606256485258-ae784908699f?w=300 1.5x, https://images.unsplash.com/photo-1606256485258-ae784908699f?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1606256485258-ae784908699f?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（一）从这里开始</title><link>https://itest2025.pages.dev/tutorials/16-001-%E4%B8%80%E4%BB%8E%E8%BF%99%E9%87%8C%E5%BC%80%E5%A7%8B/</link><pubDate>Wed, 17 Jan 2018 14:55:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/16-001-%E4%B8%80%E4%BB%8E%E8%BF%99%E9%87%8C%E5%BC%80%E5%A7%8B/</guid><description>&lt;p>其实，本Java教程是写给自己的，所以，肯定不是零基础，也不会告诉你Java有多么的好，也不会吹嘘它能做多少事情。&lt;/p>
&lt;p>这里简单的总结一下对我编程语言的学习过程。我真正在开始学习Java是在2010年的时候，当时是希望找一份Java开发的工作，于是，开始看马士兵、李兴华他们的Java视频教程。可以跟着例子敲，但关掉它们的视频，我却写不出一行代码。&lt;/p>
&lt;p>归结原因有两点：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>自己基础太差，大学时没有培养自己的编程能力，除了对C语言有些了解。再加上自己确实比较笨。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>没有以需求驱动，也不具备这样的能力。总之，也不知道自己学的这些代码和工作中的项目有什么直接关系。边学边忘。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>后来，在工作中，我开始学Python，这一次很清楚自己要python + Selenium实现自动化，再加上整个项目组用Python开发社区的项目，耳听目染的达到了学以致用的目的。我觉得一部分原因是因为Python确实简单，另一方面是有这样的学习环境。&lt;/p>
&lt;p>再回过头来学Java的时候，我是边用边学的，因为有Python的基础，再加我很明确要用Java实现什么功能。但是，对Java语言中的诸多概念仍然处于模糊状态。&lt;/p>
&lt;p>所以，通过整理该系列文章的同学，自己再系统的梳理一下Java的知识。&lt;/p>
&lt;p>&lt;strong>学编程无技巧，多练，多思考。&lt;/strong>&lt;/p>
&lt;p>Java环境的搭建，参考：&lt;a href="https://itest2025.pages.dev/selenium_java/install-java/" rel="">环境安装之Java&lt;/a>&lt;/p>
&lt;p>开发工具为IntelliJ IDEA，参考：&lt;a href="https://itest2025.pages.dev/selenium_java/install-idea/" rel="">环境安装之IntelliJ IDEA&lt;/a> ，更系统的教程：&lt;a href="https://itest2025.pages.dev/idea/" rel="">《IntelliJ-IDEA-Tutorial》&lt;/a>&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1611647832580-377268dba7cb?w=300"
 data-srcset="https://images.unsplash.com/photo-1611647832580-377268dba7cb?w=300, https://images.unsplash.com/photo-1611647832580-377268dba7cb?w=300 1.5x, https://images.unsplash.com/photo-1611647832580-377268dba7cb?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1611647832580-377268dba7cb?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>TDD实战（一）开发模式</title><link>https://itest2025.pages.dev/tutorials/32-001-tdd%E5%AE%9E%E6%88%98%E4%B8%80%E5%BC%80%E5%8F%91%E6%A8%A1%E5%BC%8F/</link><pubDate>Mon, 08 Jan 2018 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/32-001-tdd%E5%AE%9E%E6%88%98%E4%B8%80%E5%BC%80%E5%8F%91%E6%A8%A1%E5%BC%8F/</guid><description>&lt;h4 id="tdd-介绍">TDD 介绍&lt;/h4>
&lt;hr>
&lt;p>TDD是测试驱动开发（Test-Driven Development）的英文简称，是敏捷开发中的一项核心实践和技术，也是一种设计方法论。TDD的原理是在开发功能代码之前，先编写单元测试用例代码，测试代码确定需要编写什么产品代码。TDD虽是敏捷方法的核心实践，但不只适用于XP（Extreme Programming），同样可以适用于其他开发方法和过程。&lt;/p>
&lt;p>&amp;ndash; &lt;strong>百度百科&lt;/strong>&lt;/p>
&lt;h4 id="准备工具">准备工具&lt;/h4>
&lt;hr>
&lt;p>TDD只是一种开发模式，它并没有用到新的技术。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Java : 因为它是主流的编程语言，应用广泛，相关实践也非常多。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="http://www.testclass.net/idea/" target="_blank" rel="noopener noreffer ">IntelliJ-IDEA&lt;/a> : Java 主流IDE（集成开发工具）。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="http://www.testclass.net/junit/" target="_blank" rel="noopener noreffer ">JUnit&lt;/a> ： Java 主流单元测试框架，当然，你选择 &lt;a href="http://www.testclass.net/testng/" target="_blank" rel="noopener noreffer ">TestNG&lt;/a> 也是完全可以的。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Gradle : 构建工具。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h4 id="tdd-开发模式">TDD 开发模式&lt;/h4>
&lt;hr>
&lt;p>&lt;font color="red">“&lt;strong>红灯 &amp;ndash; 绿灯 &amp;ndash; 重构&lt;/strong>”&lt;/font> 流程是TDD的基石。 这个过程就像打乒乓球，快速的在测试代码和实现代码之间切换。&lt;/p>
&lt;p>TDD 开的过程： 每次只考虑一个需求。首先编写一个测试，看看它是否未通过；然后编写实现这个测试的代码，运行所有测试并验证它们是否全部通过；最后，通过重构改进代码。不断重复这个过程，直到成功实现所有需求。&lt;/p>
&lt;h4 id="需求">需求&lt;/h4>
&lt;hr>
&lt;p>本系列实战 “&lt;strong>井字游戏&lt;/strong>” ，这是一个非常简单的小游戏。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/tdd_jingzi_game.png"
 data-srcset="http://img.testclass.net/tdd_jingzi_game.png, http://img.testclass.net/tdd_jingzi_game.png 1.5x, http://img.testclass.net/tdd_jingzi_game.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/tdd_jingzi_game.png"
 title="http://img.testclass.net/tdd_jingzi_game.png" />&lt;/p>
&lt;p>&lt;strong>说明：&lt;/strong>&lt;/p>
&lt;p>是一种在3*3格子上进行的连珠游戏，和五子棋比较类似，由于棋盘一般不画边框，格线排成井字故得名。游戏需要的工具仅为纸和笔，然后由分别代表O和X的两个游戏者轮流在格子里留下标记（一般来说先手者为X）。由最先在任意一条直线上成功连接三个标记的一方获胜。&lt;/p>
&lt;p>不会玩的同学可以先去完两把：&lt;a href="http://www.4399.com/flash/46864_3.htm" target="_blank" rel="noopener noreffer ">井字小游戏&lt;/a>。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1542435503-956c469947f6?w=300"
 data-srcset="https://images.unsplash.com/photo-1542435503-956c469947f6?w=300, https://images.unsplash.com/photo-1542435503-956c469947f6?w=300 1.5x, https://images.unsplash.com/photo-1542435503-956c469947f6?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1542435503-956c469947f6?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>Android测试（一）：在Android中测试App</title><link>https://itest2025.pages.dev/tutorials/17-001-android%E6%B5%8B%E8%AF%95%E4%B8%80%E5%9C%A8android%E4%B8%AD%E6%B5%8B%E8%AF%95app/</link><pubDate>Wed, 20 Dec 2017 14:55:12 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/17-001-android%E6%B5%8B%E8%AF%95%E4%B8%80%E5%9C%A8android%E4%B8%AD%E6%B5%8B%E8%AF%95app/</guid><description>&lt;p>原文：https://developer.android.com/training/testing/index.html&lt;/p>
&lt;p>&lt;strong>测试你的App是开发过程中的重要组成部分。通过对应用程序持续的运行测试，你可以验证程序的正确性、功能和可用在发布之前。&lt;/strong>&lt;/p>
&lt;p>测试还提供了以下优点：&lt;/p>
&lt;ul>
&lt;li>快速反馈失败。&lt;/li>
&lt;li>开发周期的早期问题检测。&lt;/li>
&lt;li>安全地重构代码，让你优化代码而不用担心回归。&lt;/li>
&lt;li>稳定开发速度，帮助你减少技术债务。&lt;/li>
&lt;/ul>
&lt;p>这里的特指测试通过代码实现的“单元”测试。所以，它可以更早、更快的帮我们发现问题，使我们的代码重构更有信心；单元测试虽然前期编写会比较耗时，但是它可以有效的代码的质量，不会导致项目后期代码充满坏味道，严重拖慢开发进度；所以，减少你技术债务。&lt;/p>
&lt;h3 id="资源">资源&lt;/h3>
&lt;hr>
&lt;p>在Android测试库、Android平台和开源社区都提供了帮助你编写Android应用测试的工具：&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/android_testing_app.png"
 data-srcset="http://img.testclass.net/android_testing_app.png, http://img.testclass.net/android_testing_app.png 1.5x, http://img.testclass.net/android_testing_app.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/android_testing_app.png"
 title="http://img.testclass.net/android_testing_app.png" />&lt;/p>
&lt;h4 id="espesso">Espesso&lt;/h4>
&lt;hr>
&lt;p>Espresso是android应用开发自带测试库。他是一款白盒风格的UI测试工具。UI测试就都是黑盒的么？为什么会是白盒风格。&lt;/p>
&lt;p>说白盒是因为，通过Espresso编写测试调用Android控件的方式和 Android开发中是一样的。
来看一段Android开发中，Activity中编写的代码。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="cm">/** Called when the user clicks the Send button */&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">sendMessage&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">View&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">view&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// Do something in response to button&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Intent&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">intent&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Intent&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">this&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">DisplayMessageActivity&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">class&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">EditText&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">editText&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">EditText&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">findViewById&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">id&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">edit_message&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">editText&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">getText&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="na">toString&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">intent&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">putExtra&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">EXTRA_MESSAGE&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">startActivity&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">intent&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>通过 &lt;code>R.id.edit_message&lt;/code> 调用布局文件中输入框中的内容，并转交到另外一个Activity处理。&lt;/p></description></item><item><title>Fiddler（一）介绍与安装</title><link>https://itest2025.pages.dev/tutorials/23-001-fiddler%E4%B8%80%E4%BB%8B%E7%BB%8D%E4%B8%8E%E5%AE%89%E8%A3%85/</link><pubDate>Tue, 19 Dec 2017 13:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/23-001-fiddler%E4%B8%80%E4%BB%8B%E7%BB%8D%E4%B8%8E%E5%AE%89%E8%A3%85/</guid><description>&lt;p>Fildder是一款免费的web调试代理工具，支持任何浏览器、系统或平台。&lt;/p>
&lt;p>官方网站：https://www.telerik.com/fiddler&lt;/p>
&lt;h4 id="工作原理">工作原理&lt;/h4>
&lt;hr>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/fiddler_01.png"
 data-srcset="http://img.testclass.net/fiddler_01.png, http://img.testclass.net/fiddler_01.png 1.5x, http://img.testclass.net/fiddler_01.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/fiddler_01.png"
 title="http://img.testclass.net/fiddler_01.png" />&lt;/p>
&lt;p>Fiddler是以代理Web服务器的形式工作的,浏览器与服务器之间通过建立TCP连接以HTTP协议进行通信，浏览器默认通过自己发送HTTP请求到服务器，它使用代理地址:&lt;code>127.0.0.1&lt;/code>, 端口:&lt;code>8888&lt;/code>。&lt;/p>
&lt;p>开启Fiddler后，通过浏览器访问：http://127.0.0.1:8888&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/fiddler_02.png"
 data-srcset="http://img.testclass.net/fiddler_02.png, http://img.testclass.net/fiddler_02.png 1.5x, http://img.testclass.net/fiddler_02.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/fiddler_02.png"
 title="http://img.testclass.net/fiddler_02.png" />&lt;/p>
&lt;h4 id="安装">安装&lt;/h4>
&lt;hr>
&lt;p>点击&lt;a href="https://www.telerik.com/download/fiddler" target="_blank" rel="noopener noreffer ">这里&lt;/a>下载Fiddler。不过，更简单的方式是直接在百度中搜索，通过百度软件中心下载。&lt;/p>
&lt;p>安装过程这里省略。启动Fiddler，主界面如下：&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/fiddler_03.png"
 data-srcset="http://img.testclass.net/fiddler_03.png, http://img.testclass.net/fiddler_03.png 1.5x, http://img.testclass.net/fiddler_03.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/fiddler_03.png"
 title="http://img.testclass.net/fiddler_03.png" />&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1468428936365-099c2f70e495?w=300"
 data-srcset="https://images.unsplash.com/photo-1468428936365-099c2f70e495?w=300, https://images.unsplash.com/photo-1468428936365-099c2f70e495?w=300 1.5x, https://images.unsplash.com/photo-1468428936365-099c2f70e495?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1468428936365-099c2f70e495?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>爬虫介绍</title><link>https://itest2025.pages.dev/tutorials/27-001-%E7%88%AC%E8%99%AB%E4%BB%8B%E7%BB%8D/</link><pubDate>Mon, 18 Dec 2017 02:52:34 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/27-001-%E7%88%AC%E8%99%AB%E4%BB%8B%E7%BB%8D/</guid><description>&lt;h3 id="什么是爬虫">什么是爬虫&lt;/h3>
&lt;p>爬虫实际上就是采集网络上数据的一段程序，如果把互联网比喻成一个蜘蛛网，那么蜘蛛就是在网上爬来爬去的蜘蛛，爬虫程序通过请求url地址，根据响应的内容进行解析采集数据， 比如：如果响应内容是html，分析dom结构，进行dom解析、或者正则匹配，如果响应内容是xml/json数据，就可以转数据对象，然后对数据进行解析。&lt;/p>
&lt;h3 id="资源视角">资源视角&lt;/h3>
&lt;p>互联网上一切都是资源，比如视频资源，新闻资源等，爬虫实际上就是批量将别人的资源采集下来变成自己的资源的程序。&lt;/p>
&lt;h3 id="爬虫的一些例子">爬虫的一些例子&lt;/h3>
&lt;ul>
&lt;li>从其他网站爬取特定类型的商品信息，然后发布在自己的网上商城里&lt;/li>
&lt;li>从其他网站爬取一些特定图片，展示在自己的网站里&lt;/li>
&lt;li>搜索引擎爬取网站基本信息，收录在自己的搜索结果里&lt;/li>
&lt;/ul>
&lt;h3 id="最简单的爬虫套路">最简单的爬虫套路&lt;/h3>
&lt;ul>
&lt;li>访问1个站点，获取该站点的html代码&lt;/li>
&lt;li>解析html代码，把感兴趣的数据从html代码里分离出来&lt;/li>
&lt;li>保存这些数据&lt;/li>
&lt;/ul>
&lt;h3 id="实际例子">实际例子&lt;/h3>
&lt;p>假设我需要抓取&lt;a href="http://www.itest.info/courses" target="_blank" rel="noopener noreffer ">重定向科技目前开设的所有测试课程&lt;/a>，那么&lt;/p>
&lt;ul>
&lt;li>先访问&lt;a href="http://www.itest.info/courses" target="_blank" rel="noopener noreffer ">所有课程页面&lt;/a>，把html代码拿到&lt;/li>
&lt;li>解析html代码，从里面抠出来课程的名称和详情地址&lt;/li>
&lt;li>保存课程的名称和地址&lt;/li>
&lt;/ul>
&lt;p>这样就可以实现一个最简单的网络爬虫了。&lt;/p>
&lt;h3 id="爬虫对于测试的意义">爬虫对于测试的意义&lt;/h3>
&lt;p>有时候自己去造一些测试数据是很麻烦的事情，这时候我们就可以使用爬虫去获取其他站点的类似数据，对数据进行加工后就可以当测试数据来使用了。&lt;/p>
&lt;h3 id="reference">Reference&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="https://blog.thankbabe.com/2017/09/25/spider" target="_blank" rel="noopener noreffer ">大话爬虫的基本套路&lt;/a>&lt;/li>
&lt;li>推荐另一个不错的&lt;a href="https://zhuanlan.zhihu.com/p/21479334" target="_blank" rel="noopener noreffer ">python爬虫教程&lt;/a>，应该是基于python2.7&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1422493757035-1e5e03968f95?w=300"
 data-srcset="https://images.unsplash.com/photo-1422493757035-1e5e03968f95?w=300, https://images.unsplash.com/photo-1422493757035-1e5e03968f95?w=300 1.5x, https://images.unsplash.com/photo-1422493757035-1e5e03968f95?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1422493757035-1e5e03968f95?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（一）Maven 介绍</title><link>https://itest2025.pages.dev/tutorials/41-001-%E4%B8%80maven-%E4%BB%8B%E7%BB%8D/</link><pubDate>Sat, 25 Nov 2017 12:55:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/41-001-%E4%B8%80maven-%E4%BB%8B%E7%BB%8D/</guid><description>&lt;p>Apache Maven 是一个软件项目管理的综合工具。基于项目对象模型（POM）的概念，Maven 可以从一个中心资料片管理项目构建，报告和文件。本章将和你一起学习 Maven 的基本使用。&lt;/p>
&lt;p>官方网站：http://maven.apache.org/&lt;/p>
&lt;h4 id="maven-介绍">Maven 介绍？&lt;/h4>
&lt;hr>
&lt;p>Maven 是一个项目管理和综合工具。 Maven 提供了开发人员构建一个完整的生命周期框架。 开发团队可以自动完成项目的基础工具建设， Maven 使用标准的目录结构和默认构建生命周期。在多个开发团队环境时， Maven 可以设置按标准在非常短的时间里完成配置工作。 由于大部分项目的设置都很简单， 并且可重复使用， Maven 让开发人员的工作更轻松， 同时创建报表， 检查， 构建和测试自动化设置。&lt;/p>
&lt;p>Maven 提供了开发人员的方式来管理：&lt;/p>
&lt;ul>
&lt;li>Builds&lt;/li>
&lt;li>Documentation&lt;/li>
&lt;li>Reporting&lt;/li>
&lt;li>Dependencies&lt;/li>
&lt;li>SCM（Software Configuration Management）&lt;/li>
&lt;li>Releases&lt;/li>
&lt;li>Distribution&lt;/li>
&lt;li>mailing list&lt;/li>
&lt;/ul>
&lt;p>概括地说， Maven 简化和标准化项目建设过程。 处理编译， 分配， 文档， 团队协作和其他任务的无缝连接。 Maven 增加可重用性并负责建立相关的任务。&lt;/p>
&lt;h4 id="为什么学习-maven">为什么学习 Maven？&lt;/h4>
&lt;hr>
&lt;p>不学习 Maven 不能做 Java 开发么？ 当然不是，但是随着你 Java 开发越用越熟悉，涉及到第三方包也会越来越多，比如 web开发，自动化测试，这里面会用到大量的第三方库，不同库之间的依赖关系，如何快速有效果的管理这些库；以及在多人开发的团队中，如何有效的保证每个开发人员所使用的第三方库的一致性。这个时间 Maven 就起来了非常重要的作用。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1434030216411-0b793f4b4173?w=300"
 data-srcset="https://images.unsplash.com/photo-1434030216411-0b793f4b4173?w=300, https://images.unsplash.com/photo-1434030216411-0b793f4b4173?w=300 1.5x, https://images.unsplash.com/photo-1434030216411-0b793f4b4173?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1434030216411-0b793f4b4173?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（一）mock 与 Mockito 介绍</title><link>https://itest2025.pages.dev/tutorials/45-001-%E4%B8%80mock-%E4%B8%8E-mockito-%E4%BB%8B%E7%BB%8D/</link><pubDate>Sat, 25 Nov 2017 12:55:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/45-001-%E4%B8%80mock-%E4%B8%8E-mockito-%E4%BB%8B%E7%BB%8D/</guid><description>&lt;h4 id="什么是mock-">什么是mock ？&lt;/h4>
&lt;hr>
&lt;p>mock在翻译过来是模拟的意思。这里要介绍的mock是辅助单元测试的一个模块。它允许你用模拟对象来替换你的系统的部分，并对它们已使用的方式进行断言。&lt;/p>
&lt;p>什么意思呢？说的直白些，我们要测试一个模块（类、方法或接口），但是这个模块还没有实现，或者它属于第三方模块，真的去调用会比较麻烦，这个时候就可以借助 mock 技术，给该模块设置预期结果。&lt;/p>
&lt;p>可能你和我一样会有疑问，把要测试的模块都mock掉了，这不是自己骗自己嘛，那我们还测什么？&lt;/p>
&lt;p>但是，在实际生产中的项目是非常复杂的，对其进行单元测试的时候，会遇到以下问题：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>接口的依赖&lt;/p>
&lt;/li>
&lt;li>
&lt;p>外部接口调用&lt;/p>
&lt;/li>
&lt;li>
&lt;p>测试环境非常复杂&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>单元测试应该只针对当前单元进行测试, 所有的内部或外部的依赖应该是稳定的, 已经在别处进行测试过的.使用mock 就可以对外部依赖组件实现进行模拟并且替换掉，从而使得单元测试将焦点只放在当前的单元功能。&lt;/p>
&lt;p>&lt;strong>mock技术的目的和作用就是模拟一些在应用中不容易构造或者比较复杂的对象，从而把测试与测试边界以外的对象隔离开。&lt;/strong>&lt;/p>
&lt;h4 id="什么是-mockito-">什么是 Mockito ?&lt;/h4>
&lt;hr>
&lt;p>官方网站：http://site.mockito.org/&lt;/p>
&lt;p>Tasty mocking framework for unit tests in Java&lt;/p>
&lt;p>优雅的mock框架用于Java的单元测试。&lt;/p>
&lt;p>GitHub 地址：https://github.com/mockito/mockito&lt;/p>
&lt;h4 id="安装-mockito">安装 Mockito&lt;/h4>
&lt;hr>
&lt;p>以 &lt;a href="https://itest2025.pages.dev/maven/" rel="">Maven&lt;/a> 方式安装为例。&lt;/p>
&lt;pre tabindex="0">&lt;code> &amp;lt;dependency&amp;gt;
 &amp;lt;groupId&amp;gt;org.mockito&amp;lt;/groupId&amp;gt;
 &amp;lt;artifactId&amp;gt;mockito-all&amp;lt;/artifactId&amp;gt;
 &amp;lt;version&amp;gt;2.0.2-beta&amp;lt;/version&amp;gt;
 &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code>&lt;/pre>&lt;p>因为 Mockito是其于单元测试的框架，所以，接下来的练习最好在单元框架框架下运行，通过 Maven 配置 JUnit 单元测试框架。&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;lt;dependency&amp;gt;
 &amp;lt;groupId&amp;gt;junit&amp;lt;/groupId&amp;gt;
 &amp;lt;artifactId&amp;gt;junit&amp;lt;/artifactId&amp;gt;
 &amp;lt;version&amp;gt;4.12&amp;lt;/version&amp;gt;
 &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code>&lt;/pre>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1508830524289-0adcbe822b40?w=300"
 data-srcset="https://images.unsplash.com/photo-1508830524289-0adcbe822b40?w=300, https://images.unsplash.com/photo-1508830524289-0adcbe822b40?w=300 1.5x, https://images.unsplash.com/photo-1508830524289-0adcbe822b40?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1508830524289-0adcbe822b40?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（一）TestNG介绍与安装</title><link>https://itest2025.pages.dev/tutorials/36-001-%E4%B8%80testng%E4%BB%8B%E7%BB%8D%E4%B8%8E%E5%AE%89%E8%A3%85/</link><pubDate>Sat, 25 Nov 2017 12:55:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/36-001-%E4%B8%80testng%E4%BB%8B%E7%BB%8D%E4%B8%8E%E5%AE%89%E8%A3%85/</guid><description>&lt;h4 id="介绍">介绍&lt;/h4>
&lt;hr>
&lt;p>TestNG 官方网址：http://testng.org/doc/&lt;/p>
&lt;p>TestNG是一个测试框架的灵感来自JUnit和NUnit,但引入一些新的功能，使它更强大和更容易使用，如：&lt;/p>
&lt;ul>
&lt;li>注释。&lt;/li>
&lt;li>在任意大线程池中运行测试，并提供各种策略（所有方法都在自己的线程中，每个测试类有一个线程，等等）。&lt;/li>
&lt;li>测试你的代码多线程是安全的。&lt;/li>
&lt;li>灵活的测试配置。&lt;/li>
&lt;li>数据驱动的测试支持（@dataProvider）。&lt;/li>
&lt;li>参数支持。&lt;/li>
&lt;li>强大的执行模型(不再有TestSuite)。&lt;/li>
&lt;li>通过各种工具和插件支持（Eclipse, IDEA, Maven 等..）。&lt;/li>
&lt;li>通过进一步的灵活性Beanshell。&lt;/li>
&lt;li>运行时和日志的默认JDK功能(无依赖性)。&lt;/li>
&lt;li>应用服务器测试的相关方法。&lt;/li>
&lt;/ul>
&lt;p>TestNG 表示下一代(Next Generation的首字母)。它的设计覆盖所有类别的测试：单元、功能、端到端、集成等。&lt;/p>
&lt;h4 id="安装">安装&lt;/h4>
&lt;hr>
&lt;p>本教程基于 &lt;a href="https://itest2025.pages.dev/idea/" rel="">IntelliJ IDEA&lt;/a> 和 &lt;a href="https://itest2025.pages.dev/maven/" rel="">Maven&lt;/a> ，所以，这里只介绍 Maven 的安装方式。&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;lt;!-- https://mvnrepository.com/artifact/org.testng/testng --&amp;gt;
&amp;lt;dependency&amp;gt;
 &amp;lt;groupId&amp;gt;org.testng&amp;lt;/groupId&amp;gt;
 &amp;lt;artifactId&amp;gt;testng&amp;lt;/artifactId&amp;gt;
 &amp;lt;version&amp;gt;6.13&amp;lt;/version&amp;gt;
 &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code>&lt;/pre>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1498758536662-35b82cd15e29?w=300"
 data-srcset="https://images.unsplash.com/photo-1498758536662-35b82cd15e29?w=300, https://images.unsplash.com/photo-1498758536662-35b82cd15e29?w=300 1.5x, https://images.unsplash.com/photo-1498758536662-35b82cd15e29?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1498758536662-35b82cd15e29?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>如何安装requests?</title><link>https://itest2025.pages.dev/tutorials/42-001-%E5%A6%82%E4%BD%95%E5%AE%89%E8%A3%85requests/</link><pubDate>Wed, 22 Nov 2017 03:23:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/42-001-%E5%A6%82%E4%BD%95%E5%AE%89%E8%A3%85requests/</guid><description>&lt;p>&lt;a href="http://docs.python-requests.org/en/master/user/install/#install" target="_blank" rel="noopener noreffer ">官方文档&lt;/a>&lt;/p>
&lt;p>官方给出的安装方式是使用&lt;a href="http://pipenv.org/" target="_blank" rel="noopener noreffer ">pipenv&lt;/a>&lt;/p>
&lt;pre tabindex="0">&lt;code>pipenv install requests
&lt;/code>&lt;/pre>&lt;p>当然也可以直接使用pip安装&lt;/p>
&lt;pre tabindex="0">&lt;code>pip install requests
&lt;/code>&lt;/pre>&lt;p>还可以从源码安装&lt;/p>
&lt;pre tabindex="0">&lt;code>git clone git://github.com/requests/requests.git
cd requests
pip install .
&lt;/code>&lt;/pre>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1559523182-a284c3fb7cff?w=300"
 data-srcset="https://images.unsplash.com/photo-1559523182-a284c3fb7cff?w=300, https://images.unsplash.com/photo-1559523182-a284c3fb7cff?w=300 1.5x, https://images.unsplash.com/photo-1559523182-a284c3fb7cff?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1559523182-a284c3fb7cff?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（一）JUnit 介绍</title><link>https://itest2025.pages.dev/tutorials/31-001-%E4%B8%80junit-%E4%BB%8B%E7%BB%8D/</link><pubDate>Mon, 13 Nov 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/31-001-%E4%B8%80junit-%E4%BB%8B%E7%BB%8D/</guid><description>&lt;h4 id="什么是单元测试">什么是单元测试？&lt;/h4>
&lt;hr>
&lt;p>单元测试负责对最小的软件设计单元（模块）进行验证，它使用软件设计文档中对模块的描述作为指南，对重要的程序分支进行测试以发现模块中的错误。&lt;/p>
&lt;p>单元测试是个听起来高大上的话题，貌似只有白盒测试或开发人员才能胜任这项工作。其实，它并没有想象的那么高级。&lt;/p>
&lt;h4 id="什么是单元测试框架">什么是单元测试框架？&lt;/h4>
&lt;hr>
&lt;p>对于单元测试框架来讲，它主要完成以下几件事。&lt;/p>
&lt;p>&lt;strong>提供用例组织与执行：&lt;/strong>
当你的测试用例只有几条时，可以不必考虑用例的组织，但是，当测试用例达到成百上千条时，大量的测试用例堆砌在一起，就产生了扩展性与维护性等问题，需要考虑用例的规范与组织
问题了。单元测试框架就是用来解决这个问题的。。&lt;/p>
&lt;p>&lt;strong>提供丰富的断言方法：&lt;/strong> 不论是功能测试，还是单元测试，在用例执行完成之后都需要将实际结果与进行预期结果的进行比较（断言），从而断定用例是否执行通过。单元测试框架一般会提供丰富的断言方法。例如，判断相等/不等、包含/不包含、True/False的断言方法等。&lt;/p>
&lt;p>&lt;strong>提供丰富的日志：&lt;/strong> 当测试用例执行失败时能抛出清晰的失败原因，当所有用例执行完成后能提供丰富的执行结果。例如，总执行时间、失败用例数、成功用例数等。&lt;/p>
&lt;p>从这些特性来看单元测试框架的作用是：&lt;strong>帮助我们更自动化测试完成测试，所以，它是自动化测试的基础。&lt;/strong>&lt;/p>
&lt;h4 id="什么是-junit">什么是 JUnit？&lt;/h4>
&lt;hr>
&lt;p>Junit 官网：http://junit.org/&lt;/p>
&lt;p>JUnit 是一个编写可重复测试的简单框架。它是单元测试框架的 xUnit 架构的一个实例。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1581093577421-f561a654a353?w=300"
 data-srcset="https://images.unsplash.com/photo-1581093577421-f561a654a353?w=300, https://images.unsplash.com/photo-1581093577421-f561a654a353?w=300 1.5x, https://images.unsplash.com/photo-1581093577421-f561a654a353?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1581093577421-f561a654a353?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>1. 基本概念</title><link>https://itest2025.pages.dev/tutorials/35-001-1-%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5/</link><pubDate>Thu, 09 Nov 2017 06:23:31 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/35-001-1-%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5/</guid><description>&lt;p>&lt;a href="https://docs.python.org/2/library/unittest.html#module-unittest" target="_blank" rel="noopener noreffer ">unittest&lt;/a>是python自带的单元测试框架，有时候又被称为&amp;quot;PyUnit&amp;quot;，是python版本的&lt;a href="http://junit.org/" target="_blank" rel="noopener noreffer ">JUint&lt;/a>实现。&lt;/p>
&lt;p>该框架的作者是 Kent Beck和Erich Gamma，感谢祖师爷赏饭吃。&lt;/p>
&lt;p>在学习使用unittest库之前，我们需要了解一下unittest库的一些重要概念:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>test fixture&lt;/strong>: 代表了用例执行前的准备工作和用例执行之后的清理工作。比如在用例执行前创建临时文件和文件夹，又或者启动1个server进程等；&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>test case&lt;/strong>: 测试用例，这个相信大家都不陌生。是测试的最小单位，一般检查一组输入的响应(输出)是否符合预期。&lt;a href="https://docs.python.org/2/library/unittest.html#module-unittest" target="_blank" rel="noopener noreffer ">unittest&lt;/a>模块提供了&lt;a href="https://docs.python.org/2/library/unittest.html#unittest.TestCase" target="_blank" rel="noopener noreffer ">TestCase&lt;/a>类来帮助我们创建测试用例；&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>test suite&lt;/strong>: 经常被翻译成&amp;quot;测试套件&amp;quot;，也有人称为&amp;quot;测试套&amp;quot;，是测试用例或测试套件的集合，一般用来把需要一起执行的用例组合到一起;&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>test runner&lt;/strong>: 用来执行测试用例并输出测试结果的组件。可以是图形界面或命令行界面;&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>总之&lt;/p>
&lt;ul>
&lt;li>test fixture的功能可以理解成是初始化和清理测试数据及环境&lt;/li>
&lt;li>test case是测试用例&lt;/li>
&lt;li>test suite是用例集合&lt;/li>
&lt;li>test runner的作用是运行用例并返回结果&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1524749292158-7540c2494485?w=300"
 data-srcset="https://images.unsplash.com/photo-1524749292158-7540c2494485?w=300, https://images.unsplash.com/photo-1524749292158-7540c2494485?w=300 1.5x, https://images.unsplash.com/photo-1524749292158-7540c2494485?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1524749292158-7540c2494485?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>1. 第一个程序</title><link>https://itest2025.pages.dev/tutorials/28-001-1-%E7%AC%AC%E4%B8%80%E4%B8%AA%E7%A8%8B%E5%BA%8F/</link><pubDate>Tue, 07 Nov 2017 08:17:22 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/28-001-1-%E7%AC%AC%E4%B8%80%E4%B8%AA%E7%A8%8B%E5%BA%8F/</guid><description>&lt;h3 id="背景">背景&lt;/h3>
&lt;p>我们的第一个python程序将要实现最简单的打印测试报告的功能。&lt;/p>
&lt;p>我们希望可以将回归测试的结果打印到命令行窗口里。测试结果如下所示&lt;/p>
&lt;pre tabindex="0">&lt;code>本次测试功能点5个
测试用例20个
共执行测试用例20个
共发现缺陷0个
用例通过率100%
&lt;/code>&lt;/pre>&lt;h3 id="代码实现">代码实现&lt;/h3>
&lt;p>新建名为&lt;code>print_report.py&lt;/code>的文本文件，用文本编辑器打开，输入如下内容:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;本次测试功能点5个&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;测试用例20个&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;共执行测试用例20个&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;共发现缺陷0个&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;用例通过率100%&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行">运行&lt;/h3>
&lt;p>在命令行中使用下面的命令去执行代码&lt;/p>
&lt;pre tabindex="0">&lt;code>python print_report.py
&lt;/code>&lt;/pre>&lt;p>注意: &lt;strong>初学者一般不知道如何在命令行中cd进具体的文件夹，macos可能相对简单一些，对于使用windows的同学来说，cd到具体的文件夹需要两步&lt;/strong>&lt;/p>
&lt;p>比如我们需要cd到E:\code文件夹，那么步骤应该是&lt;/p>
&lt;ul>
&lt;li>首先敲盘符&lt;code>E:&lt;/code>，然后回车，表示进入E盘先&lt;/li>
&lt;li>然后敲&lt;code>cd code&lt;/code>并回车，表示进入code目录&lt;/li>
&lt;/ul>
&lt;h3 id="你应该可以看到">你应该可以看到&lt;/h3>
&lt;p>如果没有出错的话，你应该可以看到命令行窗口显示如下的内容&lt;/p>
&lt;pre tabindex="0">&lt;code>本次测试功能点5个
测试用例20个
共执行测试用例20个
共发现缺陷0个
用例通过率100%
&lt;/code>&lt;/pre>&lt;p>如果你遇到错误，那么很多情况下可能会提示&lt;/p>
&lt;pre tabindex="0">&lt;code>python print_report.py // 1
 File &amp;#34;print_report.py&amp;#34;, line 4 // 2
 print(&amp;#39;共发现缺陷0个) // 3
 ^ // 4
SyntaxError: EOL while scanning string literal // 5
&lt;/code>&lt;/pre>&lt;p>作为初学者，把代码尽可能敲正确和看懂错误提示是非常关键的两件事。&lt;/p>
&lt;p>我们在写代码的时候经常会遇到各种各样的错误提示，我们一般可以从错误提示里获得如下的信息&lt;/p>
&lt;ul>
&lt;li>哪一行代码出错了&lt;/li>
&lt;li>出错的原因具体是什么&lt;/li>
&lt;/ul>
&lt;p>现在我们来具体分析上面的错误信息&lt;/p>
&lt;ol>
&lt;li>我们运行了名为的print_report.py的脚本&lt;/li>
&lt;li>pytnon告诉我们print_report.py的文件的第4行有错误&lt;/li>
&lt;li>python把出错行的内容打印出来&lt;/li>
&lt;li>然后python通过&lt;code>^&lt;/code>字符告诉我们错误具体发生在哪里。可以看出我们漏掉了一个单引号&lt;/li>
&lt;li>最后python告诉我们具体的错误是什么，这里是&amp;quot;SyntaxError&amp;quot;。一般情况下，我们可以把错误信息，也就是&lt;code>SyntaxError: EOL while scanning string literal&lt;/code>这一行直接拷贝到搜索引擎里去搜索具体的解决方案，大部分情况下，我们都可以得到满意的结果&lt;/li>
&lt;/ol>
&lt;h3 id="动手时间">动手时间&lt;/h3>
&lt;p>尝试去做下面一些事情&lt;/p></description></item><item><title>1.快速开始</title><link>https://itest2025.pages.dev/tutorials/25-001-1%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B/</link><pubDate>Thu, 02 Nov 2017 07:22:42 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/25-001-1%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B/</guid><description>&lt;h3 id="简介">简介&lt;/h3>
&lt;p>pytest测试框架可以让我们很方便的编写测试用例，这些用例写起来虽然简单，但仍然可以规模化以及编写更加复杂的测试用例。&lt;/p>
&lt;p>&lt;a href="https://docs.pytest.org/en/latest/index.html" target="_blank" rel="noopener noreffer ">官方文档&lt;/a>&lt;/p>
&lt;h3 id="安装">安装&lt;/h3>
&lt;pre tabindex="0">&lt;code>pip install -U pytest
&lt;/code>&lt;/pre>&lt;p>用下面的命令去检查一下pytest是否成功安装&lt;/p>
&lt;pre tabindex="0">&lt;code>$ pytest --version
This is pytest version 3.x.y, imported from $PYTHON_PREFIX/lib/python3.5/site-packages/pytest.py
&lt;/code>&lt;/pre>&lt;h3 id="快速开始">快速开始&lt;/h3>
&lt;p>创建名为&lt;code>test_quick_start.py&lt;/code>的文件，敲如下内容&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">reverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">string&lt;/span>&lt;span class="p">[::&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">test_reverse&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">string&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;good&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="n">reverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;doog&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">another_string&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;itest&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="n">reverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">another_string&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;tseti&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上面的代码做了2件事情&lt;/p>
&lt;ul>
&lt;li>定义了名为&lt;code>reverse(string)&lt;/code>的全局函数，作用是把string反转并返回。比如输入&amp;quot;abc&amp;quot;会反转成&amp;quot;cba&amp;quot;&lt;/li>
&lt;li>定义了名为&lt;code>test_reverse()&lt;/code>的函数，包含了2个断言，用来测试&lt;code>reverse()&lt;/code>方法的正确性&lt;/li>
&lt;/ul>
&lt;p>在命令行中使用下面的命令去运行用例&lt;/p>
&lt;pre tabindex="0">&lt;code>pytest
&lt;/code>&lt;/pre>&lt;p>结果应该大致如下&lt;/p>
&lt;pre tabindex="0">&lt;code>========================================================================= test session starts =========================================================================
platform darwin -- Python 2.7.12, pytest-3.2.3, py-1.4.34, pluggy-0.4.0
rootdir: /Users/easonhan/code/testclass.net/src/pytest, inifile:
collected 1 item

test_quick_start.py .

====================================================================== 1 passed in 0.01 seconds =======================================================================
&lt;/code>&lt;/pre>&lt;h3 id="总结">总结&lt;/h3>
&lt;p>这是最简单的单元测试实例，实现了用代码去测试代码的目的。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1533880020541-22c0ff17d4a2?w=300"
 data-srcset="https://images.unsplash.com/photo-1533880020541-22c0ff17d4a2?w=300, https://images.unsplash.com/photo-1533880020541-22c0ff17d4a2?w=300 1.5x, https://images.unsplash.com/photo-1533880020541-22c0ff17d4a2?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1533880020541-22c0ff17d4a2?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>1. webium简介及安装</title><link>https://itest2025.pages.dev/tutorials/43-001-1-webium%E7%AE%80%E4%BB%8B%E5%8F%8A%E5%AE%89%E8%A3%85/</link><pubDate>Sun, 29 Oct 2017 06:55:26 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/43-001-1-webium%E7%AE%80%E4%BB%8B%E5%8F%8A%E5%AE%89%E8%A3%85/</guid><description>&lt;p>webium是基于python的一个Page Object实现, API简单友好，可以在一定程度上提升Web UI测试的生产力，值得我们进行学习。&lt;/p>
&lt;p>不过注意: webium要配合selenium一起使用。&lt;/p>
&lt;h3 id="用有的链接">用有的链接&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="https://github.com/wgnet/webium" target="_blank" rel="noopener noreffer ">项目主页&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://wgnet.github.io/webium/" target="_blank" rel="noopener noreffer ">文档&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/wgnet/webium/tree/master/examples" target="_blank" rel="noopener noreffer ">例子&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="安装">安装&lt;/h3>
&lt;pre tabindex="0">&lt;code>pip install webium
&lt;/code>&lt;/pre>&lt;h3 id="常用类">常用类&lt;/h3>
&lt;p>一般来说我们会经常用到下面几个类&lt;/p>
&lt;ul>
&lt;li>webium.Find: 在page中定位单个元素&lt;/li>
&lt;li>webium.Finds: 在page中定位一组元素&lt;/li>
&lt;li>webium.BasePage: 页面的基类，其他页面都必须是该类的子类&lt;/li>
&lt;/ul>
&lt;h3 id="使用方式">使用方式&lt;/h3>
&lt;p>下面以百度搜索&lt;a href="www.itest.info" rel="">重定向科技&lt;/a>为例&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># baidu.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">webdriver&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium.webdriver.common.by&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">By&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">webium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">BasePage&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Find&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Finds&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">time&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">BaiduPage&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BasePage&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">url&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;https://www.baidu.com&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">keyword&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Find&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">by&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ID&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;kw&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">button&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Find&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">by&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ID&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;su&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">ResultsPage&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BasePage&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">first_result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Find&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">by&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">CSS_SELECTOR&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;.result&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">webdriver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Chrome&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">baidu_page&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">BaiduPage&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">dr&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">baidu_page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">open&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">baidu_page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">keyword&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">send_keys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;重定向科技&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">baidu_page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">button&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">click&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">results_page&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ResultsPage&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">dr&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">results_page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">first_result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dr&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">quit&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行及结果">运行及结果&lt;/h3>
&lt;pre tabindex="0">&lt;code>python baidu.py

重定向科技
重定向科技(www.itest.info)致力于培养中国软件测试行业中高端人才,公司长年专注于软件测试教育领域,拥有先进的软件测试教育体系,向个人和企业客户提供领先的软件测试...
itest.info/ - 百度快照
&lt;/code>&lt;/pre>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1483058712412-4245e9b90334?w=300"
 data-srcset="https://images.unsplash.com/photo-1483058712412-4245e9b90334?w=300, https://images.unsplash.com/photo-1483058712412-4245e9b90334?w=300 1.5x, https://images.unsplash.com/photo-1483058712412-4245e9b90334?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1483058712412-4245e9b90334?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>收藏清单:Java测试相关资源汇总</title><link>https://itest2025.pages.dev/tutorials/34-001-%E6%94%B6%E8%97%8F%E6%B8%85%E5%8D%95java%E6%B5%8B%E8%AF%95%E7%9B%B8%E5%85%B3%E8%B5%84%E6%BA%90%E6%B1%87%E6%80%BB/</link><pubDate>Fri, 27 Oct 2017 08:19:06 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/34-001-%E6%94%B6%E8%97%8F%E6%B8%85%E5%8D%95java%E6%B5%8B%E8%AF%95%E7%9B%B8%E5%85%B3%E8%B5%84%E6%BA%90%E6%B1%87%E6%80%BB/</guid><description>&lt;h2 id="virtual-environments-虚拟化环境">Virtual environments 虚拟化环境&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://www.vagrantup.com/" target="_blank" rel="noopener noreffer ">Vagrant&lt;/a> - 配置简单可信赖的虚拟化环境管理工具&lt;/li>
&lt;li>&lt;a href="https://www.docker.com" target="_blank" rel="noopener noreffer ">Docker&lt;/a> - docker就不用多说了&lt;/li>
&lt;/ul>
&lt;h2 id="performance--stress--load-性能测试">Performance &amp;amp; stress &amp;amp; load 性能测试&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="http://jmeter.apache.org/" target="_blank" rel="noopener noreffer ">Apache JMeter&lt;/a> - 支持性能及功能测试&lt;/li>
&lt;li>&lt;a href="http://grinder.sourceforge.net/" target="_blank" rel="noopener noreffer ">The Grinder&lt;/a> - 使用多台测试机运行分布式性能测试的框架&lt;/li>
&lt;li>&lt;a href="http://automatictester.github.io/lightning/" target="_blank" rel="noopener noreffer ">Lightning&lt;/a> - 融合JMeter，不支持功能测试，支持CI/CD&lt;/li>
&lt;li>&lt;a href="http://tsung.erlang-projects.org/" target="_blank" rel="noopener noreffer ">Tsung&lt;/a> - 基于Erlang的性能测试工具，支持多协议&lt;/li>
&lt;li>&lt;a href="http://gatling.io/" target="_blank" rel="noopener noreffer ">Gatling&lt;/a> - Gatling是基于Scala, Akka 和 Netty的开源性能测试框架. 非常适合做压力测试。它的设计初衷是易用，好维护和高性能。 DSL易于理解，测试场景可以自解释，脚本维护简单，可以直接在代码库中进行管理。&lt;/li>
&lt;/ul>
&lt;h2 id="build-tools-构建工具">Build Tools 构建工具&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="http://ant.apache.org/" target="_blank" rel="noopener noreffer ">Apache Ant&lt;/a> - 不用多解释了，构建java项目的自动化工具&lt;/li>
&lt;li>&lt;a href="http://maven.apache.org/" target="_blank" rel="noopener noreffer ">Apache Maven&lt;/a> - Apache Maven 是软件项目管理的综合工具. 基于 project object model (POM), Maven可以从中心信息管理项目构建,报告及文档&lt;/li>
&lt;li>&lt;a href="https://gradle.org/" target="_blank" rel="noopener noreffer ">Gradle&lt;/a> - Gradle 是开源的自动化构建系统。 Gradle可以自动化的构建，测试，发布及部署。&lt;/li>
&lt;/ul>
&lt;h2 id="continuous-integration-持续集成">Continuous Integration 持续集成&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="http://jenkins-ci.org/" target="_blank" rel="noopener noreffer ">jenkins&lt;/a> - 可扩展的开源持续集成server&lt;/li>
&lt;li>&lt;a href="https://www.jetbrains.com/teamcity/" target="_blank" rel="noopener noreffer ">TeamCity&lt;/a> - 功能强大，用户友好的持续集成及部署工具，开箱即用&lt;/li>
&lt;/ul>
&lt;h2 id="reporting-报告">Reporting 报告&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://github.com/reportportal/reportportal" target="_blank" rel="noopener noreffer ">ReportPortal&lt;/a> - 强大的服务端报告工具。降低了处理结果的工作量。 提供了测试执行的历史数据，日志截图以及任意二进制文件的记录和存储。&lt;/li>
&lt;li>&lt;a href="https://docs.qameta.io/allure/latest" target="_blank" rel="noopener noreffer ">Allure&lt;/a> - 开源框架，目的是为团队中的每个人创建清晰的测试报告。&lt;/li>
&lt;li>&lt;a href="https://github.com/d10xa/gradle-allure-plugin" target="_blank" rel="noopener noreffer ">Gradle Allure Plugin&lt;/a> - 第三方的 Gradle Allure插件可以将Allure集成到spock, testing 和junit用例中。&lt;/li>
&lt;li>&lt;a href="http://relevantcodes.com/extentreports-for-selenium/" target="_blank" rel="noopener noreffer ">ExtentReports&lt;/a> - HTML报告库支持.NET和Java，使使用简单，可以创建美观的测试报告。&lt;/li>
&lt;li>&lt;a href="http://reportng.uncommons.org/" target="_blank" rel="noopener noreffer ">ReportNG&lt;/a> - ReportNG 是一个简单的 TestNG HTML报告插件。&lt;/li>
&lt;/ul>
&lt;h2 id="editors-ide-consoles-编辑器-ide">Editors, IDE, consoles 编辑器 IDE&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://www.jetbrains.com/idea/" target="_blank" rel="noopener noreffer ">IntelliJ IDEA&lt;/a> - 免费开源的IDE 支持 Java, Groovy, Scala 和 Android 开发
&lt;ul>
&lt;li>&lt;a href="http://perfect-test.com/index.php/ru/instruments-rus-menu/15-selenium-plugin-rus" target="_blank" rel="noopener noreffer ">IntelliJ IDEA Selenium plugin&lt;/a> - IntelliJ Idea 插件，使selenium用例编写更简单。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="https://eclipse.org/ide/" target="_blank" rel="noopener noreffer ">Eclipse&lt;/a> - 最有名的JavaIDE同时也支持 C/C++和PHP
&lt;ul>
&lt;li>&lt;a href="https://sourceforge.net/adobe/genie/wiki2/FAQ/" target="_blank" rel="noopener noreffer ">Genie plugin&lt;/a> - 测试AS 3.0 SWF和Flash游戏的功能测试工具&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="https://netbeans.org/features/index.html" target="_blank" rel="noopener noreffer ">NetBeans&lt;/a> - NetBeans IDE 是Java 8的官方IDE&lt;/li>
&lt;/ul>
&lt;h2 id="orm-frameworks-and-libraries-orm框架和库">ORM frameworks and libraries ORM框架和库&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="http://hibernate.org/orm/" target="_blank" rel="noopener noreffer ">Hibernate&lt;/a> - SSH里的H&lt;/li>
&lt;li>&lt;a href="https://github.com/mongodb/morphia" target="_blank" rel="noopener noreffer ">Morphia&lt;/a> - Morphia一款是轻量的类型安全的MongoDB对象mapping库&lt;/li>
&lt;li>&lt;a href="http://www.mybatis.org/mybatis-3" target="_blank" rel="noopener noreffer ">MyBatis&lt;/a> - MyBatis 是一款优秀的持久层框架，它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息，将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。&lt;/li>
&lt;/ul>
&lt;h2 id="useful-libs-有用的库">Useful libs 有用的库&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://github.com/amaembo/streamex" target="_blank" rel="noopener noreffer ">StreamEx&lt;/a> - Java 8 Streams加强库。&lt;/li>
&lt;li>&lt;a href="https://github.com/vavr-io/vavr" target="_blank" rel="noopener noreffer ">Vavr&lt;/a> - Vavr 是Java 8的object-functional 语言扩展, 目的是减少代码行数和增强代码质量。&lt;/li>
&lt;li>&lt;a href="https://projectlombok.org" target="_blank" rel="noopener noreffer ">Lombok&lt;/a> - Lombok是一个可以通过简单的注解形式来帮助我们简化消除一些必须有但显得很臃肿的Java代码的工具，通过使用对应的注解，可以在编译源码的时候生成对应的方法。&lt;/li>
&lt;li>&lt;a href="https://eclipse.org/aspectj" target="_blank" rel="noopener noreffer ">AspectJ&lt;/a> - Java的面向切面编程工具.&lt;/li>
&lt;li>&lt;a href="https://github.com/yandex-qatools/ashot" target="_blank" rel="noopener noreffer ">aShot&lt;/a> - WebDriver 截图工具.&lt;/li>
&lt;li>&lt;a href="https://code.google.com/p/rest-assured/" target="_blank" rel="noopener noreffer ">rest-assured&lt;/a> - 用Java来测试REST服务比动态语言比如Ruby Groovy要难。 REST Assured 可以给Java带来类似动态语言测试REST服务的体验&lt;/li>
&lt;li>&lt;a href="http://wiremock.org/" target="_blank" rel="noopener noreffer ">WireMock&lt;/a> 灵活的 web 服务mock库，跟一般的mock目的不同的是，WireMock使用了真实的web服务&lt;/li>
&lt;li>&lt;a href="http://www.mock-server.com/" target="_blank" rel="noopener noreffer ">MockServer&lt;/a> 可以用来mock任何基于HTTP和HTTPS的系统 (比如services, web sites,等).&lt;/li>
&lt;li>&lt;a href="http://www.xmlunit.org/" target="_blank" rel="noopener noreffer ">XMLUnit&lt;/a> - 测试和比较 XML，支持 Java 和 .NET&lt;/li>
&lt;li>&lt;a href="https://github.com/awaitility/awaitility" target="_blank" rel="noopener noreffer ">Awaitility&lt;/a> - Awaitility是测试异步代码的库&lt;/li>
&lt;li>&lt;a href="https://github.com/keepcosmos/beanmother" target="_blank" rel="noopener noreffer ">Beanmother&lt;/a> - 初始化Java Bean作为test data的库&lt;/li>
&lt;/ul>
&lt;h1 id="resources-资源">Resources 资源&lt;/h1>
&lt;ul>
&lt;li>&lt;a href="http://thucydides.info/docs/thucydides-one-page/thucydides.html" target="_blank" rel="noopener noreffer ">Serenity BDD (Thucydides) libraries&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://habrahabr.ru/post/168451/" target="_blank" rel="noopener noreffer ">Automation tests structure&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="websites-网站">Websites 网站&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="http://automated-testing.info" target="_blank" rel="noopener noreffer ">automated-testing.info&lt;/a> - 自动化测试社区&lt;/li>
&lt;li>&lt;a href="http://atinfo.github.io/at.info-knowledge-base/" target="_blank" rel="noopener noreffer ">atinfo.github.io/at.info-knowledge-base&lt;/a> - 各种工具和技术实现的自动化测试的例子&lt;/li>
&lt;li>&lt;a href="http://www.testclass.net/" target="_blank" rel="noopener noreffer ">测试教程网&lt;/a>: 最权威的中文测试教程汇总网站&lt;/li>
&lt;li>&lt;a href="http://seleniumsimplified.com/" target="_blank" rel="noopener noreffer ">selenium-simplified&lt;/a> - 让selenium webdriver测试更简单&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p></description></item><item><title>（一）Locust 介绍</title><link>https://itest2025.pages.dev/tutorials/38-001-%E4%B8%80locust-%E4%BB%8B%E7%BB%8D/</link><pubDate>Mon, 16 Oct 2017 14:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/38-001-%E4%B8%80locust-%E4%BB%8B%E7%BB%8D/</guid><description>&lt;p>Locust 官方网站：https://www.locust.io/&lt;/p>
&lt;h4 id="locust-介绍">Locust 介绍&lt;/h4>
&lt;hr>
&lt;p>An open source load testing tool.&lt;/p>
&lt;p>一个开源性能测试工具。&lt;/p>
&lt;p>define user behaviour with python code, and swarm your system with millions of simultaneous users.&lt;/p>
&lt;p>使用 Python 代码来定义用户行为。用它可以模拟百万计的并发用户访问你的系统。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/locust_UI.png"
 data-srcset="http://img.testclass.net/locust_UI.png, http://img.testclass.net/locust_UI.png 1.5x, http://img.testclass.net/locust_UI.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/locust_UI.png"
 title="http://img.testclass.net/locust_UI.png" />&lt;/p>
&lt;br>
#### 性能工具对比
----
__LoadRunner__ 是非常有名的商业性能测试工具，功能非常强大。使用也比较复杂，目前大多介绍性能测试的书籍都以该工具为基础，甚至有些书整本都在介绍 LoadRunner 的使用。
&lt;p>&lt;strong>Jmeter&lt;/strong> 同样是非常有名的开源性能测试工具，功能也很完善，在本书中介绍了它作为接口测试工具的使用。但实际上，它是一个标准的性能测试工具。关于Jmeter相关的资料也非常丰富，它的官方文档也很完善。&lt;/p>
&lt;p>&lt;strong>Locust&lt;/strong> 同样是性能测试工具，虽然官方这样来描述它 “An open source load testing tool.” 。但其它和前面两个工具有着较大的不同。相比前面两个工具，功能上要差上不少，但它也并非优点全无。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Locust 完全基本 Python 编程语言，采用 Pure Python 描述测试脚本，并且 HTTP 请求完全基于 Requests 库。除了 HTTP/HTTPS 协议，Locust 也可以测试其它协议的系统，只需要采用Python调用对应的库进行请求描述即可。&lt;/p></description></item><item><title>（一）持续集成与 Jenkins 介绍</title><link>https://itest2025.pages.dev/tutorials/18-001-%E4%B8%80%E6%8C%81%E7%BB%AD%E9%9B%86%E6%88%90%E4%B8%8E-jenkins-%E4%BB%8B%E7%BB%8D/</link><pubDate>Mon, 16 Oct 2017 14:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/18-001-%E4%B8%80%E6%8C%81%E7%BB%AD%E9%9B%86%E6%88%90%E4%B8%8E-jenkins-%E4%BB%8B%E7%BB%8D/</guid><description>&lt;br>
#### 持续集成
----
持续集成（Continuous integration，简称 CI），随着近几年的发展，持续集成在项目中得到了广泛的推广和应用。本章将带领读者一起了解持续集成工具 Jenkins 的安装与使用。
&lt;p>&lt;strong>1．什么是持续集成？&lt;/strong>&lt;/p>
&lt;p>软件集成就是用一种较好的方式，使多种软件的功能集成到一个软件里，或是把软件的各部分组合在一起。如果项目开发的规模较小，且对外部系统的依赖很小，那么软件集成不是问题，例如一个人的项目。但是随着软件项目复杂度的增加，会对集成和确保软件组件能够在一起工作提出了更多的要求&amp;ndash;&amp;gt;要早集成、常集成。早集成、频繁的集成能够帮助项目开发者在早期发现项目风险和质量问题，越到后期发现的问题，解决的成本越高，从而有可能导致项目延期或者项目失败。&lt;/p>
&lt;p>&lt;strong>2．定义&lt;/strong>&lt;/p>
&lt;p>大师 Martin Fowler 对持续集成是这样定义的：持续集成是一种软件开发实践，即团队开发成员经常集成他们的工作，通常每个成员每天至少集成一次，也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建（包括编译、发布、自动化测试）来验证，从而尽快地发现集成错误。许多团队发现这个过程可以大大减少集成的问题，让团队能够更快地开发内聚的软件。&lt;/p>
&lt;br>
#### Jenkins
----
&lt;p>Jenkins 官方网站：https://jenkins.io/&lt;/p>
&lt;p>提到 Jenkins 就不得不提另一个持续集成工具——Hudson ， Hudson 由 Sun 公司开发，2010 年 Sun 公司被 Oracle 公司收购， oracle 公司声称对 hudson 拥有商标所有权。 Jenkins是从 Hudson 中分离出来的一个版本，并将继续走 Open Source 的道路。二者现在由不同的团队在维护。&lt;/p>
&lt;p>Jenkins 主要用于监视执行重复工作，如建立一个软件项目或工作运行的计划任务。当前 Jenkins 关注以下两个工作。&lt;/p>
&lt;p>&lt;strong>不断地进行项目的构建/测试软件：&lt;/strong> 就像 CruiseControl 或 DamageControl。概括地说，Jenkins 提供了一个易于使用的所谓的持续集成系统，使开发人员更容易修改整合到项目中，并使它更容易为用户获得一个新的版本。自动连续生成提高了生产效率。&lt;/p>
&lt;p>&lt;strong>监控外部运行的作业：&lt;/strong> 如计划任务作业和 Qrocmail 的工作，即使是那些在远程机器上运行的计划任务。 Jenkins 生成这些日志并且很容易让你注意到错误的出现。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1627757691655-7afffb88d7b2?w=300"
 data-srcset="https://images.unsplash.com/photo-1627757691655-7afffb88d7b2?w=300, https://images.unsplash.com/photo-1627757691655-7afffb88d7b2?w=300 1.5x, https://images.unsplash.com/photo-1627757691655-7afffb88d7b2?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1627757691655-7afffb88d7b2?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>01. IntelliJ IDEA 介绍（新用户必看）</title><link>https://itest2025.pages.dev/tutorials/37-001-01-intellij-idea-%E4%BB%8B%E7%BB%8D%E6%96%B0%E7%94%A8%E6%88%B7%E5%BF%85%E7%9C%8B/</link><pubDate>Mon, 16 Oct 2017 12:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/37-001-01-intellij-idea-%E4%BB%8B%E7%BB%8D%E6%96%B0%E7%94%A8%E6%88%B7%E5%BF%85%E7%9C%8B/</guid><description>&lt;h1 id="介绍">介绍&lt;/h1>
&lt;h2 id="本系列教程介绍">本系列教程介绍&lt;/h2>
&lt;p>本系列教程从 IntelliJ IDEA 的安装、卸载、软件设置、项目配置等各个方面进行讲解。通过本系列教程的学习，也希望你能爱上 IntelliJ IDEA，爱上它的体贴。同时学完本系列教程对于你学习 JetBrains 公司下的其他产品也有好处，其他产品包括：&lt;/p>
&lt;blockquote>
&lt;ul>
&lt;li>&lt;a href="http://www.jetbrains.com/phpstorm/" title="PhpStorm 主要用于开发 PHP" target="_blank" rel="noopener noreffer ">PhpStorm&lt;/a> 主要用于开发 PHP&lt;/li>
&lt;li>&lt;a href="http://www.jetbrains.com/ruby/" title="RubyMine 主要用于开发 Ruby" target="_blank" rel="noopener noreffer ">RubyMine&lt;/a> 主要用于开发 Ruby&lt;/li>
&lt;li>&lt;a href="http://www.jetbrains.com/pycharm/" title="PyCharm 主要用于开发 Python" target="_blank" rel="noopener noreffer ">PyCharm&lt;/a> 主要用于开发 Python&lt;/li>
&lt;li>&lt;a href="http://www.jetbrains.com/objc/" title="AppCode 主要用于开发 Objective-C" target="_blank" rel="noopener noreffer ">AppCode&lt;/a> 主要用于开发 Objective-C / Swift&lt;/li>
&lt;li>&lt;a href="http://www.jetbrains.com/clion/" title="CLion 主要用于开发 C/C&amp;#43;&amp;#43;" target="_blank" rel="noopener noreffer ">CLion&lt;/a> 主要用于开发 C / C++&lt;/li>
&lt;li>&lt;a href="http://www.jetbrains.com/webstorm/" title="WebStorm 主要用于开发 JavaScript 等前端技术" target="_blank" rel="noopener noreffer ">WebStorm&lt;/a> 主要用于开发 JavaScript、HTML5、CSS3 等前端技术&lt;/li>
&lt;li>&lt;a href="http://www.jetbrains.com/dbe/" title="0xDBE 主要用于开发 SQL" target="_blank" rel="noopener noreffer ">0xDBE&lt;/a> 主要用于开发 SQL&lt;/li>
&lt;li>&lt;a href="http://developer.android.com/tools/studio/" title="Android Studio 主要用于开发 Android" target="_blank" rel="noopener noreffer ">Android Studio&lt;/a> 主要用于开发 Android（Google 基于 IntelliJ IDEA 社区版进行迭代所以也姑且算上）&lt;/li>
&lt;/ul>&lt;/blockquote>
&lt;h2 id="intellij-idea-介绍">IntelliJ IDEA 介绍&lt;/h2>
&lt;blockquote>
&lt;ul>
&lt;li>IntelliJ IDEA 官网：&lt;a href="https://www.jetbrains.com/idea/" target="_blank" rel="noopener noreffer ">https://www.jetbrains.com/idea/&lt;/a>&lt;/li>
&lt;/ul>&lt;/blockquote>
&lt;p>IntelliJ IDEA 在 2015 年 06 月官网主页是这样介绍自己的：&lt;/p></description></item><item><title>（一）Web Services基本概念</title><link>https://itest2025.pages.dev/tutorials/26-001-%E4%B8%80web-services%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5/</link><pubDate>Thu, 21 Sep 2017 02:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/26-001-%E4%B8%80web-services%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5/</guid><description>&lt;br>
整理这一章资料的过程是比较痛苦的，Web Services 是一项不太容易讲清楚技术，我花不少时间来阅读相关的资料，由于涉及的概念比较多，不同的厂商和专家对这些概念的解释也不完全相同。在概念的选择上我比较倾向于已出版的书籍中的解释。不过，我仍然希望你带怀疑的态度来学习这一章。
&lt;h4 id="soa">SOA&lt;/h4>
&lt;hr>
&lt;p>全称: Service-Oriented Architecture，简称 SOA，面向服务架构又称“面向服务的体系结构”。&lt;/p>
&lt;p>SOA的提出是在企业计算领域，就是要将紧耦合的系统，划分为面向业务的，粗粒度，松耦合，无状态的服务。服务发布出来供其他服务调用，一组互相依赖的服务就构成了 SOA 架构下的系统。
既然称它为一种架构，那么一般认为 SOA 是包含了运行环境，编程模型，架构风格和相关方法论等在内的一整套新的分布式软件系统构造方法和环境，涵盖服务的整个生命周期。&lt;/p>
&lt;p>service-architecture.com 网站对 SOA的定义：&lt;/p>
&lt;p>SOA 本质上是服务的集合。服务间彼此通信，这种通信可能是简单的数据传送，也可能是两个或更多的服务协调进行某些活动。服务间需要某些方法进行连接。&lt;/p>
&lt;p>所谓 &lt;strong>服务&lt;/strong> 就是精确定义、封装完善、独立于其他服务所处环境和状态的函数。&lt;/p>
&lt;p>虽然不同厂商或个人对 SOA 有着不同的理解，但是我们仍然可以从上述的定义中看到 SOA 的几个关键特性：&lt;/p>
&lt;p>&lt;strong>一种粗粒度、松耦合服务架构，服务之间通过简单、精确定义接口进行通讯，不涉及底层编程接口和通信模型。&lt;/strong>&lt;/p>
&lt;p>对于SOA来说，我们不需要太过较真 SOA 到是一个怎样的架构。只要符合它的定义和规范的软件系统都可以认为是SOA架构。　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　&lt;/p>
&lt;h4 id="soa-与-web-services">SOA 与 Web Services&lt;/h4>
&lt;hr>
&lt;p>早在1996年Gartner就前瞻性地提出了面向服务架构的思想（SOA），SOA 阐述了“对于复杂的企业IT系统，应按照不同的、可重用的粒度划分，将功能相关的一组功能提供者组织在一起为消费者提供服务”，其目的是为了解决企业内部不同IT资源之间无法互联而导致的信息孤岛问题。&lt;/p>
&lt;p>直到2000年左右，ESB（Enterprise Service Bus）、Web Services、SOAP 等这类技术的出现，才使得 SOA 渐渐落地。同时，更多的厂商像 IBM、Oracle 等也分别提出基于 SOA 的解决方案或者产品。&lt;/p>
&lt;p>因为现在几乎所有的 SOA 应用场合都是和 Web Services 绑定的，所以不免有时候这两个概念混用。不可否认 Web Services 是现在最适合实现 SOA 的技术，SOA 的走红在很大程度上归功于Web Services标准的成熟和应用普及。因为现在大家基本上认同 Web Services 技术在几方面体现了 SOA 的需要：&lt;/p>
&lt;p>首先，是基于标准访问的独立功能实体满足了松耦合要求：在 Web Services 中所有的访问都通过 SOAP 访问进行，用WSDL定义的接口封装，通过 UDDI 进行目录查找，可以动态改变一个服务的提供方而无需影响客户端的配置，外界客户端根本不必关心访问服务器端的实现。&lt;/p></description></item><item><title>appium新手入门（1）—— appium介绍</title><link>https://itest2025.pages.dev/tutorials/21-001-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A81-appium%E4%BB%8B%E7%BB%8D/</link><pubDate>Fri, 08 Sep 2017 12:24:12 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/21-001-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A81-appium%E4%BB%8B%E7%BB%8D/</guid><description>&lt;h3 id="appium介绍">appium介绍&lt;/h3>
&lt;hr>
&lt;p>&lt;a href="http://appium.io/" target="_blank" rel="noopener noreffer ">官方网站&lt;/a>&lt;/p>
&lt;h4 id="1特点">1、特点&lt;/h4>
&lt;hr>
&lt;p>appium 是一个自动化测试开源工具，支持 iOS 平台和 Android 平台上的原生应用，web应用和混合应用。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>“移动原生应用”是指那些用iOS或者 Android SDK 写的应用（Application简称app）。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>“移动web应用”是指使用移动浏览器访问的应用（appium支持iOS上的Safari和Android上的 Chrome）。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>“混合应用”是指原生代码封装网页视图——原生代码和 web 内容交互。比如，像 Phonegap，可以帮助开发者使用网页技术开发应用，然后用原生代码封装，这些就是混合应用。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>重要的是，appium是一个跨平台的工具：它允许测试人员在不同的平台（iOS，Android）使用同一套API来写自动化测试脚本，这样大大增加了iOS和Android测试套件间代码的复用性。&lt;/p>
&lt;h4 id="2appium与selenium">2、appium与Selenium&lt;/h4>
&lt;hr>
&lt;p>appium类库封装了标准Selenium客户端类库，为用户提供所有常见的JSON格式selenium命令以及额外的移动设备控制相关的命令，如多点触控手势和屏幕朝向。&lt;/p>
&lt;p>appium客户端类库实现了Mobile JSON Wire Protocol（一个标准协议的官方扩展草稿）和W3C WebDriver spec（一个传输不可预知的自动化协议，该协议定义了MultiAction 接口）的元素。&lt;/p>
&lt;p>appium服务端定义了官方协议的扩展，为appium 用户提供了方便的接口来执行各种设备动作，例如在测试过程中安装/卸载App。这就是为什么我们需要appium特定的客户端，而不是通用的Selenium 客户端。当然，appium 客户端类库只是增加了一些功能，而实际上这些功能就是简单的扩展了Selenium 客户端，所以他们仍然可以用来运行通用的Selenium会话。&lt;/p>
&lt;h4 id="3支持多平台多语言">3、支持多平台、多语言&lt;/h4>
&lt;hr>
&lt;p>appium是跨平台的，可以用在OSX，Windows以及Linux桌面系统上运行。&lt;/p>
&lt;p>appium选择了Client/Server的设计模式。只要client能够发送http请求给server，那么的话client用什么语言来实现都是可以的，这就是appium及Selenium(WebDriver)如何做到支持多语言的原因；&lt;/p>
&lt;p>appium扩展了WebDriver的协议，没有自己重新去实现一套。这样的好处是以前的WebDriver API能够直接被继承过来，以前的Selenium（WebDriver）各种语言的binding都可以拿来就用，省去了为每种语言开发一个client的工作量；&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">语言/框架&lt;/th>
 &lt;th style="text-align: left">Github地址&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">Ruby&lt;/td>
 &lt;td style="text-align: left">&lt;a href="https://github.com/appium/ruby_lib" target="_blank" rel="noopener noreffer ">https://github.com/appium/ruby_lib&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">Python&lt;/td>
 &lt;td style="text-align: left">&lt;a href="https://github.com/appium/python-client" target="_blank" rel="noopener noreffer ">https://github.com/appium/python-client&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">Java&lt;/td>
 &lt;td style="text-align: left">&lt;a href="https://github.com/appium/java-client" target="_blank" rel="noopener noreffer ">https://github.com/appium/java-client&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">JavaScript (Node.js)&lt;/td>
 &lt;td style="text-align: left">&lt;a href="https://github.com/admc/wd" target="_blank" rel="noopener noreffer ">https://github.com/admc/wd&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">Objective C&lt;/td>
 &lt;td style="text-align: left">&lt;a href="https://github.com/appium/selenium-objective-c" target="_blank" rel="noopener noreffer ">https://github.com/appium/selenium-objective-c&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">PHP&lt;/td>
 &lt;td style="text-align: left">&lt;a href="https://github.com/appium/php-client" target="_blank" rel="noopener noreffer ">https://github.com/appium/php-client&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">C# (.NET)&lt;/td>
 &lt;td style="text-align: left">&lt;a href="https://github.com/appium/appium-dotnet-driver" target="_blank" rel="noopener noreffer ">https://github.com/appium/appium-dotnet-driver&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">RobotFramework&lt;/td>
 &lt;td style="text-align: left">&lt;a href="https://github.com/jollychang/robotframework-appiumlibrary" target="_blank" rel="noopener noreffer ">https://github.com/jollychang/robotframework-appiumlibrary&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h4 id="4appium工作原理">4、appium工作原理&lt;/h4>
&lt;hr>
&lt;p>在安装和介绍appium之前，非常有必要介绍一下appium是如何工作的。&lt;/p></description></item><item><title>JMeter官方文档：1. 新手入门</title><link>https://itest2025.pages.dev/tutorials/22-001-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A31-%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A8/</link><pubDate>Wed, 06 Sep 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/22-001-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A31-%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A8/</guid><description>&lt;p>&lt;a href="https://itest2025.pages.dev/2017/08/24/jmeter-translation-plans/" rel="">《JMeter官方文档&amp;ndash;翻译计划》&lt;/a> &lt;a href="http://jmeter.apache.org/usermanual/get-started.html" target="_blank" rel="noopener noreffer ">原文地址&lt;/a>&lt;/p>
&lt;p>注：不知道怎么的翻译的句子保留的英文。&lt;/p>
&lt;h2 id="1-新手入门">1. 新手入门&lt;/h2>
&lt;hr>
&lt;h3 id="10-概述">1.0 概述&lt;/h3>
&lt;hr>
&lt;p>当你使用JMeter的时候一般会遵循以下过程：&lt;/p>
&lt;h4 id="101-创建测试计划">1.0.1 创建测试计划&lt;/h4>
&lt;hr>
&lt;p>首先，你需要启动&lt;a href="http://jmeter.apache.org/usermanual/get-started.html#running" target="_blank" rel="noopener noreffer ">JMeter GUI&lt;/a>&lt;/p>
&lt;p>然后，你可以选择从浏览器或本地应用程序记录应用程序。通过菜单：&lt;strong>文件  →  Templates&amp;hellip;  → Recording&lt;/strong>。&lt;/p>
&lt;p>注意，你还可以通过手动生成测试计划，你需要阅读&lt;a href="http://jmeter.apache.org/usermanual/test_plan.html" target="_blank" rel="noopener noreffer ">文档&lt;/a>并理解上面概念。&lt;/p>
&lt;p>你还可以通过下面的方式进行调试：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>运行 → Start no pauses&lt;/strong>&lt;/li>
&lt;li>&lt;strong>运行 → 启动&lt;/strong>&lt;/li>
&lt;li>&lt;strong>验证&lt;a href="http://jmeter.apache.org/usermanual/component_reference.html#Thread_Group" target="_blank" rel="noopener noreffer ">线程组&lt;/a>&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>和&lt;a href="http://jmeter.apache.org/usermanual/component_reference.html#View_Results_Tree" target="_blank" rel="noopener noreffer ">查看结果树&lt;/a>的渲染和调试（CSS/JQUERY, JSON, Regexp, XPath）。
确保在构建测试计划时遵循&lt;a href="http://jmeter.apache.org/usermanual/best-practices.html" target="_blank" rel="noopener noreffer ">最佳实践&lt;/a>。&lt;/p>
&lt;h4 id="102-负载测试执行">1.0.2 负载测试执行&lt;/h4>
&lt;hr>
&lt;p>一旦测试计划就绪，就可以开始负载测试了。第一步是配置运行JMeter的注入器，这对于任何其他负载测试工具包括：&lt;/p>
&lt;ul>
&lt;li>在CPU、内存和网络方面对机器进行正确的调整。&lt;/li>
&lt;li>操作系统的优化&lt;/li>
&lt;li>&lt;strong>Java设置：&lt;/strong> 确保你安装Java支持的JMeter的最新版本。&lt;/li>
&lt;li>&lt;strong>正确调整Java堆大小：&lt;/strong> 默认的JMeter以512MB的堆运行，这可能对你的测试没什么帮助，主要取决于你的测试计划和你想要运行的线程数。&lt;/li>
&lt;/ul>
&lt;p>一旦一切就绪，你将使用命令行模式（称为非GUI模式）来运行负载测试。&lt;/p>
&lt;blockquote>
&lt;p>不要使用GUI模式运行负载测试!&lt;/p>&lt;/blockquote>
&lt;p>使用非gui模式，你可以生成包含CSV(或XML)结果的文件，并在负载测试结束时生成JMeter生成HTML报告。默认情况下，JMeter将在运行时提供负载测试的摘要。&lt;/p>
&lt;p>你还可以使用后端侦听器在测试期间获得实时结果。&lt;/p>
&lt;h4 id="103-负载测试分析">1.0.3 负载测试分析&lt;/h4>
&lt;hr>
&lt;p>负载测试结果后，可以使用HTML报告来分析负载测试。&lt;/p>
&lt;h4 id="104-让我们开始吧">1.0.4 让我们开始吧&lt;/h4>
&lt;hr>
&lt;p>开始使用JMeter最简单的方法是首先&lt;a href="http://jmeter.apache.org/download_jmeter.cgi" target="_blank" rel="noopener noreffer ">下载最新的产品版本&lt;/a>并安装它。该版本包含构建和运行大多数类型的测试所需的所有文件，例如 Web(HTTP / HTTPS)、FTP、JDBC、LDAP、Java、JUnit等。&lt;/p>
&lt;p>如果你想要执行JDBC测试，那么你当然需要来数据库供应商JDBC驱动程序。JMeter不包含任何JDBC驱动程序。&lt;/p></description></item><item><title>（一）认识Git与GitHub</title><link>https://itest2025.pages.dev/tutorials/33-001-%E4%B8%80%E8%AE%A4%E8%AF%86git%E4%B8%8Egithub/</link><pubDate>Thu, 31 Aug 2017 06:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/33-001-%E4%B8%80%E8%AE%A4%E8%AF%86git%E4%B8%8Egithub/</guid><description>&lt;h4 id="git的诞生">Git的诞生&lt;/h4>
&lt;p>Linus Torvalds在1991年创建了开源系统Linux，在2002年以前，世界各地的志愿者把源代码文件通过diff的方式发给Linus，然后由Linus本人通过手工方式合并代码！然后，Linux系统已经发展了十年了，代码库之大让Linus很难继续通过手工方式管理了。&lt;/p>
&lt;p>于是，Linus Torvalds花了两周时间自己用C写了一个分布式版本控制系统，这就是Git！一个月之内，Linux系统的源码已经由Git管理了！&lt;/p>
&lt;h4 id="git介绍">Git介绍&lt;/h4>
&lt;p>Git是一个开源的分布式版本控制系统，用以有效、高速地处理从很小到非常大的项目版本管理。相比CVS、SVN等版本控制工具，Git无疑更加优秀，功能更加强大，在项目版本管理中被越来越多的人广泛的使用。但 Git 相对来说比较难学。&lt;/p>
&lt;p>使用Git来管理项目有两种方式：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>一种是本地部署Git版本管理系统。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>另一种是通过在线代码托管。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>本地部署Git版本管理系统，需要自己来搭建环境，但项目的提交与更新速度快，更适合较为封闭的项目；使用在线托管最大的好处是在有网络的情况下可以随时随地提交自己的代码，但项目是公开的，当然也可以创建私有项目，大多属于付费服务。&lt;/p>
&lt;h4 id="github">GitHub&lt;/h4>
&lt;p>GitHub就是基于Git的在线代码托管平台。&lt;/p>
&lt;p>GitHub为当前最流行的开源项目托管平台，数以万计优秀的开源项目被托管在GitHub上面。随着越来越多的应用程序转移到云上，Github已经成为了管理软件开发以及发现已有代码的首选方法。对于普通开发人员来讲，其在GitHub上托管的项目已经成为了他的一张个人名片。许多优秀的互联网公司在招聘开发人员时都希望对方能提供个人的GitHub地址。当然，GitHub作为一个开源软件的大宝库，学习和使用它，也会为我们的日常开发带来许多便利。&lt;/p>
&lt;h4 id="测试为什么学习git-">测试为什么学习Git ？&lt;/h4>
&lt;ul>
&lt;li>工作需要&lt;/li>
&lt;/ul>
&lt;p>我们工作中需要对项目代码进行管理，我的工作中就先后使用了SVN和Git对项目的版本进行管理。所以，这是测试人员必备技能。&lt;/p>
&lt;ul>
&lt;li>学习需要&lt;/li>
&lt;/ul>
&lt;p>你工作中所使用的编程语言的第三方库，大量都在GitHub上面托管，要想安装这些库就会用到Git；另外一些主流的Selenium、Appium开源项目也都是在GitHub上进行维护。&lt;/p>
&lt;ul>
&lt;li>个人名片&lt;/li>
&lt;/ul>
&lt;p>将你自己工作中的一些项目和代码放到GitHub上面进行管理。这无疑是对个人能力最好的展示。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1580894732930-0babd100d356?w=300"
 data-srcset="https://images.unsplash.com/photo-1580894732930-0babd100d356?w=300, https://images.unsplash.com/photo-1580894732930-0babd100d356?w=300 1.5x, https://images.unsplash.com/photo-1580894732930-0babd100d356?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1580894732930-0babd100d356?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>1.为什么要做接口测试</title><link>https://itest2025.pages.dev/tutorials/40-001-1%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E5%81%9A%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95/</link><pubDate>Wed, 30 Aug 2017 04:41:43 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/40-001-1%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E5%81%9A%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95/</guid><description>&lt;p>很多同学反馈现在面试的时候都会问到为什么要做接口测试以及如何做接口测试的问题，那么我们就稍微来科普一下。&lt;/p>
&lt;p>&lt;strong>本文讨论的接口均是服务级的接口，不是代码级&lt;/strong>&lt;/p>
&lt;h3 id="接口是什么">接口是什么&lt;/h3>
&lt;p>在讨论为什么要做接口测试之前，我们可以先稍微了解一下接口是什么？&lt;/p>
&lt;p>接口可以很不准确的理解成是与资源打交道，这个资源可能是本系统的，也可能是其他系统的。&lt;/p>
&lt;p>举个例子，假如我们在开发1个bug管理系统，该系统需要拿到公司的所有开发和测试人员的信息，这样开发和测试人员不用注册都可以登录进去了，这应该很好理解。&lt;/p>
&lt;p>那么这些人员的信息储存在哪里呢？一般存储在hr系统里。现在的需求更加明确了，我们要到hr系统中去拿到人员信息，获取hr系统中的人员资源。&lt;/p>
&lt;p>怎么拿呢？很多种方式，可以直接把hr系统的数据库拷贝一份放到bug管理系统里，不过这样不好，因为数据的同步会有点麻烦；还可以直接连hr系统的数据库去查，这样也不太好，这样我们就需要了解hr系统的数据存储结构和逻辑，一旦hr系统的数据字段发生改变，bug管理系统也要去该，以便同步。&lt;/p>
&lt;p>比较好的做法是，hr系统暴露一些接口，通过这些接口去获取人员信息资源，这样bug系统就不需要关心hr系统的数据存储实现了。&lt;/p>
&lt;p>这些接口可能是这样的：&lt;/p>
&lt;ul>
&lt;li>登录的接口，提供人员的用户名和密码，去hr系统中判断该人员是否存在，如果存在验证用户名和密码，如果验证通过就返回1个token，该token就是这个人员的通行证，通过token可以登录到bug管理系统中去；&lt;/li>
&lt;li>获取人员信息的接口，返回该人员的职位：测试还是开发，以及用户名，昵称等信息；&lt;/li>
&lt;/ul>
&lt;p>综上：接口可以理解成是不同系统或模块之间资源交流方式；&lt;/p>
&lt;h3 id="接口测试实际上是黑盒测试">接口测试实际上是黑盒测试&lt;/h3>
&lt;p>作为黑盒测试，基本的测试思路是通过输入和输出判断被测系统或者对象的逻辑。&lt;/p>
&lt;p>获取人员的信息，我需要把人员的用户名传给hr系统接口，这样hr系统的接口会返回给我用户的一些更加具体的信息。这里的输入是用户名，输出是用户的详细信息。&lt;/p>
&lt;h3 id="为什么要做接口测试">为什么要做接口测试&lt;/h3>
&lt;p>既然是接口获取和操作资源的方式，而大部分系统和产品中，资源一般都是产品的核心，比如微信核心资源就是通讯录关系链和聊天记录等，因此资源是必测的。&lt;/p>
&lt;p>另外接口中大部分的内容是数据，通过数据的对比我们能推测到系统和产品的逻辑，测接口就是测逻辑。&lt;/p>
&lt;p>最后接口中的返回相对单纯，不像web页面，html代码中有太多ui的东西，ui最不稳定，变化太快，接口相对稳定一点点，但是里面的干扰信息更少，断言相对容易很多。&lt;/p>
&lt;h3 id="接口测试用例怎么写">接口测试用例怎么写&lt;/h3>
&lt;p>还是3a原则，这个我以前的回答里有。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>A: arrange 初始化测试数据，就是造数据，这里的数据有我们输入的数据，也有目标接口所涉及的资源，比如hr系统中的用户信息，我们必须先有几条人员的详细信息才能去测获取人员信息的接口（当然只是正常的流程，我们有时候还需要清掉数据以便测试资源为空的情况）；&lt;/p>
&lt;/li>
&lt;li>
&lt;p>A: act 调用接口，传入输入数据；&lt;/p>
&lt;/li>
&lt;li>
&lt;p>A: assert 断言， 对返回的资源信息进行断言，比如获取用户信息的接口返回了用户信息之后，我们要判断返回的用户是不是我们想要的那个用户，我们获取的是李雷的信息，接口如果返回韩梅梅，那么接口的逻辑就是不对的；&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="接口测试笔试题">接口测试笔试题&lt;/h3>
&lt;p>&lt;a href="http://www.testclass.net/interview/interface/" target="_blank" rel="noopener noreffer ">测试教程网接口测试笔试题&lt;/a>&lt;/p>
&lt;h3 id="有哪些常见的接口">有哪些常见的接口&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>携程订飞机票，飞机票的信息一般都是通过各大航空公司的接口拿到的；&lt;/p>
&lt;/li>
&lt;li>
&lt;p>淘宝的物流信息，一般淘宝的物流信息都是通过各个物流公司的接口拿到的；&lt;/p>
&lt;/li>
&lt;li>
&lt;p>第三方微博客户端，个人用户的微博等信息都是通过微博的接口拿到的；&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="常见的接口测试工具">常见的接口测试工具&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="https://www.getpostman.com/" target="_blank" rel="noopener noreffer ">postman&lt;/a>： 推荐。基本功能免费。最简单的基于http接口的调试和测试工具;&lt;/li>
&lt;li>&lt;a href="http://jmeter.apache.org/" target="_blank" rel="noopener noreffer ">jmeter&lt;/a>：后置处理器配合断言基本上可以满足接口测试需求，就是测试报告要做二次开发&lt;/li>
&lt;li>自己撸代码：推荐。配合类似xunit测试框架，基本可以满足一切需求；&lt;a href="https://ke.qq.com/course/232868#tuin=1eb87ef" target="_blank" rel="noopener noreffer ">零基础实现python接口自动化视频教程，一起撸代码吧&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.soapui.org/" target="_blank" rel="noopener noreffer ">soapui&lt;/a>: 收费的；&lt;/li>
&lt;li>&lt;a href="https://insomnia.rest/" target="_blank" rel="noopener noreffer ">insomnia&lt;/a>：强力推荐。postman的弱化版，基本功能免费，重要的是工具代码开源，可以自己改；&lt;/li>
&lt;li>&lt;a href="https://paw.cloud/" target="_blank" rel="noopener noreffer ">paw&lt;/a>: 强力推荐。mac上最强，淘宝买个授权好像就百把块钱；&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1506935412676-6fa7f9de5bda?w=300"
 data-srcset="https://images.unsplash.com/photo-1506935412676-6fa7f9de5bda?w=300, https://images.unsplash.com/photo-1506935412676-6fa7f9de5bda?w=300 1.5x, https://images.unsplash.com/photo-1506935412676-6fa7f9de5bda?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1506935412676-6fa7f9de5bda?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>appium简明教程（1）——appium和它的哲学世界</title><link>https://itest2025.pages.dev/tutorials/21-001-appium%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B1appium%E5%92%8C%E5%AE%83%E7%9A%84%E5%93%B2%E5%AD%A6%E4%B8%96%E7%95%8C/</link><pubDate>Sun, 20 Aug 2017 06:05:07 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/21-001-appium%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B1appium%E5%92%8C%E5%AE%83%E7%9A%84%E5%93%B2%E5%AD%A6%E4%B8%96%E7%95%8C/</guid><description>&lt;h3 id="什么是appium">什么是appium？&lt;/h3>
&lt;p>下面这段介绍来自于appium的官网。&lt;/p>
&lt;blockquote>
&lt;p>Appium is an open-source tool you can use to automate mobile native, mobile web, and mobile hybrid applications on iOS and Android platforms. “Mobile native apps” are those written using the iOS or Android SDKs. “Mobile web apps” are web apps accessed using a mobile browser (Appium supports Safari on iOS and Chrome on Android). “Mobile hybrid apps” have a native wrapper around a “webview” – a native control that enables interaction with web content. Projects like Phonegap, for example, make it easy to build apps using web technologies that are then bundled into a native wrapper – these are hybrid apps.&lt;/p></description></item><item><title>（一）初始化环境</title><link>https://itest2025.pages.dev/tutorials/20-001-%E4%B8%80%E5%88%9D%E5%A7%8B%E5%8C%96%E7%8E%AF%E5%A2%83/</link><pubDate>Sun, 13 Aug 2017 05:24:16 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/20-001-%E4%B8%80%E5%88%9D%E5%A7%8B%E5%8C%96%E7%8E%AF%E5%A2%83/</guid><description>&lt;p>MacOS&lt;/p>
&lt;ul>
&lt;li>nodejs版本: 6.2.0&lt;/li>
&lt;li>selenium-webdriver版本: 3.4.0&lt;/li>
&lt;li>chrome版本: 版本 59.0.3071.86（正式版本）64位&lt;/li>
&lt;li>chrome driver版本: ChromeDriver 2.30.477690&lt;/li>
&lt;/ul>
&lt;p>Windows&lt;/p>
&lt;p>TODO&lt;/p>
&lt;h3 id="安装nodejs">安装nodejs&lt;/h3>
&lt;p>TODO&lt;/p>
&lt;h3 id="安装selenium-webdriver">安装selenium webdriver&lt;/h3>
&lt;pre tabindex="0">&lt;code>mkdir se
cd se
cnpm install selenium-webdriver

[selenium-webdriver@*] installed at node_modules/.npminstall/selenium-webdriver/3.4.0/selenium-webdriver (20 packages, use 4s, speed 447.48kB/s, json 34.34kB, tarball 1.54MB)

All packages installed (20 packages installed from npm registry, use 4s, speed 446kB/s, json 22(34.34kB), tarball 1.54MB)
&lt;/code>&lt;/pre>&lt;h3 id="安装chrome-driver">安装chrome driver&lt;/h3>
&lt;p>chrome driver建议通过科学上网的方式下载。&lt;/p>
&lt;p>&lt;a href="https://sites.google.com/a/chromium.org/chromedriver/downloads" target="_blank" rel="noopener noreffer ">下载地址&lt;/a>&lt;/p>
&lt;p>&lt;strong>下载完成后请将chromedriver.exe(windows)放到&lt;a href="http://jingyan.baidu.com/article/ed2a5d1f3655ca09f6be17a4.html" target="_blank" rel="noopener noreffer ">系统PATH&lt;/a>中&lt;/strong>&lt;/p>
&lt;p>验证chrome driver是否正确安装，请在命令行中输入&lt;/p>
&lt;pre tabindex="0">&lt;code>chromedriver -h
Usage: chromedriver [OPTIONS]

Options
 --port=PORT port to listen on
 --adb-port=PORT adb server port
 --log-path=FILE write server log to file instead of stderr, increases log level to INFO
 --verbose log verbosely
 --version print the version number and exit
 --silent log nothing
 --url-base base URL path prefix for commands, e.g. wd/url
 --port-server address of server to contact for reserving a port
 --whitelisted-ips comma-separated whitelist of remote IPv4 addresses which are allowed to connect to ChromeDriver
&lt;/code>&lt;/pre>&lt;p>如能看到上述结果则证明安装成功&lt;/p></description></item><item><title>性能测试基础（一）性能测试分类</title><link>https://itest2025.pages.dev/tutorials/14-001-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E5%9F%BA%E7%A1%80%E4%B8%80%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E5%88%86%E7%B1%BB/</link><pubDate>Fri, 11 Aug 2017 15:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/14-001-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E5%9F%BA%E7%A1%80%E4%B8%80%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E5%88%86%E7%B1%BB/</guid><description>&lt;br>
&lt;p>关于性能测试有几个名词：性能测试、负载测试、压力测试、并发测试，很多人都是混合使用，或者有时压力测试，有时叫并发测试。这些名词除了非测试人员分不清楚，甚至许多专业测试人员也对这些名词也很模糊。关于这个分类我翻阅了一些资料，解释都比较模糊，并没有给出本质上的区别。只是从不同角度和关注点来解释。我们先来看看这些解释。&lt;/p>
&lt;br>
#### 性能测试（狭义）
----
性能测试方法是通过模拟生产运行的业务压力量和使用场景组合，测试系统的性能是否满足生产性能要求。通俗地说，这种方法就是要在特定的运行条件下验证系统的处理能力。
&lt;p>&lt;strong>特点：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>这种测试方法的主要目的是验证系统是否有系统宣称具有的能力。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>这种测试方法要事先了解被测试系统经典场景，并具有确定的性能目标。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>这种测试方法要求在已经确定的环境下运行。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>也就是说，这种方法是对系统性能已经有了解的前提，并对需求有明确的目标，并在已经确定的环境下进行的。&lt;/p>
&lt;br>
#### 负载测试
----
&lt;p>通过在被测系统上不断加压，直到性能指标达到极限，例如“响应时间”超过预定指标或都某种资源已经达到饱和状态。&lt;/p>
&lt;p>&lt;strong>特点：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>这种测试方法的主要目的是找到系统处理能力的极限。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>这种测试方法需要在给定的测试环境下进行，通常也需要考虑被测试系统的业务压力量和典型场景、使得测试结果具有业务上的意义。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>这种测试方法一般用来了解系统的性能容量，或是配合性能调优来使用。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>也就是说，这种方法是对一个系统持续不段的加压，看你在什么时候已经超出“预期要求”或系统崩溃。&lt;/p>
&lt;br>
#### 压力测试（强度测试）
---
&lt;p>压力测试方法测试系统在一定饱和状态下，例如CPU、内存在饱和使用情况下，系统能够处理的会话能力，以及系统是否会出现错误。&lt;/p>
&lt;p>&lt;strong>特点：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>这种测试方法的主要目的是检查系统处于压力性能下时，应用的表现。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>这种测试方法一般通过模拟负载等方法，使得系统的资源使用达到较高的水平。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>这种测试方法一般用于测试系统的稳定性。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>也就是说，这种测试是让系统处在很大强度的压力之下，看系统是否稳定，哪里会出问题。&lt;/p>
&lt;p>&lt;br> &lt;/p>
&lt;h3 id="并发测试">并发测试&lt;/h3>
&lt;hr>
&lt;p>并发测试通过模拟用户并发访问，测试多用户并发访问同一个应用、同一个模块或者数据记录时是否存在死锁或其者他性能问题。&lt;/p>
&lt;p>&lt;strong>特点：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>这种测试方法的主要目的是发现系统中可能隐藏并发访问时的问题。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>这种测试方法主要关注系统可能存在的并发问题，例如系统中的内存泄漏、线程锁和资源争用方面的问题。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>这种测试方法可以在开发的各个阶段使用需要相关的测试工具的配合和支持。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>也就是说，这种测试关注点是多个用户同时（并发）对一个模块或操作进行加压。&lt;/p>
&lt;br>
####	配置测试
---
配置测试方法通过对被测系统的软\硬件环境的调整，了解各种不同对系统的性能影响的程度，从而找到系统各项资源的最优分配原则。
__特点：__
&lt;ul>
&lt;li>
&lt;p>这种性能测试方法的主要目的是了解各种不同因素对系统性能影响的程度，从而判断出最值得进行的调优操作。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>这种性能测试方法一般在对系统性能状况有初步了解后进行。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>这种性能测试方法一般用于性能调优和规划能力。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>也就是说，这种测试关注点是“微调”，通过对软硬件的不段调整，找出这他们的最佳状态，使系统达到一个最强的状态。&lt;/p>
&lt;br>
####	可靠性测试
---
在给系统加载一定业务压力的情况下，使系统运行一段时间，以此检测系统是否稳定。
&lt;p>&lt;strong>特点：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>这种性能测试方法的主要目的是验证是否支持长期稳定的运行。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>这种性能测试方法需要在压力下持续一段时间的运行。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>测试过程中需要关注系统的运行状况。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>也就是说，这种测试的关注点是“稳定”，不需要给系统太大的压力，只要系统能够长期处于一个稳定的状态。&lt;/p>
&lt;p>除了上面的分类，还有失效性测试，就是系统局部发生问题时，其它模块是否可以正常的运行。这个在极少数情况下进行，这里就不介绍了。&lt;/p>
&lt;br>
#### 性能测试分类之我见
---
&lt;p>上面的类分完了，似乎得到不少专家的认同。但我们在做性能测试过程中真的能把它们区分的很清楚么?你能严格区分出你这次的测试到底并发测试还是压力测试。&lt;/p>
&lt;p>我中学时练过几年体育，对于一个体育运动员来说，那么多的体育项目，其实，考核他的就两方面：爆发力和耐力。其实，我们在进行性能测试时主要关注的也是这两方面。&lt;/p>
&lt;p>&lt;strong>爆发力：&lt;/strong> 拿一个举重选手来说，他的重点在重量上，因为你只要能举起三秒就算你成功了。关键是看你能举起一个什么样的重量。&lt;/p>
&lt;p>&lt;strong>耐力：&lt;/strong> 拿一个马拉松运动员来说，你百米速度跑得再快没用。关键是这40公里路程中，最先跑到终点的人才是赢家。&lt;/p>
&lt;p>&lt;strong>整体协调性：&lt;/strong> 作为一个教练，在训练运动员时，除了看这个运动员的实际成绩之外，分析运动员的整体协调性，并发现运动员的短板是最关键的。比如一个运行员身体各位部位练得非常强壮，但右臂先天性萎缩。虽然他的最终的跑步成绩不错。但他在跑的过程中，身体有各个部位明显都在分担右臂的不足。右臂影响了整个体能的发挥。&lt;/p>
&lt;p>回到性能测试上上，爆发力就是系统能承受的最大压力，没准系统承受的压力很大，但过半个小时之间就挂掉了。耐力就是这个系统长时间处于压力下的稳定性，这系统超级稳定，跑个几十年都不用重启服务器。那么整体协调性就是看系统有没系统瓶颈（短板），并对其进行系统调优。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1592853625511-ad0edcc69c07?w=300"
 data-srcset="https://images.unsplash.com/photo-1592853625511-ad0edcc69c07?w=300, https://images.unsplash.com/photo-1592853625511-ad0edcc69c07?w=300 1.5x, https://images.unsplash.com/photo-1592853625511-ad0edcc69c07?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1592853625511-ad0edcc69c07?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（一）环境安装之Java</title><link>https://itest2025.pages.dev/tutorials/19-001-%E4%B8%80%E7%8E%AF%E5%A2%83%E5%AE%89%E8%A3%85%E4%B9%8Bjava/</link><pubDate>Sun, 30 Jul 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/19-001-%E4%B8%80%E7%8E%AF%E5%A2%83%E5%AE%89%E8%A3%85%E4%B9%8Bjava/</guid><description>&lt;br>
### 安装java
&lt;p>点击 &lt;a href="http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html" target="_blank" rel="noopener noreffer ">JDK8下载&lt;/a>，根据自己的平台，选择相应的版本进行下载。&lt;/p>
&lt;pre tabindex="0">&lt;code>小知识：
Java环境分JDK和JRE ，JDK就是Java Development Kit。简单的说JDK是面向开发人员使用的SDK，它提供了Java的开发
环境和运行环境。JRE是Java Runtime Enviroment是指Java的运行环境，是面向 Java 程序的使用者。
&lt;/code>&lt;/pre>&lt;p>我们以 Windows安装JDK为例，双击下载的JDK，设置安装路径。这里我选择默认安装在__&amp;ldquo;D:\Program Files\Java\jdk1.8.0_101&amp;rdquo;__目录下。&lt;/p>
&lt;p>下面设置环境变量：&lt;/p>
&lt;p>“我的电脑” 右键菜单&amp;mdash;&amp;gt;属性&amp;mdash;&amp;gt;高级&amp;mdash;&amp;gt;环境变量&amp;mdash;&amp;gt;系统变量&amp;mdash;&amp;gt;新建..&lt;/p>
&lt;pre tabindex="0">&lt;code>变量名： JAVA_HOME
变量值： D:\Program Files\Java\jdk1.8.0_101
变量名： CALSS_PATH
变量值： .;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;
&lt;/code>&lt;/pre>&lt;p>找到 path 变量名—&amp;gt;“编辑” 添加：&lt;/p>
&lt;pre tabindex="0">&lt;code>变量名： PATH
变量值： %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;
&lt;/code>&lt;/pre>&lt;p>在Windows命令提示符(cmd)下验证 Java 是否成功：&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt; java
用法: java [-options] class [args...]
 (执行类)
 或 java [-options] -jar jarfile [args...]
 (执行 jar 文件)
其中选项包括:
 -d32 使用 32 位数据模型 (如果可用)
 -d64 使用 64 位数据模型 (如果可用)
 -client 选择 &amp;#34;client&amp;#34; VM
 -server 选择 &amp;#34;server&amp;#34; VM
 默认 VM 是 client.
......

&amp;gt; javac
用法: javac &amp;lt;options&amp;gt; &amp;lt;source files&amp;gt;
其中, 可能的选项包括:
 -g 生成所有调试信息
 -g:none 不生成任何调试信息
 -g:{lines,vars,source} 只生成某些调试信息
 -nowarn 不生成任何警告
 -verbose 输出有关编译器正在执行的操作的消息
 -deprecation 输出使用已过时的 API 的源位置
 -classpath &amp;lt;路径&amp;gt; 指定查找用户类文件和注释处理程序的位置
.......
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>java 命令可以运行 class 文件字节码。&lt;/li>
&lt;li>javac 命令可以将 Java 源文件编译为 class 字节码文件。&lt;/li>
&lt;/ul>
&lt;p>可能读者当前下载的 Java 版本与本书不同， 但安装方法是一样的。&lt;/p></description></item><item><title>（一）软件测试实质</title><link>https://itest2025.pages.dev/tutorials/29-001-%E4%B8%80%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E5%AE%9E%E8%B4%A8/</link><pubDate>Fri, 28 Jul 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/29-001-%E4%B8%80%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E5%AE%9E%E8%B4%A8/</guid><description>&lt;br>
&lt;p>Ron Patton所著的《软件测试》2002年的中文版，已经十五年了，但它对“软件的实质”的解释仍然是经典，这里摘录与大家分享。&lt;/p>
&lt;p>&lt;strong>实质&lt;/strong>，哲学中的本质，又称为“实质”是指某一对象或事物本身所必然固有的。说的通俗点也就是说软件测试的本来的面目。&lt;/p>
&lt;br>
#### 软件缺陷的定义 
&lt;p>来看一下Ron Patton 为我们的软件缺陷所下的定义。&lt;/p>
&lt;p>&lt;strong>1、软件没有实现产品的说明书所描述的功能。&lt;/strong>&lt;/p>
&lt;p>&lt;strong>2、软件实现了产品说明书描述不应有的功能。&lt;/strong>&lt;/p>
&lt;p>&lt;strong>3、软件执行了产品说明书没讲的操作。&lt;/strong>&lt;/p>
&lt;p>&lt;strong>4、软件没有实现产品说明书没讲但应该实现的功能。&lt;/strong>&lt;/p>
&lt;p>&lt;strong>5、从软件测试员的角度来看，软件难以理解、不易使用、运行缓慢，或者最终用户认为不对。&lt;/strong>&lt;/p>
&lt;p>为什么一个定义要这么多条来描述？这个“缺陷”的定义有这么复杂么？不，它其实并不复杂，作者只是想更加全面的来给“缺陷”下定义。&lt;/p>
&lt;p>下面我们来以建一栋房子为例，来说明一下每一条定义的意思。需要说明的是没有十分完美而且一成不变的产品说明说，而且在实际项目中，它可能非常简陋，模棱两可，甚至经常变动。&lt;/p>
&lt;p>&lt;strong>1、&lt;/strong> 软件没有实现产品说明书的描述的功能。房子的主人希望有一个落地的大窗户，让阳光更好的照进屋子里，而且他特意在房子的设计图纸中画出来，并且还加以说明。结果，他看到的是四面全是墙壁，只有一个小门的房子。那么对于测试人员来说，他就是一个缺陷。&lt;/p>
&lt;p>&lt;strong>2、&lt;/strong> 软件实现了产品说明书中描述的不应有的功能。由于房子的主人生活在南方，天气温暖，而请来的泥瓦匠是北方的，结果给主人建造的房子具然有一个大大的取暖的烟筒，而且主人特意在房子的设计图纸中说明，自己的房子不要烟筒。那么对于测试人员来说，这也是个缺陷。&lt;/p>
&lt;p>&lt;strong>3、&lt;/strong> 软件执行了产品说明书没讲的操作。与第二条类似，不同的是第二条是主人已经明确说了自己不要烟筒，而这一条强调的是在主人没说的情况下。泥瓦匠自作聪明的加了一个烟筒上去。对于测试人员来说，画蛇添足的功能同样被视为缺陷。&lt;/p>
&lt;p>&lt;strong>4、&lt;/strong> 软件没有实现产品说明书没讲但应该实现的功能。房子的主要对屋子的高度、格局，材料，颜色描述的非常清楚。泥瓦匠在建造房子的时候发现，主人没有提地基这回事，为了使房子牢固，所以，所有的房子都是必须要先打地基的，虽然主人没有说，但地基的功能必须要做。如果因为没有描述没有去做，但这又一件必须去做的事。对于测试人员来说，也可以视其这缺陷。&lt;/p>
&lt;p>&lt;strong>5、&lt;/strong> 从软件测试员的角度看，软件难以理解、不易使用、运行缓慢，或者最终用户认为不对。软件测试员是软件除了测试软件运行的缺陷，同样是作为一个用户在再对软件进行使用。如果感觉自己都很难使用，或软件效率非常低且界面丑陋等情况，也可以认为其存在缺陷。或者是最终用户拿到产品时发现这根本不是自己想要的东西，也可以现其为缺陷。当然，用户说不是自己想要的东西，也不能凭借一面之词，可以拿合约，产品说明书来评估。&lt;/p>
&lt;br>
#### 完全测试程序的可能性 
&lt;p>初做软件测试者可能认为拿到软件后就可以进行完全测试了，找出所有软件缺陷，并使软件完美。遗憾的是这是不可能的，我们无法对一个软件进行完全测试，即使最简单的程序也不行。主要原因如下：&lt;/p>
&lt;ul>
&lt;li>输入量太大&lt;/li>
&lt;li>输出结果太多&lt;/li>
&lt;li>软件实现的途径太多&lt;/li>
&lt;li>软件说明书没有客观标准。从不同的角度看，软件缺陷的标准不同&lt;/li>
&lt;/ul>
&lt;p>以上的“太多”的可能性加在一起，致使测试条件难以确定。&lt;/p>
&lt;p>以126邮箱为登录测试为例，其用户长度为50个字符，密码确实不太好计算（因为都是*号），所以这里也按50个字符来计算。&lt;/p>
&lt;p>在输入正确用户名的情况下：&lt;/p>
&lt;pre tabindex="0">&lt;code>1、输入正确的密码名是还否可以登录，

2、那么错误输入0 呢？1呢？2呢？......直到

99999999999999999999999999999999999999999999999999 ，

3、如果密码不是数字，而是字符呢，a 、b、c ... aa、bb 、cc .....

4、如果是大写呢 A 、B、C.... AA 、BB、CC.....

5、如果是大小写呢 Aa、Ab ....

6、如果是小写+数字呢 1a 、1b 、1c ....2a 、2b 、2c.....

7、如果是大写+数字呢 1A 、1B 、1Cc....2A 、2A 、2A.....

8、如果是大写+小写+数字呢 1Aa 、1Bb 、1Cc ....1Aa 、1Bb 、1Cc.....

9、如果有特殊字符呢 @#￥%……&amp;amp;*

10、如果输入字符有空格呢 a b、adbc ee......

11、如果是其它字符+大小写字母+数字呢+空格呢 ！@#&amp;amp;+123AIBKIkklzcb ......

......

12、再换正确的密码，错误的文件名再来一次。

13、用错误的用户名和密码再把上面的情况验证一次。（这样会匹配到所有的用户名密码）

14、什么都不输，直接点击登录
&lt;/code>&lt;/pre>&lt;p>这样穷举下去，就算是计算机也可能需要运行很久。&lt;strong>如果觉得某些测试条件是重复的或者是无必要的，而将其剔除，那么就不能称为完全测试。&lt;/strong>&lt;/p></description></item><item><title>接口测试面试题1</title><link>https://itest2025.pages.dev/tutorials/44-001-%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95%E9%9D%A2%E8%AF%95%E9%A2%981/</link><pubDate>Tue, 18 Jul 2017 09:30:25 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/44-001-%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95%E9%9D%A2%E8%AF%95%E9%A2%981/</guid><description>&lt;h3 id="原题图片">原题图片&lt;/h3>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://wx2.sinaimg.cn/mw690/726a2979gy1fho69rmzejj20eq0itdh4.jpg"
 data-srcset="http://wx2.sinaimg.cn/mw690/726a2979gy1fho69rmzejj20eq0itdh4.jpg, http://wx2.sinaimg.cn/mw690/726a2979gy1fho69rmzejj20eq0itdh4.jpg 1.5x, http://wx2.sinaimg.cn/mw690/726a2979gy1fho69rmzejj20eq0itdh4.jpg 2x"
 data-sizes="auto"
 alt="http://wx2.sinaimg.cn/mw690/726a2979gy1fho69rmzejj20eq0itdh4.jpg"
 title="http://wx2.sinaimg.cn/mw690/726a2979gy1fho69rmzejj20eq0itdh4.jpg" />&lt;/p>
&lt;h3 id="参考答案">参考答案&lt;/h3>
&lt;h4 id="1">1&lt;/h4>
&lt;p>tps就是吞吐量，transaction per second。&lt;/p>
&lt;p>吞吐量下降是可能因为频繁访问redis，而频繁访问redis的原因是参数过多，解决的思路很容易想到: &lt;strong>减少参数&lt;/strong>。&lt;/p>
&lt;p>我们可以把多组参数变成json字符串之类的一个参数，从而达到信息量不减少而参数个数变少的效果。&lt;/p>
&lt;h4 id="2">2&lt;/h4>
&lt;p>对称加密: 信息交换的双方使用同一个密钥加密解密，就像是用同一把钥匙开一把锁&lt;/p>
&lt;p>非对称加密&lt;/p>
&lt;p>公开密钥加密（英语：Public-key cryptography），也称为非对称加密（英语：asymmetric cryptography），是密码学的一种算法，它需要两个密钥，一个是公开密钥，另一个是私有密钥；一个用作加密的时候，另一个则用作解密。使用其中一个密钥把明文加密后所得的密文，只能用相对应的另一个密钥才能解密得到原本的明文；甚至连最初用来加密的密钥也不能用作解密。由于加密和解密需要两个不同的密钥，故被称为非对称加密；不同于加密和解密都使用同一个密钥的对称加密。虽然两个密钥在数学上相关，但如果知道了其中一个，并不能凭此计算出另外一个；因此其中一个可以公开，称为公钥，任意向外发布；不公开的密钥为私钥，必须由用户自行严格秘密保管，绝不通过任何途径向任何人提供，也不会透露给要通信的另一方，即使他被信任。&lt;/p>
&lt;p>基于公开密钥加密的特性，它还提供数字签名的功能，使电子文件可以得到如同在纸本文件上亲笔签署的效果。&lt;/p>
&lt;p>如何测试：略&lt;/p>
&lt;h4 id="3">3&lt;/h4>
&lt;p>UI与接口测试的协同可以从下面的方向考虑&lt;/p>
&lt;ul>
&lt;li>UI的操作实际上就是用另一种方式调用接口，那么接口有多少种参数组合就要求UI用例要构造多少种操作进行调用&lt;/li>
&lt;li>UI操作所需要的数据可以用接口来生成&lt;/li>
&lt;li>接口测试可以保证数据和逻辑的准确性，UI测试需要考虑交互和界面展示的逻辑正确性&lt;/li>
&lt;li>UI测试需要重视接口调用不成功或者接口异常情况下UI的呈现方式和用户体验&lt;/li>
&lt;li>UI中可能会有一些状态的缓存信息（这样就不需要每次频繁调用接口去获取了），比如鉴权信息等，需要重点关注这些缓存的更新策略&lt;/li>
&lt;/ul>
&lt;h4 id="4">4&lt;/h4>
&lt;p>上下游接口的数据依赖无非就是准备测试数据。&lt;/p>
&lt;p>假如一个事务需要顺序调用3个接口，A B C， C依赖于AB， 而AB有数据依赖，这时候就需要准备好A和B的数据。&lt;/p>
&lt;p>数据一般有两种方式生成&lt;/p>
&lt;ul>
&lt;li>
&lt;p>动态方式：假如B依赖A创造的数据，那么每次执行B之前必须执行A去做数据创建&lt;/p>
&lt;/li>
&lt;li>
&lt;p>静态方式：独立统一的测试数据库, ABC需要的数据都可以从库里拿到&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h4 id="5">5&lt;/h4>
&lt;p>依赖第三方就mock掉，可以自己写mock server&lt;/p>
&lt;h4 id="6">6&lt;/h4>
&lt;p>依赖登录态，那么每次测试该接口之前都需要调用登录的接口&lt;/p>
&lt;p>如果是jwt之类的token based auth的话，每次在调用接口时提供token就可以了&lt;/p>
&lt;h4 id="7">7&lt;/h4>
&lt;p>不知道，感觉出题者的理解可能有点偏差。&lt;/p>
&lt;h4 id="8">8&lt;/h4>
&lt;p>修改的接口，也就是update的接口一般只需要传：&lt;strong>被更新了的字段&lt;/strong> 以及 被更新实体的 &lt;strong>主键&lt;/strong> 比如id。&lt;/p>
&lt;p>这是开发常识，如果大家研究过jsonapi规格的话，可以直接套用jsonapi的设计进行阐述。&lt;/p>
&lt;h4 id="9">9&lt;/h4>
&lt;p>swagger文档可以解决这个问题。&lt;/p>
&lt;h4 id="10">10&lt;/h4>
&lt;p>看不清。&lt;/p>
&lt;h3 id="总结">总结&lt;/h3>
&lt;p>题目涉及到一些开发的知识点，很正常，现在测试面试时一般也会考察一下开发基础。&lt;/p>
&lt;p>总的来说题目出的一般，也不算太难，希望这些解答对大家有所帮助。&lt;/p>
&lt;p>原始封面&lt;/p></description></item><item><title>（一）安装selenium</title><link>https://itest2025.pages.dev/tutorials/24-001-%E4%B8%80%E5%AE%89%E8%A3%85selenium/</link><pubDate>Fri, 30 Jun 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/24-001-%E4%B8%80%E5%AE%89%E8%A3%85selenium/</guid><description>&lt;br>
### 安装python
&lt;p>打开 &lt;a href="https://www.python.org/" target="_blank" rel="noopener noreffer ">Python官网&lt;/a>，找到“Download”, 在其下拉菜单中选择自己的平台（Windows/Mac）,一般的Linux平台已经自带的Python，所以不需要安装，通过打开“终端” ，输入“python”命令来验证。&lt;/p>
&lt;p>如果你是第一次接触Python，一定会迷惑Python为什么会提供Python2.x 和 Python3.x两个版本？那么，直接使用Python3.x的最新版本就好了。因为Python2.x预计到2020年不在维护。&lt;/p>
&lt;p>如果你是Windows平台用户，会遇到一个版本为什么会提供多种个下载链接。例如：&lt;/p>
&lt;ul>
&lt;li>Python 3.6.1 - 2017-03-21
&lt;ul>
&lt;li>Download Windows x86 web-based installer&lt;/li>
&lt;li>Download Windows x86 executable installer&lt;/li>
&lt;li>Download Windows x86 embeddable zip file&lt;/li>
&lt;li>Download Windows x86-64 web-based installer&lt;/li>
&lt;li>Download Windows x86-64 executable installer&lt;/li>
&lt;li>Download Windows x86-64 embeddable zip file&lt;/li>
&lt;li>Download Windows help file&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>x86 只支持32位的系统； x86-64 支持64位的系统。 web-based 在安装的过程中需要联网；executable 可执行文件(.exe)方式安装；embeddable zip file 嵌入式版本，可以集成到其它应用中。&lt;/p>
&lt;p>注意：在安装的过程中需要勾选：“Add Python 3.x to PATH” , 如果没有勾选，需要在安装完成之后，将Python的安装目录（如：C:\Python36）添加到环境变量PATH下面。&lt;/p>
&lt;p>打开Windows命令提示符（cmd）/ Linux终端输入：&lt;/p></description></item><item><title>软件测试分类</title><link>https://itest2025.pages.dev/tutorials/13-002-%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E5%88%86%E7%B1%BB/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/13-002-%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E5%88%86%E7%B1%BB/</guid><description>&lt;br>
软件测试领域名词颇多，许多测试新手容易混淆概念。因为从不同的角度对软件测试有不同的分类方法，所以，这里汇总常见软件测试的相关名词，让读者对软件测试领域有个概括性了解。
&lt;br>
#### 根据项目流程阶段划分软件测试
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/testclass_01.png"
 data-srcset="http://img.testclass.net/testclass_01.png, http://img.testclass.net/testclass_01.png 1.5x, http://img.testclass.net/testclass_01.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/testclass_01.png"
 title="http://img.testclass.net/testclass_01.png" />&lt;/p>
&lt;p>是一个典型的“V”模型软件开发流程，各项软件测试工作是在项目开发流程中循序渐进进行的。下面将介绍各个阶段测试的含义。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>单元测试：单元测试（或模块测试）是对程序中的单个子程序或具有独立功能的代码段进行测试的过程。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>集成测试：集成测试是在单元测试的基础上，先通过单元模块组装成系统或子系统，再进行测试。重点是检查模块之间的接口是否正确。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>系统测试：系统测试是针对整个产品系统进行的测试，验证系统是否满足需求规格的定义，以及软件系统的正确性和性能等是否满足其需求规格的要求。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>验收测试：验收测试是部署软件之前的最后一个测试阶段。验收测试的目的是确保软件准备就绪，向软件购买者展示该软件系统能够满足用户的需求。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;br>
#### 白盒测试、黑盒测试、灰盒测试
&lt;p>白盒测试与黑盒测试，主要是根据软件测试工作中对软件代码的可见程度进行的划分。这也是软件测试领域中最基本的概念之一。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/testclass_02.png"
 data-srcset="http://img.testclass.net/testclass_02.png, http://img.testclass.net/testclass_02.png 1.5x, http://img.testclass.net/testclass_02.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/testclass_02.png"
 title="http://img.testclass.net/testclass_02.png" />&lt;/p>
&lt;ul>
&lt;li>黑盒测试&lt;/li>
&lt;/ul>
&lt;p>黑盒测试，指的是把被测的软件看作一个黑盒子，我们不去关心盒子里面的结构是什么样子的，只关心软件的输入数据和输出结果。
它只检查程序呈现给用户的功能是否按照需求规格说明书的规定正常使用、程序是否能接收输入数据并产生正确的输出信息。黑盒测试着眼于程序外部结构，不考虑内部逻辑结构，主要针对软件界面和软件功能进行测试。&lt;/p>
&lt;ul>
&lt;li>白盒测试&lt;/li>
&lt;/ul>
&lt;p>白盒测试，指的是把盒子打开，去研究里面的源代码和程序执行结果。
它是按照程序内部的结构测试程序，通过测试来检测产品内部动作是否按照设计规格说明书的规定正常进行，检验程序中的每条逻辑路径是否都能按预定要求正确工作。&lt;/p>
&lt;ul>
&lt;li>灰盒测试&lt;/li>
&lt;/ul>
&lt;p>灰盒测试介于黑盒测试与白盒测试之间。&lt;/p>
&lt;p>可以这样理解，灰盒测试既关注输出对于输入的正确性，同时也关注内部表现。但这种关注不像白盒测试那样详细、完整，它只是通过一些表征性的现象、事件、标志来判断内部的运行状态。有时候输出是正确的，但内部其实已经错误了，这种情况非常多。如果每次都通过白盒测试来操作，效率会很低，因此需要采取灰盒测试的方法。&lt;/p>
&lt;br>
#### 功能测试与性能测试
&lt;p>从软件的不同测试面可以划分为功能测试与性能测试。&lt;/p>
&lt;ul>
&lt;li>功能测试&lt;/li>
&lt;/ul>
&lt;p>功能测试主要检查实际功能是否符合用户的需求，因此测试的大部分工作也是围绕软件的功能进行。设计软件的目的就是满足用户对其功能的需求，如果偏离了这个目的，则任何测试工作都是没有意义的。&lt;/p>
&lt;p>功能测试又可以细分为很多种：逻辑功能测试、界面测试、易用性测试、安装测试、兼容性测试等。&lt;/p>
&lt;ul>
&lt;li>性能测试&lt;/li>
&lt;/ul>
&lt;p>性能测试是通过自动化的测试工具模拟多种正常、峰值以及异常负载条件来对系统的各项性能指标进行的测试。&lt;/p>
&lt;p>软件的性能包括很多方面，主要有时间性能和空间性能两种。&lt;/p>
&lt;p>&lt;strong>时间性能&lt;/strong>：主要是指软件的一个具体的响应时间。例如一个登录所需要的时间，一个商品交易所需要的时间等。当然，抛开具体的测试环境，来分析一次事务的响应时间是没有任何意义的，它需要在搭建好的一个具体且独立的测试环境下进行。&lt;/p>
&lt;p>&lt;strong>空间性能&lt;/strong>：主要指软件运行时所消耗的系统资源，例如硬件资源，CPU、内存、网络带宽消耗等。&lt;/p>
&lt;br>
#### 手工测试与自动化测试
&lt;p>从对软件测试工作的自动化程度可以划分为手工测试与自动化测试。&lt;/p>
&lt;ul>
&lt;li>手工测试&lt;/li>
&lt;/ul>
&lt;p>手工测试就是由测试人员一个一个地去执行测试用例，通过键盘鼠标等输入一些参数，并查看返回结果是否符合预期结果。&lt;/p>
&lt;p>手工测试并非专业术语，手工测试通常是指我们在系统测试阶段所进行的功能测试，为了更明显地与自动化测试进行区分，这里使用了手工测试这种说法。&lt;/p>
&lt;ul>
&lt;li>自动化测试&lt;/li>
&lt;/ul>
&lt;p>自动化测试是把以人为驱动的测试行为转化为机器执行的一种过程。通常，在设计测试用例并通过评审之后，由测试人员根据测试用例中描述的规则流程一步步执行测试，把得到的实际结果与期望结果进行比较。在此过程中，为了节省人力、时间和硬件资源，提高测试效率，便引入了自动化测试的概念。&lt;/p>
&lt;p>自动化测试又可分为：功能自动化测试与性能自动化测试。&lt;/p>
&lt;p>&lt;strong>功能自动化测试&lt;/strong>：是把以人为驱动的测试行为转化为机器执行的一种过程。通过测试工具（或框架）录制/编写测试脚本，对软件的功能进行测试，并验证测试结果是否正确，从而代替部分的手工测试工作，达到节约人力成本和时间成本的目的。&lt;/p>
&lt;p>&lt;strong>性能自动化测试&lt;/strong>：通过性能工具来模拟成千上万的虚拟用户向系统发送请求，从而验证系统的处理能力。&lt;/p>
&lt;br>
#### 冒烟测试、回归测试、随机测试、探索性测试和安全测试
&lt;p>这几种测试出现在软件测试的周期中，既不算具体明确的测试阶段，也不是具体的测试方法。&lt;/p>
&lt;ul>
&lt;li>冒烟测试&lt;/li>
&lt;/ul>
&lt;p>是指在对一个新版本进行大规模的系统测试之前，先验证一下软件的基本功能是否实现，是否具备可测性。&lt;/p>
&lt;p>引入到软件测试中，就是指测试小组在正式测试一个新版本之前，先投入较少的人力和时间验证一个软件的主要功能，如果主要功能都没有运行通过，则打回开发组重新开发。这样做的好处是可以节省时间和人力投入到不可测的项目中。&lt;/p>
&lt;ul>
&lt;li>回归测试&lt;/li>
&lt;/ul>
&lt;p>回归测试是指修改了旧代码后，重新进行测试以确认修改后没有引入新的错误或导致其他代码产生错误。&lt;/p>
&lt;p>回归测试一般是在进行第二轮软件测试时开始的，验证第一轮软件测试中发现的问题是否得到修复。当然，回归也是一个循环的过程，如果回归的问题通不过，则需要开发人员修改后再次进行回归，直到所有问题回归通过为止。&lt;/p>
&lt;ul>
&lt;li>随机测试&lt;/li>
&lt;/ul>
&lt;p>是指测试中的所有输入数据都是随机生成的，其目的是模拟用户的真实操作，并发现一些边缘性的错误。&lt;/p></description></item><item><title>wrk系列教程(2)简单使用</title><link>https://itest2025.pages.dev/tutorials/15-002-wrk%E7%B3%BB%E5%88%97%E6%95%99%E7%A8%8B2%E7%AE%80%E5%8D%95%E4%BD%BF%E7%94%A8/</link><pubDate>Sat, 02 Mar 2019 02:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/15-002-wrk%E7%B3%BB%E5%88%97%E6%95%99%E7%A8%8B2%E7%AE%80%E5%8D%95%E4%BD%BF%E7%94%A8/</guid><description>&lt;p>简单起见，建议大家可以先安装python。&lt;/p>
&lt;h3 id="在本机启动被测服务">在本机启动被测服务&lt;/h3>
&lt;p>创建一个&lt;code>index.html&lt;/code>文件&lt;/p>
&lt;pre tabindex="0">&lt;code>echo &amp;#39;&amp;lt;h3&amp;gt;It works&amp;lt;/h3&amp;gt;&amp;#39; &amp;gt; index.html
&lt;/code>&lt;/pre>&lt;p>index.html里面文件内容很简单，一句话&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;lt;h3&amp;gt;It works&amp;lt;/h3&amp;gt;&amp;#39;
&lt;/code>&lt;/pre>&lt;p>使用下面命令启动web服务。&lt;/p>
&lt;pre tabindex="0">&lt;code>python -m SimpleHTTPServer #python2

python -m http.server #python3
&lt;/code>&lt;/pre>&lt;p>预期结果应该是下面这个样子&lt;/p>
&lt;pre tabindex="0">&lt;code>Serving HTTP on 0.0.0.0 port 8000 ...
&lt;/code>&lt;/pre>&lt;h3 id="验证web服务">验证web服务&lt;/h3>
&lt;p>新开1个terminal窗口，使用下面命令&lt;/p>
&lt;pre tabindex="0">&lt;code>curl localhost:8000/index.html
&lt;/code>&lt;/pre>&lt;p>这时候命令行应该显示正确的返回&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;lt;h3&amp;gt;It works&amp;lt;/h3&amp;gt;
&lt;/code>&lt;/pre>&lt;h3 id="开始压测">开始压测&lt;/h3>
&lt;p>使用命令 &lt;code>wrk -c200 -t10 -d30s http://127.0.0.1:8000/index.html&lt;/code>&lt;/p>
&lt;p>解释一下主要参数&lt;/p>
&lt;ul>
&lt;li>c: connections 表示一共起多少个链接&lt;/li>
&lt;li>t: 表示用多少个&lt;/li>
&lt;/ul>
&lt;h3 id="结果展示">结果展示&lt;/h3>
&lt;p>在我的机器上结果是这个样子的&lt;/p>
&lt;pre tabindex="0">&lt;code>Running 30s test @ http://127.0.0.1:8000/index.html
 10 threads and 200 connections
 Thread Stats Avg Stdev Max +/- Stdev
 Latency 3.24ms 6.54ms 154.00ms 95.36%
 Req/Sec 167.54 227.05 1.81k 84.83%
 16145 requests in 30.08s, 3.13MB read
 Socket errors: connect 0, read 1208, write 31, timeout 0
Requests/sec: 536.78
Transfer/sec: 106.41KB
&lt;/code>&lt;/pre>&lt;p>对我们来说最重要的1个数据就是倒数第二行的&lt;code>Requests/sec: 536.78&lt;/code>。这说明我们测出的服务的QPS是536。&lt;/p></description></item><item><title>python简明教程: 2. 变量和集合</title><link>https://itest2025.pages.dev/tutorials/39-002-python%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B-2-%E5%8F%98%E9%87%8F%E5%92%8C%E9%9B%86%E5%90%88/</link><pubDate>Wed, 21 Nov 2018 03:23:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/39-002-python%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B-2-%E5%8F%98%E9%87%8F%E5%92%8C%E9%9B%86%E5%90%88/</guid><description>&lt;p>本文内容基本上翻译自&lt;a href="http://cheat.sh/python/:learn" target="_blank" rel="noopener noreffer ">http://cheat.sh/python/:learn)&lt;/a>&lt;/p>
&lt;p>&lt;strong>非原创, 非原创, 非原创!!!&lt;/strong>&lt;/p>
&lt;p>感谢原文社区作者&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Python 有 print 语句&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span> &lt;span class="s2">&amp;#34;I&amp;#39;m Python. Nice to meet you!&amp;#34;&lt;/span> &lt;span class="c1"># =&amp;gt; I&amp;#39;m Python. Nice to meet you!&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Python3 的时候你应该这么写&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;I&amp;#39;m Python. Nice to meet you!&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; I&amp;#39;m Python. Nice to meet you!&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 从控制台获取输入的简便方法&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">input_string_var&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">raw_input&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Enter some data: &amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 返回字符串&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">input_var&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">input&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Enter some data: &amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 把输入作为python代码执行&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 警告: 使用input() 方法时千万请小心谨慎&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 注意: python 3里input()方法被废弃了，并且raw_input()被重命名成了input()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 给变量赋值之前是不需要声明的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">some_var&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">5&lt;/span> &lt;span class="c1"># 一般约定使用下划线去给变量名分词 lower_case_with_underscores&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">some_var&lt;/span> &lt;span class="c1"># =&amp;gt; 5&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 访问没有定义的变量会抛出异常&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 在控制流部分可以查看更多关于异常处理的信息&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">some_other_var&lt;/span> &lt;span class="c1"># Raises a name error&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># if可以作为表达式使用&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 跟 C语言中 &amp;#39;?:&amp;#39; 三元操作符等价&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;yahoo!&amp;#34;&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="mi">3&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;yahoo!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">li&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 你可以定义一个预填充(或者叫非空的列表可能比较好)列表&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">other_li&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">6&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 使用append方法向列表的尾部添加元素&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">li&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># li is now [1]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">li&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># li is now [1, 2]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">li&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># li is now [1, 2, 4]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">li&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># li is now [1, 2, 4, 3]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 使用pop将元素从列表尾部移除&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">li&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pop&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1"># =&amp;gt; 3 and li is now [1, 2, 4]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 重新加回去&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">li&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># li is now [1, 2, 4, 3] again.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 访问列表元素跟访问数组元素的语法是相同的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">li&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># =&amp;gt; 1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 使用 = 可以给已经初始化过的索引赋新值&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">li&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">42&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">li&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># =&amp;gt; 42&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">li&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="c1"># 注意: 设置回原先的值&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 访问最后1个元素&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">li&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># =&amp;gt; 3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 访问越界的话会抛出 IndexError&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">li&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># Raises an IndexError&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 使用切片(slice)语法可以访问列表中的部分元素.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># (It&amp;#39;s a closed/open range for you mathy types.)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">li&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># =&amp;gt; [2, 4]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 忽略开头&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">li&lt;/span>&lt;span class="p">[:&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># =&amp;gt; [1, 2, 4]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 忽略结尾&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">li&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">:]&lt;/span> &lt;span class="c1"># =&amp;gt; [4, 3]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 每隔2个元素选择1个&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">li&lt;/span>&lt;span class="p">[::&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># =&amp;gt;[1, 4]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 反转列表的拷贝&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">li&lt;/span>&lt;span class="p">[::&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># =&amp;gt; [3, 4, 2, 1]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Use any combination of these to make advanced slices&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 使用上述的各种组合来创建更加复杂的切片&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># li[start:end:step]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 使用 &amp;#34;del&amp;#34; 来删除任意元素&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">del&lt;/span> &lt;span class="n">li&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># li is now [1, 2, 3]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 列表可以相加&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">li&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">other_li&lt;/span> &lt;span class="c1"># =&amp;gt; [1, 2, 3, 4, 5, 6]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 注意: li 和 for other_li 的值没有变化的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 使用&amp;#34;extend()&amp;#34;来连接列表&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 注意: li的值变化了的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">li&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">extend&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">other_li&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># Now li is [1, 2, 3, 4, 5, 6]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 移除第一个满足条件的值&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">li&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">remove&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># li is now [1, 3, 4, 5, 6]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">li&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">remove&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 抛出ValueError, 2已经不在列表里了&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 在特定的索引(index)处插入元素&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">li&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">insert&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># li is now [1, 2, 3, 4, 5, 6] again&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 返回第1个满足条件的值的索引&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">li&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">index&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; 1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">li&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">index&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">7&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 抛出ValueError，因为7不在列表里&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 用 &amp;#34;in&amp;#34; 来检查元素是否在列表中存在&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">1&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">li&lt;/span> &lt;span class="c1"># =&amp;gt; True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 用 &amp;#34;len()&amp;#34; 来返回列表的长度&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">li&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; 6&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 元组(Tuples) 跟列表很想，区别是元组是不可变的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tup&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tup&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># =&amp;gt; 1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tup&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">3&lt;/span> &lt;span class="c1"># 抛出TypeError异常&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 你可以在元组上做下面一些的列表操作&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">tup&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; 3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tup&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">6&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; (1, 2, 3, 4, 5, 6)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tup&lt;/span>&lt;span class="p">[:&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># =&amp;gt; (1, 2)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">2&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">tup&lt;/span> &lt;span class="c1"># =&amp;gt; True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># You can unpack tuples (or lists) into variables&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 你可以把元组(或列表) unpack成变量&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">c&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># a is now 1, b is now 2 and c is now 3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">d&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">f&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">6&lt;/span> &lt;span class="c1"># 你都可以省略括号&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 如果你不加括号的话，默认情况下会创建元组&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">g&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">6&lt;/span> &lt;span class="c1"># =&amp;gt; (4, 5, 6)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 看一下，交换变量的值那是相当容易的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">d&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">d&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">e&lt;/span> &lt;span class="c1"># d is now 5 and e is now 4&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 字典是用来存储属性名(key)和属性值(value)的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">empty_dict&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 这是预填充的字典&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">filled_dict&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;one&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;two&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;three&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 用[]来查找属性的值(value)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">filled_dict&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;one&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># =&amp;gt; 1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 用&amp;#34;keys()&amp;#34;来返回所有key的列表&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">filled_dict&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">keys&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1"># =&amp;gt; [&amp;#34;three&amp;#34;, &amp;#34;two&amp;#34;, &amp;#34;one&amp;#34;]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 注意 - 字典key的顺序是不保证的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 你自己的结果可能会跟上面不同&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># &amp;#34;values()&amp;#34;返回所有值(value)的列表&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">filled_dict&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">values&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1"># =&amp;gt; [3, 2, 1]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 注意 - 排序问题跟上面的类似&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># &amp;#34;items()&amp;#34; 返回所有的键值对(key-value)的元组组成的列表&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">filled_dicts&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1"># =&amp;gt; [(&amp;#34;one&amp;#34;, 1), (&amp;#34;two&amp;#34;, 2), (&amp;#34;three&amp;#34;, 3)]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 用&amp;#34;in&amp;#34;来判断某个属性名/某个键是否存在&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;one&amp;#34;&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">filled_dict&lt;/span> &lt;span class="c1"># =&amp;gt; True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">1&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">filled_dict&lt;/span> &lt;span class="c1"># =&amp;gt; False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 访问不存在的属性名/键的时候会抛出 KeyError&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">filled_dict&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;four&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># KeyError&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 用&amp;#34;get()&amp;#34;方法可以避免 KeyError&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">filled_dict&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;one&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; 1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">filled_dict&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;four&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># get支持当属性名/键不存在的时候返回1个设定的默认值&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">filled_dict&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;one&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; 1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">filled_dict&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;four&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; 4&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 注意: filled_dict.get(&amp;#34;four&amp;#34;) 仍然是 =&amp;gt; None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># (get 并不会设置字典的值)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 为某个属性名/键赋值跟列表赋值的方式差不多&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">filled_dict&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;four&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">4&lt;/span> &lt;span class="c1"># now, filled_dict[&amp;#34;four&amp;#34;] =&amp;gt; 4&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># &amp;#34;setdefault()&amp;#34; 方法在给定的属性名/键不存在的时候会插入具体的值&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">filled_dict&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">setdefault&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;five&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># filled_dict[&amp;#34;five&amp;#34;] 被设置成 5&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">filled_dict&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">setdefault&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;five&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">6&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># filled_dict[&amp;#34;five&amp;#34;] 仍然是 5&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 集合是存储... 好吧，集合 (跟列表差不多，只是不能有重复的项)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">empty_set&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">set&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 初始化的时候赋一些值&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">some_set&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">set&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">])&lt;/span> &lt;span class="c1"># some_set 现在等于set([1, 2, 3, 4])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 顺序是不被保证的, 即使有时候看起来像排过序一样&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">another_set&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">set&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">])&lt;/span> &lt;span class="c1"># another_set 现在是 set([1, 2, 3, 4])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 从Python 2.7开始, {} 可以被用来声明集合&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">filled_set&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">}&lt;/span> &lt;span class="c1"># =&amp;gt; {1, 2, 3, 4}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 往集合里添加更多项&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">filled_set&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># filled_set is now {1, 2, 3, 4, 5}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 用 &amp;amp; 来取交集&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">other_set&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">6&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">filled_set&lt;/span> &lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">other_set&lt;/span> &lt;span class="c1"># =&amp;gt; {3, 4, 5}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 用 | 取并集&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">filled_set&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="n">other_set&lt;/span> &lt;span class="c1"># =&amp;gt; {1, 2, 3, 4, 5, 6}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 用 - 来取差集&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">}&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">}&lt;/span> &lt;span class="c1"># =&amp;gt; {1, 4}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 用 ^ 取对称差集&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">}&lt;/span> &lt;span class="o">^&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">}&lt;/span> &lt;span class="c1"># =&amp;gt; {1, 4, 5}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 判断左边的集合是不是右边的超集&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">}&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">}&lt;/span> &lt;span class="c1"># =&amp;gt; False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 判断左边的集合是不是右边的子集&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">}&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">}&lt;/span> &lt;span class="c1"># =&amp;gt; True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 用in来判断元素在集合中是否存在&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">2&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">filled_set&lt;/span> &lt;span class="c1"># =&amp;gt; True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="mi">10&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">filled_set&lt;/span> &lt;span class="c1"># =&amp;gt; False&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p></description></item><item><title>（二）Docker安装（Ubuntu）</title><link>https://itest2025.pages.dev/tutorials/30-002-%E4%BA%8Cdocker%E5%AE%89%E8%A3%85ubuntu/</link><pubDate>Mon, 22 Jan 2018 14:55:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/30-002-%E4%BA%8Cdocker%E5%AE%89%E8%A3%85ubuntu/</guid><description>&lt;p>官方文档：https://docs.docker.com/&lt;/p>
&lt;p>Docker 支持多平台的安装（Linux/Windows/OS X）。&lt;/p>
&lt;p>因为Docker原生支持Linux，所以，可以直接在Linux上运行，而且在Windows和 OS X 平台则需要借助轻量级的 Linux VM 运行。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/docker-platform.png"
 data-srcset="http://img.testclass.net/docker-platform.png, http://img.testclass.net/docker-platform.png 1.5x, http://img.testclass.net/docker-platform.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/docker-platform.png"
 title="http://img.testclass.net/docker-platform.png" />&lt;/p>
&lt;h3 id="ubuntu安装">Ubuntu安装&lt;/h3>
&lt;hr>
&lt;p>在Ubuntu上安装Docker的说明取决于您使用的是Docker企业版（Docker EE）还是Docker社区版（Docker CE）。&lt;/p>
&lt;p>参考文档：https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/&lt;/p>
&lt;h4 id="使用仓库进行安装">使用仓库进行安装&lt;/h4>
&lt;p>首次在新的主机上安装Docker CE之前，需要设置Docker仓库。 之后，你可以从存储库安装和更新Docker。&lt;/p>
&lt;h5 id="设置仓库">设置仓库&lt;/h5>
&lt;p>1、更新 &lt;code>apt&lt;/code> 包索引:&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo apt-get update
&lt;/code>&lt;/pre>&lt;p>2、安装软件包，使它允许&lt;code>apt&lt;/code>通过HTTPS使用仓库：&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo apt-get install apt-transport-https ca-certificates curl software-properties-common
&lt;/code>&lt;/pre>&lt;p>3、添加Docker的官方GPG密钥：&lt;/p>
&lt;pre tabindex="0">&lt;code>$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
&lt;/code>&lt;/pre>&lt;p>通过搜索密钥的最后8个字符，确认您现在已经拥有指纹 &lt;code>9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88&lt;/code> 的密钥。&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo apt-key fingerprint 0EBFCD88

pub 4096R/0EBFCD88 2017-02-22
 密钥指纹 = 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88
uid Docker Release (CE deb) &amp;lt;docker@docker.com&amp;gt;
sub 4096R/F273FCD8 2017-02-22
&lt;/code>&lt;/pre>&lt;p>4、使用以下命令来设置 &lt;strong>stable&lt;/strong> 的仓库。即使你想从 __edge __ 或 &lt;strong>test&lt;/strong> 仓库安装构建，也总是需要 &lt;strong>stable&lt;/strong> 的仓库。要添加 __edge __ 或 &lt;strong>test&lt;/strong> 仓库，请在下面的命令中在单词stable之后添加edge或test（或两者）。&lt;/p></description></item><item><title>（二）Hello world</title><link>https://itest2025.pages.dev/tutorials/16-002-%E4%BA%8Chello-world/</link><pubDate>Wed, 17 Jan 2018 14:45:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/16-002-%E4%BA%8Chello-world/</guid><description>&lt;h4 id="hello-world">Hello world&lt;/h4>
&lt;hr>
&lt;p>按照管理先用Java写一个 &amp;ldquo;Hello world&amp;rdquo; 。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">package&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">Base&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">HelloWrold&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Hello World!&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>main()方法的定义：&lt;/strong>&lt;/p>
&lt;p>&lt;code>main()&lt;/code>方法是Java应用程序的入口方法，也就是程序运行时的第一个方法。声明为：&lt;code>public static void main()&lt;/code>。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>public static：由于JVM在运行这个Java应用程序的时候，首先会调用main()方法，调用时不实例化这个类的对象，而是通过类名直接调用因此需要是限制为&lt;code>public static&lt;/code> 即 &lt;code>main()&lt;/code> 方法是一个公共的（public）静态（static）方法。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>void ： JVM有限制，因此不能有返回值类型为void。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>String[] args : main()方法中必须有一个入参，必须是字符串数组（&lt;code>String[]&lt;/code>），这个是java的规范。至于字符串数组的名字，是可以随便取的。但根据习惯，这个字符串数组的名字一般和SUN Java规范范例中main参数名保持一致，取名为args。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>println()方法输出&lt;/strong>&lt;/p>
&lt;p>因为Java不允许独立于类外的方法存在，所以在命名空间内不存在直接的类函数调用。&lt;/p>
&lt;p>&lt;code>System&lt;/code>是&lt;code>java.lang&lt;/code>中的一个类。 &lt;code>System.out&lt;/code>中的&lt;code>out&lt;/code>代表了&lt;code>System&lt;/code>类中的静态对象&lt;code>PrintStream&lt;/code>，&lt;code>println()&lt;/code>是&lt;code>PrintStream&lt;/code>中的方法。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1551033406-611cf9a28f67?w=300"
 data-srcset="https://images.unsplash.com/photo-1551033406-611cf9a28f67?w=300, https://images.unsplash.com/photo-1551033406-611cf9a28f67?w=300 1.5x, https://images.unsplash.com/photo-1551033406-611cf9a28f67?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1551033406-611cf9a28f67?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>TDD实战（二）“井字游戏” 需求一</title><link>https://itest2025.pages.dev/tutorials/32-002-tdd%E5%AE%9E%E6%88%98%E4%BA%8C%E4%BA%95%E5%AD%97%E6%B8%B8%E6%88%8F-%E9%9C%80%E6%B1%82%E4%B8%80/</link><pubDate>Mon, 08 Jan 2018 12:55:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/32-002-tdd%E5%AE%9E%E6%88%98%E4%BA%8C%E4%BA%95%E5%AD%97%E6%B8%B8%E6%88%8F-%E9%9C%80%E6%B1%82%E4%B8%80/</guid><description>&lt;p>保证你会玩“&lt;strong>井字游戏&lt;/strong>” 并理解它的规则。&lt;/p>
&lt;h3 id="需求1">需求1&lt;/h3>
&lt;hr>
&lt;p>先定义边界，以及将棋子放在哪些地方非法。&lt;/p>
&lt;blockquote>
&lt;p>可将棋子放在3×3棋盘上任何没有棋子的地方。&lt;/p>&lt;/blockquote>
&lt;p>将需求分成三个测试：&lt;/p>
&lt;ul>
&lt;li>如果棋子放在超出了X轴边界的地方，就引发 &lt;code>RuntimeException&lt;/code> 异常。&lt;/li>
&lt;li>如果棋子放在超出了Y轴边界的地方，就引发 &lt;code>RuntimeException&lt;/code> 异常。&lt;/li>
&lt;li>如果棋子放在已经有棋子的地方，就引发 &lt;code>RuntimeException&lt;/code> 异常。&lt;/li>
&lt;/ul>
&lt;h4 id="测试用例-1">测试用例 1&lt;/h4>
&lt;hr>
&lt;p>默认你已经会使用 JUnit 单元测试框架了，根据上面的三个测试，我们先来完成第一个。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.Before&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.Rule&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.Test&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.rules.ExpectedException&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">TicTacToeTest&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Rule&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ExpectedException&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">exception&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ExpectedException&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">none&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">private&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">TicTacToe&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ticTacToe&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Before&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">final&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">before&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">ticTacToe&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">TicTacToe&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">whenXOutsideBoardThenRuntimeException&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">exception&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">expect&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">RuntimeException&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">class&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">ticTacToe&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">play&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">5&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>测试调用 &lt;code>TicTacToe&lt;/code> 类的 &lt;code>play()&lt;/code> 方法，假设第一个参数是 x 轴，第二个参数是 y 轴，前面需求已经规定，棋盘是3×3的规格，所以参数必须不能小于1或大于3。
x 轴为5会引发异常。在 &lt;code>whenXOutsideBoardThenRuntimeException()&lt;/code> 测试用例中，预期这被测代码会抛出 &lt;code>RuntimeException&lt;/code>异常。&lt;/p></description></item><item><title>Android测试（二）：Android 测试基础</title><link>https://itest2025.pages.dev/tutorials/17-002-android%E6%B5%8B%E8%AF%95%E4%BA%8Candroid-%E6%B5%8B%E8%AF%95%E5%9F%BA%E7%A1%80/</link><pubDate>Wed, 20 Dec 2017 14:50:12 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/17-002-android%E6%B5%8B%E8%AF%95%E4%BA%8Candroid-%E6%B5%8B%E8%AF%95%E5%9F%BA%E7%A1%80/</guid><description>&lt;p>原文：https://developer.android.com/training/testing/fundamentals.html&lt;/p>
&lt;p>用户在不同的级别上与你的应用产生交互。从按下按钮到将信息下载到他们的设备上，因此，你应该在迭代开发应用程序时测试各种用例和交互。&lt;/p>
&lt;h3 id="使用迭代开发工作流">使用迭代开发工作流&lt;/h3>
&lt;hr>
&lt;p>当你的应用程序进行扩展时，你可能会发现需要从服务器获取数据，与设备的传感器进行交互，可以还需要访问本地存储，或呈现复杂的用户界面。应用程序的多样性需要一个全面的测试策略。&lt;/p>
&lt;p>在迭代开发一个新的特性时，首先需要编写一个新的测试，或者在现有单元测试中添加新的测试例和断言。测试一开始是失败的，因为这个新特性还没有实现。&lt;/p>
&lt;p>在设计新功能时，考虑单元测试的设计很重要。对于每个功能单元编写一个相应的单元测试。你的单元测试应该尽可多的涵盖到所有可能与单元的交互，包括标准的交互、无效的输入、以及资源不可用的情况。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/android_testing_workflow.png"
 data-srcset="http://img.testclass.net/android_testing_workflow.png, http://img.testclass.net/android_testing_workflow.png 1.5x, http://img.testclass.net/android_testing_workflow.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/android_testing_workflow.png"
 title="http://img.testclass.net/android_testing_workflow.png" />&lt;/p>
&lt;p>图：测试驱动开发：两个周期与迭代过程。&lt;/p>
&lt;p>完整的工作流，如上图，包含一系列嵌套的循环迭代。其中长、慢、UI驱动的集成测试，你可以用更短、更快的单元测试驱动开发周期来完成。这一系列循环一直持续到你的应用程序满足每个用例为止。&lt;/p>
&lt;h3 id="测试金字塔">测试金字塔&lt;/h3>
&lt;hr>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/android_pyramid.png"
 data-srcset="http://img.testclass.net/android_pyramid.png, http://img.testclass.net/android_pyramid.png 1.5x, http://img.testclass.net/android_pyramid.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/android_pyramid.png"
 title="http://img.testclass.net/android_pyramid.png" />&lt;/p>
&lt;p>图：测试金字塔，显示应该在应用程序的测试套件中包含的三个测试类别。&lt;/p>
&lt;p>测试金字塔，如上图所示，说明你的应用程序应该如何包括三种类型的测试：小测试、中测试和大测试。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>小测试是你可以在与生产系统隔离的情况下运行的单元测试。它们通常会mock所有主要组件，并在PC上快速运行。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>中测试是介于小测试和大测试之间的集成测试。它们集成了几个组件，并在Android模拟器或真实设备上运行。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>大测试是通过完成UI工作流来运行的集成和UI测试。它们确保关键的终端用户任务在Android模拟器或真实设备上正常工作。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>&lt;font color="red">注：这里测试金字塔的定义是Google针对Android应用的测试划分。不同类型的应用，通过测试金字塔模型进行划层级的划分，以及每层的定义会有所不同。&lt;/font>&lt;/p>
&lt;p>尽管小测试的速度很快，而且重点突出，可以让您快速处理失败，但它们是低保真和独立的，让你很难相信通过测试的应用是可以正常运行的，所以需要通过大测试进行补足。&lt;/p>
&lt;p>由于每个测试类别的不同特性，你的测试工作应该包含测试金字塔的每一层测试。尽管每个类别的测试比例可能因应用程序的使用情况而有所不同，但我们通常建议以下分类：70%的小测试、20%的中等测试和10%的大测试。&lt;/p>
&lt;h4 id="小测试">小测试&lt;/h4>
&lt;hr>
&lt;p>在添加和更改应用程序的功能时，通过创建和编写单元测试来确保这些功能按照预期的来运行。虽然可以在Android模拟器或真实设备中运行单元测试，但是在开发环境中运行单元测试通常会更快、更容易，根据需要添加Stub或mock方法实现与Android系统进行交互。&lt;/p>
&lt;h5 id="robolectric">Robolectric&lt;/h5>
&lt;p>如果你的应用程序的测试环境要求单元测试与Android框架进行更广泛的交互，那么你可以使用Robolectric。此工具执行测试友好、基于Java 逻辑Stub来模拟Android框架，由社区来维护这些Stub。&lt;/p>
&lt;p>Robolectric测试几乎完全符合Android设备上运行测试的完全保真度，但仍比设备测试运行得更快。它还支持Android平台的以下几个方面:&lt;/p>
&lt;ul>
&lt;li>Android 4.1（API等级16）及更高版本&lt;/li>
&lt;li>Android Gradle插件2.4及更高版本&lt;/li>
&lt;li>组件生命周期&lt;/li>
&lt;li>事件循环&lt;/li>
&lt;li>所有资源&lt;/li>
&lt;/ul>
&lt;p>Robolectric有自己的一套测试API，并引入了一些新概念。有关将Robolectric的API与应用程序的测试相结合的更多信息，请参见该工具的 &lt;a href="http://robolectric.org/configuring/" target="_blank" rel="noopener noreffer ">用户指南&lt;/a>&lt;/p>
&lt;h5 id="mock对象">Mock对象&lt;/h5>
&lt;p>你可以通过修改Android.jar版本来运行单元测试，从而来监控应用与之交互的Android框架元素。这个JAR文件不包含任何代码，所以你的应用程序调用Android框架默认会抛出异常。 要测试与Android系统交互的代码元素，请使用像Mockito这样的框架来配置模拟对象。&lt;/p>
&lt;h5 id="检测单元测试">检测单元测试&lt;/h5>
&lt;p>你也可以在Andorid模拟器或真实设备上运行检测单元测试，而不涉及任何stub或mock框架。因为这种测试形式的执行时间明显比本地单元测试慢，所以最好仅在需要评估应用程序对当前设备硬件的行为时才依赖此方法。&lt;/p>
&lt;h4 id="中测试">中测试&lt;/h4>
&lt;hr>
&lt;p>在开发环境中测试了应用程序的每个单元之后，应验证在模拟器或设备上运行时组件的行为是否正确。 中等测试允许您完成这部分的开发过程。 如果某些应用程序的组件依赖于物理硬件，则这些测试对于创建和运行尤其重要。&lt;/p>
&lt;p>中等测试你的应用程序如何协调多个单元，但它们不测试完整的应用程序。中等测试的用例包括服务测试、集成测试以及mock外部依赖性行为的UI测试。&lt;/p>
&lt;p>通常情况下，最好在Android模拟器或Firebase测试实验室等基于云服务上测试应用程序，而不是在真实设备上测试应用程序，因为你可以更轻松，快速地测试多种屏幕大小和硬件配置组合。&lt;/p>
&lt;h4 id="大测试">大测试&lt;/h4>
&lt;hr>
&lt;p>尽管测试应用程序中的每一层的功能是非常重要的，但是测试涉及整个堆栈的常见工作流和用例（从UI到业务逻辑到数据层）同样重要。&lt;/p>
&lt;p>如果您的应用程序足够小，则可能只需要一套大型测试来评估你的应用程序。 否则，你应该根据团队所有权，垂直功能或用户目标来划分你的大型测试套件。&lt;/p>
&lt;blockquote>
&lt;p>对于你所编写的每一个大型的基于工作流程的测试，你还应该编写中测试来检查工作流中包含的每个UI组件的功能。通过这种方式，即使在最初的几个步骤中，相应的大型测试也会失败了，你的测试套件仍然可以在关键用户操作的每一步中继续识别潜在的问题。&lt;/p>&lt;/blockquote>
&lt;p>AndroidJUnitRunner类定义了一个基于JUnit框架的测试运行器，它允许你在Android设备上运行JUnit 3或JUnit 4样式的测试类。便于将测试包和应用程序加载到真实设备或Android模拟器上，运行测试并报告结果。&lt;/p></description></item><item><title>Fiddler（二）主界面介绍</title><link>https://itest2025.pages.dev/tutorials/23-002-fiddler%E4%BA%8C%E4%B8%BB%E7%95%8C%E9%9D%A2%E4%BB%8B%E7%BB%8D/</link><pubDate>Tue, 19 Dec 2017 13:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/23-002-fiddler%E4%BA%8C%E4%B8%BB%E7%95%8C%E9%9D%A2%E4%BB%8B%E7%BB%8D/</guid><description>&lt;p>在开始Fiddler工具之前，请先学习 &lt;a href="https://itest2025.pages.dev/proxy_tools/http-base/" rel="">HTTP基础&lt;/a>&lt;/p>
&lt;h3 id="fiddler主界面">Fiddler主界面&lt;/h3>
&lt;hr>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/fiddler_04.png"
 data-srcset="http://img.testclass.net/fiddler_04.png, http://img.testclass.net/fiddler_04.png 1.5x, http://img.testclass.net/fiddler_04.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/fiddler_04.png"
 title="http://img.testclass.net/fiddler_04.png" />&lt;/p>
&lt;p>Fiddler 工具界面如上图。&lt;/p>
&lt;h4 id="请求列表左侧窗口">请求列表（左侧窗口）&lt;/h4>
&lt;hr>
&lt;p>显示Fiddler 工具拦截的 HTTP/HTTPS 请求。&lt;/p>
&lt;ul>
&lt;li>&lt;code>#&lt;/code> 显示资源类型与编号。&lt;/li>
&lt;/ul>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/fiddler_04_1.png"
 data-srcset="http://img.testclass.net/fiddler_04_1.png, http://img.testclass.net/fiddler_04_1.png 1.5x, http://img.testclass.net/fiddler_04_1.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/fiddler_04_1.png"
 title="http://img.testclass.net/fiddler_04_1.png" />&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;code>Result&lt;/code> 表示HTTP返回的状态码。如 200、302、500等。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>Protocol&lt;/code> 表示请求的协议：HTTP/HTTPS&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>Host&lt;/code> 请求的IP或网址。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>URL&lt;/code> 请求的路径。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>Body&lt;/code> 请求资源的大小。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>Caching&lt;/code> 请求的缓存过期时间或者缓存控制值。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>Content-Type&lt;/code> 请求响应的类型。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>Process&lt;/code> 发送此请求的进程：进程ID。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>Comments&lt;/code> 允许用户为此回话添加备注。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>Custom&lt;/code> 允许用户设置自定义值。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h4 id="statistics右则窗statistics标签">Statistics（右则窗Statistics标签）&lt;/h4>
&lt;hr>
&lt;p>Statistics 显示关于HTTP请求的性能以及数据分析。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/fiddler_04_2.png"
 data-srcset="http://img.testclass.net/fiddler_04_2.png, http://img.testclass.net/fiddler_04_2.png 1.5x, http://img.testclass.net/fiddler_04_2.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/fiddler_04_2.png"
 title="http://img.testclass.net/fiddler_04_2.png" />&lt;/p>
&lt;h4 id="inspectors-右则窗inspectors标签">Inspectors （右则窗Inspectors标签）&lt;/h4>
&lt;hr>
&lt;p>Inspectors 是用于查看会话的内容，上半部分是请求的内容，下半部分是响应的内容。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/fiddler_04_3.png"
 data-srcset="http://img.testclass.net/fiddler_04_3.png, http://img.testclass.net/fiddler_04_3.png 1.5x, http://img.testclass.net/fiddler_04_3.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/fiddler_04_3.png"
 title="http://img.testclass.net/fiddler_04_3.png" />&lt;/p></description></item><item><title>搭建开发环境</title><link>https://itest2025.pages.dev/tutorials/27-002-%E6%90%AD%E5%BB%BA%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83/</link><pubDate>Sun, 17 Dec 2017 02:52:34 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/27-002-%E6%90%AD%E5%BB%BA%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83/</guid><description>&lt;h3 id="开发环境介绍">开发环境介绍&lt;/h3>
&lt;p>我们使用python来实现最简单的爬虫。&lt;/p>
&lt;ul>
&lt;li>使用python的&lt;a href="http://docs.python-requests.org/en/master/" target="_blank" rel="noopener noreffer ">requests&lt;/a>库来发起http请求并获取目标站点的html代码。&lt;/li>
&lt;li>使用python的&lt;a href="https://www.crummy.com/software/BeautifulSoup/bs4/doc/" target="_blank" rel="noopener noreffer ">BeautifulSoup&lt;/a>库来解析html，从html中提取感兴趣的内容。&lt;/li>
&lt;/ul>
&lt;h3 id="requests教程">Requests教程&lt;/h3>
&lt;p>大家可以在&lt;a href="https://itest2025.pages.dev/requests" rel="">测试教程网requests教程&lt;/a>中找到requests库的一些典型用法。&lt;/p>
&lt;h3 id="环境搭建">环境搭建&lt;/h3>
&lt;ul>
&lt;li>安装python3，可以参考&lt;a href="https://itest2025.pages.dev/selenium_python/install-selenium/" rel="">这里&lt;/a>&lt;/li>
&lt;li>安装requests，可以参考&lt;a href="https://itest2025.pages.dev/requests/install/" rel="">这里&lt;/a>&lt;/li>
&lt;li>安装BeautifulSoup，可以参考&lt;a href="https://www.crummy.com/software/BeautifulSoup/bs4/doc/#installing-beautiful-soup" target="_blank" rel="noopener noreffer ">这里&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="作者使用软件版本">作者使用软件版本&lt;/h3>
&lt;p>我的电脑上环境是这样&lt;/p>
&lt;ul>
&lt;li>python: 3.5.2&lt;/li>
&lt;li>requests: 2.13.0&lt;/li>
&lt;li>beautifulsoup4: 4.6.0&lt;/li>
&lt;/ul>
&lt;p>不需要与我的版本保持完全一致，只需要大于等于我使用的版本就可以了&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1433838552652-f9a46b332c40?w=300"
 data-srcset="https://images.unsplash.com/photo-1433838552652-f9a46b332c40?w=300, https://images.unsplash.com/photo-1433838552652-f9a46b332c40?w=300 1.5x, https://images.unsplash.com/photo-1433838552652-f9a46b332c40?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1433838552652-f9a46b332c40?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（二）验证某些行为</title><link>https://itest2025.pages.dev/tutorials/45-002-%E4%BA%8C%E9%AA%8C%E8%AF%81%E6%9F%90%E4%BA%9B%E8%A1%8C%E4%B8%BA/</link><pubDate>Sat, 25 Nov 2017 12:55:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/45-002-%E4%BA%8C%E9%AA%8C%E8%AF%81%E6%9F%90%E4%BA%9B%E8%A1%8C%E4%B8%BA/</guid><description>&lt;p>跟着我们的示例来mock 一个List,因为大家都知道它的接口（例如add(),get(), clear()）。不要mock一个真实的List类型,使用一个真实的实例来替代。&lt;/p>
&lt;h4 id="验证某些行为">验证某些行为&lt;/h4>
&lt;hr>
&lt;p>例子：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.Test&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">java.util.List&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 静态导入会使代码更简洁&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.mockito.Mockito.*&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">MockitoDemo&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">verify_behaviour&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// mock creation 创建mock对象&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">List&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">mock&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">List&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">class&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//using mock object 使用mock对象&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;one&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">clear&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//verification 验证&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">verify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="na">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;one&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">verify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="na">clear&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>一旦mock对象被创建了，mock对象会记住所有的交互。然后你就可能选择性的验证你感兴趣的交互。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1524749292158-7540c2494485?w=300"
 data-srcset="https://images.unsplash.com/photo-1524749292158-7540c2494485?w=300, https://images.unsplash.com/photo-1524749292158-7540c2494485?w=300 1.5x, https://images.unsplash.com/photo-1524749292158-7540c2494485?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1524749292158-7540c2494485?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（二）Maven 安装</title><link>https://itest2025.pages.dev/tutorials/41-002-%E4%BA%8Cmaven-%E5%AE%89%E8%A3%85/</link><pubDate>Sat, 25 Nov 2017 12:50:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/41-002-%E4%BA%8Cmaven-%E5%AE%89%E8%A3%85/</guid><description>&lt;h4 id="准备工作">准备工作&lt;/h4>
&lt;hr>
&lt;p>&lt;a href="https://itest2025.pages.dev/selenium_java/install-java/" rel="">JDK&lt;/a> ： Java 开发程序所使用的环境。&lt;/p>
&lt;p>&lt;a href="https://itest2025.pages.dev/idea/" rel="">IntelliJ IDEA&lt;/a> ： Java 开发程序所使用的 IDE。&lt;/p>
&lt;p>Maven ： 下载地址 &lt;a href="http://maven.apache.org/download.cgi" target="_blank" rel="noopener noreffer ">http://maven.apache.org/download.cgi&lt;/a>&lt;/p>
&lt;h4 id="环境配置">环境配置&lt;/h4>
&lt;hr>
&lt;p>将 Maven 下载到本地解压， 这里以下载当前最新版本（apache-maven-3.5.0-bin.zip）为例， 解压到得到 apache-maven-3.5.0 目录。&lt;/p>
&lt;p>&lt;strong>下面设置环境变量&lt;/strong>：&lt;/p>
&lt;p>“此电脑” 右键菜单&amp;mdash;&amp;gt;属性&amp;mdash;&amp;gt;高级&amp;mdash;&amp;gt;环境变量&amp;mdash;&amp;gt;系统变量&amp;mdash;&amp;gt;新建..&lt;/p>
&lt;blockquote>
&lt;p>变量名： MAVEN_HOME&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>变量值： D:\java\apache-maven-3.5.0&lt;/p>&lt;/blockquote>
&lt;p>找到 path 变量名—&amp;gt;“编辑” 添加：&lt;/p>
&lt;blockquote>
&lt;p>变量名： PATH&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>变量值： %MAVEN_HOME%\bin;&lt;/p>&lt;/blockquote>
&lt;p>验证 Maven 环境是否配置成功&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/maven_version.png"
 data-srcset="http://img.testclass.net/maven_version.png, http://img.testclass.net/maven_version.png 1.5x, http://img.testclass.net/maven_version.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/maven_version.png"
 title="http://img.testclass.net/maven_version.png" />&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1462826303086-329426d1aef5?w=300"
 data-srcset="https://images.unsplash.com/photo-1462826303086-329426d1aef5?w=300, https://images.unsplash.com/photo-1462826303086-329426d1aef5?w=300 1.5x, https://images.unsplash.com/photo-1462826303086-329426d1aef5?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1462826303086-329426d1aef5?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（二）第一个测试用例</title><link>https://itest2025.pages.dev/tutorials/36-002-%E4%BA%8C%E7%AC%AC%E4%B8%80%E4%B8%AA%E6%B5%8B%E8%AF%95%E7%94%A8%E4%BE%8B/</link><pubDate>Sat, 25 Nov 2017 12:50:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/36-002-%E4%BA%8C%E7%AC%AC%E4%B8%80%E4%B8%AA%E6%B5%8B%E8%AF%95%E7%94%A8%E4%BE%8B/</guid><description>&lt;h4 id="第一个测试用例">第一个测试用例&lt;/h4>
&lt;hr>
&lt;p>通过 &lt;a href="https://itest2025.pages.dev/idea/" rel="">IntelliJ IDEA&lt;/a> 创建 FirstTest 测试类。编写如下代码：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.testng.annotations.Test&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.testng.AssertJUnit.assertEquals&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">FirstTest&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">testCase&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">4&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>通过 &lt;strong>@Test&lt;/strong> 注解一个方法为测试用例。&lt;/li>
&lt;li>通过 &lt;strong>assertEquals()&lt;/strong> 方法来断言两个数是否相等。&lt;/li>
&lt;/ul>
&lt;p>运行测试：&lt;/p>
&lt;pre tabindex="0">&lt;code>===============================================
Default Suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================
&lt;/code>&lt;/pre>&lt;p>我们先感官上对TestNG使用有一个初步认识。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1502810190503-8303352d0dd1?w=300"
 data-srcset="https://images.unsplash.com/photo-1502810190503-8303352d0dd1?w=300, https://images.unsplash.com/photo-1502810190503-8303352d0dd1?w=300 1.5x, https://images.unsplash.com/photo-1502810190503-8303352d0dd1?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1502810190503-8303352d0dd1?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>requests如何发送get请求?</title><link>https://itest2025.pages.dev/tutorials/42-002-requests%E5%A6%82%E4%BD%95%E5%8F%91%E9%80%81get%E8%AF%B7%E6%B1%82/</link><pubDate>Wed, 22 Nov 2017 03:23:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/42-002-requests%E5%A6%82%E4%BD%95%E5%8F%91%E9%80%81get%E8%AF%B7%E6%B1%82/</guid><description>&lt;p>&lt;a href="http://docs.python-requests.org/en/master/user/quickstart/#make-a-request" target="_blank" rel="noopener noreffer ">官方文档&lt;/a>&lt;/p>
&lt;p>使用requests发送请求其实非常简单。&lt;/p>
&lt;p>首先导入Requests模块&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; import requests
&lt;/code>&lt;/pre>&lt;p>下面试着去发送具体的请求，比如获取github的timeline信息&lt;/p>
&lt;pre tabindex="0">&lt;code>r = requests.get(&amp;#39;https://api.github.com/events&amp;#39;)
&lt;/code>&lt;/pre>&lt;p>r是requests的&lt;a href="http://docs.python-requests.org/en/master/api/#requests.Response" target="_blank" rel="noopener noreffer ">响应(Response)&lt;/a>对象，我们可以从r里面获取各种信息，比如获取响应的内容&lt;code>print(r.text)&lt;/code>&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1513470270416-d3ff6f16b22f?w=300"
 data-srcset="https://images.unsplash.com/photo-1513470270416-d3ff6f16b22f?w=300, https://images.unsplash.com/photo-1513470270416-d3ff6f16b22f?w=300 1.5x, https://images.unsplash.com/photo-1513470270416-d3ff6f16b22f?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1513470270416-d3ff6f16b22f?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（二）JUnit 安装</title><link>https://itest2025.pages.dev/tutorials/31-002-%E4%BA%8Cjunit-%E5%AE%89%E8%A3%85/</link><pubDate>Mon, 13 Nov 2017 12:55:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/31-002-%E4%BA%8Cjunit-%E5%AE%89%E8%A3%85/</guid><description>&lt;p>Junit目前分两个版本，Junit4 和 Junit5 , 本系列教程打算从 Junit4 开始介绍，最后，再介绍 Junit5 有哪些新特性。&lt;/p>
&lt;h4 id="intellij-idea-安装-junit">IntelliJ IDEA 安装 Junit&lt;/h4>
&lt;hr>
&lt;p>Java 开发的同学，推荐使用 IntelliJ IDEA，推荐阅读《&lt;a href="https://itest2025.pages.dev/idea/" rel="">IntelliJ IDEA 教程&lt;/a>》。&lt;/p>
&lt;p>1、下载 &lt;strong>junit-4.12.jar&lt;/strong> 文件：https://github.com/junit-team/junit4/releases&lt;/p>
&lt;p>2、 打开 IntelliJ IDEA ，菜单栏：&lt;strong>File菜单 &amp;ndash;&amp;gt; Porject Structure 选项 &amp;ndash;&amp;gt; Dependencies 标签 &amp;ndash;&amp;gt; 点击 &amp;ldquo;+&amp;rdquo; 号 &amp;ndash;&amp;gt; Library&amp;hellip; &amp;ndash;&amp;gt; Java 。&lt;/strong> 选择下载的 &lt;strong>junit-4.12.jar&lt;/strong> 进行添加。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/junit_add_jar.png"
 data-srcset="http://img.testclass.net/junit_add_jar.png, http://img.testclass.net/junit_add_jar.png 1.5x, http://img.testclass.net/junit_add_jar.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/junit_add_jar.png"
 title="http://img.testclass.net/junit_add_jar.png" />&lt;/p>
&lt;p>3、以同样的方式下载和导入 &lt;strong>hamcrest&lt;/strong>： &lt;a href="https://github.com/hamcrest/JavaHamcrest/releases" target="_blank" rel="noopener noreffer ">https://github.com/hamcrest/JavaHamcrest/releases&lt;/a> ,否则，你将无法运行 Junit 单元测试。&lt;/p>
&lt;h4 id="maven-安装-junit">Maven 安装 Junit&lt;/h4>
&lt;hr>
&lt;p>相比较而言，Maven 的安装要简单很多，打开你 Maven 项目中的 pom.xml 文件，添加如下配置：&lt;/p></description></item><item><title>2. 基本用法</title><link>https://itest2025.pages.dev/tutorials/35-002-2-%E5%9F%BA%E6%9C%AC%E7%94%A8%E6%B3%95/</link><pubDate>Wed, 08 Nov 2017 06:23:31 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/35-002-2-%E5%9F%BA%E6%9C%AC%E7%94%A8%E6%B3%95/</guid><description>&lt;p>我们通过最简单的例子来看一下unittest的基本用法，下面的代码测试了3个python字符串方法，基本上满足了大部分情况下的测试需求&lt;/p>
&lt;pre tabindex="0">&lt;code>import unittest

class TestStringMethods(unittest.TestCase):

 def test_upper(self):
 self.assertEqual(&amp;#39;foo&amp;#39;.upper(), &amp;#39;FOO&amp;#39;)

 def test_isupper(self):
 self.assertTrue(&amp;#39;FOO&amp;#39;.isupper())
 self.assertFalse(&amp;#39;Foo&amp;#39;.isupper())

 def test_split(self):
 s = &amp;#39;hello world&amp;#39;
 self.assertEqual(s.split(), [&amp;#39;hello&amp;#39;, &amp;#39;world&amp;#39;])
 # check that s.split fails when the separator is not a string
 with self.assertRaises(TypeError):
 s.split(2)

if __name__ == &amp;#39;__main__&amp;#39;:
 unittest.main()
&lt;/code>&lt;/pre>&lt;p>解释一下关键点&lt;/p>
&lt;ul>
&lt;li>
&lt;p>可以通过继承&lt;a href="https://docs.python.org/2/library/unittest.html#unittest.TestCase" target="_blank" rel="noopener noreffer ">unittest.TestCase&lt;/a>类来定义我们自己的测试用例，1个测试用例类下面可以有多个测试方法(test)或者叫做测试点&lt;/p>
&lt;/li>
&lt;li>
&lt;p>记住这个套路：测试用例中方法名以&lt;code>test&lt;/code>开头的方法才是测试方法，比如上面的例子里定义了3个以test开头的方法，分别是&lt;code>test_upper&lt;/code>，&lt;code>test_isupper&lt;/code>和&lt;code>test_split&lt;/code>。非测试方法是不会被test runner执行的&lt;/p>
&lt;/li>
&lt;li>
&lt;p>断言是测试用例的核心。我们使用&lt;a href="https://docs.python.org/2/library/unittest.html#unittest.TestCase.assertEqual" target="_blank" rel="noopener noreffer ">assertEqual()&lt;/a>来判断预期结果，用&lt;a href="https://docs.python.org/2/library/unittest.html#unittest.TestCase.assertTrue" target="_blank" rel="noopener noreffer ">assertTrue()&lt;/a>和&lt;a href="https://docs.python.org/2/library/unittest.html#unittest.TestCase.assertFalse" target="_blank" rel="noopener noreffer ">assertFalse&lt;/a>来做是非判断，以及用&lt;a href="https://docs.python.org/2/library/unittest.html#unittest.TestCase.assertRaises" target="_blank" rel="noopener noreffer ">assertRaises()&lt;/a>来判断预期的异常是否有被抛出。这些unittest提供的以assert开头的方法就是断言，一般情况下,每个测试方法里都必须有断言&lt;/p>
&lt;/li>
&lt;li>
&lt;p>最后, &lt;a href="https://docs.python.org/2/library/unittest.html#unittest.main" target="_blank" rel="noopener noreffer ">unittest.main&lt;/a>提供了最简单的运行用例的方式。当我们从命令行运行上面的代码时，我们可以看到如下的输出&lt;/p>
&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>...
----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK
&lt;/code>&lt;/pre>&lt;p>除了使用&lt;a href="https://docs.python.org/2/library/unittest.html#unittest.main" target="_blank" rel="noopener noreffer ">unittest.main&lt;/a>，还有其他的方式可以运行测试用例，比如把最后2行替换为&lt;/p>
&lt;pre tabindex="0">&lt;code>suite = unittest.TestLoader().loadTestsFromTestCase(TestStringMethods)
unittest.TextTestRunner(verbosity=2).run(suite)
&lt;/code>&lt;/pre>&lt;p>运行用例，结果将会如下所示&lt;/p></description></item><item><title>2. #及注释</title><link>https://itest2025.pages.dev/tutorials/28-002-2-%E5%8F%8A%E6%B3%A8%E9%87%8A/</link><pubDate>Mon, 06 Nov 2017 08:17:22 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/28-002-2-%E5%8F%8A%E6%B3%A8%E9%87%8A/</guid><description>&lt;h3 id="背景">背景&lt;/h3>
&lt;p>注释是代码中非常重要的部分，一般来说注释的作用有下面一些&lt;/p>
&lt;ul>
&lt;li>告诉你这段代码中实现了些什么，帮助你或其他阅读代码的人去理解代码&lt;/li>
&lt;li>暂时让某段代码失效&lt;/li>
&lt;/ul>
&lt;h3 id="代码实现">代码实现&lt;/h3>
&lt;p>新建名为&lt;code>report_with_comments.py&lt;/code>的文本文件，用文本编辑器打开，输入如下内容:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 打印出本次测试的测试结果&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;本次测试功能点5个&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 本次回归测试涉及到多个功能点&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;测试用例20个&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 这些功能点一共编写了多少用例&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;共执行测试用例20个&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 回归了多少个&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;共发现缺陷0个&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 这些用例总用发现了多少个缺陷&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;用例通过率100%&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 通过率计算公式: 执行成功的用例/用例总数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 结束打印&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;回归通过&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>注意: 照着上面代码敲一遍，敲完以后检查一遍，因为对于新手来说，一次性就敲准确不那么容易。&lt;/p>
&lt;h3 id="运行">运行&lt;/h3>
&lt;p>在命令行中使用下面的命令去执行代码&lt;/p>
&lt;pre tabindex="0">&lt;code>python report_with_comments.py
&lt;/code>&lt;/pre>&lt;h3 id="你应该可以看到">你应该可以看到&lt;/h3>
&lt;p>如果没有出错的话，你应该可以看到命令行窗口显示如下的内容&lt;/p>
&lt;pre tabindex="0">&lt;code>本次测试功能点5个
测试用例20个
共执行测试用例20个
共发现缺陷0个
用例通过率100%
回归通过
&lt;/code>&lt;/pre>&lt;h3 id="动手时间">动手时间&lt;/h3>
&lt;ul>
&lt;li>自己搞清楚&lt;code>#&lt;/code>的作用是什么&lt;/li>
&lt;li>把上面的代码大声读出来，没错，跟读课文一样读出来，看能不能找到自己代码中的错误&lt;/li>
&lt;li>把上面的代码反过来阅读一遍，这次就不用读出声来了，看能不能发现更多的错误&lt;/li>
&lt;/ul>
&lt;h3 id="常见问题">常见问题&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>&lt;code>print('Hi, # there')&lt;/code>中的&amp;quot;#&amp;ldquo;为什么没有注释的作用？ 因为当&amp;rdquo;#&amp;ldquo;在字符串中(字符串就是用一对单引号或双引号包围的文本或文字)的时候，&amp;rdquo;#&amp;ldquo;就不再是注释的符号，而是只是一个普通字符，会被原原本本打印出来&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>如何注释多行代码呢？&lt;/strong> 在每一行前面都加个&amp;rdquo;#&amp;ldquo;号&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>为什么我需要倒过来读代码？&lt;/strong> 这可以让你换个角度看自己写的东西，更容易发现代码中的错误&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1516315720917-231ef9acce48?w=300"
 data-srcset="https://images.unsplash.com/photo-1516315720917-231ef9acce48?w=300, https://images.unsplash.com/photo-1516315720917-231ef9acce48?w=300 1.5x, https://images.unsplash.com/photo-1516315720917-231ef9acce48?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1516315720917-231ef9acce48?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>2.运行多个文件</title><link>https://itest2025.pages.dev/tutorials/25-002-2%E8%BF%90%E8%A1%8C%E5%A4%9A%E4%B8%AA%E6%96%87%E4%BB%B6/</link><pubDate>Wed, 01 Nov 2017 07:22:42 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/25-002-2%E8%BF%90%E8%A1%8C%E5%A4%9A%E4%B8%AA%E6%96%87%E4%BB%B6/</guid><description>&lt;h3 id="背景">背景&lt;/h3>
&lt;p>在现实的测试活动中，我们经常会定义多个用例文件，用来实现业务逻辑或其他逻辑上用例的物理分隔，比如&lt;/p>
&lt;pre tabindex="0">&lt;code>login_test.py # 登录相关功能的测试用例
cart_test.py # 购物车相关功能的测试用例
checkout_test.py # 结算相关功能的用例
order_test.py # 订单相关功能的用例
&lt;/code>&lt;/pre>&lt;p>使用pytest可以很方便的执行批量执行一组文件中定义的用例。&lt;/p>
&lt;h3 id="潜规则">潜规则&lt;/h3>
&lt;p>在批量执行用例之前，我们需要了解一下pytest的潜规则，注意，由于pytest可以支持丰富的定制选项，下面的潜规则是在&lt;strong>没有定制的默认情况下&lt;/strong>的缺省规则&lt;/p>
&lt;ul>
&lt;li>pytest会找当前以及递查找子文件夹下面所有的&lt;code>test_*.py&lt;/code>或&lt;code>*_test.py&lt;/code>的文件，把其当作测试文件&lt;/li>
&lt;li>在这些文件里，pytest会收集下面的一些函数或方法，当作测试用例
&lt;ul>
&lt;li>不在类定义中的以&lt;code>test_&lt;/code>开头的函数或方法&lt;/li>
&lt;li>在以&lt;code>Test&lt;/code>开头的类中(不能包含&lt;code>__init__&lt;/code>方法)，以&lt;code>test_&lt;/code>开头的方法&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>pytest也支持unittest模式的用例定义&lt;/li>
&lt;/ul>
&lt;h3 id="实例">实例&lt;/h3>
&lt;p>新建&lt;code>test_calc.py&lt;/code>文件，与上一节的&lt;code>test_quick_start.py&lt;/code>放在同一文件夹下，敲入下面的内容&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">y&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">test_add&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="n">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="n">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="n">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">99&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">100&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>现在当前文件夹下应该有2个文件&lt;/p>
&lt;pre tabindex="0">&lt;code>test_calc.py
test_quick_start.py
&lt;/code>&lt;/pre>&lt;h3 id="运行">运行&lt;/h3>
&lt;p>在当前文件夹敲下面的命令&lt;/p>
&lt;pre tabindex="0">&lt;code>pytest
&lt;/code>&lt;/pre>&lt;p>结果大致应该如下所示&lt;/p>
&lt;pre tabindex="0">&lt;code>$ pytest
========================================================================= test session starts =========================================================================
platform darwin -- Python 2.7.12, pytest-3.2.3, py-1.4.34, pluggy-0.4.0
rootdir: /Users/easonhan/code/testclass.net/src/pytest, inifile:
collected 2 items

test_calc.py .
test_quick_start.py .

====================================================================== 2 passed in 0.01 seconds =======================================================================
&lt;/code>&lt;/pre>&lt;h3 id="总结">总结&lt;/h3>
&lt;p>上面的例子里&lt;/p>
&lt;ul>
&lt;li>所有以test_开头的py文件都被当成了测试文件&lt;/li>
&lt;li>所有测试文件中以test开头的方法被当成了测试用例执行&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p></description></item><item><title>2. BasePage</title><link>https://itest2025.pages.dev/tutorials/43-002-2-basepage/</link><pubDate>Sat, 28 Oct 2017 06:55:26 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/43-002-2-basepage/</guid><description>&lt;p>页面类是Page Object设计模式的核心。在使用webium创建页面类的时候，必须继承&lt;code>webium.base_page.BasePage&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">webium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">BasePage&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">MyPage&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BasePage&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">pass&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="url">url&lt;/h3>
&lt;p>如果页面的url是固定的，那么可以在&lt;code>__init__&lt;/code>方法中指定它，然后你就可以使用&lt;code>open()&lt;/code>方法来跳转到该页面。&lt;/p>
&lt;p>url也可以被定义成是类的静态属性。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">webium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">BasePage&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">PageWithUrl&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BasePage&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">super&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">PageWithUrl&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;http://www.testclass.net/&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">AnotherPageWithUrl&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BasePage&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">url&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;http://www.itest.info&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">page&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PageWithUrl&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">open&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">itest&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AnotherPageWithUrl&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">itest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">open&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="driver">driver&lt;/h3>
&lt;p>页面类必须持有&lt;code>WebDriver&lt;/code>的实例以便操控浏览器。默认情况下，webium会使用&lt;code>webium.settings.driver_class&lt;/code>来创建&lt;code>WebDriver&lt;/code>实例。如果你需要获取driver的实例，你可以使用&lt;code>webium.driver.get_driver()&lt;/code>来达到目的。&lt;/p>
&lt;p>在实例化页面类时，我们也可以通过&lt;code>driver&lt;/code>参数来显示传入&lt;code>WebDriver&lt;/code>实例。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium.webdriver&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Firefox&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">webium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">BasePage&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">DriverHandlingPage&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BasePage&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">**&lt;/span>&lt;span class="n">kwargs&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">super&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">DriverHandlingPage&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;http://testclass.net/&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">**&lt;/span>&lt;span class="n">kwargs&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">my_driver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Firefox&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">page&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">DriverHandlingPage&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">my_driver&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">open&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Page title: &amp;#39;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">my_driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">title&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">my_driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">quit&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1508873699372-7aeab60b44ab?w=300"
 data-srcset="https://images.unsplash.com/photo-1508873699372-7aeab60b44ab?w=300, https://images.unsplash.com/photo-1508873699372-7aeab60b44ab?w=300 1.5x, https://images.unsplash.com/photo-1508873699372-7aeab60b44ab?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1508873699372-7aeab60b44ab?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>收藏清单:Java自动化测试工具汇总</title><link>https://itest2025.pages.dev/tutorials/34-002-%E6%94%B6%E8%97%8F%E6%B8%85%E5%8D%95java%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7%E6%B1%87%E6%80%BB/</link><pubDate>Thu, 26 Oct 2017 08:19:06 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/34-002-%E6%94%B6%E8%97%8F%E6%B8%85%E5%8D%95java%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7%E6%B1%87%E6%80%BB/</guid><description>&lt;h2 id="xunit-frameworks-单元测试框架">xUnit frameworks 单元测试框架&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="http://junit.org/" target="_blank" rel="noopener noreffer ">JUnit&lt;/a> - 常用的测试框架&lt;/li>
&lt;li>&lt;a href="http://testng.org/" target="_blank" rel="noopener noreffer ">TestNG&lt;/a> - 测试框架
&lt;ul>
&lt;li>&lt;a href="https://github.com/sskorol/test-data-supplier" target="_blank" rel="noopener noreffer ">Test Data Supplier&lt;/a> - TestNG DataProvider封装，让数据的生成更加灵活&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="tdd--atdd--bdd">TDD \ ATDD \ BDD&lt;/h2>
&lt;ul>
&lt;li>工具
&lt;ul>
&lt;li>&lt;a href="http://jbehave.org/" target="_blank" rel="noopener noreffer ">JBehave&lt;/a> - Behaviour-Driven Development (BDD)测试框架. BDD是从 test-driven development (TDD) 和 acceptance-test演进而来, 让用例的编写对新手更加友好和直觉化&lt;/li>
&lt;li>&lt;a href="https://github.com/cucumber/cucumber-jvm" target="_blank" rel="noopener noreffer ">Cucumber-JVM&lt;/a> - 纯 java的Cucumber实现,支持大部分流行的jvm语言&lt;/li>
&lt;li>&lt;a href="https://github.com/TNG/JGiven" target="_blank" rel="noopener noreffer ">JGiven&lt;/a> - 开发者友好且实用的BDD工具. 开发者使用纯java及流利API编写测试场景, JGiven负责生成领域专家可读的报告&lt;/li>
&lt;li>&lt;a href="http://easyb.org/" target="_blank" rel="noopener noreffer ">easyb&lt;/a> - Java平台的BDD框架. 通过使用Domain Specific Language(DSL), easyb致力于让文档可读可执行&lt;/li>
&lt;li>&lt;a href="http://robotframework.org/" target="_blank" rel="noopener noreffer ">robotframework&lt;/a> - 最有名的acceptance test-driven development (ATDD)测试框架
&lt;ul>
&lt;li>&lt;a href="https://github.com/fkromer/awesome-robotframework" target="_blank" rel="noopener noreffer ">awesome-robotframework&lt;/a> - 各种rf的扩展库&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>&lt;a href="https://github.com/greghaskins/spectrum" target="_blank" rel="noopener noreffer ">Spectrum&lt;/a> - BDD-style test runner，支持Java 8. 灵感来自于Jasmine, RSpec和Cucumber.&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;/tbody>
&lt;/table>
&lt;/li>
&lt;li>&lt;a href="https://github.com/porscheinformatik/cucumber-report-db" target="_blank" rel="noopener noreffer ">cucumber-report-db&lt;/a> - 把Cucumber的结果存到数据库里，并且提供测试报告&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="model-based-testing">Model-Based Testing&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="http://graphwalker.org/" target="_blank" rel="noopener noreffer ">GraphWalker&lt;/a> - Model-Based测试框架. 这个工具可以从 graphml, dot 或 json文件中读取model，然后自动创建测试用例&lt;/li>
&lt;/ul>
&lt;h2 id="code-analysis-and-coverage-代码扫描和代码覆盖率">Code analysis and coverage 代码扫描和代码覆盖率&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="http://www.sonarqube.org" target="_blank" rel="noopener noreffer ">SonarQube&lt;/a> - 管理代码质量的开源工具&lt;/li>
&lt;li>&lt;a href="https://github.com/xvik/gradle-quality-plugin" target="_blank" rel="noopener noreffer ">Gradle Quality Plugin&lt;/a> - 静态代码分析工具，支持Java和Groovy，使用 Checkstyle, PMD, FindBugs 和CodeNarc. 插件使用了统一的控制台输出并简化了开发者的工作流: 查看不规范的错误时只需要留意控制台就好，并且控制台输出的体验跟java编译错误的输入体验一致&lt;/li>
&lt;li>&lt;a href="https://github.com/teamed/qulice" target="_blank" rel="noopener noreffer ">Qulice&lt;/a> - Qulice是Java项目的代码扫描和质量控制工具. 包含了最好的静态代码扫描工具和预配置选项。你不需要单独再对这些工具进行配置了。&lt;/li>
&lt;li>&lt;a href="https://github.com/jacoco/jacoco" target="_blank" rel="noopener noreffer ">JaCoCo&lt;/a> - JaCoCo是免费的代码覆盖率统计工具，应该也是应用最广泛的覆盖率工具了。&lt;/li>
&lt;/ul>
&lt;h2 id="web-ui-test-automation-web-ui自动化工具">Web UI test automation web ui自动化工具&lt;/h2>
&lt;ul>
&lt;li>libraries
&lt;ul>
&lt;li>&lt;a href="http://docs.seleniumhq.org/" target="_blank" rel="noopener noreffer ">Selenium&lt;/a> - 浏览器自动化工具&lt;/li>
&lt;li>&lt;a href="http://www.sikulix.com/" target="_blank" rel="noopener noreffer ">SikuliX&lt;/a> - 基于OpenCV的 GUI 测试框架, 使用图片识别技术，支持windows/linux/mac系统&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>frameworks and wrappers 框架及封装
&lt;ul>
&lt;li>&lt;a href="http://selenide.org/" target="_blank" rel="noopener noreffer ">Selenide&lt;/a> - 简洁的Selenium封装,让 UI用例的编写更容易&lt;/li>
&lt;li>&lt;a href="https://github.com/Coveros/selenified" target="_blank" rel="noopener noreffer ">Selenified&lt;/a> - 开源的测试框架，目的是让selenium测试更加简单,提供了简单的接口去添加测试报告，错误处理以及线程安全的运行模式。可以运行在本机或云端(Grid or SauceLabs).&lt;/li>
&lt;li>&lt;a href="http://www.thucydides.info/" target="_blank" rel="noopener noreffer ">Serenity BDD (Thucydides)&lt;/a> - 创新的开源库，让你可以更高效的编写用户验收用例, 并可以根据用例去生成项目文档及测试报告&lt;/li>
&lt;li>&lt;a href="https://github.com/yandex-qatools/htmlelements" target="_blank" rel="noopener noreffer ">htmlelements&lt;/a> - 让web测试时元素交互更加简单的java库&lt;/li>
&lt;li>&lt;a href="https://bitbucket.org/atlassian/atlassian-selenium" target="_blank" rel="noopener noreffer ">atlassian-selenium&lt;/a> - 让开发者可以更高效的编写Selenium/WebDriver功能测试的开源库&lt;/li>
&lt;li>&lt;a href="https://github.com/persado/stevia" target="_blank" rel="noopener noreffer ">stevia&lt;/a> - Persado出品的开源自动化测试框架&lt;/li>
&lt;li>&lt;a href="https://github.com/darcy-framework" target="_blank" rel="noopener noreffer ">darcy&lt;/a> - 开源的测试框架，支持java 8，提供了具有表意性以及使用简单的API&lt;/li>
&lt;li>&lt;a href="http://satisfy.tapack.io" target="_blank" rel="noopener noreffer ">Satisfy&lt;/a> - 基于Thucydides和Jbehave的开源测试框架。支持WebUI, SOAP, REST, emails, files，并支持创建随机数据，开箱即用&lt;/li>
&lt;li>&lt;a href="https://github.com/epam/JDI/" target="_blank" rel="noopener noreffer ">JDI UI Test Automation Framework&lt;/a> - UI自动化测试框架。扩展了Page Object设计模式，并加入了一些常用的元素&lt;/li>
&lt;li>&lt;a href="http://gebish.org/" target="_blank" rel="noopener noreffer ">Geb Framework&lt;/a> - 基于groovy自动化测试框架。专为Webdriver Page Object设计模式以及Spock Framework(BDD)的集成而设计。&lt;/li>
&lt;li>&lt;a href="https://github.com/FluentLenium/FluentLenium" target="_blank" rel="noopener noreffer ">FluentLenium&lt;/a> - FluentLenium可以帮助你写出可读性好, 可重用, 可靠且灵活的Web UI功能测试用例. FluentLenium 提供了为Selenium实现的流利api,并为selenium用户的一些常见问题提供了解决方案。&lt;/li>
&lt;li>&lt;a href="https://github.com/paypal/SeLion" target="_blank" rel="noopener noreffer ">Selion&lt;/a> - 基于TestNG和Selenium提供了一系列的功能，让你可以在短时间内搞定webdriver. 支持web和移动端测试&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>extensions 扩展
&lt;ul>
&lt;li>&lt;a href="https://github.com/lightbody/browsermob-proxy" target="_blank" rel="noopener noreffer ">BrowserMob Proxy&lt;/a> -从浏览器获取性能数据的简单工具, 一般跟自动化工具，比如Selenium和Watir配合使用&lt;/li>
&lt;li>&lt;a href="https://github.com/groupon/Selenium-Grid-Extras" target="_blank" rel="noopener noreffer ">Selenium-Grid-Extras&lt;/a> - 让Selenium Grid 节点的管理更加简单， 并通过清理测试环境的方式让节点更加稳定&lt;/li>
&lt;li>&lt;a href="https://github.com/sterodium/selenium-grid-extensions" target="_blank" rel="noopener noreffer ">Selenium Grid Extensions&lt;/a> - 扩展了Selenium grid，以及可以在执行selenium用例的同时执行Sikuli用例&lt;/li>
&lt;li>&lt;a href="https://github.com/seleniumkit/gridrouter" target="_blank" rel="noopener noreffer ">Selenium Grid Router&lt;/a> 轻量级的server，作用是把Selenium Wedriver的请求分发到多个Selenium hub。&lt;/li>
&lt;li>&lt;a href="https://github.com/sskorol/docker-selenium-grid" target="_blank" rel="noopener noreffer ">Docker Selenium Grid&lt;/a> - 提供了native的视频录制功能，支持Selenium Grid，最初被设计为跟docker-selenium一同使用。&lt;/li>
&lt;li>&lt;a href="https://github.com/SergeyPirogov/video-recorder-java" target="_blank" rel="noopener noreffer ">Video Recorder Java&lt;/a> - 使用自动化测试用例来录制视频的java库&lt;/li>
&lt;li>&lt;a href="https://github.com/zalando/zalenium" target="_blank" rel="noopener noreffer ">Zalenium&lt;/a> - 提供一次性的灵活的Docker-based Selenium Grid视频录制功能, 支持实时预览和online/offline控制面板。&lt;/li>
&lt;li>&lt;a href="https://github.com/marcoslimaqa/sikuli-factory" target="_blank" rel="noopener noreffer ">SikuliFactory&lt;/a> - 为SikuliX提供了PageFactory实现。&lt;/li>
&lt;li>&lt;a href="https://github.com/mailosaur/mailosaur-java" target="_blank" rel="noopener noreffer ">Mailosaur&lt;/a> - 邮件自动化测试工具，基于Mailosaur。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="mobile-test-automation-移动自动化测试">Mobile test automation 移动自动化测试&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="http://appium.io/" target="_blank" rel="noopener noreffer ">Appium&lt;/a> - 开源的自动化测试框架，可以测试native/hybrid/mobile web应用。核心是基于webdriver协议进行了扩展&lt;/li>
&lt;li>&lt;a href="http://calaba.sh/" target="_blank" rel="noopener noreffer ">Calabash&lt;/a> - 跨平台的自动化测试框架，支持Android和iOS的原生应用以及hybrid应用。 Calabash的语法非常容易理解，甚至可以让非技术人员编写和执行基于上述平台的自动化测试用例。&lt;/li>
&lt;li>&lt;a href="https://code.google.com/p/robotium/" target="_blank" rel="noopener noreffer ">Robotium&lt;/a> - 安卓自动化测试框架，支持原生及hybrid应用. Robotium让我们可以非常方便的编写强大和稳定的黑盒UI测试用例。 有了Robotium的支持, 测试开发工程师可以编写安卓应用的功能用例系统用例以及用户验收用例。&lt;/li>
&lt;li>&lt;a href="http://developer.android.com/tools/help/uiautomator/index.html" target="_blank" rel="noopener noreffer ">UIautomator&lt;/a> - 提供了高效的测试UI的方式。 可以创建支持真机及模拟器运行的自动化测试用例，并包含了可以查看和分析安卓UI的viewer。&lt;/li>
&lt;li>&lt;a href="https://code.google.com/p/android-test-kit/wiki/Espresso" target="_blank" rel="noopener noreffer ">Espresso&lt;/a> - 比较新的开源自动化测试框架, 让开发者和测试人员都可以编写UI用例。 Espresso的api简单且易学，你可以非常快的使用这个框架上手安卓自动化测试&lt;/li>
&lt;/ul>
&lt;h2 id="api-test-automation-接口自动化测试">API test automation 接口自动化测试&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://github.com/intuit/karate" target="_blank" rel="noopener noreffer ">Karate-DSL&lt;/a> - Karate是BDD风格的使用javascript实现的测试框架。可以让你调用任何web-service类型的接口并对响应进行断言。&lt;/li>
&lt;/ul>
&lt;h2 id="windows-ui-test-automation-windows-ui自动化测试工具">Windows UI test automation windows ui自动化测试工具&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="http://sikulix.com/" target="_blank" rel="noopener noreffer ">SikuliX&lt;/a> - 基于OpenCV的 GUI 测试框架, 使用图片识别技术，支持多操作系统&lt;/li>
&lt;li>&lt;a href="https://github.com/2gis/Winium.Desktop/" target="_blank" rel="noopener noreffer ">Winium.Desktop&lt;/a> - 测试Windows应用(主要是基于WinForms和WPF平台)的自动化测试工具. 实现了Selenium Remote WebDriver协议&lt;/li>
&lt;/ul>
&lt;h2 id="unix--linux-ui-test-automation-unix--linux-ui自动化工具">Unix \ Linux UI test automation Unix \ Linux ui自动化工具&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="http://sikulix.com/" target="_blank" rel="noopener noreffer ">SikuliX&lt;/a> - 基于OpenCV的 GUI 测试框架, 使用图片识别技术，支持多操作系统&lt;/li>
&lt;/ul>
&lt;h2 id="macos-ui-test-automation-mac-ui自动化工具">MacOS UI test automation mac ui自动化工具&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="http://sikulix.com/" target="_blank" rel="noopener noreffer ">SikuliX&lt;/a> - 基于OpenCV的 GUI 测试框架, 使用图片识别技术，支持多操作系统&lt;/li>
&lt;/ul>
&lt;h2 id="server-side-test-automation-服务端自动化测试工具">Server side test automation 服务端自动化测试工具&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://github.com/christophd/citrus" target="_blank" rel="noopener noreffer ">Citrus&lt;/a> - Javas实现的测试框架，支持企业级SOA应用的e2e服务测试， 支持 HTTP, JMS, TCP/IP, FTP, SOAP协议，以及XML和JSON.&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p></description></item><item><title>（二）Jenkins 环境搭建</title><link>https://itest2025.pages.dev/tutorials/18-002-%E4%BA%8Cjenkins-%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/</link><pubDate>Mon, 16 Oct 2017 14:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/18-002-%E4%BA%8Cjenkins-%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/</guid><description>&lt;p>Jenkins 是基于Java开发的一种持续集成工具，所以，Jenkins需要Java环境。关于Java环境的配置我们在第9章使用Selenium Grid 时已经作了介绍，这里不在讲解。&lt;/p>
&lt;h3 id="安装-tomcat">安装 Tomcat&lt;/h3>
&lt;hr>
&lt;p>Tomcat是针对Java的一个开源中间件服务器（容器），基于Java Web的项目需要借助Tomcat 才能运行起来。&lt;/p>
&lt;p>Tomcat官方网站：http://tomcat.apache.org/ ，打开后首页如图2.1所示&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/jenkins_tomecat.png"
 data-srcset="http://img.testclass.net/jenkins_tomecat.png, http://img.testclass.net/jenkins_tomecat.png 1.5x, http://img.testclass.net/jenkins_tomecat.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/jenkins_tomecat.png"
 title="http://img.testclass.net/jenkins_tomecat.png" />
图2.1 下载Tomcat&lt;/p>
&lt;p>单击页面左侧Tomcat 版本进行下载，对下载的压缩包进行解压，目录结构如图2.2所示。
&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/jenkins_tomecat2.png"
 data-srcset="http://img.testclass.net/jenkins_tomecat2.png, http://img.testclass.net/jenkins_tomecat2.png 1.5x, http://img.testclass.net/jenkins_tomecat2.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/jenkins_tomecat2.png"
 title="http://img.testclass.net/jenkins_tomecat2.png" />
图2.2 webapps目录用于web项目
通常将需要运行的应用放到webapps/目录下，进入bin/目录下，双击startup.bat，启动Tomcat服务器。&lt;/p>
&lt;h4 id="安装-jenkins">安装 Jenkins&lt;/h4>
&lt;hr>
&lt;p>Jenkins官方网站：https://jenkins.io/ ，打开后首页如图2.3所示。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/jenkins_dwonload.png"
 data-srcset="http://img.testclass.net/jenkins_dwonload.png, http://img.testclass.net/jenkins_dwonload.png 1.5x, http://img.testclass.net/jenkins_dwonload.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/jenkins_dwonload.png"
 title="http://img.testclass.net/jenkins_dwonload.png" />
图2.3 下载Jenkins&lt;/p>
&lt;p>点击“Download” 链接进入下载页面，根据自己的系统选择对应的 Jenkins 版本进行下载。&lt;/p>
&lt;p>下载完成，双击进行安装，如图2.4所示。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/jenkins_install.png"
 data-srcset="http://img.testclass.net/jenkins_install.png, http://img.testclass.net/jenkins_install.png 1.5x, http://img.testclass.net/jenkins_install.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/jenkins_install.png"
 title="http://img.testclass.net/jenkins_install.png" />
图2.4 双击Jenkins安装&lt;/p>
&lt;p>单击“next”按钮，我们直接将其安装到Tomcat的 &lt;strong>webapps&lt;/strong> 目录下，如图2.5所示。&lt;font color='red'>一定要选择TomCat 的 webapps 目录。&lt;/font>&lt;/p></description></item><item><title>（二）Locust 安装</title><link>https://itest2025.pages.dev/tutorials/38-002-%E4%BA%8Clocust-%E5%AE%89%E8%A3%85/</link><pubDate>Mon, 16 Oct 2017 13:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/38-002-%E4%BA%8Clocust-%E5%AE%89%E8%A3%85/</guid><description>&lt;p>&lt;font color='red'>Locust 是基于 Python 语言的一个性能测试库，如果要想使用它来做性能测试必须要先安装 Python 。&lt;/font>&lt;/p>
&lt;p>Python安装，&lt;a href="https://itest2025.pages.dev/selenium_python/install-selenium/" rel="">参考&lt;/a>&lt;/p>
&lt;br>
#### Locust 安装
----
方式一：通过 pip 命令安装
&lt;pre tabindex="0">&lt;code>&amp;gt; pip install locust

Collecting locust
 Downloading locust-0.8.tar.gz (225kB)
 59% |███████████████████ | 133kB 199kB/s eta 0:00:0
 63% |████████████████████▍ | 143kB 304kB/s eta 0:00:
 68% |█████████████████████▉ | 153kB 358kB/s eta 0:0
 72% |███████████████████████▎ | 163kB 355kB/s eta 0:
 77% |████████████████████████▊ | 174kB 421kB/s eta
 81% |██████████████████████████▏ | 184kB 449kB/s eta
 86% |███████████████████████████▋ | 194kB 439kB/s e
 90% |█████████████████████████████ | 204kB 487kB/s
 95% |██████████████████████████████▌ | 215kB 492kB/s
 99% |████████████████████████████████| 225kB 487kB
 100% |████████████████████████████████| 235kB 417k

 ....
&lt;/code>&lt;/pre>&lt;p>方式二：GitHub下载安装&lt;/p></description></item><item><title>（二）Web Services技术之SOAP</title><link>https://itest2025.pages.dev/tutorials/26-002-%E4%BA%8Cweb-services%E6%8A%80%E6%9C%AF%E4%B9%8Bsoap/</link><pubDate>Thu, 21 Sep 2017 01:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/26-002-%E4%BA%8Cweb-services%E6%8A%80%E6%9C%AF%E4%B9%8Bsoap/</guid><description>&lt;br>
__早前的 Web Services 技术由 SOAP、WSDL 和 UDDI 就构成。__
&lt;h4 id="soap">SOAP&lt;/h4>
&lt;hr>
&lt;p>Simple Object Access Protocol，简称 SOAP，简单对象访问协议。&lt;/p>
&lt;p>SOAP 是基于 XML 在分散或分布式的环境中交换信息的简单的协议。允许服务提供者和服务客户经过防火墙在互联网上进行通信。&lt;/p>
&lt;p>SOAP 的设计是为了在一个松散的、分布的环境中使用 XML 对等地交换结构化的和类型化的信息提供了一个简单且轻量级的机制。&lt;/p>
&lt;p>XML是可以扩展标记语言。&lt;/p>
&lt;pre>&lt;code>&amp;lt;bookstore&amp;gt;
 &amp;lt;book category=&amp;quot;COOKING&amp;quot;&amp;gt;
 &amp;lt;title lang=&amp;quot;en&amp;quot;&amp;gt;Everyday Italian&amp;lt;/title&amp;gt;
 &amp;lt;author&amp;gt;Giada De Laurentiis&amp;lt;/author&amp;gt;
 &amp;lt;year&amp;gt;2005&amp;lt;/year&amp;gt;
 &amp;lt;price&amp;gt;30.00&amp;lt;/price&amp;gt;
 &amp;lt;/book&amp;gt;
&amp;lt;/bookstore&amp;gt;
&lt;/code>&lt;/pre>
&lt;p>SOAP 消息的基本结构&lt;/p>
&lt;pre>&lt;code>&amp;lt;?xml version=&amp;quot;1.0&amp;quot;?&amp;gt;
&amp;lt;soap:Envelope xmlns:soap=&amp;quot;http://www.w3.org/2001/12/soap-envelope&amp;quot;
soap:encodingStyle=&amp;quot;http://www.w3.org/2001/12/soap-encoding&amp;quot;&amp;gt;

 &amp;lt;soap:Header&amp;gt;
 ...
 ...
 &amp;lt;/soap:Header&amp;gt;

 &amp;lt;soap:Body&amp;gt;
 ...
 ...
 &amp;lt;soap:Fault&amp;gt;
 ...
 ...
 &amp;lt;/soap:Fault&amp;gt;
 &amp;lt;/soap:Body&amp;gt;

&amp;lt;/soap:Envelope&amp;gt;
&lt;/code>&lt;/pre>
&lt;p>当 SOAP 消息真正需要在网络上传输的时候，SOAP 消息能够与不同的底层传输协议进行绑定，同时，SOAP 消息也可以在很多种消息传输模式中使用。包括超文本传输协议（HTTP），简单邮件传输协议（SMTP），多用途网际邮件扩充协议（MIME）。它还支持从消息系统到远程过程调用协议（RPC）等大量的应用程序。&lt;/p>
&lt;p>&lt;font color=#DC143C> 当然，大多的情况还是绑定在 HTTP 协议上面传输。所以，这就导致许多人认为 SOAP 就是 HTTP + XML，或者认为 SOAP 是 HTTP 的 POST 请求的一个专用版本，遵循一种特殊的 XML 消息格式。虽然，我们看到的情况确实如此，但显然这些观点对SOAP的解释是错误和片面的。&lt;/font>&lt;/p></description></item><item><title>appium新手入门（2）—— 安装 Android SDK</title><link>https://itest2025.pages.dev/tutorials/21-002-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A82-%E5%AE%89%E8%A3%85-android-sdk/</link><pubDate>Thu, 07 Sep 2017 12:24:12 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/21-002-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A82-%E5%AE%89%E8%A3%85-android-sdk/</guid><description>&lt;p>&lt;font color=#DC143C>&lt;strong>注明：&lt;/strong> 理论上这一章不是必须的，如果你不想使用 Android 模拟器运行测试的话可以跳过，不过，建议安装；原生 Android 好折腾！关键是它自带的一些工具是你做 appium 测试必须要用的！&lt;/font>&lt;/p>
&lt;h3 id="安装android-sdk">安装Android SDK&lt;/h3>
&lt;hr>
&lt;p>Android SDK（Software Development Kit，软件开发工具包）提供了 Android API 库和开发工具构建，测试和调试应用程序。简单来讲，Android SDK 可以看做用于开发和运行 Android 应用的一个软件。&lt;/p>
&lt;h4 id="1下载android-sdk">1、下载Android SDK&lt;/h4>
&lt;hr>
&lt;p>我在官网上没有找到单独 Android SDK 的下载链接，官方推荐下载包含 Android SDK 的 Android Studio。&lt;/p>
&lt;p>Android Studio &amp;amp; Android SDK 下载地址：https://developer.android.com/studio/index.html?hl=zh-cn&lt;/p>
&lt;p>拖到页面底部，你将找到下载链接，根据自己的平台选择对应的链接下载。&lt;/p>
&lt;p>一方面是包含 Android SDK 的 Android Studio 的安装包很大。另一方面它们二者也不是强关联的。因为 Appium也会用到 Android SDK，而 Android Studio 也可以调用真机来运行 Android程序。&lt;/p>
&lt;p>所以，Android SDK 下载地址（才是我们想要的）：&lt;/p>
&lt;p>&lt;a href="http://tools.android-studio.org/index.php/sdk" target="_blank" rel="noopener noreffer ">http://tools.android-studio.org/index.php/sdk&lt;/a>&lt;/p>
&lt;p>你可以通过别的网站进行下载，身为IT从业人员，如何利用搜索工具和科学上网工具是你的必备技能。&lt;/p>
&lt;p>将下载的 Android SDK 解压，将得到如下目录。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/appium_sdk_path.png"
 data-srcset="http://img.testclass.net/appium_sdk_path.png, http://img.testclass.net/appium_sdk_path.png 1.5x, http://img.testclass.net/appium_sdk_path.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/appium_sdk_path.png"
 title="http://img.testclass.net/appium_sdk_path.png" />&lt;/p></description></item><item><title>（二）GitHub注册与Git安装</title><link>https://itest2025.pages.dev/tutorials/33-002-%E4%BA%8Cgithub%E6%B3%A8%E5%86%8C%E4%B8%8Egit%E5%AE%89%E8%A3%85/</link><pubDate>Thu, 31 Aug 2017 03:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/33-002-%E4%BA%8Cgithub%E6%B3%A8%E5%86%8C%E4%B8%8Egit%E5%AE%89%E8%A3%85/</guid><description>&lt;h4 id="注册github">注册GitHub&lt;/h4>
&lt;hr>
&lt;p>GitHub官方地址：https://github.com。&lt;/p>
&lt;p>在浏览器中打开GitHub网址，通过首页进行注册，如下图所示。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/github_page.png"
 data-srcset="http://img.testclass.net/github_page.png, http://img.testclass.net/github_page.png 1.5x, http://img.testclass.net/github_page.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/github_page.png"
 title="http://img.testclass.net/github_page.png" />&lt;/p>
&lt;h4 id="安装git">安装Git&lt;/h4>
&lt;hr>
&lt;p>Git官方下载地址：http://git-scm.com/download/。&lt;/p>
&lt;p>Git支持多平台（Mac OS X/Windows/Linux/Solaris）,读者可根据自己的平台选择相应的版本下载。&lt;/p>
&lt;p>Linux 各版本下安装Git：&lt;/p>
&lt;pre>&lt;code> Debian/Ubuntu $ apt-get install git-core

 Fedora $ yum install git

 Gentoo $ emerge --ask --verbose dev-vcs/git

 Arch Linux $ pacman -S git
&lt;/code>&lt;/pre>
&lt;p>下载并安装完成后，我们通常在Mac OSX及Linux平台下用终端工具(Terminal)来使用Git，而在Windows平台下用Git Bash工具，如下图所示。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/git_menu.png"
 data-srcset="http://img.testclass.net/git_menu.png, http://img.testclass.net/git_menu.png 1.5x, http://img.testclass.net/git_menu.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/git_menu.png"
 title="http://img.testclass.net/git_menu.png" />&lt;/p>
&lt;h4 id="建立链接">建立链接&lt;/h4>
&lt;hr>
&lt;p>本地Git与GitHub服务器之间保持通信时，我们使用SSH key认证方式来保证通信安全，所以在使用GitHub前你必须先建创自已的SSH key。
我们后续操作以Windows为例，打开Git Bash，如下图所示。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/git_window.png"
 data-srcset="http://img.testclass.net/git_window.png, http://img.testclass.net/git_window.png 1.5x, http://img.testclass.net/git_window.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/git_window.png"
 title="http://img.testclass.net/git_window.png" />&lt;/p></description></item><item><title>2.最简单的接口长什么样</title><link>https://itest2025.pages.dev/tutorials/40-002-2%E6%9C%80%E7%AE%80%E5%8D%95%E7%9A%84%E6%8E%A5%E5%8F%A3%E9%95%BF%E4%BB%80%E4%B9%88%E6%A0%B7/</link><pubDate>Tue, 29 Aug 2017 04:41:43 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/40-002-2%E6%9C%80%E7%AE%80%E5%8D%95%E7%9A%84%E6%8E%A5%E5%8F%A3%E9%95%BF%E4%BB%80%E4%B9%88%E6%A0%B7/</guid><description>&lt;p>接口测试由浅入深的学习才可以尽量减少挫败感，避免从入门到放弃的悲剧。&lt;/p>
&lt;p>从入门到放弃其实最可惜，毕竟花了那么多时间去学习，最后放弃掉，花费掉的青春就一去不复返了。&lt;/p>
&lt;h3 id="获取资源的接口">获取资源的接口&lt;/h3>
&lt;p>我们先来看一下获取资源的接口。&lt;/p>
&lt;p>&lt;a href="https://www.v2ex.com/" target="_blank" rel="noopener noreffer ">v2ex&lt;/a>是一个讨论区，也就是大家常说的论坛，这是一个小众的讨论区，基本上只有程序员光顾。&lt;/p>
&lt;p>&lt;a href="https://www.v2ex.com/" target="_blank" rel="noopener noreffer ">v2ex&lt;/a>里有很多的节点，节点可以理解成是讨论板块，比如&lt;a href="https://www.v2ex.com/go/python" target="_blank" rel="noopener noreffer ">这个板块&lt;/a>就是讨论python技术的。&lt;/p>
&lt;p>v2ex提供了一些接口，可以让我们去获取v2ex站点的一些资源，比如讨论区的信息，热门帖子等，这很符合互联网的分享精神。&lt;/p>
&lt;p>v2ex的api描述页面在&lt;a href="https://www.v2ex.com/p/7v9TEc53" target="_blank" rel="noopener noreffer ">这里&lt;/a>, 文档相对简洁，基本上是给看得懂的人看的。&lt;/p>
&lt;p>我们仔细研究一下获取节点信息的接口。这个接口可以获取指定节点的名字，简介，URL 及头像图片的地址。&lt;/p>
&lt;p>下面是这个接口的具体描述&lt;/p>
&lt;pre tabindex="0">&lt;code>获得指定节点的名字，简介，URL 及头像图片的地址。

https://www.v2ex.com/api/nodes/show.json

Method: GET
Authentication: None
接受参数：

name: 节点名（V2EX 的节点名全是半角英文或者数字）
例如：

https://www.v2ex.com/api/nodes/show.json?name=python
&lt;/code>&lt;/pre>&lt;p>我们从这个接口文档里可以获得哪些信息呢？换一句话说，我们能不能通过接口文档去了解这个接口是做什么的呢？&lt;/p>
&lt;h3 id="接口分析">接口分析&lt;/h3>
&lt;p>从上面的描述里，我们可以得到下面一些信息&lt;/p>
&lt;ul>
&lt;li>接口的协议：https协议，也就是更安全版本的http协议；&lt;/li>
&lt;li>请求的方法：http协议里定义了一些请求的方法或者叫动词，这些方法和动词可以进一步定义请求的目的，比如是获取资源还是创建资源等；上面的例子里，请求方法是GET;&lt;/li>
&lt;li>请求参数：http协议里规定了请求的时候可以传递一些参数给服务端，这些参数可以更加具体的描述资源，比如获取多少个资源，这个资源的名字是什么。上面的例子里，我们可以传递name参数指定资源的名称，比如获取名字叫python的资源，这里资源就是节点；&lt;/li>
&lt;li>鉴权：简单来说，就是要不要登录，很显然，上面的接口是不需要登录的&lt;/li>
&lt;/ul>
&lt;p>合起来，我们应该可以得到这样的信息：&lt;/p>
&lt;p>当我们发送:&lt;code>https://www.v2ex.com/api/nodes/show.json?name=python&lt;/code>，这个http的get请求给服务器之后，服务器应该返回相应的资源，那么这时候就需要探讨一下&lt;/p>
&lt;ul>
&lt;li>
&lt;p>什么是请求: &lt;a href="https://ke.qq.com/webcourse/index.html#course_id=229839&amp;amp;term_id=100271202&amp;amp;taid=1419130209272271&amp;amp;vid=b1419h42e0i" target="_blank" rel="noopener noreffer ">视频在这里&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>什么是响应: &lt;a href="https://ke.qq.com/webcourse/index.html#course_id=229839&amp;amp;term_id=100271202&amp;amp;taid=1419134504239567&amp;amp;vid=m1419qedwye" target="_blank" rel="noopener noreffer ">视频在这里&lt;/a>&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="如何查看接口的返回">如何查看接口的返回&lt;/h3>
&lt;p>我们现在已经知道了这个接口的情况了，如何查看接口的返回呢？&lt;/p>
&lt;p>我们可以使用一些辅助工具帮助我们进行接口的调用，查看接口返回，最简单的跨平台调试工具推荐使用&lt;a href="https://www.getpostman.com/" target="_blank" rel="noopener noreffer ">postman&lt;/a>&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1507831273071-5db7707d651b?w=300"
 data-srcset="https://images.unsplash.com/photo-1507831273071-5db7707d651b?w=300, https://images.unsplash.com/photo-1507831273071-5db7707d651b?w=300 1.5x, https://images.unsplash.com/photo-1507831273071-5db7707d651b?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1507831273071-5db7707d651b?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>JMeter官方文档：2. 创建测试计划</title><link>https://itest2025.pages.dev/tutorials/22-002-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A32-%E5%88%9B%E5%BB%BA%E6%B5%8B%E8%AF%95%E8%AE%A1%E5%88%92/</link><pubDate>Thu, 24 Aug 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/22-002-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A32-%E5%88%9B%E5%BB%BA%E6%B5%8B%E8%AF%95%E8%AE%A1%E5%88%92/</guid><description>&lt;p>&lt;a href="https://itest2025.pages.dev/2017/08/24/jmeter-translation-plans/" rel="">《JMeter官方文档&amp;ndash;翻译计划》&lt;/a> &lt;a href="http://jmeter.apache.org/usermanual/build-test-plan.html" target="_blank" rel="noopener noreffer ">原文地址&lt;/a>&lt;/p>
&lt;h2 id="2构建测试计划">2.构建测试计划&lt;/h2>
&lt;hr>
&lt;p>测试计划描述了当程序运行起来时JMeter会执行的一系列步骤，一个完整的测试计划会由以几部分组成，包括一个或多个线程组、逻辑控制器、示例生成控制器、侦听器、定时器、断言、和配置元素组成。&lt;/p>
&lt;h3 id="21-添加和删除元素">2.1 添加和删除元素&lt;/h3>
&lt;hr>
&lt;p>我们可以通过下面两种方式添加&lt;a href="http://jmeter.apache.org/usermanual/test_plan.html" target="_blank" rel="noopener noreffer ">元素到测试计划&lt;/a>，一种是右键点击树上的元素，从“&lt;strong>添加&lt;/strong>”列表中选择一个新元素；或者也可以通过选择菜单栏“文件”&amp;ndash;“&lt;strong>合并&lt;/strong>”或“&lt;strong>打开&lt;/strong>”选项从文件中加载元素。&lt;/p>
&lt;p>确保元素是被选中的，右键单击元素，选择“&lt;strong>删除&lt;/strong>”选项可以将元素移除.&lt;/p>
&lt;h3 id="22-加载和保存元素">2.2 加载和保存元素&lt;/h3>
&lt;hr>
&lt;p>通过文件加载元素，右键选择向其中添加加载元素的树元素，选择“合并”选项选择元素保存的文件，JMeter会将元素合并到树中去。&lt;/p>
&lt;p>右键一个元素并选择“选中部分保存为…”选项以保存树元素。JMeter保存树元素时会连带的将它下面的子节点一起保存。通过这种方式，在后面的运用中你可以成段的或者单独的保存元素。&lt;/p>
&lt;pre>&lt;code>默认情况下，工作台不会被自动保存到测试计划，但是它能够通过在工作台元素上勾选“Save Workbean”去保存.
&lt;/code>&lt;/pre>
&lt;h3 id="23-配置树元素">2.3 配置树元素&lt;/h3>
&lt;hr>
&lt;p>测试树中的任何元素在JMeter的右手框架中都被表现为控制器。这些控制器允许你为特定的测试元素配置行为。具体有哪些行为可以配置取决于是何种类型的元素。&lt;/p>
&lt;pre>&lt;code>测试树本身可以被测试树周围的拖放控件操作.
&lt;/code>&lt;/pre>
&lt;h3 id="24-保存测试计划">2.4 保存测试计划&lt;/h3>
&lt;hr>
&lt;p>尽管没有硬性要求，我们还是建议你在执行测试计划前先保存测试计划到文件。保存一个测试计划可以从文件按钮中选择“保存测试计划”或者“保存测试计划为…”（如果你是用的最新发布版本的JMeter，就不需要在保存之前先选中测试计划）&lt;/p>
&lt;pre>&lt;code>JMeter允许你保存整个测试计划树或者计划树里面的一部分。如果只是保存特定分支的计划树里面的元素，
可以从开始的分支里面选择测试计划树元素，右键选择“选中部分保存为…”菜单选项。或者也可以先选
择正确的测试计划元素然后通过编辑按钮选择“选中部分保存为…” 选项。
&lt;/code>&lt;/pre>
&lt;h3 id="25-运行一个测试计划">2.5 运行一个测试计划&lt;/h3>
&lt;hr>
&lt;p>运行测试计划，从“运行”菜单选项中选择“启动”（&lt;code>Control + R&lt;/code>）按钮。当JMeter运行的时候，它会在菜单栏下面的左手边显示一个绿色的小盒子的形状。你也可以通过检查“运行”菜单选项去检查测试计划是否运行起来，如果“启动”是禁用的，并且 “停止” 是启用的，这样JMeter就正在运行你的测试计划。（或者至少在我看来是这样的）
绿色边框左下角的数字就是活动线程除以总共线程，这种计算方式只是适用在本地运行测试测试；不包含任何在远程服务器上启动的线程当使用的是 &lt;strong>客户端-服务器&lt;/strong> 模式的时候。&lt;/p>
&lt;pre>&lt;code>这里所描述的GUI模式只是适用于调试测试计划，如果运行真实的load test，请用非GUI模式。
&lt;/code>&lt;/pre>
&lt;h3 id="26-停止测试">2.6 停止测试&lt;/h3>
&lt;hr>
&lt;p>在菜单中有两种停止的测试命令可供选择：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>停止（&lt;code>Control + .&lt;/code>）-尽可能立即停止线程。很多采样器会被中断这意味着那些活跃的采样器也会被立即终止。停止命令会检查在默认设置的5s超时的时间内是不是所有的线程都终止了。[这个默认时间是可以通过JMeter（ &lt;strong>jmeterengine.threadstop.wait&lt;/strong>）的属性设置的] 如果有线程没有终止，这时会有一条提示信息显示出来。停止命令会重试，如果还是失败，有必要通过直接退出JMeter去清理。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>关闭（&lt;code>Control + ，&lt;/code>）-请求在当前任何工作的末尾去结束线程，不会中途干扰活跃的采样器。 这种情况下关闭对话框会一直保持活跃直到所有的线程都终止。
如果关闭花费太长时间。关掉对话框选择 &lt;strong>运行/停止&lt;/strong> ， 或者按下&lt;code>Control + . &lt;/code>.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>这儿是没有菜单的当运行non-GUI模式的时候，并且JMeter对像&lt;code>Control + . &lt;/code>这样的快捷键不会做出反应。 因此JMeter non-GUI模式会在特定端口来监控这些命令。（默认端口是4445，参见JMeter的 &lt;strong>jmeterengine.nongui.port&lt;/strong> 属性）。 Jmeter是支持自动切换端口的当默认端口被占用的时候（举个例子被其他Jmeter的实例占用）。 在这种情况下，Jmeter会尝试更大数值的端口号，直到达到Jmeter 属性 &lt;strong>jmeterengine.nongui.maxport&lt;/strong> 的最大值4455。如果最大端口小于或者等于端口号， 端口扫描就不会发生。
选择的端口会在控制窗口显示。&lt;/p></description></item><item><title>appium简明教程（2）——appium的基本概念</title><link>https://itest2025.pages.dev/tutorials/21-002-appium%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B2appium%E7%9A%84%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5/</link><pubDate>Sat, 19 Aug 2017 06:14:09 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/21-002-appium%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B2appium%E7%9A%84%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5/</guid><description>&lt;h3 id="clientserver-architecture">Client/Server Architecture&lt;/h3>
&lt;p>appium的核心其实是一个暴露了一系列REST API的server。&lt;/p>
&lt;p>这个server的功能其实很简单：监听一个端口，然后接收由client发送来的command。翻译这些command，把这些command转成移动设备可以理解的形式发送给移动设备，然后移动设备执行完这些command后把执行结果返回给appium server，appium server再把执行结果返回给client。&lt;/p>
&lt;p>在这里client其实就是发起command的设备，一般来说就是我们代码执行的机器，执行appium测试代码的机器。狭义点理解，可以把client理解成是代码，这些代码可以是java/ruby/python/js的，只要它实现了webdriver标准协议就可以。&lt;/p>
&lt;p>这样的设计思想带来了一些好处：&lt;/p>
&lt;ul>
&lt;li>1，可以带来多语言的支持；&lt;/li>
&lt;li>2，可以把server放在任意机器上，哪怕是云服务器都可以；（是的，appium和webdriver天生适合云测试）&lt;/li>
&lt;/ul>
&lt;h3 id="session">Session&lt;/h3>
&lt;p>session就是一个会话，在webdriver/appium，你的所有工作永远都是在session start后才可以进行的。一般来说，通过POST /session这个URL，然后传入&lt;strong>Desired Capabilities&lt;/strong>就可以开启session了。&lt;/p>
&lt;p>开启session后，会返回一个全局唯一的session id，以后几乎所有的请求都必须带上这个session id，因为这个seesion id代表了你所打开的浏览器或者是移动设备的模拟器。&lt;/p>
&lt;p>进一步思考一下，由于session id是全局唯一，那么在同一台机器上启动多个session就变成了可能，这也就是selenium gird所依赖的具体理论根据。&lt;/p>
&lt;h3 id="desired-capabilities">Desired Capabilities&lt;/h3>
&lt;p>Desired Capabilities携带了一些配置信息。从本质上讲，这个东东是key-value形式的对象。你可以理解成是java里的map，python里的字典，ruby里的hash以及js里的json对象。实际上Desired Capabilities在传输时就是json对象。&lt;/p>
&lt;p>Desired Capabilities最重要的作用是告诉server本次测试的上下文。这次是要进行浏览器测试还是移动端测试？如果是移动端测试的话是测试android还是ios，如果测试android的话那么我们要测试哪个app？ server的这些疑问Desired Capabilities都必须给予解答，否则server不买账，自然就无法完成移动app或者是浏览器的启动。&lt;/p>
&lt;p>具体例子如下：&lt;/p>
&lt;blockquote>
&lt;p>For example, we might set the platformName capability to iOS to tell Appium that we want an iOS session, rather than an Android one. Or we might set the safariAllowPopupscapability to true in order to ensure that, during a Safari automation session, we’re allowed to use JavaScript to open up new windows. See the capabilities doc for the complete list of capabilities available for Appium&lt;/p></description></item><item><title>（二）实战: 最简单的自动化脚本</title><link>https://itest2025.pages.dev/tutorials/20-002-%E4%BA%8C%E5%AE%9E%E6%88%98-%E6%9C%80%E7%AE%80%E5%8D%95%E7%9A%84%E8%87%AA%E5%8A%A8%E5%8C%96%E8%84%9A%E6%9C%AC/</link><pubDate>Sat, 12 Aug 2017 08:26:17 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/20-002-%E4%BA%8C%E5%AE%9E%E6%88%98-%E6%9C%80%E7%AE%80%E5%8D%95%E7%9A%84%E8%87%AA%E5%8A%A8%E5%8C%96%E8%84%9A%E6%9C%AC/</guid><description>&lt;h3 id="目的">目的&lt;/h3>
&lt;ul>
&lt;li>熟悉selenium webdriver 代码套路&lt;/li>
&lt;li>体验元素定位的最简单情形&lt;/li>
&lt;li>学会如何模拟输入键盘按键&lt;/li>
&lt;/ul>
&lt;h3 id="如何学习">如何学习&lt;/h3>
&lt;p>将代码抄一遍，然后精读一遍，了解每一行代码的意义。&lt;/p>
&lt;h3 id="场景">场景&lt;/h3>
&lt;p>本节我们需要使用selenium打开chrome浏览器，跳转到百度首页(&lt;a href="http://www.baidu.com" target="_blank" rel="noopener noreffer ">http://www.baidu.com&lt;/a>)，在搜索框中输入selenium并按下回车键。&lt;/p>
&lt;h3 id="代码">代码&lt;/h3>
&lt;p>新建文件simple_automation_script.js，并键入下面的内容。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">webdriver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;selenium-webdriver&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">By&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">Key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Key&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">dr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Builder&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">forBrowser&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;chrome&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">build&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;http://www.baidu.com&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;kw&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;selenium&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;kw&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">Key&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">RETURN&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;quit driver&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">quit&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行">运行&lt;/h3>
&lt;p>在命令行中运行&lt;/p>
&lt;pre tabindex="0">&lt;code>node simple_automation_script.js
&lt;/code>&lt;/pre>&lt;h3 id="常见错误">常见错误&lt;/h3>
&lt;ul>
&lt;li>&lt;code>WebDriverError: unknown error: unhandled inspector error: {&amp;quot;code&amp;quot;:-32000,&amp;quot;message&amp;quot;:&amp;quot;Cannot navigate to invalid URL&amp;quot;}&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>这是get时url拼写错误导致的，检查&lt;code>dr.get('http://www.baidu.com')&lt;/code>这一行url地址是否准确。&lt;/p>
&lt;ul>
&lt;li>&lt;code>NoSuchElementError: no such element: Unable to locate element: {&amp;quot;method&amp;quot;:&amp;quot;css selector&amp;quot;,&amp;quot;selector&amp;quot;:&amp;quot;*[id=&amp;quot;www&amp;quot;]&amp;quot;}&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>selenium找不到元素时会报的错，这是selenium开发者最常见的错误，没有之一。上面错误提示中很明确的告诉我们，页面上没有id为www的元素。遇到这种问题时，我们需要多尝试几种定位元素的方式。&lt;/p>
&lt;h3 id="总结">总结&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>&lt;code>new webdriver.Builder('browser name').build()&lt;/code>语句可以打开我们指定的浏览器，另外使用Builder，我们还可以使用环境变量在运行时动态指定浏览器类型，这对于持续集成来说非常方便;&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>dr.findElement(By.id('element id'))&lt;/code>语句使用id来定位具体的元素;&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>element.sendKeys('something')&lt;/code>语句可以向文本框中输入具体的内容;&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>Key.RETURN&lt;/code>代表回车键，这些具体的键值通常与sendKeys配合使用;&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1493979969019-a78fdb263931?w=300"
 data-srcset="https://images.unsplash.com/photo-1493979969019-a78fdb263931?w=300, https://images.unsplash.com/photo-1493979969019-a78fdb263931?w=300 1.5x, https://images.unsplash.com/photo-1493979969019-a78fdb263931?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1493979969019-a78fdb263931?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>性能测试基础（二）并发用户</title><link>https://itest2025.pages.dev/tutorials/14-002-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E5%9F%BA%E7%A1%80%E4%BA%8C%E5%B9%B6%E5%8F%91%E7%94%A8%E6%88%B7/</link><pubDate>Fri, 11 Aug 2017 14:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/14-002-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E5%9F%BA%E7%A1%80%E4%BA%8C%E5%B9%B6%E5%8F%91%E7%94%A8%E6%88%B7/</guid><description>&lt;br>
![](http://img.testclass.net/vusers.png)
&lt;br>
#### 并发的两种情况
----
一种是严格意义上的并发，即所有的用户在同一时间点做同一件事或操作，这种操作一般指做同一类型的业务。比如，所有用户同一时刻做并发登陆，同一时刻做表单提交。
&lt;p>另外一种并发是广义范围的并发，这种并发与前一种并发的区别是，尽管多个用户对系统发出了请求或者进行了操作，但是这些请求或都操作可以是相同的，也可以是不同的。比如，在同一时刻有用户在登录，有用户在提交表单。&lt;/p>
&lt;p>&lt;br> &lt;/p>
&lt;h3 id="从服务器的角度来看并发">从服务器的角度来看并发&lt;/h3>
&lt;hr>
&lt;p>前面的两种解释都是从用户业务的角度来解释并发的，因为我们平时所做的性能测试也是从用户端对业务层的操作来进行并发测试的。&lt;/p>
&lt;p>如果考虑整个系统运行过程中服务器所承受的压力是这样的：在该系统的运行过程中，把整个运行过程划分为离散的时间点，在每个点上都有一个“同时向服务端发送请求的用户数”，这个就是所谓的服务器所承受的并发访问数。&lt;/p>
&lt;br>
#### 真正意义上的并发不存在
----
&lt;p>从性能测试工具的角度来看，虽然，性能测试工具可以1秒模拟成千上万个请求，那么这些请求的产生同样分前后顺序。就算这些请求被真正的“同时”生产出来，通过网络传输到过服务器时，因为受网络带宽、延迟等影响，也无法真正的对服务器构成“同时”请求。&lt;/p>
&lt;p>从服务器角度，当它接收到并发请求，在处理这些请求时同样需要分前后顺序，因为它处理每个请求的时间极短；每秒可以处理几千几万次请求；所以，我们说它的并发能力是每秒/次。&lt;/p>
&lt;p>（&lt;strong>注：&lt;/strong> 这里假设模拟虚拟用户的服务器和系统服务器为单核CPU的情况下）&lt;/p>
&lt;br>
#### 系统用户数与同时在线人数
----
&lt;p>在实际的性能测试中，经常还会遇到与并发相关的两个概念“系统用户数”与“同时在线人数”。&lt;/p>
&lt;p>假设有一个网站，注册用户才能登录使用各种功能，如上传头像，阅读专家文章等。该系统有20万注册用户，这就是说有20万用户可以使用这个网站的所有功能，20万就是这个网站的“系统用户数”，网站有一个在线统计功能，从统计数据中可以看到，同时登录网站的人数的最高记录是2万，就是有2万人同时用浏览器打开着这个网站。2万就是“同时在线人数”。
那么系统的并发用户数2万么？不是的！这2万只表示在系统最高峰时有这么多用户登录了网站，并不代表服务器的实际承受压力。因为服务器承受压力还与具体的用户访问模式相关，在这2万用户中考察某一个时间点对用户发出请求数，可以会大大缩水。那么，该系统的服务端承受的最大并发访问数是多少呢？这个取决于业务并发用户数和业务场景，一般可以通过服务器日志的分析得到。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1468930830753-6699377de411?w=300"
 data-srcset="https://images.unsplash.com/photo-1468930830753-6699377de411?w=300, https://images.unsplash.com/photo-1468930830753-6699377de411?w=300 1.5x, https://images.unsplash.com/photo-1468930830753-6699377de411?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1468930830753-6699377de411?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（二）软件测试分类</title><link>https://itest2025.pages.dev/tutorials/29-002-%E4%BA%8C%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E5%88%86%E7%B1%BB/</link><pubDate>Thu, 27 Jul 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/29-002-%E4%BA%8C%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E5%88%86%E7%B1%BB/</guid><description>&lt;br>
软件测试领域名词颇多，许多测试新手容易混淆概念。因为从不同的角度对软件测试有不同的分类方法，所以，这里汇总常见软件测试的相关名词，让读者对软件测试领域有个概括性了解。
&lt;br>
#### 根据项目流程阶段划分软件测试
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/testclass_01.png"
 data-srcset="http://img.testclass.net/testclass_01.png, http://img.testclass.net/testclass_01.png 1.5x, http://img.testclass.net/testclass_01.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/testclass_01.png"
 title="http://img.testclass.net/testclass_01.png" />&lt;/p>
&lt;p>是一个典型的“V”模型软件开发流程，各项软件测试工作是在项目开发流程中循序渐进进行的。下面将介绍各个阶段测试的含义。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>单元测试：单元测试（或模块测试）是对程序中的单个子程序或具有独立功能的代码段进行测试的过程。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>集成测试：集成测试是在单元测试的基础上，先通过单元模块组装成系统或子系统，再进行测试。重点是检查模块之间的接口是否正确。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>系统测试：系统测试是针对整个产品系统进行的测试，验证系统是否满足需求规格的定义，以及软件系统的正确性和性能等是否满足其需求规格的要求。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>验收测试：验收测试是部署软件之前的最后一个测试阶段。验收测试的目的是确保软件准备就绪，向软件购买者展示该软件系统能够满足用户的需求。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;br>
#### 白盒测试、黑盒测试、灰盒测试
&lt;p>白盒测试与黑盒测试，主要是根据软件测试工作中对软件代码的可见程度进行的划分。这也是软件测试领域中最基本的概念之一。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/testclass_02.png"
 data-srcset="http://img.testclass.net/testclass_02.png, http://img.testclass.net/testclass_02.png 1.5x, http://img.testclass.net/testclass_02.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/testclass_02.png"
 title="http://img.testclass.net/testclass_02.png" />&lt;/p>
&lt;ul>
&lt;li>黑盒测试&lt;/li>
&lt;/ul>
&lt;p>黑盒测试，指的是把被测的软件看作一个黑盒子，我们不去关心盒子里面的结构是什么样子的，只关心软件的输入数据和输出结果。
它只检查程序呈现给用户的功能是否按照需求规格说明书的规定正常使用、程序是否能接收输入数据并产生正确的输出信息。黑盒测试着眼于程序外部结构，不考虑内部逻辑结构，主要针对软件界面和软件功能进行测试。&lt;/p>
&lt;ul>
&lt;li>白盒测试&lt;/li>
&lt;/ul>
&lt;p>白盒测试，指的是把盒子打开，去研究里面的源代码和程序执行结果。
它是按照程序内部的结构测试程序，通过测试来检测产品内部动作是否按照设计规格说明书的规定正常进行，检验程序中的每条逻辑路径是否都能按预定要求正确工作。&lt;/p>
&lt;ul>
&lt;li>灰盒测试&lt;/li>
&lt;/ul>
&lt;p>灰盒测试介于黑盒测试与白盒测试之间。&lt;/p>
&lt;p>可以这样理解，灰盒测试既关注输出对于输入的正确性，同时也关注内部表现。但这种关注不像白盒测试那样详细、完整，它只是通过一些表征性的现象、事件、标志来判断内部的运行状态。有时候输出是正确的，但内部其实已经错误了，这种情况非常多。如果每次都通过白盒测试来操作，效率会很低，因此需要采取灰盒测试的方法。&lt;/p>
&lt;br>
#### 功能测试与性能测试
&lt;p>从软件的不同测试面可以划分为功能测试与性能测试。&lt;/p>
&lt;ul>
&lt;li>功能测试&lt;/li>
&lt;/ul>
&lt;p>功能测试主要检查实际功能是否符合用户的需求，因此测试的大部分工作也是围绕软件的功能进行。设计软件的目的就是满足用户对其功能的需求，如果偏离了这个目的，则任何测试工作都是没有意义的。&lt;/p>
&lt;p>功能测试又可以细分为很多种：逻辑功能测试、界面测试、易用性测试、安装测试、兼容性测试等。&lt;/p>
&lt;ul>
&lt;li>性能测试&lt;/li>
&lt;/ul>
&lt;p>性能测试是通过自动化的测试工具模拟多种正常、峰值以及异常负载条件来对系统的各项性能指标进行的测试。&lt;/p>
&lt;p>软件的性能包括很多方面，主要有时间性能和空间性能两种。&lt;/p>
&lt;p>&lt;strong>时间性能&lt;/strong>：主要是指软件的一个具体的响应时间。例如一个登录所需要的时间，一个商品交易所需要的时间等。当然，抛开具体的测试环境，来分析一次事务的响应时间是没有任何意义的，它需要在搭建好的一个具体且独立的测试环境下进行。&lt;/p>
&lt;p>&lt;strong>空间性能&lt;/strong>：主要指软件运行时所消耗的系统资源，例如硬件资源，CPU、内存、网络带宽消耗等。&lt;/p>
&lt;br>
#### 手工测试与自动化测试
&lt;p>从对软件测试工作的自动化程度可以划分为手工测试与自动化测试。&lt;/p>
&lt;ul>
&lt;li>手工测试&lt;/li>
&lt;/ul>
&lt;p>手工测试就是由测试人员一个一个地去执行测试用例，通过键盘鼠标等输入一些参数，并查看返回结果是否符合预期结果。&lt;/p>
&lt;p>手工测试并非专业术语，手工测试通常是指我们在系统测试阶段所进行的功能测试，为了更明显地与自动化测试进行区分，这里使用了手工测试这种说法。&lt;/p>
&lt;ul>
&lt;li>自动化测试&lt;/li>
&lt;/ul>
&lt;p>自动化测试是把以人为驱动的测试行为转化为机器执行的一种过程。通常，在设计测试用例并通过评审之后，由测试人员根据测试用例中描述的规则流程一步步执行测试，把得到的实际结果与期望结果进行比较。在此过程中，为了节省人力、时间和硬件资源，提高测试效率，便引入了自动化测试的概念。&lt;/p>
&lt;p>自动化测试又可分为：功能自动化测试与性能自动化测试。&lt;/p>
&lt;p>&lt;strong>功能自动化测试&lt;/strong>：是把以人为驱动的测试行为转化为机器执行的一种过程。通过测试工具（或框架）录制/编写测试脚本，对软件的功能进行测试，并验证测试结果是否正确，从而代替部分的手工测试工作，达到节约人力成本和时间成本的目的。&lt;/p>
&lt;p>&lt;strong>性能自动化测试&lt;/strong>：通过性能工具来模拟成千上万的虚拟用户向系统发送请求，从而验证系统的处理能力。&lt;/p>
&lt;br>
#### 冒烟测试、回归测试、随机测试、探索性测试和安全测试
&lt;p>这几种测试出现在软件测试的周期中，既不算具体明确的测试阶段，也不是具体的测试方法。&lt;/p>
&lt;ul>
&lt;li>冒烟测试&lt;/li>
&lt;/ul>
&lt;p>是指在对一个新版本进行大规模的系统测试之前，先验证一下软件的基本功能是否实现，是否具备可测性。&lt;/p>
&lt;p>引入到软件测试中，就是指测试小组在正式测试一个新版本之前，先投入较少的人力和时间验证一个软件的主要功能，如果主要功能都没有运行通过，则打回开发组重新开发。这样做的好处是可以节省时间和人力投入到不可测的项目中。&lt;/p>
&lt;ul>
&lt;li>回归测试&lt;/li>
&lt;/ul>
&lt;p>回归测试是指修改了旧代码后，重新进行测试以确认修改后没有引入新的错误或导致其他代码产生错误。&lt;/p>
&lt;p>回归测试一般是在进行第二轮软件测试时开始的，验证第一轮软件测试中发现的问题是否得到修复。当然，回归也是一个循环的过程，如果回归的问题通不过，则需要开发人员修改后再次进行回归，直到所有问题回归通过为止。&lt;/p>
&lt;ul>
&lt;li>随机测试&lt;/li>
&lt;/ul>
&lt;p>是指测试中的所有输入数据都是随机生成的，其目的是模拟用户的真实操作，并发现一些边缘性的错误。&lt;/p></description></item><item><title>database测试笔试题1</title><link>https://itest2025.pages.dev/tutorials/44-002-database%E6%B5%8B%E8%AF%95%E7%AC%94%E8%AF%95%E9%A2%981/</link><pubDate>Tue, 18 Jul 2017 09:30:25 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/44-002-database%E6%B5%8B%E8%AF%95%E7%AC%94%E8%AF%95%E9%A2%981/</guid><description>&lt;h3 id="主键的值可以为空么">主键的值可以为空么？&lt;/h3>
&lt;p>can the value of primary key be NULL? no&lt;/p>
&lt;p>答案 ： 不行&lt;/p>
&lt;h3 id="创建索引是为了提高性能么">创建索引是为了提高性能么？&lt;/h3>
&lt;p>Is the index used to improve the peformance? 答案：yes&lt;/p>
&lt;p>答案： 是&lt;/p>
&lt;h3 id="关键字-select-distinct-是用来分组的么">关键字 select distinct 是用来分组的么？&lt;/h3>
&lt;p>is the keyword &amp;ldquo;select distinct&amp;rdquo; used to group result-set by one or more columns? no&lt;/p>
&lt;p>答案： 不是&lt;/p>
&lt;h3 id="哪个关键字是用来对结果排序">哪个关键字是用来对结果排序？&lt;/h3>
&lt;p>which keyword is used to sort the result-set? order by&lt;/p>
&lt;p>答案 ： Order by&lt;/p>
&lt;h3 id="哪个关键字是用来修改已经存在的数据">哪个关键字是用来修改已经存在的数据？&lt;/h3>
&lt;p>which keyword is used to modify the existing records in table? update&lt;/p></description></item><item><title>（二）环境安装之IntelliJ IDEA</title><link>https://itest2025.pages.dev/tutorials/19-002-%E4%BA%8C%E7%8E%AF%E5%A2%83%E5%AE%89%E8%A3%85%E4%B9%8Bintellij-idea/</link><pubDate>Thu, 06 Jul 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/19-002-%E4%BA%8C%E7%8E%AF%E5%A2%83%E5%AE%89%E8%A3%85%E4%B9%8Bintellij-idea/</guid><description>&lt;br>
### 安装IntelliJ IDEA
&lt;p>你可能会问，为什么不用Eclipse呢？随着发展IntelliJ IDEA有超越Eclipse的势头，JetBrains公司的IDE基本上已经一统了各家主流编程语言的江湖。考虑到 Java IDE的流行趋势，本书中决定选用IntelliJ IDEA。&lt;/p>
&lt;p>当然， 选择什么样的IDE充满着个人喜好。你依然可以参考其它资料安装Java IDE。这不会影响你阅读该系列文章。
点击 &lt;a href="https://www.jetbrains.com/idea" target="_blank" rel="noopener noreffer ">IntelliJ IDEA下载&lt;/a>，根据自己的平台，选择相应的版本进行下载。&lt;/p>
&lt;p>IntelliJ IDEA安装过程省略&amp;hellip;&lt;/p>
&lt;p>如果第一次打开IntelliJ IDEA，会看到如下界面。
&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://orru5lls3.bkt.clouddn.com/idea.png"
 data-srcset="http://orru5lls3.bkt.clouddn.com/idea.png, http://orru5lls3.bkt.clouddn.com/idea.png 1.5x, http://orru5lls3.bkt.clouddn.com/idea.png 2x"
 data-sizes="auto"
 alt="http://orru5lls3.bkt.clouddn.com/idea.png"
 title="http://orru5lls3.bkt.clouddn.com/idea.png" />&lt;/p>
&lt;p>点击&amp;quot;Create New Project&amp;quot;选项创建新的Java项目。选择项目类型为Java，然后，继续&amp;quot;Next&amp;quot;。
&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://orru5lls3.bkt.clouddn.com/idea2.png"
 data-srcset="http://orru5lls3.bkt.clouddn.com/idea2.png, http://orru5lls3.bkt.clouddn.com/idea2.png 1.5x, http://orru5lls3.bkt.clouddn.com/idea2.png 2x"
 data-sizes="auto"
 alt="http://orru5lls3.bkt.clouddn.com/idea2.png"
 title="http://orru5lls3.bkt.clouddn.com/idea2.png" />&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Project name: 项目名称。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Project location: 项目在硬盘上的路径。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>点击&amp;quot;Finish&amp;quot;结束项目创建完成。&lt;/p>
&lt;br>
### 编写Hello World！
&lt;p>首先，打开IntelliJ IDEA，点击左侧项目列表，在src下面创建__包__和__类文件__。&lt;/p>
&lt;p>1)右键左侧项目列表 src&amp;mdash;&amp;gt;New &amp;mdash;&amp;gt; Package 弹出窗口， 输入包的名：javaBase。&lt;/p>
&lt;p>2)右键左侧创建的包名：java &amp;mdash;&amp;gt;New &amp;mdash;&amp;gt; Java Class 弹出窗口， 输入类的名：HelloWorld。
&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://orru5lls3.bkt.clouddn.com/idea4.png"
 data-srcset="http://orru5lls3.bkt.clouddn.com/idea4.png, http://orru5lls3.bkt.clouddn.com/idea4.png 1.5x, http://orru5lls3.bkt.clouddn.com/idea4.png 2x"
 data-sizes="auto"
 alt="http://orru5lls3.bkt.clouddn.com/idea4.png"
 title="http://orru5lls3.bkt.clouddn.com/idea4.png" />&lt;/p></description></item><item><title>（二）selenium3 浏览器驱动</title><link>https://itest2025.pages.dev/tutorials/24-002-%E4%BA%8Cselenium3-%E6%B5%8F%E8%A7%88%E5%99%A8%E9%A9%B1%E5%8A%A8/</link><pubDate>Thu, 29 Jun 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/24-002-%E4%BA%8Cselenium3-%E6%B5%8F%E8%A7%88%E5%99%A8%E9%A9%B1%E5%8A%A8/</guid><description>&lt;br>
### 下载浏览器驱动
&lt;p>当selenium升级到3.0之后，对不同的浏览器驱动进行了规范。如果想使用selenium驱动不同的浏览器，必须单独下载并设置不同的浏览器驱动。&lt;/p>
&lt;p>各浏览器下载地址：&lt;/p>
&lt;p>Firefox浏览器驱动：&lt;a href="https://github.com/mozilla/geckodriver/releases" target="_blank" rel="noopener noreffer ">geckodriver&lt;/a>&lt;/p>
&lt;p>Chrome浏览器驱动：&lt;a href="https://sites.google.com/a/chromium.org/chromedriver/home" target="_blank" rel="noopener noreffer ">chromedriver&lt;/a> , &lt;a href="https://npm.taobao.org/mirrors/chromedriver" target="_blank" rel="noopener noreffer ">taobao备用地址&lt;/a>&lt;/p>
&lt;p>IE浏览器驱动：&lt;a href="http://selenium-release.storage.googleapis.com/index.html" target="_blank" rel="noopener noreffer ">IEDriverServer&lt;/a>&lt;/p>
&lt;p>Edge浏览器驱动：&lt;a href="https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver" target="_blank" rel="noopener noreffer ">MicrosoftWebDriver&lt;/a>&lt;/p>
&lt;p>Opera浏览器驱动：&lt;a href="https://github.com/operasoftware/operachromiumdriver/releases" target="_blank" rel="noopener noreffer ">operadriver&lt;/a>&lt;/p>
&lt;p>PhantomJS浏览器驱动：&lt;a href="http://phantomjs.org" target="_blank" rel="noopener noreffer ">phantomjs&lt;/a>&lt;/p>
&lt;p>注：部分浏览器驱动地址需要科学上网。&lt;/p>
&lt;br>
### 设置浏览器驱动
&lt;p>设置浏览器的地址非常简单。
我们可以手动创建一个存放浏览器驱动的目录，如： C:\driver , 将下载的浏览器驱动文件（例如：chromedriver、geckodriver）丢到该目录下。&lt;/p>
&lt;p>我的电脑&amp;ndash;&amp;gt;属性&amp;ndash;&amp;gt;系统设置&amp;ndash;&amp;gt;高级&amp;ndash;&amp;gt;环境变量&amp;ndash;&amp;gt;系统变量&amp;ndash;&amp;gt;Path，将“C:\driver”目录添加到Path的值中。&lt;/p>
&lt;ul>
&lt;li>Path&lt;/li>
&lt;li>;C:\driver&lt;/li>
&lt;/ul>
&lt;br>
### 设置浏览器驱动
&lt;p>验证不同的浏览器驱动是否正常使用。&lt;/p>
&lt;pre tabindex="0">&lt;code>from selenium import webdriver


driver = webdriver.Firefox() # Firefox浏览器

driver = webdriver.Chrome() # Chrome浏览器

driver = webdriver.Ie() # Internet Explorer浏览器

driver = webdriver.Edge() # Edge浏览器

driver = webdriver.Opera() # Opera浏览器

driver = webdriver.PhantomJS() # PhantomJS

……
&lt;/code>&lt;/pre>&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/34/BA1yLjNnQCI1yisIZGEi_2013-07-16_1922_IMG_9873.jpg?w=300"
 data-srcset="https://images.unsplash.com/34/BA1yLjNnQCI1yisIZGEi_2013-07-16_1922_IMG_9873.jpg?w=300, https://images.unsplash.com/34/BA1yLjNnQCI1yisIZGEi_2013-07-16_1922_IMG_9873.jpg?w=300 1.5x, https://images.unsplash.com/34/BA1yLjNnQCI1yisIZGEi_2013-07-16_1922_IMG_9873.jpg?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/34/BA1yLjNnQCI1yisIZGEi_2013-07-16_1922_IMG_9873.jpg?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>趣谈软件需求分析</title><link>https://itest2025.pages.dev/tutorials/13-003-%E8%B6%A3%E8%B0%88%E8%BD%AF%E4%BB%B6%E9%9C%80%E6%B1%82%E5%88%86%E6%9E%90/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/13-003-%E8%B6%A3%E8%B0%88%E8%BD%AF%E4%BB%B6%E9%9C%80%E6%B1%82%E5%88%86%E6%9E%90/</guid><description>&lt;h4 id="什么是需求分析">什么是需求分析？&lt;/h4>
&lt;p>通俗的讲，对用户的意图不断揭示和验叛的过程，要对经过系统可行性分析所确定的系统目标做更为详细的描述。&lt;/p>
&lt;p>假如你是个建筑工程师，有个客户找你建一个鸡窝，这个时候要需要与客户沟通，来确定客户到底想要一个什么样子的鸡窝。我们应该注意三点：&lt;/p>
&lt;p>&lt;strong>1、准确的理解和描述客户需要的功能。&lt;/strong>&lt;/p>
&lt;p>客户说，我的鸡窝要三层的，带电梯，饮水池，厕所，饮水池要自动判断水位供水，电梯要可以同时乘坐10只鸡&amp;hellip;.客户滔滔不绝的讲了一大堆，你也都非常忠实的按照自己的理解再一一的向客户描述一遍，以便于确认客户的需求是否正确。&lt;/p>
&lt;p>&lt;strong>2、帮助客户挖掘需求。&lt;/strong>&lt;/p>
&lt;p>等客户把自己的需求说完了，你发现客户没有说鸡的卧室，于是，你向客户提议说：“你看，这鸡的卧室要什么样子的？”，客户连连的拍着脑门说，我差点给忘记了，鸡们啊喜欢晚上在一起聊天，所以呢，需要一个长而大的卧室，但一定要舒适。&lt;/p>
&lt;p>&lt;strong>3、分析客户需求的可行性。&lt;/strong>&lt;/p>
&lt;p>客户临走时又说，最近啊，黄鼠狼很多，我这个鸡窝啊，一楼就不用盖了，直接盖二楼和三楼吧！以免晚上遭遇黄鼠狼的攻击。你这么一分析，客户这要求，按照目前的技术可没法建啊，于是，你向客户提议，一楼采用坚固架子来支撑二三楼的建筑。&lt;/p>
&lt;br>
#### 需求分析困难在哪儿？
&lt;p>有几种原因使需求分析变得困难：（1）客户说不清楚需求；（2）需求自身经常变动；（3）分析人员或客户理解有误。&lt;/p>
&lt;p>&lt;strong>1、客户说不清楚需求&lt;/strong>&lt;/p>
&lt;p>有些客户对需求只有朦胧的感觉，当然说不清楚具体的需求。例如全国各地的很多政府机构在搞网络建设，这些单位的领导和办公人员大多不清楚计算机网络有什么用，反而要软件系统分析人员替他们设想需求。这类工程的需求是如此的主观，以致产生很多贪污腐败现象。&lt;/p>
&lt;p>有些客户心里非常清楚想要什么，但却说不明白。你可能很不以为然。就举日常生活的事例吧，比如说买鞋子。我们非常了解自已的脚，但没法说清楚脚的大小和形状。只能拿鞋子去试，试穿时感觉到舒服才会买鞋（居然也有神通广大的售货员，看一眼客户的手，就知道应该穿什么样的鞋）。&lt;/p>
&lt;p>如果客户本身就懂软件开发，能把需求说得清清楚楚，这样的需求分析将会非常轻松、愉快。如果客户全不懂软件，但信任软件开发方，这事也好办。分析人员可以引导客户，先阐述常规的需求，再由客户否定不需要的，最终确定客户真正的需求。最怕的就是“不懂装懂”或者“半懂充内行”的客户，他们会提出不切实际的需求。如果这些客户甚至觉得自己是上帝的爸爸，那么沟通和协商都会很困难。&lt;/p>
&lt;p>&lt;strong>2、需求自身经常变动&lt;/strong>&lt;/p>
&lt;p>唐僧曾说：“妖要是有了仁慈之心，就不再是妖，是人妖。”（《大话西游之大圣娶亲》）&lt;/p>
&lt;p>连妖都会变心，别说人了。所以喜新厌旧乃人之常情，世界也因此变得多姿多彩。&lt;/p>
&lt;p>软件的需求会变化吗？&lt;/p>
&lt;p>答：据历史记载，没有一个软件的需求改动少于三次。唯一只改动需求两次的客户是个死人。这个可怜的家伙还是在运送第三次需求的路上被车子撞死的。[Cline 1995]&lt;/p>
&lt;p>让我们先接受“需求会变动”这个事实吧，免得在需求变动时惊慌失措。明白“需求会变动”这个道理后，在进行需求分析时就要留点神：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>尽可能地分析清楚哪些是稳定的需求，哪些是易变的需求。以便在进行系统设计时，将软件的核心建筑在稳定的需求上，否则将会吃尽苦头。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>在合同中一定要说清楚“做什么”和“不做什么”。如果合同含含糊糊，日后扯皮的事情就多。要防止象韩复渠那样，在别人请他喝酒吃饭时他什么都点头（人家就更加献殷勤），吃完了他就宣布刚才答应的事都不算数，便扬长而去。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>3、分析人员和顾客理解有误&lt;/strong>&lt;/p>
&lt;p>有个外星人间谍潜伏到地球刺探情报，它给上司写了一份报告：“主宰地球的是车。它们喝汽油，靠四个轮子滚动前进。嗓门极大，在夜里双眼能射出强光。……有趣的是，车里住着一种叫作‘人’的寄生虫，这些寄生虫完全控制了车。”&lt;/p>
&lt;p>软件系统分析人员不可能都是全才。客户表达的需求，不同的分析人员可能有不同的理解。如果分析人员理解错了，可能会导致开发人员白干活，吃力不讨好。我读中学时候最怕写作文逃题，如果逃题了，不管作文写得多长，总是零分。所以分析人员写好需求说明书后，要请客户方的各个代表验证。如果问题很复杂，双方都不太明白，就有必要请开发人员快速构造软件的原型，双方再次论证需求说明书是否正确。&lt;/p>
&lt;p>由于客户大多不懂软件，他们可能觉得软件是万能的，会提出一些无法实现的需求。有时客户还会把软件系统分析人员的建议或答复给想歪了。&lt;/p>
&lt;p>有一个软件人员滔滔不绝地向客户讲解在“信息高速公路上做广告”的种种好处，客户听得津津有味。最后，心动的客户对软件人员说：“好得很，就让我们马上行动起来吧。请您决定广告牌的尺寸和放在哪条高速公路上，我立即派人去做。”&lt;/p>
&lt;h4 id="需求分析的分类">需求分析的分类&lt;/h4>
&lt;p>需求分析一般可分为功能需求、非功能需求和领域需求&lt;/p>
&lt;p>&lt;strong>1、功能需求&lt;/strong>&lt;/p>
&lt;p>功能需求主要说明了系统实际应做到什么。这是用户最直观也是最主要的需求，如系统的输入输出、系统能完成的功能以及其它相关处理等；&lt;/p>
&lt;p>&lt;strong>2、非功能需求&lt;/strong>&lt;/p>
&lt;p>非功能需求又称“约束”，它主要从各个角度对系统起约束和限制作用。如响应时间、存储效率、报表的规格和界面的样式等&lt;/p>
&lt;p>&lt;strong>3、领域需求&lt;/strong>&lt;/p>
&lt;p>领域需求的来源不是用户，而是系统应用的领域，其主要反映了该领域的基本问题。例如勤工俭学管理系统，其领域需求就涉及到诸如应聘合同书、酬金发放及劳工考核等相关内容，如果这些需求得不到满足，系统就无法正常运行。值得一提的是，领域需求可能是功能需求，也可能是非功能需求。&lt;/p>
&lt;h4 id="如何进行需求分析">如何进行需求分析&lt;/h4>
&lt;p>进行需求分析不象情人之间的浪漫做法——“让我摸摸你的头发，感觉它是什么颜色。”我们需要了解需求分析的渠道和过程。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/requirement-analysis_01.png"
 data-srcset="http://img.testclass.net/requirement-analysis_01.png, http://img.testclass.net/requirement-analysis_01.png 1.5x, http://img.testclass.net/requirement-analysis_01.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/requirement-analysis_01.png"
 title="http://img.testclass.net/requirement-analysis_01.png" />&lt;/p>
&lt;p>需求分析的过程：&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/requirement-analysis_02.png"
 data-srcset="http://img.testclass.net/requirement-analysis_02.png, http://img.testclass.net/requirement-analysis_02.png 1.5x, http://img.testclass.net/requirement-analysis_02.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/requirement-analysis_02.png"
 title="http://img.testclass.net/requirement-analysis_02.png" />&lt;/p>
&lt;p>&lt;strong>（1）可行性研究&lt;/strong>&lt;/p>
&lt;p>它指明现有的软件、硬件技术能否实现用户对系统的要求，从业务角度来决定系统开发是否可行以及在预算范围内能否开发出来。可行性研究的结果是清楚的回答：该系统是否值得开发&lt;/p>
&lt;p>&lt;strong>（2）需求导出和分析&lt;/strong>&lt;/p>
&lt;p>这是一个通过对现有系统分析、与潜在客户讨论、进行任务分析等导出系统需求的过程，也可能需要开发一个或多个不同的系统原型，以帮助分析员了解所要描述的系统。&lt;/p>
&lt;p>&lt;strong>（3）需求描述&lt;/strong>&lt;/p>
&lt;p>需求描述就是把在分析活动中收集的信息通过分析整理之后以文档的形式确定下来。该文档中有两类需求：用户需求是从客户和最终用户角度对系统需求的抽象描述；系统需求是对系统要提供的功能的详尽描述。&lt;/p>
&lt;p>&lt;strong>（4）需求有效性验证&lt;/strong>&lt;/p>
&lt;p>主要是通过评审、验证等一系列活动来找出需求文档中的错漏并加以改正。&lt;/p>
&lt;p>&lt;strong>（5）需求管理&lt;/strong>&lt;/p>
&lt;p>需求管理需求管理是一种系统化方法，可用于获取、组织和记录系统需求并使用户和开发方在系统变更需求上始终保持一致&lt;/p>
&lt;br>
#### 需求分析的方法
&lt;p>&lt;strong>1、功能分析方法&lt;/strong>&lt;/p></description></item><item><title>wrk系列教程(3)统计结果</title><link>https://itest2025.pages.dev/tutorials/15-003-wrk%E7%B3%BB%E5%88%97%E6%95%99%E7%A8%8B3%E7%BB%9F%E8%AE%A1%E7%BB%93%E6%9E%9C/</link><pubDate>Sun, 03 Mar 2019 02:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/15-003-wrk%E7%B3%BB%E5%88%97%E6%95%99%E7%A8%8B3%E7%BB%9F%E8%AE%A1%E7%BB%93%E6%9E%9C/</guid><description>&lt;p>回到上一节的统计结果，我们来看一下这些结果是如何统计出来的。&lt;/p>
&lt;pre tabindex="0">&lt;code>Running 30s test @ http://127.0.0.1:8000/index.html
 10 threads and 200 connections
 Thread Stats Avg Stdev Max +/- Stdev
 Latency 3.24ms 6.54ms 154.00ms 95.36%
 Req/Sec 167.54 227.05 1.81k 84.83%
 16145 requests in 30.08s, 3.13MB read
 Socket errors: connect 0, read 1208, write 31, timeout 0
Requests/sec: 536.78
Transfer/sec: 106.41KB
&lt;/code>&lt;/pre>&lt;p>我们一行一行来看一下这些统计数据。&lt;/p>
&lt;ul>
&lt;li>&lt;code>Running 30s test @ http://127.0.0.1:8000/index.html&lt;/code>，测试持续时间已经被测url&lt;/li>
&lt;li>&lt;code>10 threads and 200 connections&lt;/code>，总共多少个thread和connection&lt;/li>
&lt;li>&lt;code>Latency 3.24ms 6.54ms 154.00ms 95.36% &lt;/code>，时延的平均值，标准差以及最大值以及值落在标准差区间内的百分比&lt;/li>
&lt;li>&lt;code>Req/Sec 167.54 227.05 1.81k 84.83%&lt;/code>，每个线程运行时的qps平均值，标准差以及百分比区间。看了一圈源码，没太看懂这个统计的意义&lt;/li>
&lt;li>&lt;code> 16145 requests in 30.08s, 3.13MB read&lt;/code>，总请求数，运行的总时间以及传输数据的总和&lt;/li>
&lt;li>&lt;code> Socket errors: connect 0, read 1208, write 31, timeout 0&lt;/code>，socket错误的统计&lt;/li>
&lt;li>&lt;code>Requests/sec: 536.78&lt;/code>， 总请求数除以总的运行时间，也就是qps&lt;/li>
&lt;li>&lt;code>Transfer/sec: 106.41KB&lt;/code>， 传输的总数据除以总的运行时间&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p></description></item><item><title>python简明教程: 3. 控制流</title><link>https://itest2025.pages.dev/tutorials/39-003-python%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B-3-%E6%8E%A7%E5%88%B6%E6%B5%81/</link><pubDate>Tue, 20 Nov 2018 03:23:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/39-003-python%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B-3-%E6%8E%A7%E5%88%B6%E6%B5%81/</guid><description>&lt;p>本文内容基本上翻译自&lt;a href="http://cheat.sh/python/:learn" target="_blank" rel="noopener noreffer ">http://cheat.sh/python/:learn)&lt;/a>&lt;/p>
&lt;p>&lt;strong>非原创, 非原创, 非原创!!!&lt;/strong>&lt;/p>
&lt;p>感谢原文社区作者&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">####################################################&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3. 控制流&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">####################################################&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 定义变量&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">some_var&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">5&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 这是if语句，注意缩进，在python里缩进非常重要！&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 结果是打印 &amp;#34;some_var is smaller than 10&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="n">some_var&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span> &lt;span class="s2">&amp;#34;some_var is totally bigger than 10.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">elif&lt;/span> &lt;span class="n">some_var&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="c1"># elif 分支是可选的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span> &lt;span class="s2">&amp;#34;some_var is smaller than 10.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="c1"># 这也是可选的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span> &lt;span class="s2">&amp;#34;some_var is indeed 10.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">用for去遍历list
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">打印结果:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> dog is a mammal
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> cat is a mammal
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> mouse is a mammal
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">animal&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;dog&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;cat&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;mouse&amp;#34;&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 可以用{0}语法去格式化打印，参考之前的教程&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{0}&lt;/span>&lt;span class="s2"> is a mammal&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">animal&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;range(number)&amp;#34; 返回1个列表，列表里包含一组数字
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">从0到number,不包含number
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">打印:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 0
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 1
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 2
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 3
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span> &lt;span class="n">i&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;range(lower, upper)&amp;#34; 返回1个列表，列表里包含一组数字
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">范围从lower到upper
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">prints:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 4
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 5
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 6
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 7
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">8&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span> &lt;span class="n">i&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">While会一直循环直到条件不再满足为止
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">prints:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 0
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 1
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 2
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 3
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">while&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span> &lt;span class="n">x&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="c1"># x = x + 1 的简写&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># try/except 代码库(block)用来处理异常&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 适用于Python 2.6及以上版本:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 使用&amp;#34;raise&amp;#34;来抛出异常&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">IndexError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;This is an index error&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">except&lt;/span> &lt;span class="ne">IndexError&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">pass&lt;/span> &lt;span class="c1"># Pass就是啥都不做.一般情况下，你会在这里做异常的恢复&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">except&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="ne">TypeError&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ne">NameError&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">pass&lt;/span> &lt;span class="c1"># 如果需要的话可以一次性处理多个异常&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="c1"># else分支是可选的.必须出现在所有的except分支之后&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span> &lt;span class="s2">&amp;#34;All good!&amp;#34;&lt;/span> &lt;span class="c1"># 当且仅当try代码块中没有抛出任何异常时才会运行&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">finally&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="c1"># 最后一定会执行&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span> &lt;span class="s2">&amp;#34;We can clean up resources here&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 除了使用try/finally之外，我们可以使用 with 语句来进行适当的简化&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">with&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;myfile.txt&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">line&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span> &lt;span class="n">line&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p></description></item><item><title>（三）Docker 镜像</title><link>https://itest2025.pages.dev/tutorials/30-003-%E4%B8%89docker-%E9%95%9C%E5%83%8F/</link><pubDate>Mon, 22 Jan 2018 14:45:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/30-003-%E4%B8%89docker-%E9%95%9C%E5%83%8F/</guid><description>&lt;p>Docker 运行容器前需要本地存在对应的镜像，如果镜像不存在本地， Docker	会从镜像仓库下载（默认是Docker Hub公共注册服务器中的仓库）。&lt;/p>
&lt;p>Docker Hub:https://hub.docker.com
阿里云镜像：https://dev.aliyun.com/search.html
灵雀云：https://hub.alauda.cn/&lt;/p>
&lt;h4 id="镜像">镜像&lt;/h4>
&lt;hr>
&lt;h5 id="查看镜像">查看镜像&lt;/h5>
&lt;p>列出本地镜像：&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo docker images

REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest f2a91732366c 2 months ago
&lt;/code>&lt;/pre>&lt;p>在列出信息中，可以看到几个字段信息：&lt;/p>
&lt;ul>
&lt;li>来自于哪个仓库，比如	ubuntu&lt;/li>
&lt;li>镜像的标记，比如	14.04&lt;/li>
&lt;li>它的 	ID	号（唯一）&lt;/li>
&lt;li>创建时间&lt;/li>
&lt;li>镜像大小&lt;/li>
&lt;/ul>
&lt;h5 id="获取镜像">获取镜像&lt;/h5>
&lt;p>可以使用&lt;code>docker pull&lt;/code> 命令来从仓库获取所需要的镜像。搜索 “ubuntu” 镜像。&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo docker pull ubuntu

Using default tag: latest
latest: Pulling from library/ubuntu
8f7c85c2269a: Pull complete
9e72e494a6dd: Pull complete
3009ec50c887: Pull complete
9d5ffccbec91: Pull complete
e872a2642ce1: Pull complete
Digest: sha256:d3fdf5b1f8e8a155c17d5786280af1f5a04c10e95145a515279cf17abdf0191f
Status: Downloaded newer image for ubuntu:latest
&lt;/code>&lt;/pre>&lt;p>该命令实际上相当于 &lt;code>$	docker pull registry.hub.docker.com/ubuntu&lt;/code> 命令，即从注册服务器&lt;code>registry.hub.docker.com&lt;/code>中的 &lt;code>ubuntu&lt;/code>仓库来下载的镜像。&lt;/p></description></item><item><title>（三）Java的强类型定义</title><link>https://itest2025.pages.dev/tutorials/16-003-%E4%B8%89java%E7%9A%84%E5%BC%BA%E7%B1%BB%E5%9E%8B%E5%AE%9A%E4%B9%89/</link><pubDate>Wed, 17 Jan 2018 14:42:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/16-003-%E4%B8%89java%E7%9A%84%E5%BC%BA%E7%B1%BB%E5%9E%8B%E5%AE%9A%E4%B9%89/</guid><description>&lt;p>在由Python转向Java的一个最大的感受就是Java的类型定义。Java要求你所定义的常量/变量和方法必须要声明类型。&lt;/p>
&lt;h4 id="常量变量">常量、变量&lt;/h4>
&lt;hr>
&lt;p>定义常量与变量。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">JavaType&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">final&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">double&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PI&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">3&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">14&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//定义常量&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">R&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">5&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//定义变量&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">printf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;圆周率的面积:&amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PI&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">R&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">R&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>
&lt;p>final double：final用于定义常量，double为常量PI的类型。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>int：为变量R的类型。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>更多类型&lt;/strong>&lt;/p>
&lt;p>更多一些常用的数据类型：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="kt">short&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">3&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// 定义short类型变量&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">22&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// 定义int类型变量&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kt">float&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">f&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">23f&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// 定义float类型变量&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kt">char&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="sc">&amp;#39;a&amp;#39;&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// 定义字符类型用char&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;hello world&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// 定义字符串类型String&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kt">boolean&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">status&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// 定义布尔类型类型用 boolean&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="数组与hashmap">数组与HashMap&lt;/h4>
&lt;hr>
&lt;p>这种强类型还体现在数组和HashMap中。&lt;/p></description></item><item><title>TDD实战（三）“井字游戏” 需求二</title><link>https://itest2025.pages.dev/tutorials/32-003-tdd%E5%AE%9E%E6%88%98%E4%B8%89%E4%BA%95%E5%AD%97%E6%B8%B8%E6%88%8F-%E9%9C%80%E6%B1%82%E4%BA%8C/</link><pubDate>Mon, 08 Jan 2018 12:50:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/32-003-tdd%E5%AE%9E%E6%88%98%E4%B8%89%E4%BA%95%E5%AD%97%E6%B8%B8%E6%88%8F-%E9%9C%80%E6%B1%82%E4%BA%8C/</guid><description>&lt;h3 id="需求2">需求2&lt;/h3>
&lt;hr>
&lt;p>现在处理轮到哪个玩家落子问题。&lt;/p>
&lt;blockquote>
&lt;p>需要提供一种途径，用于判断接下来该谁落子。&lt;/p>&lt;/blockquote>
&lt;p>将需求分成三个测试：&lt;/p>
&lt;ul>
&lt;li>玩家 X 先下；&lt;/li>
&lt;li>如果上一次是 X 下的，接下来将轮到 O 下。&lt;/li>
&lt;li>如果上一次是 O 下的，接下来将轮到 X 下。&lt;/li>
&lt;/ul>
&lt;h4 id="测试用例1">测试用例1&lt;/h4>
&lt;hr>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.Assert.*&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="err">……&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">givenFirstTurnWhenNextPlayerThenX&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sc">&amp;#39;X&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ticTacToe&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">nextPlayer&lt;/span>&lt;span class="p">());&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在这条用例中用到了 JUnit 的断言方法 &lt;code>assertEquals()&lt;/code>，通过 &lt;code>nextPlayer()&lt;/code> 判断下一个下棋的是否是 X 玩家。&lt;/p>
&lt;h5 id="实现代码1">实现代码1&lt;/h5>
&lt;p>对于当前的测试用例来说，根本不需要检查玩家 X 是否先下，因为就目前而言，只需要让 &lt;code>nextPlayer()&lt;/code> 返回 X 就能让测试释通过。&lt;/p>
&lt;p>在 TicTacToe 类中添加 &lt;code>nextPlayer()&lt;/code> 方法。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">char&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">nextPlayer&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">return&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="sc">&amp;#39;X&amp;#39;&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>** &lt;strong>执行 测试用例1 检查它是否运行通过。&lt;/strong>&lt;/p>
&lt;h4 id="测试用例2">测试用例2&lt;/h4>
&lt;hr>
&lt;p>现在需要确保让玩家轮流下，玩家 X 下棋后，应轮到玩家 O， 然后再轮到玩家 X， 以此类推：&lt;/p></description></item><item><title>Android测试（三）：Android 单元测试</title><link>https://itest2025.pages.dev/tutorials/17-003-android%E6%B5%8B%E8%AF%95%E4%B8%89android-%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/</link><pubDate>Wed, 20 Dec 2017 14:45:12 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/17-003-android%E6%B5%8B%E8%AF%95%E4%B8%89android-%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/</guid><description>&lt;p>原文：https://developer.android.com/training/testing/unit-testing/index.html&lt;/p>
&lt;p>单元测试是你的应用程序测试策略的基本测试。 通过针对您的代码创建和运行单元测试，你可以轻松验证各个单元的逻辑是否正确。 在每次构建之后运行单元测试可帮助你快速捕获并修复由代码更改引入到应用程序的软件回归。&lt;/p>
&lt;p>单元测试通常以可重复的方式实现尽可能小的代码单元（可以是方法，类或组件）的功能。 当你需要验证应用程序中特定代码的逻辑时，你应该构建单元测试。 例如，你创建了一个类，单元测试可以帮助检查该类是否处于正确的状态。 通常，单元测试是相对独立的，你的测试只会影响和检查被测试单元的变更，mock框架可以用来隔离你要测试单元的依赖。&lt;/p>
&lt;p>注意：单元测试不适合测试复杂的UI交互事件。 相反，您应该使用UI测试框架，如&lt;a href="https://developer.android.com/training/testing/ui-testing/index.html" target="_blank" rel="noopener noreffer ">UI自动化测试&lt;/a>中所述。&lt;/p>
&lt;p>为了测试Android应用程序，你通常需要创建这些类型的单元测试：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>本地测试：&lt;/strong> 仅在本地机器上运行的单元测试。这些测试被编译为在Java虚拟机（JVM）本地运行，以最小化执行时间。使用这种方法来运行没有依赖于Android框架的单元测试，或者可以使用mock对象来填充依赖关系。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Instrumented测试：&lt;/strong> 在Android设备或模拟器上运行的单元测试。 这些测试可以访问工具信息，例如被测试的应用程序的上下文。 使用此方法运行具有Android依赖关系的单元测试，这些测试不能使用mock对象轻松填充。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>接下来将告诉你如何构建这两种类型单元测试。&lt;/p>
&lt;p>本课的教训将告诉您如何构建这些类型的自动化单元测试。&lt;/p>
&lt;h4 id="lessons">Lessons&lt;/h4>
&lt;hr>
&lt;p>&lt;a href="https://developer.android.com/training/testing/unit-testing/local-unit-tests.html" target="_blank" rel="noopener noreffer ">Building Local Unit Tests（创建本地单元测试）&lt;/a>&lt;/p>
&lt;p>学习如何构建在本地机器上运行的单元测试。&lt;/p>
&lt;p>&lt;a href="https://developer.android.com/training/testing/unit-testing/instrumented-unit-tests.html" target="_blank" rel="noopener noreffer ">Building Instrumented Unit Tests（创建Instrumented单元测试）&lt;/a>&lt;/p>
&lt;p>了解如何构建在Android设备或模拟器上运行的单元测试。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1516251193007-45ef944ab0c6?w=300"
 data-srcset="https://images.unsplash.com/photo-1516251193007-45ef944ab0c6?w=300, https://images.unsplash.com/photo-1516251193007-45ef944ab0c6?w=300 1.5x, https://images.unsplash.com/photo-1516251193007-45ef944ab0c6?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1516251193007-45ef944ab0c6?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>Fiddler（三）代理 HTTP 请求</title><link>https://itest2025.pages.dev/tutorials/23-003-fiddler%E4%B8%89%E4%BB%A3%E7%90%86-http-%E8%AF%B7%E6%B1%82/</link><pubDate>Tue, 19 Dec 2017 13:55:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/23-003-fiddler%E4%B8%89%E4%BB%A3%E7%90%86-http-%E8%AF%B7%E6%B1%82/</guid><description>&lt;p>上一小节对Fiddler的界面了简单的认识。接下来介绍如何通过Fiddler拦截HTTP请求。&lt;/p>
&lt;h4 id="代理-http-请求">代理 HTTP 请求&lt;/h4>
&lt;hr>
&lt;p>启动 Fiddler:&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/fiddler_05.png"
 data-srcset="http://img.testclass.net/fiddler_05.png, http://img.testclass.net/fiddler_05.png 1.5x, http://img.testclass.net/fiddler_05.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/fiddler_05.png"
 title="http://img.testclass.net/fiddler_05.png" />&lt;/p>
&lt;p>1、 &lt;strong>启动代理&lt;/strong> ：点击窗口左下角，显示 “&lt;strong>Capuring&lt;/strong>” 侧说明当前处于代理状态。&lt;/p>
&lt;p>2、通过浏览器访问相关网页或执行页面操作（如，登录、搜索）。&lt;/p>
&lt;p>3、通过Fiddler查看代理的HTTP请求进行分析。&lt;/p>
&lt;h4 id="清除请求">清除请求&lt;/h4>
&lt;hr>
&lt;p>当Fiddler拦截的请求比较多时，不方便查看，我们可以清除已经代理的请求，重新代理。如上图，Fiddler提供了几种清理选项。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Remove all ： 清空整个请求列表&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Images ： 清除图片请求&lt;/p>
&lt;/li>
&lt;li>
&lt;p>COMMECTs ： 清除HTTP的CONNECT请求&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Non-200s ： 清除HTTP状态不是 200 的请求&lt;/p>
&lt;/li>
&lt;li>
&lt;p>……&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1581922820051-88380611f5b8?w=300"
 data-srcset="https://images.unsplash.com/photo-1581922820051-88380611f5b8?w=300, https://images.unsplash.com/photo-1581922820051-88380611f5b8?w=300 1.5x, https://images.unsplash.com/photo-1581922820051-88380611f5b8?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1581922820051-88380611f5b8?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>最简单的web爬虫:获取所有课程信息</title><link>https://itest2025.pages.dev/tutorials/27-003-%E6%9C%80%E7%AE%80%E5%8D%95%E7%9A%84web%E7%88%AC%E8%99%AB%E8%8E%B7%E5%8F%96%E6%89%80%E6%9C%89%E8%AF%BE%E7%A8%8B%E4%BF%A1%E6%81%AF/</link><pubDate>Sat, 16 Dec 2017 02:52:34 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/27-003-%E6%9C%80%E7%AE%80%E5%8D%95%E7%9A%84web%E7%88%AC%E8%99%AB%E8%8E%B7%E5%8F%96%E6%89%80%E6%9C%89%E8%AF%BE%E7%A8%8B%E4%BF%A1%E6%81%AF/</guid><description>&lt;h3 id="获取所有课程信息">获取所有课程信息&lt;/h3>
&lt;p>我们现在来实现第一个超级简单的网络爬虫 用来抓取&lt;a href="http://www.itest.info/courses" target="_blank" rel="noopener noreffer ">重定向科技目前开设的所有测试课程&lt;/a>，并打印出来，步骤大概是这样子&lt;/p>
&lt;ul>
&lt;li>先访问&lt;a href="http://www.itest.info/courses" target="_blank" rel="noopener noreffer ">所有课程页面&lt;/a>，把html代码拿到，实际上就是拿到一个很长的文本，文本内容就是网页的html代码&lt;/li>
&lt;li>分析html代码，找到我们需要获取信息的html特征&lt;/li>
&lt;li>解析html代码，根据html特征，从里面抠出来课程的名称&lt;/li>
&lt;li>打印出所有课程的名称&lt;/li>
&lt;/ul>
&lt;h3 id="分析html代码">分析html代码&lt;/h3>
&lt;p>我们在编写爬虫的时候往往会花很多时间在分析html代码上，毕竟重要的信息都包含在html代码中，我们需要找到合适的特征，通过固定的套路去解析html，获取特定内容。&lt;/p>
&lt;p>课程名称部分的html代码如下所示&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">div&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;col-md-3 col-sm-6&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">div&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;servive-block-in servive-block-colored servive-block-grey&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">h4&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>性能测试从入门到精通班&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">h4&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;&lt;/span>&lt;span class="nt">div&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;&lt;/span>&lt;span class="nt">i&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;icon-rocket&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">i&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">div&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>2017年09月23日开课，为期3个月&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">div&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>可以看到，课程名称的html标签是&lt;code>h4&lt;/code>，通过搜索整个页面，我们发现页面上只有4个h4，也就是说，只要获取到页面上所有的h4，我们就能把课程名称给解析出来。&lt;/p>
&lt;p>分析html一般有下面一些套路&lt;/p>
&lt;ul>
&lt;li>缩小范围: 只解析特定区域的html，比如只遍历&lt;code>&amp;lt;nav&amp;gt;&amp;lt;/nav&amp;gt;&lt;/code>标签中的子元素&lt;/li>
&lt;li>组合属性: 有一些节点的属性是相同的，但我们经常只需要获取其中一些节点的内容，这时候可以通过组合该节点属性和其父节点属性的方式指定特定的节点&lt;/li>
&lt;li>先遍历后过滤：还是上面一种情况，我们也可以先遍历所有的目标节点，再从目标节点中过滤出我们感兴趣的内容&lt;/li>
&lt;/ul>
&lt;h3 id="解析html代码">解析html代码&lt;/h3>
&lt;p>大家可以先去了解一下html的基础知识，比较有用的是&lt;/p>
&lt;ul>
&lt;li>&lt;a href="http://www.w3school.com.cn/html/html_elements.asp" target="_blank" rel="noopener noreffer ">html元素&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://www.w3school.com.cn/html/html_attributes.asp" target="_blank" rel="noopener noreffer ">html属性&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Beautiful Soup库可以帮我们解析html代码，所谓的解析，无非是做下面的一些事情&lt;/p>
&lt;ul>
&lt;li>从html文档中找到一些元素&lt;/li>
&lt;li>获取某个元素或者一些元素的属性&lt;/li>
&lt;li>获取某个元素或者一些元素的文本&lt;/li>
&lt;/ul>
&lt;p>在这个例子里，我们就是要找到所有&lt;code>h4&lt;/code>元素，并获取所有&lt;code>h4&lt;/code>元素的文本。&lt;/p>
&lt;h3 id="代码">代码&lt;/h3>
&lt;p>新建名为&lt;code>get_courses.py&lt;/code>的文件，输入下面的内容&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">requests&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">bs4&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">BeautifulSoup&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">url&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;http://www.itest.info/courses&amp;#39;&lt;/span> &lt;span class="c1"># 定义被抓取页面的url&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 获取被抓取页面的html代码，并使用html.parser来实例化BeautifulSoup，属于固定套路&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">soup&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">BeautifulSoup&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">requests&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;html.parser&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 遍历页面上所有的h4&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">course&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">soup&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_all&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;h4&amp;#39;&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 打印出h4的text属性&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">course&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行">运行&lt;/h3>
&lt;p>在命令行中输入&lt;/p>
&lt;pre tabindex="0">&lt;code>python get_courses.py
&lt;/code>&lt;/pre>&lt;h3 id="预期结果">预期结果&lt;/h3>
&lt;p>如果一切正常，那么应该可以看到下面的结果&lt;/p>
&lt;pre tabindex="0">&lt;code>性能测试从入门到精通班
接口自动化测试开发--Python班
Selenium自动化测试--Java班
Selenium自动化测试--Python班
&lt;/code>&lt;/pre>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1508923567004-3a6b8004f3d7?w=300"
 data-srcset="https://images.unsplash.com/photo-1508923567004-3a6b8004f3d7?w=300, https://images.unsplash.com/photo-1508923567004-3a6b8004f3d7?w=300 1.5x, https://images.unsplash.com/photo-1508923567004-3a6b8004f3d7?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1508923567004-3a6b8004f3d7?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（三）如何做一些测试桩 (Stub)</title><link>https://itest2025.pages.dev/tutorials/45-003-%E4%B8%89%E5%A6%82%E4%BD%95%E5%81%9A%E4%B8%80%E4%BA%9B%E6%B5%8B%E8%AF%95%E6%A1%A9-stub/</link><pubDate>Sat, 25 Nov 2017 12:50:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/45-003-%E4%B8%89%E5%A6%82%E4%BD%95%E5%81%9A%E4%B8%80%E4%BA%9B%E6%B5%8B%E8%AF%95%E6%A1%A9-stub/</guid><description>&lt;h4 id="何做一些测试桩-stub">何做一些测试桩 (Stub)&lt;/h4>
&lt;hr>
&lt;p>例子：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.Test&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">java.util.LinkedList&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.mockito.Mockito.*&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">MockitoDemo&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">expected&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">RuntimeException&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">class&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">when_thenReturn&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//You can mock concrete classes, not only interfaces&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 你可以mock具体的类型,不仅只是接口&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">LinkedList&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">mock&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">LinkedList&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">class&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//stubbing&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 测试桩&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">when&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">0&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">thenReturn&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;first&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">when&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">thenThrow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">RuntimeException&lt;/span>&lt;span class="p">());&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//following prints &amp;#34;first&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 输出“first”&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">0&lt;/span>&lt;span class="p">));&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//following throws runtime exception&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 抛出异常&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">));&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//following prints &amp;#34;null&amp;#34; because get(999) was not stubbed&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 因为get(999) 没有打桩，因此输出null&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">999&lt;/span>&lt;span class="p">));&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//Although it is possible to verify a stubbed invocation, usually it&amp;#39;s just redundant&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//If your code cares what get(0) returns then something else breaks (often before even verify() gets executed).&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//If your code doesn&amp;#39;t care what get(0) returns then it should not be stubbed. Not convinced? See here.&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 验证get(0)被调用的次数&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">verify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">0&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>
&lt;p>默认情况下，所有的函数都有返回值。mock函数默认返回的是null，一个空的集合或者一个被对象类型包装的内置类型，例如0、false对应的对象类型为Integer、Boolean；&lt;/p></description></item><item><title>（三）Maven 设置仓库地址</title><link>https://itest2025.pages.dev/tutorials/41-003-%E4%B8%89maven-%E8%AE%BE%E7%BD%AE%E4%BB%93%E5%BA%93%E5%9C%B0%E5%9D%80/</link><pubDate>Sat, 25 Nov 2017 12:45:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/41-003-%E4%B8%89maven-%E8%AE%BE%E7%BD%AE%E4%BB%93%E5%BA%93%E5%9C%B0%E5%9D%80/</guid><description>&lt;h4 id="修改本地仓库地址">修改本地仓库地址&lt;/h4>
&lt;hr>
&lt;p>maven 用来管理我们的 Java 第三方库，我们需要设置仓库的本地地址来存放这此第三方库。&lt;/p>
&lt;p>打开 Maven 目录下的配置文件（&lt;strong>\apache-maven-3.5.0\conf\settings.xml&lt;/strong>) ， 找到 &lt;code>&amp;lt;localRepository&amp;gt; ..&amp;lt;/localRepository&amp;gt;&lt;/code> 标签。&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;lt;!-- localRepository
 | The path to the local repository maven will use to store artifacts.
 |
 | Default: ${user.home}/.m2/repository
--&amp;gt;
&amp;lt;localRepository&amp;gt;D:/Java/maven/repo&amp;lt;/localRepository&amp;gt;
&lt;/code>&lt;/pre>&lt;p>Maven 默认将本地仓库设置在 &lt;strong>${user.home}/.m2/repository&lt;/strong> 目录下，这里修改为 &lt;strong>D:/Java/maven/repo&lt;/strong> 路径。&lt;/p>
&lt;h4 id="设置中央仓库地址">设置中央仓库地址&lt;/h4>
&lt;hr>
&lt;p>中央仓库即当我们要用到 Java 的第三方库时应该去哪里下载。&lt;/p>
&lt;p>同样打开 Maven 目录下的配置文件（&lt;strong>\apache-maven-3.5.0\conf\settings.xml&lt;/strong>) ， 找到 &lt;code>&amp;lt;mirrors&amp;gt;..&amp;lt;/mirrors&amp;gt;&lt;/code> 标签。&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;lt;mirrors&amp;gt;
 &amp;lt;!-- mirror
 | Specifies a repository mirror site to use instead of a given repository. The repository that
 | this mirror serves has an ID that matches the mirrorOf element of this mirror. IDs are used
 | for inheritance and direct lookup purposes, and must be unique across the set of mirrors.
 |
 &amp;lt;mirror&amp;gt;
 &amp;lt;id&amp;gt;mirrorId&amp;lt;/id&amp;gt;
 &amp;lt;mirrorOf&amp;gt;repositoryId&amp;lt;/mirrorOf&amp;gt;
 &amp;lt;name&amp;gt;Human Readable Name for this Mirror.&amp;lt;/name&amp;gt;
 &amp;lt;url&amp;gt;http://my.repository.com/repo/path&amp;lt;/url&amp;gt;
 &amp;lt;/mirror&amp;gt;
 --&amp;gt;
 &amp;lt;mirror&amp;gt;
 &amp;lt;id&amp;gt;alimaven&amp;lt;/id&amp;gt;
 &amp;lt;name&amp;gt;aliyun maven&amp;lt;/name&amp;gt;
 &amp;lt;url&amp;gt;http://maven.aliyun.com/nexus/content/groups/public/&amp;lt;/url&amp;gt;
 &amp;lt;!--&amp;lt;mirrorOf&amp;gt;central&amp;lt;/mirrorOf&amp;gt; --&amp;gt;
 &amp;lt;mirrorOf&amp;gt;*&amp;lt;/mirrorOf&amp;gt;
 &amp;lt;/mirror&amp;gt;
&amp;lt;/mirrors&amp;gt;
&lt;/code>&lt;/pre>&lt;p>这里将 Maven 的中央仓库地址修改为 aliyun ，国内访问速度会更快。&lt;/p></description></item><item><title>（三）TestNG 之 FixTrue</title><link>https://itest2025.pages.dev/tutorials/36-003-%E4%B8%89testng-%E4%B9%8B-fixtrue/</link><pubDate>Sat, 25 Nov 2017 12:45:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/36-003-%E4%B8%89testng-%E4%B9%8B-fixtrue/</guid><description>&lt;h4 id="什么是fixture">什么是Fixture&lt;/h4>
&lt;hr>
&lt;p>Test Fixture 是指一个测试运行所需的固定环境，准确的定义：&lt;/p>
&lt;blockquote>
&lt;p>The test fixture is everything we need to have in place to exercise the SUT&lt;/p>&lt;/blockquote>
&lt;p>在进行测试时，我们通常需要把环境设置成已知状态（如创建对象、获取资源等）来创建测试，每次测试开始时都处于一个固定的初始状态；测试结果后需要将测试状态还原，所以，测试执行所需要的固定环境称为 Test Fixture。&lt;/p>
&lt;h4 id="testng-提供的-fixture-方法">TestNG 提供的 Fixture 方法&lt;/h4>
&lt;hr>
&lt;p>表：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">注解&lt;/th>
 &lt;th style="text-align: left">说明&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">@BeforeSuite&lt;/td>
 &lt;td style="text-align: left">注解的方法在测试套件（中的所有用例）开始前运行一次&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">@AfterSuite&lt;/td>
 &lt;td style="text-align: left">注解的方法在测试套件（中的所有用例）结束后运行一次。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">@BeforeClass&lt;/td>
 &lt;td style="text-align: left">注解的方法在当前测试类（中所有用例）开始前运行一次。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">@AfterClass&lt;/td>
 &lt;td style="text-align: left">注解的方法在当前测试类（中所有用例）结束后运行一次。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">@BeforeTest&lt;/td>
 &lt;td style="text-align: left">对于套件测试，在运行属于&lt;test>标签内的类的所有测试方法之前运行。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">@AfterTest&lt;/td>
 &lt;td style="text-align: left">对于套件测试，在运行属于&lt;test>标签内的类的所有测试方法之后运行。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">@BeforeGroups&lt;/td>
 &lt;td style="text-align: left">在调用属于该组的所有测试方法之前运行。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">@AfterGroups&lt;/td>
 &lt;td style="text-align: left">在调用属于该组的所有测试方法之后运行。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">@BeforeMethod&lt;/td>
 &lt;td style="text-align: left">注解的方法将在每个测试方法之前运行。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">@AfterMethod&lt;/td>
 &lt;td style="text-align: left">注释的方法将在每个测试方法之后执行。&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h4 id="实例">实例&lt;/h4>
&lt;hr>
&lt;p>接下来通过例子演示上面部分注解的用法。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.testng.annotations.*&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">FixtureTest&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//在当前测试类开始时运行。&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@BeforeClass&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">beforeClass&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;-------------------beforeClass&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//在当前测试类结束时运行。&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@AfterClass&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">afterClass&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;-------------------afterClass&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//每个测试方法运行之前运行&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@BeforeMethod&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">before&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;=====beforeMethod&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//每个测试方法运行之后运行&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@AfterMethod&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">after&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;=====afterMethod&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">testCase1&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;test case 1&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">testCase2&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;test case 2&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>运行上面的测试，执行结果如下。&lt;/p></description></item><item><title>requests如何发送post请求?</title><link>https://itest2025.pages.dev/tutorials/42-003-requests%E5%A6%82%E4%BD%95%E5%8F%91%E9%80%81post%E8%AF%B7%E6%B1%82/</link><pubDate>Wed, 22 Nov 2017 03:23:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/42-003-requests%E5%A6%82%E4%BD%95%E5%8F%91%E9%80%81post%E8%AF%B7%E6%B1%82/</guid><description>&lt;p>&lt;a href="http://docs.python-requests.org/en/master/user/quickstart/#make-a-request" target="_blank" rel="noopener noreffer ">官方文档&lt;/a>&lt;/p>
&lt;p>发送post请求跟发送get请求类似，使用&lt;code>requests.post&lt;/code>方法就可以了，如果需要传post data的话，直接将data以dict的格式传递就好。&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; import requests
&amp;gt;&amp;gt;&amp;gt; r = requests.post(&amp;#39;http://httpbin.org/post&amp;#39;, data = {&amp;#39;key&amp;#39;:&amp;#39;value&amp;#39;})
&lt;/code>&lt;/pre>&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/21/mac-glasses.JPG?w=300"
 data-srcset="https://images.unsplash.com/21/mac-glasses.JPG?w=300, https://images.unsplash.com/21/mac-glasses.JPG?w=300 1.5x, https://images.unsplash.com/21/mac-glasses.JPG?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/21/mac-glasses.JPG?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（三）JUnit 编写单元测试</title><link>https://itest2025.pages.dev/tutorials/31-003-%E4%B8%89junit-%E7%BC%96%E5%86%99%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/</link><pubDate>Mon, 13 Nov 2017 12:50:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/31-003-%E4%B8%89junit-%E7%BC%96%E5%86%99%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/</guid><description>&lt;h4 id="编写单元测试">编写单元测试&lt;/h4>
&lt;hr>
&lt;p>创建 JunitDemo 类，编写第一个单元测试用例。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.Assert.assertEquals&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.Test&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">JunitDemo&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">myFirstTest&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">4&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>@Test&lt;/strong> 用来注释一个普通的方法为一条测试用例。&lt;/p>
&lt;p>&lt;strong>assertEquals()&lt;/strong> 方法用于断言两个值是否相关。&lt;/p>
&lt;h4 id="测试功能模块">测试功能模块&lt;/h4>
&lt;hr>
&lt;p>创建一个被测试类：Count ，代码如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">Count&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="cm">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * 计算并返回两个参数的和
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> */&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">return&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Count 类的实现非常简单，看注释就可以了。&lt;/p>
&lt;p>接下来，创建 CountTest 类，用于测试 Count 类。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.Assert.assertEquals&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.Test&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">CountTest&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">testAdd&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Count&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">count&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Count&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">count&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">4&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>new&lt;/strong> 出 Count 类，调用 add() 方法并传参，通过 assertEquals() 断言 返回结果。&lt;/p></description></item><item><title>3. 实例: 测试弱密码</title><link>https://itest2025.pages.dev/tutorials/35-003-3-%E5%AE%9E%E4%BE%8B-%E6%B5%8B%E8%AF%95%E5%BC%B1%E5%AF%86%E7%A0%81/</link><pubDate>Wed, 08 Nov 2017 06:23:31 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/35-003-3-%E5%AE%9E%E4%BE%8B-%E6%B5%8B%E8%AF%95%E5%BC%B1%E5%AF%86%E7%A0%81/</guid><description>&lt;h3 id="背景">背景&lt;/h3>
&lt;p>考虑这样一个测试弱密码的实例，这个我们在&lt;a href="https://itest2025.pages.dev/pytest/fixture/" rel="">pytest相关教程&lt;/a>中也有过描述。&lt;/p>
&lt;p>我们需要判断用户的密码中包含简单密码，规则是这样的，密码必须至少6位，满足6位的话判断用户的密码不是password123或者password之类的弱密码。&lt;/p>
&lt;p>对于如下的测试数据，我们要如何使用unittest来进行相关测试呢？&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;jack&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;password&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;Iloverose&amp;#34;&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;rose&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;password&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;Ilovejack&amp;#34;&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;tom&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;password&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;password123&amp;#34;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="test-fixture">Test fixture&lt;/h3>
&lt;p>前文我们也说过，text fixture的主要功能是初始化测试数据或环境以及清理测试数据或环境。&lt;/p>
&lt;p>考虑上面的例子，对我们而已，在用例执行之前初始化上面的测试数据是有必要的，我们可以把上面的数据用python的数据结构来表示，比较合适的数据结构是python的字典。这样做有如下的好处&lt;/p>
&lt;ul>
&lt;li>统一初始化一些需要在多个用例之间共享的数据&lt;/li>
&lt;li>可以在初始化的时候做一些数据的处理工作，比如过滤一些无效数据等&lt;/li>
&lt;/ul>
&lt;p>Test fixture最简单的实现方式是通过自定义下面的2个方法:&lt;/p>
&lt;ul>
&lt;li>&lt;code>TestCase.setUp&lt;/code>方法在每个测试方法运行之前都会运行一次，适合为每个用例都初始化一遍数据&lt;/li>
&lt;li>&lt;code>TestCase.tearDown&lt;/code>方法在每个测试方法运行之后都会运行一次，适合为每个用例都清理一遍数据&lt;/li>
&lt;/ul>
&lt;h3 id="代码">代码&lt;/h3>
&lt;p>新建名为&lt;code>test_password_1.py&lt;/code>的文本文件，输入如下内容&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">unittest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">PasswordTeseCase&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TestCase&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">setUp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;set up&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">test_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">dict&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;jack&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">password&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;Iloverose&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">dict&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;rose&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">password&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;Ilovejack&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">dict&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;tom&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">password&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;password123&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">test_week_password&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">data&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">test_data&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">passwd&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;password&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertTrue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">passwd&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">6&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">msg&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;user &lt;/span>&lt;span class="si">%s&lt;/span>&lt;span class="s2"> has a weak password&amp;#34;&lt;/span> &lt;span class="o">%&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;name&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertTrue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">passwd&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="s1">&amp;#39;password&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">msg&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertTrue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">passwd&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="s1">&amp;#39;password123&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">msg&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">test_dummy&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">pass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">main&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行">运行&lt;/h3>
&lt;p>在命令行里输入 &lt;code>python test_password_1.py&lt;/code>来运行用例，结果如下&lt;/p>
&lt;pre tabindex="0">&lt;code>$ python test_password_1.py
set up
.set up
F
======================================================================
FAIL: test_week_password (__main__.PasswordTeseCase)
----------------------------------------------------------------------
Traceback (most recent call last):
 File &amp;#34;test_password_1.py&amp;#34;, line 21, in test_week_password
 self.assertTrue(passwd != &amp;#39;password123&amp;#39;, msg)
AssertionError: False is not true : user tom has a weak password

----------------------------------
Ran 2 tests in 0.001s

FAILED (failures=1)
&lt;/code>&lt;/pre>&lt;h3 id="解释一下">解释一下&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>setUp方法运行了2次，所以打印出了2次&amp;rsquo;set up&amp;rsquo;，这是因为上面的用例中有2个测试方法(2个方法名以test开头的方法)，setUp会在每个测试方法执行之前执行1次&lt;/p></description></item><item><title>3. 数字和计算</title><link>https://itest2025.pages.dev/tutorials/28-003-3-%E6%95%B0%E5%AD%97%E5%92%8C%E8%AE%A1%E7%AE%97/</link><pubDate>Sun, 05 Nov 2017 08:17:22 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/28-003-3-%E6%95%B0%E5%AD%97%E5%92%8C%E8%AE%A1%E7%AE%97/</guid><description>&lt;h3 id="背景">背景&lt;/h3>
&lt;p>几乎所有的编程语言都支持数学计算。不要认为不是数学高手就不能学习编程，很多时候我们在代码里只会用到非常简单的数学运算，常见的有&lt;/p>
&lt;ul>
&lt;li>+: 加法&lt;/li>
&lt;li>-: 减法&lt;/li>
&lt;li>/: 除法&lt;/li>
&lt;li>*: 乘法&lt;/li>
&lt;li>%: 整除取余&lt;/li>
&lt;li>&amp;lt;: 小于&lt;/li>
&lt;li>
&lt;blockquote>
&lt;p>: 大于&lt;/p>&lt;/blockquote>
&lt;/li>
&lt;li>
&lt;blockquote>
&lt;p>=: 大于等于&lt;/p>&lt;/blockquote>
&lt;/li>
&lt;li>&amp;lt;=: 小于等于&lt;/li>
&lt;/ul>
&lt;p>考虑这样的场景，我们的测试用例一个分布在3个模块(A/B/C)，A模块有30个用例，成功运行27个, B模块有40个用例，全部成功运行，C模块有30个用例全部运行成功，假设每个用例执行一次平均需要5分钟，打印出一些测试报告的明细。&lt;/p>
&lt;h3 id="代码实现">代码实现&lt;/h3>
&lt;p>新建名为&lt;code>report_with_math.py&lt;/code>，内容如下&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 打印出本次测试的测试结果&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># A: 27/30 B: 40/40 C: 30/30&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;本次测试覆盖了3个模块&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;测试用例总数为: &amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">30&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">40&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">30&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;执行的测试用例总数为: &amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">30&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">40&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">30&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;用例最多的模块是B模块，B模块比A模块多出的用例数为&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">40&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">30&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;A模块执行成功27个用例，执行失败的用例数为&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">30&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">27&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;B模块的用例全部执行通过， 通过率为百分之&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="mi">40&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="mi">40&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">100&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;C模块的用例全部执行通过， 通过率为百分之&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="mi">30&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="mi">30&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">100&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;B模块的用例比C模块多吗?&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">40&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">30&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;A模块的用例比C模块多吗?&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">30&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">30&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;B模块的用例比C模块少吗?&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">40&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">30&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 结束打印&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;回归不通过&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行">运行&lt;/h3>
&lt;p>在命令行中使用下面的命令去执行代码&lt;/p>
&lt;pre tabindex="0">&lt;code>python report_with_math.py
&lt;/code>&lt;/pre>&lt;h3 id="你应该可以看到">你应该可以看到&lt;/h3>
&lt;p>如果没有出错的话，你应该可以看到命令行窗口显示如下的内容&lt;/p>
&lt;pre tabindex="0">&lt;code>本次测试覆盖了3个模块
测试用例总数为: 100
执行的测试用例总数为: 100
用例最多的模块是B模块，B模块比A模块多出的用例数为 10
A模块执行成功27个用例，执行失败的用例数为 3
B模块的用例全部执行通过， 通过率为百分之 100.0
C模块的用例全部执行通过， 通过率为百分之 100.0
B模块的用例比C模块多吗? True
A模块的用例比C模块多吗? False
B模块的用例比C模块少吗? False
回归不通过
&lt;/code>&lt;/pre>&lt;h3 id="动手时间">动手时间&lt;/h3>
&lt;ul>
&lt;li>在每一行上面用#加上注释，解释一下这行代码的作用&lt;/li>
&lt;li>找一些自己需要计算的东西，比如早餐吃3个包子才能吃饱，每个包子3块钱，那么早餐要花多少钱才能吃饱。建立.py文件去计算并执行&lt;/li>
&lt;li>算一下模块A的通过率，找资料了解一下python的浮点数(float)类型，模块A的通过率的预期结果应该是0.9&lt;/li>
&lt;/ul>
&lt;h3 id="常见问题">常见问题&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>%号是怎么工作的&lt;/strong>: 取余数，比如 15 % 4 的结果是3, 16 % 4的结果是0；&lt;/li>
&lt;li>&lt;strong>运算符号的优先级是怎么样的&lt;/strong>: 跟我们小时候学习的四则混合运算一样，乘除优先于加减，有括号的话括号优先，把握不准的情况下，把需要优先计算的部分用括号括起来;&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p></description></item><item><title>3.Assert</title><link>https://itest2025.pages.dev/tutorials/25-003-3assert/</link><pubDate>Wed, 01 Nov 2017 07:22:42 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/25-003-3assert/</guid><description>&lt;p>Assert就是断言，每个测试用例都需要断言。&lt;/p>
&lt;p>与unittest不同，pytest使用的是python自带的assert关键字来进行断言，大大降低了学习成本。&lt;/p>
&lt;p>assert关键字后面可以接一个表达式，只要表达式的最终结果为True，那么断言通过，用例执行成功，否则用例执行失败。&lt;/p>
&lt;h3 id="详尽的用例失败描述">详尽的用例失败描述&lt;/h3>
&lt;p>pytest的用例失败描述非常详尽，一目了人。考虑下面的例子&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># content of test_assert1.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">f&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">test_function&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">4&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>执行上面的用例&lt;/p>
&lt;pre tabindex="0">&lt;code>$ pytest test_assert1.py
======= test session starts ========
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 item

test_assert1.py F

======= FAILURES ========
_______ test_function ________

 def test_function():
&amp;gt; assert f() == 4
E assert 3 == 4
E + where 3 = f()

test_assert1.py:5: AssertionError
======= 1 failed in 0.12 seconds ========
&lt;/code>&lt;/pre>&lt;p>可以很明显的看出，pytest给出的错误提示是：f()的值是3，也就是实际结果是3，而预期结果是4，3不等于4，因此断言未通过，用例失败。&lt;/p></description></item><item><title>3. Find</title><link>https://itest2025.pages.dev/tutorials/43-003-3-find/</link><pubDate>Fri, 27 Oct 2017 06:55:26 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/43-003-3-find/</guid><description>&lt;p>&lt;code>webium.find.Find&lt;/code> 方法可以在页面或者其他容器中定位元素，返回&lt;code>WebElement&lt;/code>实例。&lt;/p>
&lt;p>Find方法的主要用到2个参数分别是&lt;/p>
&lt;ul>
&lt;li>&lt;code>by&lt;/code>: 定位策略，比如By.ID&lt;/li>
&lt;li>&lt;code>value&lt;/code>: 定位元素时用到的具体属性值&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium.webdriver.common.by&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">By&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">webium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">BasePage&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Find&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">SomePage&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BasePage&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">buy_btn&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Find&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">by&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">CSS_SELECTOR&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;a.buy-btn&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">super&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">SomePage&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;http://itest.info&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">page&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">SomePage&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">open&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">buy_btn&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">click&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="ui_type">ui_type&lt;/h3>
&lt;p>在定位一些自定义的对象时我们可以指定&lt;code>ui_type&lt;/code>参数来定制化&lt;code>Find&lt;/code>的行为。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium.webdriver.common.by&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">By&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium.webdriver.remote.webelement&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">WebElement&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">webium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">BasePage&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Find&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Link&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">WebElement&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">is_secure&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_attribute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;href&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">startswith&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;https://&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">TypedPage&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BasePage&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">join_link&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Find&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Link&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">By&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">CSS_SELECTOR&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;a.hover-effect&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">super&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">TypedPage&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;http://itest.info&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">page&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">TypedPage&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">open&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Is link secure: &amp;#39;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">join_link&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">is_secure&lt;/span>&lt;span class="p">()))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上面的例子里，我们定义了&lt;code>Link&lt;/code>类，继承自&lt;code>WebElement&lt;/code>，用以代表一般性的链接。&lt;code>is_secure()&lt;/code>方法用来判断链接是否是https协议的。&lt;/p>
&lt;p>&lt;code>join_link = Find(Link, By.CSS_SELECTOR, 'a.hover-effect')&lt;/code>表示定位元素，并返回类型是&lt;code>Link&lt;/code>的实例。&lt;/p>
&lt;h3 id="context-上下文">context 上下文&lt;/h3>
&lt;p>有时候你可能在用例运行时才可以确定页面的结构，现代网页是动态且多变的。如果你不能在类属性的定义中使用Find，那么你应该直接把该页面对象直接传到定位代码里。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium.webdriver.common.by&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">By&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">webium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">BasePage&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Find&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">DynamicPage&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BasePage&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">super&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">DynamicPage&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;http://itest.info&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">get_link_by_href&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">href&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">Find&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">by&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">CSS_SELECTOR&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;a[href*=&amp;#34;&lt;/span>&lt;span class="si">{0}&lt;/span>&lt;span class="s1">&amp;#34;]&amp;#39;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">href&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">context&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">page&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">DynamicPage&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">open&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_link_by_href&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;registration&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">click&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上面的例子里, &lt;code>get_link_by_href(self, href)&lt;/code>方法通过动态传入的href来定为不同的对象，这时候就需要把self传入Find的对应上下文里，这是套路，因为Find方法就是这么设计以便正常工作的。&lt;/p></description></item><item><title>收藏清单: python持续集成测试报告及其他最全资源汇总</title><link>https://itest2025.pages.dev/tutorials/34-003-%E6%94%B6%E8%97%8F%E6%B8%85%E5%8D%95-python%E6%8C%81%E7%BB%AD%E9%9B%86%E6%88%90%E6%B5%8B%E8%AF%95%E6%8A%A5%E5%91%8A%E5%8F%8A%E5%85%B6%E4%BB%96%E6%9C%80%E5%85%A8%E8%B5%84%E6%BA%90%E6%B1%87%E6%80%BB/</link><pubDate>Wed, 25 Oct 2017 08:19:06 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/34-003-%E6%94%B6%E8%97%8F%E6%B8%85%E5%8D%95-python%E6%8C%81%E7%BB%AD%E9%9B%86%E6%88%90%E6%B5%8B%E8%AF%95%E6%8A%A5%E5%91%8A%E5%8F%8A%E5%85%B6%E4%BB%96%E6%9C%80%E5%85%A8%E8%B5%84%E6%BA%90%E6%B1%87%E6%80%BB/</guid><description>&lt;h2 id="continuous-integration-持续集成">Continuous Integration 持续集成&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://pypi.python.org/pypi/buildbot/" target="_blank" rel="noopener noreffer ">buildbot&lt;/a> - 自动化编译发布系统。大部分的软件项目可用&lt;/li>
&lt;li>&lt;a href="http://jenkins-ci.org/" target="_blank" rel="noopener noreffer ">jenkins&lt;/a> - 可扩展的开源持续集成server&lt;/li>
&lt;li>&lt;a href="https://travis-ci.org" target="_blank" rel="noopener noreffer ">travis-ci&lt;/a> - 免费的持续集成平台&lt;/li>
&lt;/ul>
&lt;h2 id="reporting-报告">Reporting 报告&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://github.com/allure-framework/allure-python" target="_blank" rel="noopener noreffer ">allure pytest&lt;/a> - PyTest的allure适配器&lt;/li>
&lt;li>&lt;a href="http://tungwaiyip.info/software/HTMLTestRunner.html" target="_blank" rel="noopener noreffer ">HTMLTestRunner&lt;/a> - Python 标准库unittest的扩展. 生成简单好用的html报告&lt;/li>
&lt;li>&lt;a href="https://github.com/xmlrunner/unittest-xml-reporting" target="_blank" rel="noopener noreffer ">unittest-xml-reporting&lt;/a> - 一个unittest test runner可以将测试结果保存到 XML文件。可高度定制&lt;/li>
&lt;/ul>
&lt;h2 id="documentation-generation-文档生成">Documentation generation 文档生成&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="http://sphinx-doc.org/" target="_blank" rel="noopener noreffer ">Sphinx&lt;/a> - Python文档生成器&lt;/li>
&lt;li>&lt;a href="http://www.mkdocs.org/" target="_blank" rel="noopener noreffer ">MkDocs&lt;/a> - Markdown语法友好的文档生成器&lt;/li>
&lt;li>&lt;a href="http://fitzgen.github.io/pycco/" target="_blank" rel="noopener noreffer ">Pycco&lt;/a> - The original quick-and-dirty, hundred-line-long, literate-programming-style documentation generator.&lt;/li>
&lt;/ul>
&lt;h2 id="editors-ide-consoles-编辑器-ide以及命令行工具">Editors, IDE, consoles 编辑器, IDE以及命令行工具&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://www.jetbrains.com/pycharm/" target="_blank" rel="noopener noreffer ">pycharm&lt;/a> - 智能的专业的python IDE&lt;/li>
&lt;li>&lt;a href="http://pydev.org/" target="_blank" rel="noopener noreffer ">pydev&lt;/a> - eclipse 上全功能的python插件&lt;/li>
&lt;li>&lt;a href="http://sublimetext.com/" target="_blank" rel="noopener noreffer ">sublime&lt;/a> - 简洁好用的文本编辑器&lt;/li>
&lt;li>&lt;a href="http://ipython.org/" target="_blank" rel="noopener noreffer ">ipython&lt;/a> - 支持多语言的交互式shell, 最初是为python开发&lt;/li>
&lt;/ul>
&lt;h2 id="useful-libs-有用的库">Useful libs 有用的库&lt;/h2>
&lt;p>一些可以让你构建更好的自动化测试的库&lt;/p></description></item><item><title>（三）Jenkins 创建构建任务</title><link>https://itest2025.pages.dev/tutorials/18-003-%E4%B8%89jenkins-%E5%88%9B%E5%BB%BA%E6%9E%84%E5%BB%BA%E4%BB%BB%E5%8A%A1/</link><pubDate>Mon, 16 Oct 2017 13:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/18-003-%E4%B8%89jenkins-%E5%88%9B%E5%BB%BA%E6%9E%84%E5%BB%BA%E4%BB%BB%E5%8A%A1/</guid><description>&lt;h4 id="构建项目类型">构建项目类型&lt;/h4>
&lt;hr>
&lt;p>点击 Jenkins 首页 &lt;strong>“创建一个新任务”&lt;/strong> 的链接，弹出如图3.1所示页面。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/jenkins_project_type.png"
 data-srcset="http://img.testclass.net/jenkins_project_type.png, http://img.testclass.net/jenkins_project_type.png 1.5x, http://img.testclass.net/jenkins_project_type.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/jenkins_project_type.png"
 title="http://img.testclass.net/jenkins_project_type.png" />&lt;/p>
&lt;p>图3.1 选择Jenkins任务类型&lt;/p>
&lt;p>&lt;strong>Jenkins 提供了六种类型的任务。&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>构建一个自由风格的软件项目&lt;/li>
&lt;/ul>
&lt;p>这是Jenkins的主要功能。Jenkins 会结合任何 SCM 和任何构建系统来构建你的项目, 甚至可以构建软件以外的系统。&lt;/p>
&lt;ul>
&lt;li>Pipeline&lt;/li>
&lt;/ul>
&lt;p>Orchestrates long-running activities that can span multiple build slaves. Suitable for building pipelines (formerly known as workflows) and/or organizing complex activities that do not easily fit in free-style job type. &amp;ndash; 很难用一两句话说清 Pipeline, &lt;a href="https://github.com/jenkinsci/pipeline-plugin/blob/master/TUTORIAL.md" target="_blank" rel="noopener noreffer ">参考&lt;/a> , 后面另起一文来介绍。&lt;/p>
&lt;ul>
&lt;li>构建一个多配置项目&lt;/li>
&lt;/ul>
&lt;p>适用于多配置项目,例如多环境测试、平台指定构建,等等。&lt;/p>
&lt;ul>
&lt;li>GitHub Organization&lt;/li>
&lt;/ul>
&lt;p>Scans a GitHub organization (or user account) for all repositories matching some defined markers. &amp;ndash;这个主要针对由 Github 托管的项目。&lt;/p></description></item><item><title>（三）Locust 创建性能测试</title><link>https://itest2025.pages.dev/tutorials/38-003-%E4%B8%89locust-%E5%88%9B%E5%BB%BA%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/</link><pubDate>Mon, 16 Oct 2017 12:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/38-003-%E4%B8%89locust-%E5%88%9B%E5%BB%BA%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/</guid><description>&lt;p>&lt;font color='red'> Locust 可没有傻瓜式的脚本录制功能，要想用它来做性能测试，必须撸起袖子来写代码。不过。它并不难！&lt;/font>&lt;/p>
&lt;h4 id="编写简单的性能测试脚本">编写简单的性能测试脚本&lt;/h4>
&lt;p>创建 load_test.py 文件，通过 Python 编写性能测试脚本。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">locust&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">HttpLocust&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">TaskSet&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">task&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 定义用户行为&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">UserBehavior&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">TaskSet&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@task&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">baidu_index&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">client&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;/&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">WebsiteUser&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">HttpLocust&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">task_set&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">UserBehavior&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">min_wait&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">3000&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_wait&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">6000&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>UserBehavior类继承TaskSet类，用于描述用户行为。&lt;/p>
&lt;p>baidu_index() 方法表示一个用户为行，访问百度首页。使用@task装饰该方法为一个事务。client.get()用于指请求的路径“/”，因为是百度首页，所以指定为根路径。&lt;/p>
&lt;p>WebsiteUser类用于设置性能测试。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>task_set ：指向一个定义的用户行为类。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>min_wait ：执行事务之间用户等待时间的下界（单位：毫秒）。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>max_wait ：执行事务之间用户等待时间的上界（单位：毫秒）。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="执行性能测试">执行性能测试&lt;/h3>
&lt;hr>
&lt;p>&lt;strong>启动性能测试&lt;/strong>&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt; locust -f .\load_test.py --host=https://www.baidu.com

[2017-10-16 16:44:40,839] DESKTOP-SMGQBBM/INFO/locust.main: Starting web monitor at *:8089
[2017-10-16 16:44:40,842] DESKTOP-SMGQBBM/INFO/locust.main: Starting Locust 0.8
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>-f 指定性能测试脚本文件。&lt;/li>
&lt;li>&amp;ndash;host 指定被测试应用的URL的地址，注意访问百度使用的HTTPS协议。&lt;/li>
&lt;/ul>
&lt;p>通过浏览器访问：http://localhost:8089（Locust启动网络监控器，默认为端口号为: 8089）&lt;/p>
&lt;p>&lt;strong>设置测试&lt;/strong>&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/locust_run_setings.png"
 data-srcset="http://img.testclass.net/locust_run_setings.png, http://img.testclass.net/locust_run_setings.png 1.5x, http://img.testclass.net/locust_run_setings.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/locust_run_setings.png"
 title="http://img.testclass.net/locust_run_setings.png" />&lt;/p></description></item><item><title>02. 教程介绍（新用户必看）</title><link>https://itest2025.pages.dev/tutorials/37-003-02-%E6%95%99%E7%A8%8B%E4%BB%8B%E7%BB%8D%E6%96%B0%E7%94%A8%E6%88%B7%E5%BF%85%E7%9C%8B/</link><pubDate>Mon, 16 Oct 2017 11:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/37-003-02-%E6%95%99%E7%A8%8B%E4%BB%8B%E7%BB%8D%E6%96%B0%E7%94%A8%E6%88%B7%E5%BF%85%E7%9C%8B/</guid><description>&lt;h1 id="关于">关于&lt;/h1>
&lt;h2 id="学习前提">学习前提&lt;/h2>
&lt;p>由于 IntelliJ IDEA 官网在亚洲没有设服务器，且官网用到一些类似 Twitter、Facebook 等站的脚本会使得你在国内出现访问巨慢或是不允许访问的特殊情况，所以建议你在访问官网、访问插件库、小版本本地迭代更新等操作的时候出现奇怪问题的时候，请自备VPN等网络加速工具。&lt;/p>
&lt;p>很多用户都是先学习了 Eclipse、MyEclipse 再转到 IntelliJ IDEA 的，这里需要先说明的是，在学习 IntelliJ IDEA 过程中，你暂且要放下 Eclipse 下的开发思维方式，不能按 Eclipse 的软件思想或是结构去要求 IntelliJ IDEA，这样对你学习 IntelliJ IDEA 非常不利。&lt;/p>
&lt;h2 id="适用人群">适用人群&lt;/h2>
&lt;p>用 IntelliJ IDEA 进行开发语言的学习者。&lt;/p>
&lt;p>用 IntelliJ IDEA 进行开发语言的开发工作者。&lt;/p>
&lt;p>其中对于语言开发学习者我是非常建议你使用 IntelliJ IDEA，因为一些代码格式、命名规范在 IntelliJ IDEA 下都是有良好的提示，对于我们所处的输入法下的中文全角符号也可以得到快速发现。特别是学习 Python 的学习者，当你在用 Pycharm 进行学习的时候，Pycharm 会时刻告诉你什么时候要注意空格、换行，提醒你有 PEP8 编码规范，你也可以通过快捷键快速格式化出适合 Python 要求的代码，这对于学习者来讲，真的很重要，它可以让你更专注于自己的代码。&lt;/p>
&lt;h2 id="教程演示的-intellij-idea-版本">教程演示的 IntelliJ IDEA 版本&lt;/h2>
&lt;p>IntelliJ IDEA 13 版本和 14 版本，在设置上差异很大，14 版本 IntelliJ IDEA 对整个 IDE 的设置进行了重新编排、归类，但是细节设置上所沿用的介绍是没有多大改变的。&lt;/p>
&lt;p>目前（2015 年 06 月）IntelliJ IDEA 官网最新版本信息为：&lt;strong>Version:14.1.4 Build:141.1532.4 Released:June 19th, 2015&lt;/strong>。&lt;/p></description></item><item><title>（三）Web Services技术之REST</title><link>https://itest2025.pages.dev/tutorials/26-003-%E4%B8%89web-services%E6%8A%80%E6%9C%AF%E4%B9%8Brest/</link><pubDate>Thu, 21 Sep 2017 00:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/26-003-%E4%B8%89web-services%E6%8A%80%E6%9C%AF%E4%B9%8Brest/</guid><description>&lt;br>
REST 定义了一组体系架构原则，你可以根据这些原则设计以系统资源为中心的 Web Services ，包括使用不同语言编写的客户端如何通过HTTP处理和传输资源状态。如果考虑使用它的 Web Services 的数量，REST 近年来已经成为最主要的 Web Services 设计模型。事实上，REST 对 Web 的影响非常大，由于它的使用非常方便，已经普遍地取代了基于 SOAP 和 WSDL 的接口设计。
&lt;h4 id="rest">REST&lt;/h4>
&lt;hr>
&lt;p>Representational State Transfer，简称 REST ，中文翻译为 “表现层状态转化” 。&lt;/p>
&lt;p>REST 具有夸语言、夸平台的特点。所以，它是一种遵循 REST 风格的 Web Services。&lt;/p>
&lt;p> 如果一个架构符合 REST 原则，就称它为 REST ful架构。要理解 REST ful架构，最好的方法就是去理解 Representational State Transfer 这个词组到底是什么意思，它的每一个词代表了什么涵义。如果你把这个名称搞懂了，也就不难体会 REST 是一种什么样的设计。&lt;/p>
&lt;p> &lt;strong>一、资源（Resources）&lt;/strong>&lt;/p>
&lt;p>REST 的名称 “表现层状态转化” 中，省略了主语。 “表现层” 其实指的是 “资源” （Resources）的 “表现层” 。&lt;/p>
&lt;p>所谓 “资源” ，就是网络上的一个实体，或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务，总之就是一个具体的实在。你可以用一个URI（统一资源定位符）指向它，每种资源对应一个特定的URI。要获取这个资源，访问它的URI就可以，因此URI就成了每一个资源的地址或独一无二的识别符。&lt;/p>
&lt;p>所谓 “上网” ，就是与互联网上一系列的 “资源” 互动，调用它的 URI。&lt;/p>
&lt;p>&lt;strong>二、表现层（Representation）&lt;/strong>&lt;/p>
&lt;p>“资源” 是一种信息实体，它可以有多种外在表现形式。我们把 “资源” 具体呈现出来的形式，叫做它的 “表现层” （Representation）。&lt;/p></description></item><item><title>（四）soapUI介绍与安装</title><link>https://itest2025.pages.dev/tutorials/26-003-%E5%9B%9Bsoapui%E4%BB%8B%E7%BB%8D%E4%B8%8E%E5%AE%89%E8%A3%85/</link><pubDate>Wed, 20 Sep 2017 23:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/26-003-%E5%9B%9Bsoapui%E4%BB%8B%E7%BB%8D%E4%B8%8E%E5%AE%89%E8%A3%85/</guid><description>&lt;p>&lt;strong>soapUI 是一款针对 REST 、SOAP 和其它的 API 自动化测试框架。&lt;/strong>&lt;/p>
&lt;p>如果不理解什么是 SOAP 和 REST , 参考：&lt;/p>
&lt;p>&lt;a href="https://itest2025.pages.dev/soapui/web-services2/" rel="">（二）Web Services技术之SOAP&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://itest2025.pages.dev/soapui/web-services3/" rel="">（三）Web Services技术之REST&lt;/a>&lt;/p>
&lt;h4 id="什么是soapui">什么是soapUI?&lt;/h4>
&lt;hr>
&lt;p>(SoapUI is the world&amp;rsquo;s most widely-used open source API testing tool for SOAP and REST APIs. SoapUI offers SOAP Web Services functional testing, REST API functional testing, WSDL coverage, message assertion testing and test refactoring. With over 10 years of experience backed by a vast open source community, SoapUI is the de facto method for ensuring quality when developing APIs and Web Services.)&lt;/p></description></item><item><title>appium新手入门（3）—— 安装 appium Server</title><link>https://itest2025.pages.dev/tutorials/21-003-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A83-%E5%AE%89%E8%A3%85-appium-server/</link><pubDate>Thu, 07 Sep 2017 11:24:12 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/21-003-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A83-%E5%AE%89%E8%A3%85-appium-server/</guid><description>&lt;p>我们可以在Appium官方网站上下载操作系统相应的Appium版本。&lt;/p>
&lt;p>&lt;a href="https://bitbucket.org/appium/appium.app/downloads/" target="_blank" rel="noopener noreffer ">https://bitbucket.org/appium/appium.app/downloads/&lt;/a>&lt;/p>
&lt;p>当前最新版本为 &lt;strong>AppiumForWindows_1_4_16_1.zip&lt;/strong> ，注意这是一个 Windows 版本，如果你的电脑为MAC请下载 &lt;strong>appium-1.5.3.dmg&lt;/strong> 。虽然你已经看到了这些下载包，但我不保证你能下载的下来。&lt;/p>
&lt;p>所以，再来提供一个百度网盘的下载链接：https://pan.baidu.com/s/1pKMwdfX&lt;/p>
&lt;p>我们以 Windows 为例，将下载的 AppiumForWindows.zip 进行解压，点击 &lt;strong>appium-installer.exe&lt;/strong> 进行安装。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/appium_server_install.png"
 data-srcset="http://img.testclass.net/appium_server_install.png, http://img.testclass.net/appium_server_install.png 1.5x, http://img.testclass.net/appium_server_install.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/appium_server_install.png"
 title="http://img.testclass.net/appium_server_install.png" />&lt;/p>
&lt;p>根据提示，一步一步进行安装，这里不再啰嗦。最终在会桌面上生成 &lt;strong>Appium图标&lt;/strong> , 双击启动，appium server 界面如下。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/appium_server_view.png"
 data-srcset="http://img.testclass.net/appium_server_view.png, http://img.testclass.net/appium_server_view.png 1.5x, http://img.testclass.net/appium_server_view.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/appium_server_view.png"
 title="http://img.testclass.net/appium_server_view.png" />&lt;/p>
&lt;p>Appium-Server已经可以打开了。至于Appium的使用我们放到后面的章节进行介绍。&lt;/p>
&lt;p>最后，打开Windows命令提示符，输入“appium-doctor”命令，如果出现以下提示，说明你Appium所需要的各项环境都已准备完成。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/appium_server_environment.png"
 data-srcset="http://img.testclass.net/appium_server_environment.png, http://img.testclass.net/appium_server_environment.png 1.5x, http://img.testclass.net/appium_server_environment.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/appium_server_environment.png"
 title="http://img.testclass.net/appium_server_environment.png" />&lt;/p>
&lt;p>注：如果提示：&lt;strong>“appium-doctor”不是内部或外部命令&lt;/strong>，找到Appium的安装目录，例如：&lt;/p>
&lt;p>&lt;strong>C:\Program Files\Appium\node_modules\.bin&lt;/strong>&lt;/p>
&lt;p>添加到环境变量path下面（参考Java环境的设置）。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1534088568595-a066f410bcda?w=300"
 data-srcset="https://images.unsplash.com/photo-1534088568595-a066f410bcda?w=300, https://images.unsplash.com/photo-1534088568595-a066f410bcda?w=300 1.5x, https://images.unsplash.com/photo-1534088568595-a066f410bcda?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1534088568595-a066f410bcda?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（三）Git提交代码到GitHub</title><link>https://itest2025.pages.dev/tutorials/33-003-%E4%B8%89git%E6%8F%90%E4%BA%A4%E4%BB%A3%E7%A0%81%E5%88%B0github/</link><pubDate>Thu, 31 Aug 2017 02:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/33-003-%E4%B8%89git%E6%8F%90%E4%BA%A4%E4%BB%A3%E7%A0%81%E5%88%B0github/</guid><description>&lt;p>请先阅读：&lt;a href="https://itest2025.pages.dev/git/registration-and-installation/" rel="">GitHub注册与Git安装&lt;/a>&lt;/p>
&lt;h4 id="github创建项目">GitHub创建项目&lt;/h4>
&lt;hr>
&lt;p>在GitHub选择并创建一个项目。首先，登录 GitHub，单击页面右上角加号__“+”__ ，选择__“New repository”__ 选项。&lt;/p>
&lt;p>填写项目名称及描述，默认项目为“Public”,如果想创建“Private”项目，GitHub需要收费。最后单击“Create repository”完成项目的创建，如下图所示。&lt;/p>
&lt;p>项目名称为：&lt;strong>project-name&lt;/strong>&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/git_create_project.png"
 data-srcset="http://img.testclass.net/git_create_project.png, http://img.testclass.net/git_create_project.png 1.5x, http://img.testclass.net/git_create_project.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/git_create_project.png"
 title="http://img.testclass.net/git_create_project.png" />&lt;/p>
&lt;p>创建完一个项目之后，GitHub会提示我们如何提交项目到它上面。&lt;/p>
&lt;pre>&lt;code>Quick setup — if you’ve done this kind of thing before
HTTPS https://github.com/defnngj/project-name.git
SSH git@github.com:defnngj/project-name.git

…or create a new repository on the command line

echo # project-name &amp;gt;&amp;gt; README.md
git init
git add README.md
git commit -m &amp;quot;first commit&amp;quot;
git remote add origin git@github.com:defnngj/project-name.git
git push -u origin master

…or push an existing repository from the command line

git remote add origin git@github.com:defnngj/project-name.git
git push -u origin master

…or import code from another repository

You can initialize this repository with code from a Subversion, Mercurial, or TFS project.
&lt;/code>&lt;/pre>
&lt;h4 id="第一次提交代码到github">第一次提交代码到GitHub&lt;/h4>
&lt;hr>
&lt;p>首先进行初始化配置：设置仓库人员的用户名和邮箱地址，这一步必不可少。&lt;/p></description></item><item><title>3.入门级接口测试工具:postman的安装</title><link>https://itest2025.pages.dev/tutorials/40-003-3%E5%85%A5%E9%97%A8%E7%BA%A7%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7postman%E7%9A%84%E5%AE%89%E8%A3%85/</link><pubDate>Mon, 28 Aug 2017 04:41:43 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/40-003-3%E5%85%A5%E9%97%A8%E7%BA%A7%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7postman%E7%9A%84%E5%AE%89%E8%A3%85/</guid><description>&lt;h3 id="关于postman">关于postman&lt;/h3>
&lt;p>postman是跨平台的接口调试及测试工具，非常适合初学者使用。&lt;/p>
&lt;h3 id="安装postman">安装postman&lt;/h3>
&lt;p>&lt;a href="https://www.getpostman.com/" target="_blank" rel="noopener noreffer ">下载地址&lt;/a>&lt;/p>
&lt;p>请选择相应的版本下载，windows版下载完成后双击安装就好了。&lt;/p>
&lt;h3 id="postman的界面">postman的界面&lt;/h3>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://oriphg3yh.bkt.clouddn.com/postman1.png"
 data-srcset="http://oriphg3yh.bkt.clouddn.com/postman1.png, http://oriphg3yh.bkt.clouddn.com/postman1.png 1.5x, http://oriphg3yh.bkt.clouddn.com/postman1.png 2x"
 data-sizes="auto"
 alt="http://oriphg3yh.bkt.clouddn.com/postman1.png"
 title="http://oriphg3yh.bkt.clouddn.com/postman1.png" />&lt;/p>
&lt;h3 id="发送第一个请求">发送第一个请求&lt;/h3>
&lt;p>我们发送上一节里提到的获取v2ex节点信息的api。&lt;/p>
&lt;pre tabindex="0">&lt;code>https://www.v2ex.com/api/nodes/show.json?name=python
&lt;/code>&lt;/pre>&lt;p>具体步骤如下&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://oriphg3yh.bkt.clouddn.com/send_req.gif"
 data-srcset="http://oriphg3yh.bkt.clouddn.com/send_req.gif, http://oriphg3yh.bkt.clouddn.com/send_req.gif 1.5x, http://oriphg3yh.bkt.clouddn.com/send_req.gif 2x"
 data-sizes="auto"
 alt="http://oriphg3yh.bkt.clouddn.com/send_req.gif"
 title="http://oriphg3yh.bkt.clouddn.com/send_req.gif" />&lt;/p>
&lt;h3 id="postman是如何工作的">postman是如何工作的&lt;/h3>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://oriphg3yh.bkt.clouddn.com/postman_2.png"
 data-srcset="http://oriphg3yh.bkt.clouddn.com/postman_2.png, http://oriphg3yh.bkt.clouddn.com/postman_2.png 1.5x, http://oriphg3yh.bkt.clouddn.com/postman_2.png 2x"
 data-sizes="auto"
 alt="http://oriphg3yh.bkt.clouddn.com/postman_2.png"
 title="http://oriphg3yh.bkt.clouddn.com/postman_2.png" />&lt;/p>
&lt;p>从原理图上可以看出，postman发送请求给服务器，然后从服务器接受响应，最后在postman中展示出来。&lt;/p>
&lt;h3 id="服务器响应">服务器响应&lt;/h3>
&lt;p>上图就是服务器的响应详情，这里包含了一些重要信息&lt;/p>
&lt;ul>
&lt;li>状态码: 200，表示响应是ok的&lt;/li>
&lt;li>Body: 返回的主体&lt;/li>
&lt;li>Headers: 可以简单的理解为一些键值对，对请求的主体起到了补充的作用&lt;/li>
&lt;li>Time: 响应时间&lt;/li>
&lt;li>Size: 响应的大小&lt;/li>
&lt;/ul>
&lt;h3 id="json字符串">json字符串&lt;/h3>
&lt;p>有基础的同学可以看出来，响应的主体是json格式的字符串，那么什么是json格式字符串呢？下一节我们将详细讲解。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1457612928689-a1ab27da0dad?w=300"
 data-srcset="https://images.unsplash.com/photo-1457612928689-a1ab27da0dad?w=300, https://images.unsplash.com/photo-1457612928689-a1ab27da0dad?w=300 1.5x, https://images.unsplash.com/photo-1457612928689-a1ab27da0dad?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1457612928689-a1ab27da0dad?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>JMeter官方文档：3. 测试计划中的元素</title><link>https://itest2025.pages.dev/tutorials/22-003-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A33-%E6%B5%8B%E8%AF%95%E8%AE%A1%E5%88%92%E4%B8%AD%E7%9A%84%E5%85%83%E7%B4%A0/</link><pubDate>Thu, 24 Aug 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/22-003-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A33-%E6%B5%8B%E8%AF%95%E8%AE%A1%E5%88%92%E4%B8%AD%E7%9A%84%E5%85%83%E7%B4%A0/</guid><description>&lt;p>&lt;a href="https://itest2025.pages.dev/2017/08/24/jmeter-translation-plans/" rel="">《JMeter官方文档&amp;ndash;翻译计划》&lt;/a> &lt;a href="http://jmeter.apache.org/usermanual/test_plan.html" target="_blank" rel="noopener noreffer ">原文地址&lt;/a>&lt;/p>
&lt;h2 id="3测试计划中的元素elements-of-a-test-plan">3.测试计划中的元素（elements of a test plan）&lt;/h2>
&lt;hr>
&lt;p>本节描述测试计划不同的部分。&lt;/p>
&lt;p>最小测试将包括测试计划、线程组和一个或多个采样器。&lt;/p>
&lt;h3 id="30-测试计划test-plan">3.0 测试计划（Test Plan）&lt;/h3>
&lt;hr>
&lt;p>测试计划对象有一个叫 &lt;strong>“功能测试”&lt;/strong> 的复选框，如果选择了，它将导致JMeter记录从服务器返回的每个示例的数据。如果您在测试监听器中选择了一个文件，那么这些数据将被写入文件。如果您正在执行一个小的运行，以确保JMeter的配置正确，并且您的服务器正在返回预期的结果，那么这将非常有用。其结果是，文件将快速增长，JMeter的性能将受到影响。如果您正在进行压力测试(默认情况下是off)，则该选项应该关闭。&lt;/p>
&lt;p>如果您没有将数据记录到文件中，则该选项没有任何区别。&lt;/p>
&lt;p>您还可以使用侦听器(listener)的 &lt;strong>配置&lt;/strong> 按钮来决定要保存哪些字段。&lt;/p>
&lt;h3 id="31-线程组thread-group">3.1 线程组（Thread group）&lt;/h3>
&lt;hr>
&lt;p>线程组元素是任何测试计划的起点。所有控制器和采样器必须在线程组下。其他元素，例如侦听器，可以直接置于测试计划之下，在这种情况下，它们将适用于所有的线程组。顾名思义，线程组元素控制JMeter用来执行测试的线程的数量。线程组的控件允许:&lt;/p>
&lt;ul>
&lt;li>Set the number of threads： 设置线程数&lt;/li>
&lt;li>Set the ramp-up period：设置过渡时期&lt;/li>
&lt;li>Set the number of times to execute the test：设置执行测试的次数&lt;/li>
&lt;/ul>
&lt;p>每个线程将完全独立地执行测试计划，完全独立于其他测试线程。多个线程用于模拟与服务器应用程序的并发连接。&lt;/p>
&lt;p>这个过渡时期告诉JMeter要花多长时间才能“加速”到选择的全部线程数。如果使用10个线程，并且过渡时期是100秒，那么JMeter将花费100秒来启动所有10个线程并运行。在前面的线程开始后，每个线程将开始10(100 / 10)秒。如果有30个线程和一个上升周期120秒，则每个连续线程将延迟4秒。&lt;/p>
&lt;p>需要足够长的时间来避免在测试开始时工作负载过大，足够短的时间，最后的线程在第一个线程完成之前就开始运行(除非有人希望发生这样的情况)。
从增加的线程数开始，根据需要调整向上或向下。&lt;/p>
&lt;p>默认情况下，线程组被配置为通过它的元素循环一次。&lt;/p>
&lt;p>线程组还提供了一个 &lt;strong>调度器&lt;/strong> 。单击线程组面板底部的复选框，以启用/禁用额外的字段，在该字段中您可以输入测试持续时间、启动延迟、运行的开始和结束时间。您可以配置 &lt;strong>持续时间（秒）&lt;/strong> 和 &lt;strong>启动延迟（秒）&lt;/strong> 来控制每个线程组的持续时间和启动后的秒数。当开始测试时，JMeter会等待 &lt;strong>启动延迟（秒）&lt;/strong> 之前启动的线程组的线程和运行配置的持续时间（秒）的时间。注意，这两个选项覆盖了 &lt;strong>开始时间&lt;/strong> 和 &lt;strong>结束时间&lt;/strong> 。&lt;/p>
&lt;p>或者(尽管不建议不是很灵活)，您可以使用其他两个字段 &lt;strong>开始时间&lt;/strong> 和 &lt;strong>结束时间&lt;/strong>。当测试开始时，JMeter将在必要时等待，直到到达开始时间。在每个循环的末尾，JMeter检查是否已经到达了结束时间，如果是，则停止运行，否则测试将继续运行下去，直到达到迭代限制。&lt;/p>
&lt;h3 id="32-控制器controllers">3.2 控制器（Controllers）&lt;/h3>
&lt;hr>
&lt;p>JMeter有两种控制器：采样器和逻辑控制器。这些驱动测试的处理。&lt;/p>
&lt;p>采样器告诉JMeter发送请求到服务器。例如，如果你想要JMeter发送http请求添加一个HTTP请求取样器。您还可以通过向采样器中添加一个或多个配置元素来定制请求。更多信息，参见：采样器。&lt;/p></description></item><item><title>appium简明教程（3）——appium的安装windows版</title><link>https://itest2025.pages.dev/tutorials/21-003-appium%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B3appium%E7%9A%84%E5%AE%89%E8%A3%85windows%E7%89%88/</link><pubDate>Fri, 18 Aug 2017 07:14:54 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/21-003-appium%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B3appium%E7%9A%84%E5%AE%89%E8%A3%85windows%E7%89%88/</guid><description>&lt;p>appium的哲学里有一条就是不重新发明轮子。同样，官方已经有明确的安装步骤了，因此在这里纯属搬砖。&lt;/p>
&lt;p>&lt;a href="https://github.com/appium/appium/blob/master/docs/cn/appium-setup/running-on-windows.md" target="_blank" rel="noopener noreffer ">原文地址&lt;/a>&lt;/p>
&lt;p>感谢testerhome的辛勤翻译。&lt;/p>
&lt;p>本文版权归乙醇所有，欢迎转载，但请注明作者与出处，严禁用于任何商业用途&lt;/p>
&lt;h3 id="限制">限制&lt;/h3>
&lt;p>如果你在windows上安装appium，你没法使用预编译专用于OS X的.app文件，你也将不能测试IOS apps，因为appium依赖OS X专用的库来支持IOS测试。这意味着你只能通过在mac上来运行IOS的app测试。这点限制挺大。&lt;/p>
&lt;h3 id="开始安装">开始安装&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>安装nodejs 通过官方的安装程序来安装。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>安装android的sdk包，(&lt;a href="http://developer.android.com/sdk/index.html%29" target="_blank" rel="noopener noreffer ">http://developer.android.com/sdk/index.html)&lt;/a>, 运行依赖sdk中的&amp;rsquo;android&amp;rsquo;工具。并确保你安装了Level17或以上的版本api。设置ANDROID_HOME系统变量为你的Android SDK路径，并把tools platform-tools两个目录加入到系统的Path路径里。因为这里面包含有一些执行命令&lt;/p>
&lt;/li>
&lt;li>
&lt;p>安装java的JDK，并设置JAVA_HOME 变量为你的JDK目录。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>安装Apache Ant 或者直接使用Android Windows SDK自带的ant，地址在eclipse\plugins目录，你需要把这个目录加到你的系统PATH变量中&lt;/p>
&lt;/li>
&lt;li>
&lt;p>安装&lt;a href="http://maven.apache.org/download.cgi" target="_blank" rel="noopener noreffer ">Apache Maven&lt;/a>. 并且设置M2HOME和M2环境变量，把M2环境变量添加到你的系统PATH变量中。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>安装&lt;a href="https://git-scm.com/download/win" target="_blank" rel="noopener noreffer ">Git&lt;/a>. 确保你安装了windows下的Git，以便可以运行常用的command命令&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>现在，你已经下载安装了所有的依赖，开始运行 reset.bat&lt;/p>
&lt;h3 id="运行appium">运行Appium&lt;/h3>
&lt;p>要在windows上运行测试用例，你需要先启动Android模拟器或者连接上一个API Level17以上的android真机。 然后在命令行运行appium node .&lt;/p>
&lt;h3 id="备注">备注&lt;/h3>
&lt;ul>
&lt;li>你必须带上&amp;ndash;no-reset和&amp;ndash;full-reset标记，以用于windows上的android&lt;/li>
&lt;li>有一个硬件加速模拟器用于android，但是它有自己的一些限制，如果你想了解更多，请参考页面&lt;/li>
&lt;li>确保在你的AVD的config.ini中有一个配置项为hw.battery=yes&lt;/li>
&lt;/ul>
&lt;h3 id="最简略的安装方式">最简略的安装方式&lt;/h3>
&lt;p>出于对官方文档的尊重，我按照原文翻译，如下介绍我的安装心得。官方提到的一些工具，其实并不需要安装。 下面介绍我已经测试过的安装和使用过程&lt;/p>
&lt;h3 id="安装appium">安装appium&lt;/h3>
&lt;ol>
&lt;li>
&lt;p>安装nodejs&lt;/p>
&lt;/li>
&lt;li>
&lt;p>使用npm安装appium: &lt;code>npm install -g appium&lt;/code>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>注意：在某些情况下，appium安装的时候并不会把appium的路径放进系统的PATH里，这时候需要手工去加一下。&lt;/p>
&lt;h3 id="运行appium-1">运行appium&lt;/h3>
&lt;p>启动appium，直接运行appium 即可。&lt;/p>
&lt;h3 id="更新appium">更新appium&lt;/h3>
&lt;p>通过&lt;code>npm install -g appium&lt;/code> 来更新appium即可&lt;/p>
&lt;p>下一节，appium client的安装&lt;/p>
&lt;p>本文版权归乙醇所有，欢迎转载，但请注明作者与出处，严禁用于任何商业用途&lt;/p></description></item><item><title>性能测试基础（三）经典例子--理发店原理</title><link>https://itest2025.pages.dev/tutorials/14-003-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E5%9F%BA%E7%A1%80%E4%B8%89%E7%BB%8F%E5%85%B8%E4%BE%8B%E5%AD%90--%E7%90%86%E5%8F%91%E5%BA%97%E5%8E%9F%E7%90%86/</link><pubDate>Fri, 11 Aug 2017 13:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/14-003-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E5%9F%BA%E7%A1%80%E4%B8%89%E7%BB%8F%E5%85%B8%E4%BE%8B%E5%AD%90--%E7%90%86%E5%8F%91%E5%BA%97%E5%8E%9F%E7%90%86/</guid><description>&lt;br>
接下来通过一个简单理发店模拟来理解系统的并发处理。
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/barber_shop.jpg"
 data-srcset="http://img.testclass.net/barber_shop.jpg, http://img.testclass.net/barber_shop.jpg 1.5x, http://img.testclass.net/barber_shop.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/barber_shop.jpg"
 title="http://img.testclass.net/barber_shop.jpg" />&lt;/p>
&lt;br>
__前提：__
&lt;p>1. 一个理发店有三位理发师傅。&lt;/p>
&lt;p>2. 每位理发师傅服务一位顾客需要一小时。&lt;/p>
&lt;p>3. 顾客都很忙，从进理发店起最多只能等待三小时（等待加 + 被服务的时间）。&lt;/p>
&lt;p>&lt;strong>思考：&lt;/strong>&lt;/p>
&lt;p>这里我们来理解“最佳用户数”和“最大用户数”。&lt;/p>
&lt;p>&lt;strong>最佳用户数：&lt;/strong>&lt;/p>
&lt;p>理发店的最佳状态，理发店收入最多（理发师傅没有休息时间，一直在理发），顾客满意度最高（顾客随时店随时接受服务，无需要等待）。从一个时间点来看，3个理发师傅服务3位顾客，那么这个最佳用户数是3。&lt;/p>
&lt;p>&lt;strong>最大用户数：&lt;/strong>&lt;/p>
&lt;p>理发店的最大承受状态，理发店收入最多（理发师傅没有休息时间，一直在理发），顾客的最大忍耐度（来的顾客等上三个小时才轮到自己服务）。&lt;/p>
&lt;p>假如理发店生意非常好，早上一开门一下子来了一群顾客（很多），A、B、C三位顾客先理，D、E、F顾客需要等待一小时才能得到理发师傅的服务，G、H、I三位顾客等待了两小时才得到服务，后面排队的J、K、L&amp;hellip;..等顾客，已经等了三小时还没得到服务，因为这已经得达到了他们等待的极限，所以后他们气愤和无奈离开。&lt;/p>
&lt;p>当然，理发店还会不断的来新的顾客，不断有等了三小时而没有得到服务的顾客离开，但对于理发店而言，他们在一个时间点上，能服务的最大用户数是九（三位正在接受服务、三位需要等待1小时，三位需要等待2小时）。&lt;/p>
&lt;p>对于最大用户数，需要注意的两点：&lt;/p>
&lt;p>1. 在理发店里很大，可以容纳很多位顾客（大于9），总有一部分在这里等待了三小时而没有得到服务离开，不要把等待了3小而没有得到服务的顾客纳入最大用户数里。&lt;/p>
&lt;p>2. 假如理发店很小，最多只能容纳六位顾客，当第七个顾客来时，虽然，我们知道他只需要等待2小时就可得到服务（这个时间是他可以接受的范围），但由于理发店容量有量，这第七个顾客只有改天再来了。&lt;/p>
&lt;p>关于理发店原理，&lt;a href="http://www.cnblogs.com/jackei/archive/2006/11/20/565527.html" target="_blank" rel="noopener noreffer ">参考&lt;/a>&lt;/p>
&lt;p>不知道通过上面对理发店的分析，你对性能有了一些眉目。假如理发店相当于我们的系统的话，顾客就我们向服务器所发送的请求，最佳用户数和最大用户数是我们衡量一个系统的处理能力的一种方法。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1600948836101-f9ffda59d250?w=300"
 data-srcset="https://images.unsplash.com/photo-1600948836101-f9ffda59d250?w=300, https://images.unsplash.com/photo-1600948836101-f9ffda59d250?w=300 1.5x, https://images.unsplash.com/photo-1600948836101-f9ffda59d250?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1600948836101-f9ffda59d250?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（三）查看文档</title><link>https://itest2025.pages.dev/tutorials/20-003-%E4%B8%89%E6%9F%A5%E7%9C%8B%E6%96%87%E6%A1%A3/</link><pubDate>Fri, 11 Aug 2017 07:33:35 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/20-003-%E4%B8%89%E6%9F%A5%E7%9C%8B%E6%96%87%E6%A1%A3/</guid><description>&lt;h3 id="官方文档">官方文档&lt;/h3>
&lt;p>官方文档是最权威的参考资料。在绝大多数情况下我们应该首先从官方文档里获取帮助，如果实在是找不到结果，再考虑其他方式。&lt;/p>
&lt;p>selenium javascript 版本的文档在&lt;a href="http://seleniumhq.github.io/selenium/docs/api/javascript/index.html" target="_blank" rel="noopener noreffer ">这里&lt;/a>&lt;/p>
&lt;h3 id="stackoverflow">stackoverflow&lt;/h3>
&lt;p>除了官方文档，&lt;a href="https://stackoverflow.com/" target="_blank" rel="noopener noreffer ">stackoverflow&lt;/a>也是一个非常好的选择，很多时候去一些具体场景的使用问题，这里都有答案。&lt;/p>
&lt;p>selenium javascript的问题一般都列在&lt;a href="https://stackoverflow.com/search?q=selenium&amp;#43;javascript" target="_blank" rel="noopener noreffer ">这里&lt;/a>，我们可以通过google搜索或者直接在stackoverflow的站内进行搜索。&lt;/p>
&lt;h3 id="github">github&lt;/h3>
&lt;p>除了浏览源码之外，我们还可以在github上查看selenium的wiki以及查看selenium的已知问题。&lt;/p>
&lt;p>如果你想对selenium有进一步的了解，请看&lt;a href="https://github.com/SeleniumHQ/selenium/wiki" target="_blank" rel="noopener noreffer ">这里&lt;/a>。&lt;/p>
&lt;p>如果你遇到了一些无法解决的问题，不妨在&lt;a href="https://github.com/SeleniumHQ/selenium/issues" target="_blank" rel="noopener noreffer ">这里&lt;/a>搜索一下，可能这是官方的1个bug，在后续的版本中可能有所改进。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1487715224545-78f0cedc19bd?w=300"
 data-srcset="https://images.unsplash.com/photo-1487715224545-78f0cedc19bd?w=300, https://images.unsplash.com/photo-1487715224545-78f0cedc19bd?w=300 1.5x, https://images.unsplash.com/photo-1487715224545-78f0cedc19bd?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1487715224545-78f0cedc19bd?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（三）趣谈软件需求分析</title><link>https://itest2025.pages.dev/tutorials/29-003-%E4%B8%89%E8%B6%A3%E8%B0%88%E8%BD%AF%E4%BB%B6%E9%9C%80%E6%B1%82%E5%88%86%E6%9E%90/</link><pubDate>Wed, 26 Jul 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/29-003-%E4%B8%89%E8%B6%A3%E8%B0%88%E8%BD%AF%E4%BB%B6%E9%9C%80%E6%B1%82%E5%88%86%E6%9E%90/</guid><description>&lt;br>
#### 什么是需求分析？
&lt;p>通俗的讲，对用户的意图不断揭示和验叛的过程，要对经过系统可行性分析所确定的系统目标做更为详细的描述。&lt;/p>
&lt;p>假如你是个建筑工程师，有个客户找你建一个鸡窝，这个时候要需要与客户沟通，来确定客户到底想要一个什么样子的鸡窝。我们应该注意三点：&lt;/p>
&lt;p>&lt;strong>1、准确的理解和描述客户需要的功能。&lt;/strong>&lt;/p>
&lt;p>客户说，我的鸡窝要三层的，带电梯，饮水池，厕所，饮水池要自动判断水位供水，电梯要可以同时乘坐10只鸡&amp;hellip;.客户滔滔不绝的讲了一大堆，你也都非常忠实的按照自己的理解再一一的向客户描述一遍，以便于确认客户的需求是否正确。&lt;/p>
&lt;p>&lt;strong>2、帮助客户挖掘需求。&lt;/strong>&lt;/p>
&lt;p>等客户把自己的需求说完了，你发现客户没有说鸡的卧室，于是，你向客户提议说：“你看，这鸡的卧室要什么样子的？”，客户连连的拍着脑门说，我差点给忘记了，鸡们啊喜欢晚上在一起聊天，所以呢，需要一个长而大的卧室，但一定要舒适。&lt;/p>
&lt;p>&lt;strong>3、分析客户需求的可行性。&lt;/strong>&lt;/p>
&lt;p>客户临走时又说，最近啊，黄鼠狼很多，我这个鸡窝啊，一楼就不用盖了，直接盖二楼和三楼吧！以免晚上遭遇黄鼠狼的攻击。你这么一分析，客户这要求，按照目前的技术可没法建啊，于是，你向客户提议，一楼采用坚固架子来支撑二三楼的建筑。&lt;/p>
&lt;br>
#### 需求分析困难在哪儿？
&lt;p>有几种原因使需求分析变得困难：（1）客户说不清楚需求；（2）需求自身经常变动；（3）分析人员或客户理解有误。&lt;/p>
&lt;p>&lt;strong>1、客户说不清楚需求&lt;/strong>&lt;/p>
&lt;p>有些客户对需求只有朦胧的感觉，当然说不清楚具体的需求。例如全国各地的很多政府机构在搞网络建设，这些单位的领导和办公人员大多不清楚计算机网络有什么用，反而要软件系统分析人员替他们设想需求。这类工程的需求是如此的主观，以致产生很多贪污腐败现象。&lt;/p>
&lt;p>有些客户心里非常清楚想要什么，但却说不明白。你可能很不以为然。就举日常生活的事例吧，比如说买鞋子。我们非常了解自已的脚，但没法说清楚脚的大小和形状。只能拿鞋子去试，试穿时感觉到舒服才会买鞋（居然也有神通广大的售货员，看一眼客户的手，就知道应该穿什么样的鞋）。&lt;/p>
&lt;p>如果客户本身就懂软件开发，能把需求说得清清楚楚，这样的需求分析将会非常轻松、愉快。如果客户全不懂软件，但信任软件开发方，这事也好办。分析人员可以引导客户，先阐述常规的需求，再由客户否定不需要的，最终确定客户真正的需求。最怕的就是“不懂装懂”或者“半懂充内行”的客户，他们会提出不切实际的需求。如果这些客户甚至觉得自己是上帝的爸爸，那么沟通和协商都会很困难。&lt;/p>
&lt;p>&lt;strong>2、需求自身经常变动&lt;/strong>&lt;/p>
&lt;p>唐僧曾说：“妖要是有了仁慈之心，就不再是妖，是人妖。”（《大话西游之大圣娶亲》）&lt;/p>
&lt;p>连妖都会变心，别说人了。所以喜新厌旧乃人之常情，世界也因此变得多姿多彩。&lt;/p>
&lt;p>软件的需求会变化吗？&lt;/p>
&lt;p>答：据历史记载，没有一个软件的需求改动少于三次。唯一只改动需求两次的客户是个死人。这个可怜的家伙还是在运送第三次需求的路上被车子撞死的。[Cline 1995]&lt;/p>
&lt;p>让我们先接受“需求会变动”这个事实吧，免得在需求变动时惊慌失措。明白“需求会变动”这个道理后，在进行需求分析时就要留点神：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>尽可能地分析清楚哪些是稳定的需求，哪些是易变的需求。以便在进行系统设计时，将软件的核心建筑在稳定的需求上，否则将会吃尽苦头。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>在合同中一定要说清楚“做什么”和“不做什么”。如果合同含含糊糊，日后扯皮的事情就多。要防止象韩复渠那样，在别人请他喝酒吃饭时他什么都点头（人家就更加献殷勤），吃完了他就宣布刚才答应的事都不算数，便扬长而去。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>3、分析人员和顾客理解有误&lt;/strong>&lt;/p>
&lt;p>有个外星人间谍潜伏到地球刺探情报，它给上司写了一份报告：“主宰地球的是车。它们喝汽油，靠四个轮子滚动前进。嗓门极大，在夜里双眼能射出强光。……有趣的是，车里住着一种叫作‘人’的寄生虫，这些寄生虫完全控制了车。”&lt;/p>
&lt;p>软件系统分析人员不可能都是全才。客户表达的需求，不同的分析人员可能有不同的理解。如果分析人员理解错了，可能会导致开发人员白干活，吃力不讨好。我读中学时候最怕写作文逃题，如果逃题了，不管作文写得多长，总是零分。所以分析人员写好需求说明书后，要请客户方的各个代表验证。如果问题很复杂，双方都不太明白，就有必要请开发人员快速构造软件的原型，双方再次论证需求说明书是否正确。&lt;/p>
&lt;p>由于客户大多不懂软件，他们可能觉得软件是万能的，会提出一些无法实现的需求。有时客户还会把软件系统分析人员的建议或答复给想歪了。&lt;/p>
&lt;p>有一个软件人员滔滔不绝地向客户讲解在“信息高速公路上做广告”的种种好处，客户听得津津有味。最后，心动的客户对软件人员说：“好得很，就让我们马上行动起来吧。请您决定广告牌的尺寸和放在哪条高速公路上，我立即派人去做。”&lt;/p>
&lt;br>
#### 需求分析的分类
&lt;p>需求分析一般可分为功能需求、非功能需求和领域需求&lt;/p>
&lt;p>&lt;strong>1、功能需求&lt;/strong>&lt;/p>
&lt;p>功能需求主要说明了系统实际应做到什么。这是用户最直观也是最主要的需求，如系统的输入输出、系统能完成的功能以及其它相关处理等；&lt;/p>
&lt;p>&lt;strong>2、非功能需求&lt;/strong>&lt;/p>
&lt;p>非功能需求又称“约束”，它主要从各个角度对系统起约束和限制作用。如响应时间、存储效率、报表的规格和界面的样式等&lt;/p>
&lt;p>&lt;strong>3、领域需求&lt;/strong>&lt;/p>
&lt;p>领域需求的来源不是用户，而是系统应用的领域，其主要反映了该领域的基本问题。例如勤工俭学管理系统，其领域需求就涉及到诸如应聘合同书、酬金发放及劳工考核等相关内容，如果这些需求得不到满足，系统就无法正常运行。值得一提的是，领域需求可能是功能需求，也可能是非功能需求。&lt;/p>
&lt;br>
#### 如何进行需求分析
&lt;p>进行需求分析不象情人之间的浪漫做法——“让我摸摸你的头发，感觉它是什么颜色。”我们需要了解需求分析的渠道和过程。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/requirement-analysis_01.png"
 data-srcset="http://img.testclass.net/requirement-analysis_01.png, http://img.testclass.net/requirement-analysis_01.png 1.5x, http://img.testclass.net/requirement-analysis_01.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/requirement-analysis_01.png"
 title="http://img.testclass.net/requirement-analysis_01.png" />&lt;/p>
&lt;p>需求分析的过程：&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/requirement-analysis_02.png"
 data-srcset="http://img.testclass.net/requirement-analysis_02.png, http://img.testclass.net/requirement-analysis_02.png 1.5x, http://img.testclass.net/requirement-analysis_02.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/requirement-analysis_02.png"
 title="http://img.testclass.net/requirement-analysis_02.png" />&lt;/p>
&lt;p>&lt;strong>（1）可行性研究&lt;/strong>&lt;/p>
&lt;p>它指明现有的软件、硬件技术能否实现用户对系统的要求，从业务角度来决定系统开发是否可行以及在预算范围内能否开发出来。可行性研究的结果是清楚的回答：该系统是否值得开发&lt;/p>
&lt;p>&lt;strong>（2）需求导出和分析&lt;/strong>&lt;/p>
&lt;p>这是一个通过对现有系统分析、与潜在客户讨论、进行任务分析等导出系统需求的过程，也可能需要开发一个或多个不同的系统原型，以帮助分析员了解所要描述的系统。&lt;/p>
&lt;p>&lt;strong>（3）需求描述&lt;/strong>&lt;/p>
&lt;p>需求描述就是把在分析活动中收集的信息通过分析整理之后以文档的形式确定下来。该文档中有两类需求：用户需求是从客户和最终用户角度对系统需求的抽象描述；系统需求是对系统要提供的功能的详尽描述。&lt;/p>
&lt;p>&lt;strong>（4）需求有效性验证&lt;/strong>&lt;/p>
&lt;p>主要是通过评审、验证等一系列活动来找出需求文档中的错漏并加以改正。&lt;/p></description></item><item><title>seleniuim面试题1</title><link>https://itest2025.pages.dev/tutorials/44-003-seleniuim%E9%9D%A2%E8%AF%95%E9%A2%981/</link><pubDate>Tue, 18 Jul 2017 09:44:38 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/44-003-seleniuim%E9%9D%A2%E8%AF%95%E9%A2%981/</guid><description>&lt;h3 id="selenium中如何判断元素是否存在">selenium中如何判断元素是否存在？&lt;/h3>
&lt;p>selenium中没有提供原生的方法判断元素是否存在，一般我们可以通过定位元素+异常捕获的方式判断。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 判断元素是否存在&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="n">dr&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_element_by_id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;none&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">except&lt;/span> &lt;span class="n">NoSuchElementException&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="nb">print&lt;/span> &lt;span class="s1">&amp;#39;element does not exist&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="selenium中hidden或者是display--none的元素是否可以定位到">selenium中hidden或者是display ＝ none的元素是否可以定位到？&lt;/h3>
&lt;p>不可以，selenium不能定位不可见的元素。&lt;code>display=none&lt;/code>的元素实际上是不可见元素。&lt;/p>
&lt;h3 id="selenium中如何保证操作元素的成功率也就是说如何保证我点击的元素一定是可以点击的">selenium中如何保证操作元素的成功率？也就是说如何保证我点击的元素一定是可以点击的？&lt;/h3>
&lt;ul>
&lt;li>被点击的元素一定要占一定的空间，因为selenium默认会去点这个元素的中心点，不占空间的元素算不出来中心点;&lt;/li>
&lt;li>被点击的元素不能被其他元素遮挡;&lt;/li>
&lt;li>被点击的元素不能在viewport之外，也就是说如果元素必须是可见的或者通过滚动条操作使得元素可见;&lt;/li>
&lt;li>使用&lt;code>element.is_enabled()&lt;/code>(python代码)判断元素是否是可以被点击的，如果返回false证明元素可能灰化了，这时候就不能点;&lt;/li>
&lt;/ul>
&lt;h3 id="如何提高selenium脚本的执行速度">如何提高selenium脚本的执行速度？&lt;/h3>
&lt;ul>
&lt;li>使用效率更高的语言，比如java执行速度就快过python&lt;/li>
&lt;li>不要盲目的加&lt;code>sleep&lt;/code>，尽量使用&lt;a href="https://itest2025.pages.dev/selenium_python/element-wait/" rel="">显式等待&lt;/a>&lt;/li>
&lt;li>对于firefox，考虑使用测试专用的profile，因为每次启动浏览器的时候firefox会创建1个新的profile，对于这个新的profile，所有的静态资源都是从服务器直接下载，而不是从缓存里加载，这就导致网络不好的时候用例运行速度特别慢的问题&lt;/li>
&lt;li>chrome浏览器和safari浏览器的执行速度看上去是最快的&lt;/li>
&lt;li>可以考虑分布式执行或者使用selenium grid&lt;/li>
&lt;/ul>
&lt;h3 id="用例在运行过程中经常会出现不稳定的情况也就是说这次可以通过下次就没办法通过了如何去提升用例的稳定性">用例在运行过程中经常会出现不稳定的情况，也就是说这次可以通过，下次就没办法通过了，如何去提升用例的稳定性？&lt;/h3>
&lt;ul>
&lt;li>测试专属profile，尽量让静态资源缓存&lt;/li>
&lt;li>尽量使用&lt;a href="https://itest2025.pages.dev/selenium_python/element-wait/" rel="">显式等待&lt;/a>&lt;/li>
&lt;li>尽量使用测试专用环境，避免其他类型的测试同时进行，对数据造成干扰&lt;/li>
&lt;/ul>
&lt;h3 id="你的自动化用例的执行策略是什么">你的自动化用例的执行策略是什么？&lt;/h3>
&lt;ul>
&lt;li>每日执行：比如每天晚上在主干执行一次&lt;/li>
&lt;li>周期执行：每隔2小时在开发分之执行一次&lt;/li>
&lt;li>动态执行：每次代码有提交就执行&lt;/li>
&lt;/ul>
&lt;h3 id="自动化测试的时候是不是需要连接数据库做数据校验">自动化测试的时候是不是需要连接数据库做数据校验？&lt;/h3>
&lt;p>一般不需要，因为这是单元测试层做的事情，在自动化测试层尽量不要为单元测试层没做的工作还债。&lt;/p>
&lt;h3 id="idnameclasxpath-css-selector这些属性你最偏爱哪一种为什么">id,name,clas,xpath, css selector这些属性，你最偏爱哪一种，为什么？&lt;/h3>
&lt;p>xpath和css最为灵活，所以其他的答案都不够完美。&lt;/p>
&lt;h3 id="如何去定位页面上动态加载的元素">如何去定位页面上动态加载的元素？&lt;/h3>
&lt;p>&lt;a href="https://itest2025.pages.dev/selenium_python/element-wait/" rel="">显式等待&lt;/a>&lt;/p>
&lt;h3 id="如何去定位属性动态变化的元素">如何去定位属性动态变化的元素？&lt;/h3>
&lt;p>找出属性动态变化的规律，然后根据上下文生成动态属性。&lt;/p>
&lt;h3 id="点击链接以后selenium是否会自动等待该页面加载完毕">点击链接以后，selenium是否会自动等待该页面加载完毕？&lt;/h3>
&lt;p>java binding在点击链接后会自动等待页面加载完毕。&lt;/p>
&lt;h3 id="selenium的原理是什么">selenium的原理是什么？&lt;/h3>
&lt;p>selenium的原理涉及到3个部分，分别是&lt;/p>
&lt;ul>
&lt;li>浏览器&lt;/li>
&lt;li>driver: 一般我们都会下载driver&lt;/li>
&lt;li>client: 也就是我们写的代码&lt;/li>
&lt;/ul>
&lt;p>client其实并不知道浏览器是怎么工作的，但是driver知道，在selenium启动以后，driver其实充当了服务器的角色，跟client和浏览器通信，client根据webdriver协议发送请求给driver，driver解析请求，并在浏览器上执行相应的操作，并把执行结果返回给client。这就是selenium工作的大致原理。&lt;/p>
&lt;h3 id="webdriver的协议是什么">webdriver的协议是什么？&lt;/h3>
&lt;p>client与driver之间的约定，无论client是使用java实现还是c#实现，只要通过这个约定，client就可以准确的告诉drier它要做什么以及怎么做。&lt;/p>
&lt;p>webdriver协议本身是http协议，数据传输使用json。&lt;/p>
&lt;p>&lt;a href="https://www.w3.org/TR/webdriver/#list-of-endpoints" target="_blank" rel="noopener noreffer ">这里&lt;/a>有webdriver协议的所有endpoint，稍微看一眼就知道这些endpoints涵盖了selenium的所有功能。&lt;/p>
&lt;h3 id="启动浏览器的时候用到的是哪个webdriver协议">启动浏览器的时候用到的是哪个webdriver协议？&lt;/h3>
&lt;p>&lt;a href="https://www.w3.org/TR/webdriver/#new-session" target="_blank" rel="noopener noreffer ">New Session&lt;/a>，如果创建成功，返回sessionId和&lt;a href="https://www.w3.org/TR/webdriver/#capabilities" target="_blank" rel="noopener noreffer ">capabilities&lt;/a>。&lt;/p>
&lt;h3 id="什么是page-object设计模式">什么是page object设计模式？&lt;/h3>
&lt;p>&lt;a href="https://github.com/SeleniumHQ/selenium/wiki/PageObjects" target="_blank" rel="noopener noreffer ">官方介绍&lt;/a>，简单来说就是用class去表示被测页面。在class中定义页面上的元素和一些该页面上专属的方法。&lt;/p></description></item><item><title>（三）环境安装之Selenium</title><link>https://itest2025.pages.dev/tutorials/19-003-%E4%B8%89%E7%8E%AF%E5%A2%83%E5%AE%89%E8%A3%85%E4%B9%8Bselenium/</link><pubDate>Wed, 05 Jul 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/19-003-%E4%B8%89%E7%8E%AF%E5%A2%83%E5%AE%89%E8%A3%85%E4%B9%8Bselenium/</guid><description>&lt;br>
### 通过jar包安装
&lt;p>点击 &lt;a href="http://docs.seleniumhq.org/download/" target="_blank" rel="noopener noreffer ">Selenium下载&lt;/a> 链接
你会看到Selenium Standalone Server的介绍：&lt;/p>
&lt;p>The Selenium Server is needed in order to run Remote Selenium
WebDriver. Selenium 3.X is no longer capable of running Selenium RC
directly, rather it does it through emulation and the WebDriverBackedSelenium interface.&lt;/p>
&lt;p>Download version &lt;strong>3.4.0&lt;/strong>&lt;/p>
&lt;p>点击版本号进行下载，下载完成将会得到一个__selenium-server-standalone-3.4.0.jar__文件。&lt;/p>
&lt;p>或者通过 &lt;a href="http://pan.baidu.com/s/1bFWaEa" target="_blank" rel="noopener noreffer ">网盘下载&lt;/a>。&lt;/p>
&lt;p>打开IntelliJ IDEA，导入.jar包。&lt;/p>
&lt;p>点击菜单栏 File &amp;ndash;&amp;gt; Project Structure（快捷键Ctrl + Alt + Shift + s） ，点击 Project Structure界面左侧
的“Modules” 。在“Dependencies” 标签界面下，点击右边绿色的“+” 号，选择第一个选项“JARs or directories&amp;hellip;” ，选择相应的 jar 包，点“OK” ，jar包添加成功。
&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://orru5lls3.bkt.clouddn.com/idea5.png"
 data-srcset="http://orru5lls3.bkt.clouddn.com/idea5.png, http://orru5lls3.bkt.clouddn.com/idea5.png 1.5x, http://orru5lls3.bkt.clouddn.com/idea5.png 2x"
 data-sizes="auto"
 alt="http://orru5lls3.bkt.clouddn.com/idea5.png"
 title="http://orru5lls3.bkt.clouddn.com/idea5.png" />&lt;/p></description></item><item><title>（三）selenium元素定位</title><link>https://itest2025.pages.dev/tutorials/24-003-%E4%B8%89selenium%E5%85%83%E7%B4%A0%E5%AE%9A%E4%BD%8D/</link><pubDate>Wed, 28 Jun 2017 07:37:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/24-003-%E4%B8%89selenium%E5%85%83%E7%B4%A0%E5%AE%9A%E4%BD%8D/</guid><description>&lt;br>
### selenium定位方法
&lt;p>Selenium提供了8种定位方式。&lt;/p>
&lt;ul>
&lt;li>id&lt;/li>
&lt;li>name&lt;/li>
&lt;li>class name&lt;/li>
&lt;li>tag name&lt;/li>
&lt;li>link text&lt;/li>
&lt;li>partial link text&lt;/li>
&lt;li>xpath&lt;/li>
&lt;li>css selector&lt;/li>
&lt;/ul>
&lt;p>这8种定位方式在Python selenium中所对应的方法为：&lt;/p>
&lt;ul>
&lt;li>find_element_by_id()&lt;/li>
&lt;li>find_element_by_name()&lt;/li>
&lt;li>find_element_by_class_name()&lt;/li>
&lt;li>find_element_by_tag_name()&lt;/li>
&lt;li>find_element_by_link_text()&lt;/li>
&lt;li>find_element_by_partial_link_text()&lt;/li>
&lt;li>find_element_by_xpath()&lt;/li>
&lt;li>find_element_by_css_selector()&lt;/li>
&lt;/ul>
&lt;br>
### 定位方法的用法
&lt;p>假如我们有一个Web页面，通过前端工具（如，Firebug）查看到一个元素的属性是这样的。&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;lt;html&amp;gt;
 &amp;lt;head&amp;gt;
 &amp;lt;body link=&amp;#34;#0000cc&amp;#34;&amp;gt;
 &amp;lt;a id=&amp;#34;result_logo&amp;#34; href=&amp;#34;/&amp;#34; onmousedown=&amp;#34;return c({&amp;#39;fm&amp;#39;:&amp;#39;tab&amp;#39;,&amp;#39;tab&amp;#39;:&amp;#39;logo&amp;#39;})&amp;#34;&amp;gt;
 &amp;lt;form id=&amp;#34;form&amp;#34; class=&amp;#34;fm&amp;#34; name=&amp;#34;f&amp;#34; action=&amp;#34;/s&amp;#34;&amp;gt;
 &amp;lt;span class=&amp;#34;soutu-btn&amp;#34;&amp;gt;&amp;lt;/span&amp;gt;
 &amp;lt;input id=&amp;#34;kw&amp;#34; class=&amp;#34;s_ipt&amp;#34; name=&amp;#34;wd&amp;#34; value=&amp;#34;&amp;#34; maxlength=&amp;#34;255&amp;#34; autocomplete=&amp;#34;off&amp;#34;&amp;gt;
&lt;/code>&lt;/pre>&lt;p>我们的目的是要定位input标签的输入框。&lt;/p>
&lt;ul>
&lt;li>通过id定位:&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>dr.find_element_by_id(&amp;#34;kw&amp;#34;)
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>通过name定位:&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>dr.find_element_by_name(&amp;#34;wd&amp;#34;)
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>通过class name定位:&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>dr.find_element_by_class_name(&amp;#34;s_ipt&amp;#34;)
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>通过tag name定位:&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>dr.find_element_by_tag_name(&amp;#34;input&amp;#34;)
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>通过xpath定位，xpath定位有N种写法，这里列几个常用写法:&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>dr.find_element_by_xpath(&amp;#34;//*[@id=&amp;#39;kw&amp;#39;]&amp;#34;)
dr.find_element_by_xpath(&amp;#34;//*[@name=&amp;#39;wd&amp;#39;]&amp;#34;)
dr.find_element_by_xpath(&amp;#34;//input[@class=&amp;#39;s_ipt&amp;#39;]&amp;#34;)
dr.find_element_by_xpath(&amp;#34;/html/body/form/span/input&amp;#34;)
dr.find_element_by_xpath(&amp;#34;//span[@class=&amp;#39;soutu-btn&amp;#39;]/input&amp;#34;)
dr.find_element_by_xpath(&amp;#34;//form[@id=&amp;#39;form&amp;#39;]/span/input&amp;#34;)
dr.find_element_by_xpath(&amp;#34;//input[@id=&amp;#39;kw&amp;#39; and @name=&amp;#39;wd&amp;#39;]&amp;#34;)
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>通过css定位，css定位有N种写法，这里列几个常用写法:&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">dr&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_element_by_css_selector&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;#kw&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">dr&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_element_by_css_selector&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;[name=wd]&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">dr&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_element_by_css_selector&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;.s_ipt&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">dr&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_element_by_css_selector&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;html &amp;gt; body &amp;gt; form &amp;gt; span &amp;gt; input&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">dr&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_element_by_css_selector&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;span.soutu-btn&amp;gt; input#kw&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">dr&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_element_by_css_selector&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;form#form &amp;gt; span &amp;gt; input&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>接下来，我们的页面上有一组文本链接。&lt;/p></description></item><item><title>一个bug的生命周期</title><link>https://itest2025.pages.dev/tutorials/13-004-%E4%B8%80%E4%B8%AAbug%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/13-004-%E4%B8%80%E4%B8%AAbug%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/</guid><description>&lt;br>
又一篇测试技术普及文章，希望你在被各种技术吸引的同时，能时常来整理和总结软件测试最基本的知识。
&lt;br>
#### Bug的属性
----
__Bug重现环境__
&lt;p>这个应该是我们重现bug的一个前提，如果没有这个前提，我们可能会无法重现问题，或者跟本就无从下手。&lt;/p>
&lt;ul>
&lt;li>操作系统&lt;/li>
&lt;/ul>
&lt;p>这个是一般软件运行的一大前提，基本上所有的软件都依赖于操作系统之上的，对于一个软件来说，要想在某个操作系统上运行，必须要对这个操作系统支持，这就需要有真对性的设计与开发。对于不同的操作系统，其可能存在差异（如：win xp 与 win 7）或本质的区别（如 win 7 与 CentOS linux ），所以，操作系统环境是重现问题的一个重要前提。&lt;/p>
&lt;ul>
&lt;li>浏览器&lt;/li>
&lt;/ul>
&lt;p>对于B/S系统，或面向大众的互联网产品（网站，邮箱等），浏览器的兼容性也是必须测试的一个重点，对于现在的浏览器市场，各式的浏览器都有其用户群，要想使产品大众化，必须考虑这些产品的兼容性问题。&lt;/p>
&lt;p>不同的浏览器之间（IE、 firefox、chrome、opera 等），甚至同一系列不同版本（ie6/ie7/ie8/ie9等）都可能存在兼容性问题，所以，对于这类应用，浏览器环境重现bug前提条件之一。&lt;/p>
&lt;ul>
&lt;li>其它（这个“其它”非常重要）&lt;/li>
&lt;/ul>
&lt;p>对于不同的系统发现重现问题，都会有其特定的前提，拿我测试的邮箱来说，必须要描述其是在测试线还是现网环境，而且还要附带一重现问题的帐号等。&lt;/p>
&lt;p>对于c/s软件，可能还要考虑与其它常用软的兼容等，例如，是在安装的某款软件后，对本软件的安装和使用造成影响。这些都是重现问题的必须描述的环境。&lt;/p>
&lt;p>&lt;strong>问题类型&lt;/strong>&lt;/p>
&lt;p>根据JIRA的管理系统的划分，bug 只是问题的一种，它可以用于跟踪多种不同类型的问题（其实，他只是将bug做为一子类而已）。&lt;/p>
&lt;p>JIRA系统缺省提供的问题类型（大部分的系统都可以自定义类型的，这样就增加了灵活性。）&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Bug : 测试过程、维护过程发现影响系统运行的缺陷。（这就是一般测试人员所提交的bug）&lt;/p>
&lt;/li>
&lt;li>
&lt;p>New Feature : 对系统提出的新功能。（单个的小需求可以，如果大的话，就相当于一个需求，放到这里是不合理的。）&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Task : 需要完成的一任务。（开发或测试任务指派。）&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Improvement : 对现有系统功能的改进。（一般产品经理或产品体验师做的事）&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>当然，不同的公司，他们的人员定位与职责是不太相同的，按照上面的分类，JIRA就不是简单的缺陷管理系统了，它涵盖一项目（或产品）所需要处理的任务、需求与缺陷。&lt;/p>
&lt;p>&lt;strong>Bug 类型&lt;/strong>&lt;/p>
&lt;p>这里缩小范围，单指我们测试人员在测试过程中发现的缺陷，发现产品缺陷其实就是测试人员工作的主要目的。当然，你要确定一个问题的类型，也需要对项目（或产品）有比较深的理解。是代码缺陷还是设计缺陷有时候就不太容易区分，当然，这个划分，对于开发定位问题影响很小，但对于问题类型的统计就比较重要了。&lt;/p>
&lt;p>下面看一些常见的分类：&lt;/p>
&lt;p>划分方式一：&lt;/p>
&lt;pre tabindex="0">&lt;code>　　* 代码错误

　　* 设计缺陷

　　* 界面优化

　　* 配置相关

　　* 安装部署

 * 性能问题

　　* 标准规范

　　* 测试代码

　　* 其它
&lt;/code>&lt;/pre>&lt;p>划分方式二：&lt;/p>
&lt;pre tabindex="0">&lt;code>　　* 功能类（function）

　　* 性能类（performance）

　　* 界面类（UI）

　　* 易用性类（usability）

　　* 兼容性类（compatibility）

　　* 其它（else）
&lt;/code>&lt;/pre>&lt;p>这个分类当然是可以自定义的，具我接触的缺陷管理都是可以自定义的，既然是对问题的管理，那么你当然可以拿来做特定环境下的系统来使用，或我就想用这个系统来指派任务，那么我的自定义类型为前端任务、后端任务、测试任务、配置部署&amp;hellip;&lt;/p></description></item><item><title>wrk系列教程(4)常用参数</title><link>https://itest2025.pages.dev/tutorials/15-004-wrk%E7%B3%BB%E5%88%97%E6%95%99%E7%A8%8B4%E5%B8%B8%E7%94%A8%E5%8F%82%E6%95%B0/</link><pubDate>Sun, 03 Mar 2019 02:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/15-004-wrk%E7%B3%BB%E5%88%97%E6%95%99%E7%A8%8B4%E5%B8%B8%E7%94%A8%E5%8F%82%E6%95%B0/</guid><description>&lt;p>这一节我们看一下wrk常用的命令行参数。&lt;/p>
&lt;pre tabindex="0">&lt;code>-c, --connections: HTTP连接数的总量。对于每一个线程，保持的连接数N
 N = connections/threads

-d, --duration: 测试运行时间, e.g. 2s, 2m, 2h

-t, --threads: 总的线程数

-s, --script: lua脚本，后面会讲

-H, --header: 设置请求的HTTP header, e.g. &amp;#34;User-Agent: wrk&amp;#34;

 --latency: 打印详细的时延统计

 --timeout: 如果请求的timeout的时间内没有响应，那么就记录1个timeout
&lt;/code>&lt;/pre>&lt;h3 id="具体例子">具体例子&lt;/h3>
&lt;p>10个线程100个连接跑1个小时&lt;/p>
&lt;pre tabindex="0">&lt;code>wrk -t10 -c100 -d1h www.example.com
&lt;/code>&lt;/pre>&lt;p>10个线程100个连接跑1个小时，请求的响应超时时间设置为1s&lt;/p>
&lt;pre tabindex="0">&lt;code>wrk -t10 -c100 -d1h --timeout=1s www.example.com
&lt;/code>&lt;/pre>&lt;p>模拟ios上的safari浏览器 10个线程100个连接跑1个小时&lt;/p>
&lt;pre tabindex="0">&lt;code>wrk -t10 -c100 -d1h --header=&amp;#34;User-agent: Mozilla/5.0 (iPhone; CPU iPhone OS 11_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Mobile/15E148 Safari/604.1&amp;#34; www.example.com
&lt;/code>&lt;/pre>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1511452885600-a3d2c9148a31?w=300"
 data-srcset="https://images.unsplash.com/photo-1511452885600-a3d2c9148a31?w=300, https://images.unsplash.com/photo-1511452885600-a3d2c9148a31?w=300 1.5x, https://images.unsplash.com/photo-1511452885600-a3d2c9148a31?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1511452885600-a3d2c9148a31?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>python简明教程: 4. 函数</title><link>https://itest2025.pages.dev/tutorials/39-004-python%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B-4-%E5%87%BD%E6%95%B0/</link><pubDate>Mon, 19 Nov 2018 03:23:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/39-004-python%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B-4-%E5%87%BD%E6%95%B0/</guid><description>&lt;p>本文内容基本上翻译自&lt;a href="http://cheat.sh/python/:learn" target="_blank" rel="noopener noreffer ">http://cheat.sh/python/:learn)&lt;/a>&lt;/p>
&lt;p>&lt;strong>非原创, 非原创, 非原创!!!&lt;/strong>&lt;/p>
&lt;p>感谢原文社区作者&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">####################################################&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 4. 函数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">####################################################&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 用&amp;#34;def&amp;#34; 来定义函数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span> &lt;span class="s2">&amp;#34;x is &lt;/span>&lt;span class="si">{0}&lt;/span>&lt;span class="s2"> and y is &lt;/span>&lt;span class="si">{1}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">y&lt;/span> &lt;span class="c1"># 用return语句来从函数中返回具体的值&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 调用函数并传入参数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">6&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; 打印出 &amp;#34;x is 5 and y is 6&amp;#34; 并返回 11&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 另一种调用函数的方式，使用关键字参数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">6&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 使用关键字参数的话，参数出现的顺序是可以随意的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 可以定义不定长的固定位置参数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 使用 * 加参数名的形式&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 参数将被解析成元组&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">varargs&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">args&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">varargs&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; (1, 2, 3)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 可以定义不定长的关键字参数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 使用 * 加参数名的形式&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 参数将被解析成字典&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">keyword_args&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="n">kwargs&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">kwargs&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 调用一下看会发生什么&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">keyword_args&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">big&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;foot&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">loch&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;ness&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; {&amp;#34;big&amp;#34;: &amp;#34;foot&amp;#34;, &amp;#34;loch&amp;#34;: &amp;#34;ness&amp;#34;}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 也可以将两种方式结合起来使用&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">all_the_args&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">**&lt;/span>&lt;span class="n">kwargs&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span> &lt;span class="n">args&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span> &lt;span class="n">kwargs&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">all_the_args(1, 2, a=3, b=4) prints:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> (1, 2)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> {&amp;#34;a&amp;#34;: 3, &amp;#34;b&amp;#34;: 4}
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 调用函数的时候其实就是对args/kwargs做反向操作&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 使用 * 来展开固定位置参数args, 使用 ** 去展开关键字参数kwargs&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">args&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">kwargs&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;a&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;b&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">all_the_args&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 等于是调用了 foo(1, 2, 3, 4)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">all_the_args&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="n">kwargs&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 等于 foo(a=3, b=4)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">all_the_args&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">**&lt;/span>&lt;span class="n">kwargs&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 等于 foo(1, 2, 3, 4, a=3, b=4)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 你可以将函数参数里的args/kwargs传到其他函数里去&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 分别使用 * 和 **&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">pass_all_the_args&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">**&lt;/span>&lt;span class="n">kwargs&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">all_the_args&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">**&lt;/span>&lt;span class="n">kwargs&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span> &lt;span class="n">varargs&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span> &lt;span class="n">keyword_args&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="n">kwargs&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 函数作用域&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">5&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">set_x&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 本地变量x跟全局变量x的值是不一样的，尽管同名&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="c1"># =&amp;gt; 43&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="c1"># =&amp;gt; 43&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">set_global_x&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">global&lt;/span> &lt;span class="n">x&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="c1"># =&amp;gt; 5&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="c1"># 全局变量 x 现在被设为 6&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="c1"># =&amp;gt; 6&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">set_x&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">43&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">set_global_x&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">6&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Python has first class functions&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">create_adder&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">adder&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">y&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">adder&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">add_10&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">create_adder&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">add_10&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; 13&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 这是匿名函数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="k">lambda&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)(&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="k">lambda&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">**&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">y&lt;/span> &lt;span class="o">**&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; 5&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 这是内置的高阶函数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">add_10&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">])&lt;/span> &lt;span class="c1"># =&amp;gt; [11, 12, 13]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">max&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">])&lt;/span> &lt;span class="c1"># =&amp;gt; [4, 2, 3]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">filter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">lambda&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">6&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">7&lt;/span>&lt;span class="p">])&lt;/span> &lt;span class="c1"># =&amp;gt; [6, 7]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 可以使用列表表达式去实现优雅的maps和filters&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="n">add_10&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">]]&lt;/span> &lt;span class="c1"># =&amp;gt; [11, 12, 13]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">6&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">7&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># =&amp;gt; [6, 7]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 也可以用字典表达式来构造集合和字典&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="s1">&amp;#39;abcddeef&amp;#39;&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="s1">&amp;#39;abc&amp;#39;&lt;/span>&lt;span class="p">}&lt;/span> &lt;span class="c1"># =&amp;gt; {&amp;#39;a&amp;#39;, &amp;#39;b&amp;#39;, &amp;#39;c&amp;#39;}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">**&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="p">)}&lt;/span> &lt;span class="c1"># =&amp;gt; {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p></description></item><item><title>（四）Docker 容器</title><link>https://itest2025.pages.dev/tutorials/30-004-%E5%9B%9Bdocker-%E5%AE%B9%E5%99%A8/</link><pubDate>Mon, 22 Jan 2018 14:42:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/30-004-%E5%9B%9Bdocker-%E5%AE%B9%E5%99%A8/</guid><description>&lt;p>简单的说，容器是独立运行的一个或一组应用，以及它们的运行态环境。 如果把镜像看成面向对象中的 &lt;strong>类&lt;/strong> 的话，那么容器就是 类 的实例化 &lt;strong>对象&lt;/strong>。&lt;/p>
&lt;h4 id="容器">容器&lt;/h4>
&lt;hr>
&lt;h5 id="启动容器">启动容器&lt;/h5>
&lt;p>启动容器有两种方式，一种是基于镜像新建一个容器并启动， 另外一个是将在终止状态（stopped）的容器重新启动。&lt;/p>
&lt;p>通过&lt;code>docker run&lt;/code> 命令来启动容器。&lt;/p>
&lt;p>查看运行帮助：&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo docker run --help
&lt;/code>&lt;/pre>&lt;p>下面的命令输出一个	“Hello	World”，之后终止容器。&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo docker run ubuntu /bin/echo &amp;#34;hello world&amp;#34;
hello world
&lt;/code>&lt;/pre>&lt;p>这跟在本地直接执行 &lt;code>/bin/echo	'hello	world'&lt;/code>几乎感觉不出任何区别。只不过，这里的输入是由通过 ubuntu 容器执行。&lt;/p>
&lt;p>下面进入到ubuntu容器中。&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo docker run -t -i ubuntu /bin/bash
root@543a324ea841:/#
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>
&lt;p>-t	选项让Docker分配一个伪终端（pseudo-tty）并绑定到容器的标准输入上。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>-i	则让容器的标准输入保持打开。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>此时，你已经在ubuntu容器中了。这是一个独立的ubuntu 系统。通过 &lt;strong>root@543a324ea841&lt;/strong> 标识可以看出。&lt;/p>
&lt;p>当利用&lt;code>docker run&lt;/code>	来创建容器时，Docker在后台运行的标准操作包括：&lt;/p>
&lt;ul>
&lt;li>检查本地是否存在指定的镜像，不存在就从公有仓库下载&lt;/li>
&lt;li>利用镜像创建并启动一个容器&lt;/li>
&lt;li>分配一个文件系统，并在只读的镜像层外面挂载一层可读写层&lt;/li>
&lt;li>从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去&lt;/li>
&lt;li>从地址池配置一个IP地址给容器&lt;/li>
&lt;li>执行用户指定的应用程序&lt;/li>
&lt;li>执行完毕后容器被终止&lt;/li>
&lt;/ul>
&lt;p>退出容器，可以使用exit命令。&lt;/p>
&lt;pre tabindex="0">&lt;code>root@543a324ea841:/# exit 
exit
fnngj@ubuntu:~$
&lt;/code>&lt;/pre>&lt;h5 id="守护状态运行">守护状态运行&lt;/h5>
&lt;p>更多的时候，需要让	Docker容器在后台以守护态（Daemonized）形式运行。&lt;/p></description></item><item><title>（四）Java的三种基本结构</title><link>https://itest2025.pages.dev/tutorials/16-004-%E5%9B%9Bjava%E7%9A%84%E4%B8%89%E7%A7%8D%E5%9F%BA%E6%9C%AC%E7%BB%93%E6%9E%84/</link><pubDate>Wed, 17 Jan 2018 14:40:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/16-004-%E5%9B%9Bjava%E7%9A%84%E4%B8%89%E7%A7%8D%E5%9F%BA%E6%9C%AC%E7%BB%93%E6%9E%84/</guid><description>&lt;p>结构化编程的三种基本结构？你可能会犹豫一下，它们分别是：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>顺序结构&lt;/p>
&lt;/li>
&lt;li>
&lt;p>分支结构&lt;/p>
&lt;/li>
&lt;li>
&lt;p>循环结构&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>大学学过 C 语言的同学一下就明白了，具我接触过的编程语言都提供的了这三种基本结构，不管是面向过程的编程语言，还是面向对象的编程语言。&lt;/p>
&lt;p>&lt;strong>顺序结构&lt;/strong> 表示程序中的各操作是按照它们出现的先后顺序执行的。&lt;/p>
&lt;p>&lt;strong>分支结构&lt;/strong> 表示程序的处理步骤出现了分支，它需要根据某一特定的条件选择其中的一个分支执行。&lt;/p>
&lt;p>&lt;strong>循环结构&lt;/strong> 表示程序反复执行某个或某些操作，直到某条件为假（或为真）时才可终止循环。&lt;/p>
&lt;h4 id="分支与循环例子">分支与循环例子&lt;/h4>
&lt;hr>
&lt;ul>
&lt;li>求数的阶乘，如下：&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>0！=1
1！=1
2！=2×1=2
3！=3×2×1=6
&lt;/code>&lt;/pre>&lt;p>实现代码如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">JavaStructure&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 计算10人的阶乘&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">number&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">10&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 0和1的阶乘都为1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">number&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">==&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">0&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">||&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">number&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">==&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="k">else&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//循环累乘 10&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">count&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">number&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">0&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="o">--&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">count&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">*=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">count&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>打印一个三角形，如下：&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>
 *
 ***
 *****
 *******
*********
&lt;/code>&lt;/pre>&lt;p>实现代码如下：&lt;/p></description></item><item><title>TDD实战（四）“井字游戏” 需求三</title><link>https://itest2025.pages.dev/tutorials/32-004-tdd%E5%AE%9E%E6%88%98%E5%9B%9B%E4%BA%95%E5%AD%97%E6%B8%B8%E6%88%8F-%E9%9C%80%E6%B1%82%E4%B8%89/</link><pubDate>Mon, 08 Jan 2018 12:50:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/32-004-tdd%E5%AE%9E%E6%88%98%E5%9B%9B%E4%BA%95%E5%AD%97%E6%B8%B8%E6%88%8F-%E9%9C%80%E6%B1%82%E4%B8%89/</guid><description>&lt;h3 id="需求3">需求3&lt;/h3>
&lt;hr>
&lt;p>现在考虑这个游戏的获胜规则，这部分工作会比较麻烦。我们必须检查所可能获胜的情况，只要满足其中一个，就宣布相应玩家获胜。&lt;/p>
&lt;blockquote>
&lt;p>最先在水平、锤直或对角线上将自己的3个标记连起来的玩家获胜。&lt;/p>&lt;/blockquote>
&lt;h4 id="测试用例1">测试用例1&lt;/h4>
&lt;hr>
&lt;p>首先定义&lt;code>play()&lt;/code> 的默认返回值：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">whenPlayThenNoWinner&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">actual&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ticTacToe&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">play&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;No winner&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">actual&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果不满足获胜条件，则无人获胜。&lt;/p>
&lt;h5 id="实现代码1">实现代码1&lt;/h5>
&lt;p>这个用例很容易满足，修改 &lt;code>play()&lt;/code> 方法如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">play&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">checkAxis&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">checkAxis&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">setBox&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">lastPlayer&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">nextPlayer&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">return&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;No winner&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>** &lt;strong>执行 测试用例1 检查它是否运行通过。&lt;/strong>&lt;/p>
&lt;h4 id="测试用例2">测试用例2&lt;/h4>
&lt;hr>
&lt;p>处理各种获胜条件。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">whenPlayAndWholeHorizontalLineThenWinner&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">ticTacToe&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">play&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//X&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">ticTacToe&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">play&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//O&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">ticTacToe&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">play&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//X&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">ticTacToe&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">play&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//O&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">actual&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ticTacToe&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">play&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">3&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//X&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;X is the winner&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">actual&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>X 玩家最新占满一条水平线，所以 X 玩家获胜。&lt;/p></description></item><item><title>Android测试（四）：Local 单元测试</title><link>https://itest2025.pages.dev/tutorials/17-004-android%E6%B5%8B%E8%AF%95%E5%9B%9Blocal-%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/</link><pubDate>Wed, 20 Dec 2017 14:40:12 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/17-004-android%E6%B5%8B%E8%AF%95%E5%9B%9Blocal-%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/</guid><description>&lt;p>原文：https://developer.android.com/training/testing/unit-testing/local-unit-tests.html&lt;/p>
&lt;p>如果你的单元测试没有依赖或者只有简单的Android依赖，则应该在本地开发机器上运行测试。这种测试方法非常高效，因为它可以帮助你避免每次运行测试时将目标应用程序和单元测试代码加载到真机或模拟器上的开销。因此，运行单元测试的执行时间大大减少了。通过这种方法，你通常使用mock框架（如Mockito）来完成任何依赖关系。&lt;/p>
&lt;h4 id="设置测试环境">设置测试环境&lt;/h4>
&lt;hr>
&lt;p>在你的Android Studio项目中，必须将本地单元测试的源文件存储在module-name/src/test/java/ 目录中。在创建新项目时，该目录已经存在。&lt;/p>
&lt;p>你还需要配置项目的测试依赖，以使用JUnit 4框架提供的标准API。如果你的测试需要与Android依赖关系进行交互，请包含Mockito库以简化本地单元测试。要了解有关在本地单元测试中使用模拟对象的更多信息，请参阅模拟Android依赖关系。&lt;/p>
&lt;p>在你的App程序的目录下找到build.gradle文件中，将这些库指定为依赖项：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">dependencies&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">    &lt;/span>&lt;span class="c1">// Required -- JUnit 4 framework&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">    &lt;/span>&lt;span class="n">testCompile&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">junit&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">junit&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">4&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">12&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">    &lt;/span>&lt;span class="c1">// Optional -- Mockito framework&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">    &lt;/span>&lt;span class="n">testCompile&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">org&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">mockito&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">mockito&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">core&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">10&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">19&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="创建本地单元测试类">创建本地单元测试类&lt;/h4>
&lt;hr>
&lt;p>你的本地单元测试类应该写成一个JUnit 4测试类。 JUnit是Java最流行和广泛使用的单元测试框架。这个框架的最新版本，JUnit 4，允许你用比前一版本更清晰，更灵活的方式编写测试。与以前的基于JUnit 3的Android单元测试方法（使用JUnit 4）不同，你不需要扩展junit.framework.TestCase类。也不需要在测试方法名称前加上“test”关键字，或者使用junit.framework或junit.extensions包中的任何类。&lt;/p>
&lt;p>要创建基本的JUnit 4测试类，请创建一个包含一个或多个测试方法的Java类。 测试方法从&lt;code>@Test&lt;/code>注释开始，包含代码来练习和验证要测试的组件中的单个功能。&lt;/p>
&lt;p>以下示例显示了如何实现本地单元测试类。 测试方法&lt;code>emailValidator_CorrectEmailSimple_ReturnsTrue&lt;/code>验证被测试的应用程序中的&lt;code>isValidEmail()&lt;/code>方法是否返回正确的结果。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.Test&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">java.util.regex.Pattern&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.Assert.assertFalse&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.Assert.assertTrue&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">EmailValidatorTest&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">    &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">    &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">emailValidator_CorrectEmailSimple_ReturnsTrue&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">        &lt;/span>&lt;span class="n">assertThat&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">EmailValidator&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">isValidEmail&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;name@email.com&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">is&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="p">));&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">    &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">    &lt;/span>&lt;span class="p">...&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>要测试应用程序中的组件是否会返回预期的结果，请使用junit.Assert方法执行验证检查（或断言），以便将待测组件的状态与某个预期值进行比较。 为了使测试更具可读性，可以使用Hamcrest匹配器（如is（）和equalTo（）方法）将返回的结果与期望的结果进行匹配。&lt;/p></description></item><item><title>Fiddler（四）设置代理 HTTPS 请求</title><link>https://itest2025.pages.dev/tutorials/23-004-fiddler%E5%9B%9B%E8%AE%BE%E7%BD%AE%E4%BB%A3%E7%90%86-https-%E8%AF%B7%E6%B1%82/</link><pubDate>Tue, 19 Dec 2017 13:50:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/23-004-fiddler%E5%9B%9B%E8%AE%BE%E7%BD%AE%E4%BB%A3%E7%90%86-https-%E8%AF%B7%E6%B1%82/</guid><description>&lt;h4 id="https-介绍">HTTPS 介绍&lt;/h4>
&lt;hr>
&lt;p>HTTPS（全称：Hyper Text Transfer Protocol over Secure Socket Layer），是以安全为目标的HTTP通道，简单讲是HTTP的安全版。&lt;/p>
&lt;p>HTTPS在HTTP的基础上加入了SSL协议，SSL依靠证书来验证服务器的身份，并为浏览器和服务器之间的通信加密。&lt;/p>
&lt;p>HTTPS和HTTP的区别主要为以下四点：&lt;/p>
&lt;p>一、https协议需要到ca申请证书，一般免费证书很少，需要交费。&lt;/p>
&lt;p>二、http是超文本传输协议，信息是明文传输，https 则是具有安全性的ssl加密传输协议。&lt;/p>
&lt;p>三、http和https使用的是完全不同的连接方式，用的端口也不一样，前者是80，后者是443。&lt;/p>
&lt;p>四、http的连接很简单，是无状态的；HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议，比http协议安全。&lt;/p>
&lt;h4 id="fiddler设置https代理">Fiddler设置HTTPS代理&lt;/h4>
&lt;hr>
&lt;p>1、打开Fiddler，菜单栏：&lt;strong>Tools –&amp;gt; Fiddler Options&lt;/strong> 打开fiddler配置。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/fiddler_06_1.png"
 data-srcset="http://img.testclass.net/fiddler_06_1.png, http://img.testclass.net/fiddler_06_1.png 1.5x, http://img.testclass.net/fiddler_06_1.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/fiddler_06_1.png"
 title="http://img.testclass.net/fiddler_06_1.png" />&lt;/p>
&lt;p>2、打开 HTTPS 配置项，勾选“&lt;strong>Capture HTTPS CONNECTs&lt;/strong>”和“&lt;strong>Decrypt HTTPS traffic&lt;/strong>”，然后点击“OK”。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/fiddler_06_2.png"
 data-srcset="http://img.testclass.net/fiddler_06_2.png, http://img.testclass.net/fiddler_06_2.png 1.5x, http://img.testclass.net/fiddler_06_2.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/fiddler_06_2.png"
 title="http://img.testclass.net/fiddler_06_2.png" />&lt;/p>
&lt;p>重启Fiddler，就可以实现HTTPS请求的代理了。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1459504346581-19d0b0a889dc?w=300"
 data-srcset="https://images.unsplash.com/photo-1459504346581-19d0b0a889dc?w=300, https://images.unsplash.com/photo-1459504346581-19d0b0a889dc?w=300 1.5x, https://images.unsplash.com/photo-1459504346581-19d0b0a889dc?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1459504346581-19d0b0a889dc?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>层级遍历:获取所有的热门主题</title><link>https://itest2025.pages.dev/tutorials/27-004-%E5%B1%82%E7%BA%A7%E9%81%8D%E5%8E%86%E8%8E%B7%E5%8F%96%E6%89%80%E6%9C%89%E7%9A%84%E7%83%AD%E9%97%A8%E4%B8%BB%E9%A2%98/</link><pubDate>Fri, 15 Dec 2017 02:52:34 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/27-004-%E5%B1%82%E7%BA%A7%E9%81%8D%E5%8E%86%E8%8E%B7%E5%8F%96%E6%89%80%E6%9C%89%E7%9A%84%E7%83%AD%E9%97%A8%E4%B8%BB%E9%A2%98/</guid><description>&lt;h3 id="稍微复杂一点的例子">稍微复杂一点的例子&lt;/h3>
&lt;p>在&lt;a href="https://www.v2ex.com/" target="_blank" rel="noopener noreffer ">v2ex&lt;/a>主页的右侧一般有个最热主题区域，里面列出了当日的热门讨论话题。这一节里我们就尝试使用爬虫技术获取这些热门主题文本和链接。&lt;/p>
&lt;p>&lt;strong>注意：v2ex本身提供了接口去获取这些热门主题的详细信息，本节内容只是举例，并不是最佳实践&lt;/strong>&lt;/p>
&lt;p>具体步骤&lt;/p>
&lt;ul>
&lt;li>访问v2ex主页，获取html文本&lt;/li>
&lt;li>分析html文本，找出待获取内容的特征&lt;/li>
&lt;li>解析html代码，根据特征拿出目标内容&lt;/li>
&lt;li>打印这些内容&lt;/li>
&lt;/ul>
&lt;h3 id="分析html代码">分析html代码&lt;/h3>
&lt;p>热门内容部分的html代码如下所示&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">span&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;item_hot_topic_title&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">a&lt;/span> &lt;span class="na">href&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;/t/415664&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>冬天了，身上静电咋处理？&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">a&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">span&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>可以看出我们要找到的是所有class=item_hot_topic_title的span下面的a元素&lt;/p>
&lt;h3 id="代码">代码&lt;/h3>
&lt;p>新建名为&lt;code>v2ex_hosts.py&lt;/code>的文件，输入下面的内容&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">requests&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">bs4&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">BeautifulSoup&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">url&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;https://www.v2ex.com/&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">soup&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">BeautifulSoup&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">requests&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;html.parser&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">span&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">soup&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_all&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;span&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">class_&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;item_hot_topic_title&amp;#39;&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">span&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;a&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">span&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;a&amp;#39;&lt;/span>&lt;span class="p">)[&lt;/span>&lt;span class="s1">&amp;#39;href&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行">运行&lt;/h3>
&lt;p>在命令行中输入&lt;/p>
&lt;pre tabindex="0">&lt;code>python v2ex_hosts.py
&lt;/code>&lt;/pre>&lt;h3 id="预期结果">预期结果&lt;/h3>
&lt;p>如果一切正常，那么应该可以看到&lt;strong>类似&lt;/strong>下面的结果，由于每天的热门主题不一样，所以内容是会变化的&lt;/p>
&lt;pre tabindex="0">&lt;code>小米感恩节不感恩 /t/415623
冬天了，身上静电咋处理？ /t/415664
违反一下政治正确，骂一下 Google /t/415600
做了将近 6 年程序员，没能成为大牛，考虑再三，决定改行，大家说，做点什么好呢？ /t/415701
结果还是被雷猴王给套路了 /t/415843
一直很好奇 Mac+安卓的组合是基于什么优势考虑的呢？ /t/415645
听说比特币要分叉了？ /t/415858
看到大学同学朋友圈发的北大成人通知书，心里不是滋味。 /t/415821
当码农 8 年了，要不要去读个研 /t/415854
新进一家公司遭遇的待遇~~ /t/415863
&lt;/code>&lt;/pre>&lt;h3 id="我们可以学到什么">我们可以学到什么&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>&lt;code>for span in soup.find_all('span', class_='item_hot_topic_title')&lt;/code>: 遍历所有的class=item_hot_topic_title的span。注意是&lt;code>class_&lt;/code>，不是&lt;code>class&lt;/code>，因为class是python的关键字，所以后面要加个尾巴，防止冲突&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>span.find('a').text&lt;/code>：层级遍历，先找到span，再从span下找到a，这是常用套路&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>span.find('a')['href']&lt;/code>：获取href属性，在bs4里，我们可以通过&lt;code>[attribute_name]&lt;/code>的方式来获取元素的属性&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="阅读内容">阅读内容&lt;/h3>
&lt;p>BeautifulSoup&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.crummy.com/software/BeautifulSoup/bs4/doc/#find-all" target="_blank" rel="noopener noreffer ">find_all&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.crummy.com/software/BeautifulSoup/bs4/doc/#find" target="_blank" rel="noopener noreffer ">find&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.crummy.com/software/BeautifulSoup/bs4/doc/#css-selectors" target="_blank" rel="noopener noreffer ">css_selector&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.crummy.com/software/BeautifulSoup/bs4/doc/#attributes" target="_blank" rel="noopener noreffer ">attributes&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p></description></item><item><title>（四）参数匹配器 (matchers)</title><link>https://itest2025.pages.dev/tutorials/45-004-%E5%9B%9B%E5%8F%82%E6%95%B0%E5%8C%B9%E9%85%8D%E5%99%A8-matchers/</link><pubDate>Sat, 25 Nov 2017 12:50:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/45-004-%E5%9B%9B%E5%8F%82%E6%95%B0%E5%8C%B9%E9%85%8D%E5%99%A8-matchers/</guid><description>&lt;h4 id="参数匹配器-matchers">参数匹配器 (matchers)&lt;/h4>
&lt;hr>
&lt;p>Mockito以自然的java风格来验证参数值: 使用equals()函数。有时，当需要额外的灵活性时你可能需要使用参数匹配器，也就是argument matchers :
例子&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.Test&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">java.util.LinkedList&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.mockito.Mockito.*&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">MockitoDemo&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">with_arguments&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">LinkedList&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">mock&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">LinkedList&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">class&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//stubbing using built-in anyInt() argument matcher&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 使用内置的anyInt()参数匹配器&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">when&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">anyInt&lt;/span>&lt;span class="p">())).&lt;/span>&lt;span class="na">thenReturn&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;element&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//following prints &amp;#34;element&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 输出element&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">));&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//you can also verify using an argument matcher&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 你也可以验证参数匹配器&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">verify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">anyInt&lt;/span>&lt;span class="p">());&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>参数匹配器使验证和测试桩变得更灵活。&lt;a href="http://site.mockito.org/mockito/docs/current/org/mockito/Matchers.html" target="_blank" rel="noopener noreffer ">点击这里&lt;/a>查看更多内置的匹配器以及自定义参数匹配器或者hamcrest 匹配器的示例。&lt;/p></description></item><item><title>（四）testng.xml文件解析</title><link>https://itest2025.pages.dev/tutorials/36-004-%E5%9B%9Btestngxml%E6%96%87%E4%BB%B6%E8%A7%A3%E6%9E%90/</link><pubDate>Sat, 25 Nov 2017 12:45:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/36-004-%E5%9B%9Btestngxml%E6%96%87%E4%BB%B6%E8%A7%A3%E6%9E%90/</guid><description>&lt;p>TestNG 与 Junit 比较大的一个差异就是前者通过 testng.xml 文件来配置测试用例的执行。 testng.xml文件可以很好的控制要执行的测试用例的粒度，及各种运行策略。&lt;/p>
&lt;p>目前testng.xml DTD（Document Type Definition; DTD是一种XML的约束方式。） 配置说明可以在：&lt;a href="http://testng.org/testng-1.0.dtd.php" target="_blank" rel="noopener noreffer ">这里&lt;/a>&lt;/p>
&lt;h4 id="testngmxl-文件解析">testng.mxl 文件解析&lt;/h4>
&lt;hr>
&lt;pre tabindex="0">&lt;code>&amp;lt;suite name=&amp;#34;Suite1&amp;#34; verbose=&amp;#34;1&amp;#34; &amp;gt;
 &amp;lt;test name=&amp;#34;Nopackage&amp;#34; &amp;gt;
 &amp;lt;classes&amp;gt;
 &amp;lt;class name=&amp;#34;NoPackageTest&amp;#34; /&amp;gt;
 &amp;lt;/classes&amp;gt;
 &amp;lt;/test&amp;gt;

 &amp;lt;test name=&amp;#34;Regression1&amp;#34;&amp;gt;
 &amp;lt;classes&amp;gt;
 &amp;lt;class name=&amp;#34;test.sample.ParameterSample&amp;#34;/&amp;gt;
 &amp;lt;class name=&amp;#34;test.sample.ParameterTest&amp;#34;/&amp;gt;
 &amp;lt;/classes&amp;gt;
 &amp;lt;/test&amp;gt;
&amp;lt;/suite&amp;gt;
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>&lt;code>&amp;lt;suite&amp;gt;...&amp;lt;/suite&amp;gt;&lt;/code> 表示定义了的一个测试套件。
&lt;ul>
&lt;li>name 定义测试套件的名称。&lt;/li>
&lt;li>verbose 定义命令行信息打印等级，不会影响测试报告输出内容；可选值(1|2|3|4|5) &lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;code>&amp;lt;test&amp;gt;...&amp;lt;/test&amp;gt;&lt;/code> 表示定义了一个测试。
&lt;ul>
&lt;li>name 定义测试的名称。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;code>&amp;lt;classes&amp;gt;...&amp;lt;/classes&amp;gt;&lt;/code> 表示定义一组测试类。&lt;/li>
&lt;li>&lt;code>&amp;lt;class .../&amp;gt;&lt;/code> 表示定义一个测试类。
&lt;ul>
&lt;li>name 指定要运行的测试类&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h4 id="实例">实例&lt;/h4>
&lt;hr>
&lt;p>测试项目目录结果如下：&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/testng_project.png"
 data-srcset="http://img.testclass.net/testng_project.png, http://img.testclass.net/testng_project.png 1.5x, http://img.testclass.net/testng_project.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/testng_project.png"
 title="http://img.testclass.net/testng_project.png" />&lt;/p>
&lt;p>testng.mxl 配置文件如下：&lt;/p></description></item><item><title>（四）通过 mvn 命令创建 Maven 项目</title><link>https://itest2025.pages.dev/tutorials/41-004-%E5%9B%9B%E9%80%9A%E8%BF%87-mvn-%E5%91%BD%E4%BB%A4%E5%88%9B%E5%BB%BA-maven-%E9%A1%B9%E7%9B%AE/</link><pubDate>Sat, 25 Nov 2017 12:40:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/41-004-%E5%9B%9B%E9%80%9A%E8%BF%87-mvn-%E5%91%BD%E4%BB%A4%E5%88%9B%E5%BB%BA-maven-%E9%A1%B9%E7%9B%AE/</guid><description>&lt;h4 id="通过-mvn-命令创建项目">通过 mvn 命令创建项目&lt;/h4>
&lt;hr>
&lt;p>Maven官方文档：&lt;a href="https://maven.apache.org/guides/getting-started/" target="_blank" rel="noopener noreffer ">Maven Getting Started Guide&lt;/a>&lt;/p>
&lt;p>通过 mvn 命令创建一个 Maven 项目。&lt;/p>
&lt;pre tabindex="0">&lt;code>mvn -B archetype:generate \
 -DarchetypeGroupId=org.apache.maven.archetypes \
 -DgroupId=com.mycompany.app \
 -DartifactId=my-app
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>
&lt;p>-B ：该参数表示让Maven使用批处理模式构建项目，能够避免一些需要人工参与交互而造成的挂起状态。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>archetype:generate : 创建 Maven 项目的命令。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>DarchetypeGroupId ： 指定 Apache maven 组织名。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>DgroupId ： 指定项目或公司组名。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>DartifactId ：指定项目名。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>例如：&lt;/p>
&lt;blockquote>
&lt;p>mvn -B archetype:generate -DgroupId=com.myapp.pro -DartifactId=myapp -DarchetypeArtifactId==maven-archetype-quickstart -DinteractiveMode=false&lt;/p>&lt;/blockquote>
&lt;p>将，该命令复制到 Windows 命令提示符（Linux 终端）下执行。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/maven_create_project.png"
 data-srcset="http://img.testclass.net/maven_create_project.png, http://img.testclass.net/maven_create_project.png 1.5x, http://img.testclass.net/maven_create_project.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/maven_create_project.png"
 title="http://img.testclass.net/maven_create_project.png" />&lt;/p>
&lt;p>继续通过&lt;code>mvn idea:idea&lt;/code>命令生成 IntelliJ IDEA 项目工程。&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt; cd myapp\

..\myapp&amp;gt; mvn idea:idea
&lt;/code>&lt;/pre>&lt;p>然后，通过 &lt;a href="https://itest2025.pages.dev/idea/" rel="">IntelliJ-IDEA&lt;/a> 打开 &lt;strong>myapp&lt;/strong> 项目。&lt;/p></description></item><item><title>requests如何发送其他请求</title><link>https://itest2025.pages.dev/tutorials/42-004-requests%E5%A6%82%E4%BD%95%E5%8F%91%E9%80%81%E5%85%B6%E4%BB%96%E8%AF%B7%E6%B1%82/</link><pubDate>Wed, 22 Nov 2017 03:23:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/42-004-requests%E5%A6%82%E4%BD%95%E5%8F%91%E9%80%81%E5%85%B6%E4%BB%96%E8%AF%B7%E6%B1%82/</guid><description>&lt;p>&lt;a href="http://docs.python-requests.org/en/master/user/quickstart/#make-a-request" target="_blank" rel="noopener noreffer ">官方文档&lt;/a>&lt;/p>
&lt;p>delete,options,put等类型的请求在requests中均有对应的方法&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; r = requests.put(&amp;#39;http://httpbin.org/put&amp;#39;, data = {&amp;#39;key&amp;#39;:&amp;#39;value&amp;#39;})
&amp;gt;&amp;gt;&amp;gt; r = requests.delete(&amp;#39;http://httpbin.org/delete&amp;#39;)
&amp;gt;&amp;gt;&amp;gt; r = requests.head(&amp;#39;http://httpbin.org/get&amp;#39;)
&amp;gt;&amp;gt;&amp;gt; r = requests.options(&amp;#39;http://httpbin.org/get&amp;#39;)
&lt;/code>&lt;/pre>&lt;p>也可以使用requests统一的request方法来发送各种请求&lt;/p>
&lt;pre tabindex="0">&lt;code>r = requests.request(&amp;#39;get&amp;#39;, &amp;#39;https://api.github.com/events&amp;#39;)
&amp;gt;&amp;gt;&amp;gt; r = requests.request(&amp;#39;post&amp;#39;, &amp;#39;http://httpbin.org/post&amp;#39;, data = {&amp;#39;key&amp;#39;:&amp;#39;value&amp;#39;})
&amp;gt;&amp;gt;&amp;gt; r = requests.request(&amp;#39;put&amp;#39;, &amp;#39;http://httpbin.org/put&amp;#39;, data = {&amp;#39;key&amp;#39;:&amp;#39;value&amp;#39;})
&amp;gt;&amp;gt;&amp;gt; r = requests.request(&amp;#39;delete&amp;#39;, &amp;#39;http://httpbin.org/delete&amp;#39;)
&amp;gt;&amp;gt;&amp;gt; r = requests.request(&amp;#39;head&amp;#39;, &amp;#39;http://httpbin.org/get&amp;#39;)
&amp;gt;&amp;gt;&amp;gt; r = requests.request(&amp;#39;options&amp;#39;, &amp;#39;http://httpbin.org/get&amp;#39;)
&lt;/code>&lt;/pre>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1559523182-a284c3fb7cff?w=300"
 data-srcset="https://images.unsplash.com/photo-1559523182-a284c3fb7cff?w=300, https://images.unsplash.com/photo-1559523182-a284c3fb7cff?w=300 1.5x, https://images.unsplash.com/photo-1559523182-a284c3fb7cff?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1559523182-a284c3fb7cff?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（四）JUnit 注解</title><link>https://itest2025.pages.dev/tutorials/31-004-%E5%9B%9Bjunit-%E6%B3%A8%E8%A7%A3/</link><pubDate>Mon, 13 Nov 2017 12:45:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/31-004-%E5%9B%9Bjunit-%E6%B3%A8%E8%A7%A3/</guid><description>&lt;h4 id="junit-注解">JUnit 注解&lt;/h4>
&lt;hr>
&lt;p>JUnit 注解说明：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: center">注解&lt;/th>
 &lt;th style="text-align: left">说明&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: center">@Test：&lt;/td>
 &lt;td style="text-align: left">标识一条测试用例。 (A) (expected=XXEception.class)   (B) (timeout=xxx)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: center">@Ignore: &lt;/td>
 &lt;td style="text-align: left">忽略的测试用例。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: center">@Before: &lt;/td>
 &lt;td style="text-align: left">每一个测试方法之前运行。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: center">@After : &lt;/td>
 &lt;td style="text-align: left">每一个测试方法之后运行。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: center">@BefreClass&lt;/td>
 &lt;td style="text-align: left"> 所有测试开始之前运行。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: center">@AfterClass &lt;/td>
 &lt;td style="text-align: left">所有测试结果之后运行。&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h4 id="例子">例子&lt;/h4>
&lt;hr>
&lt;p>创建被测试类 Count .&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">Count&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="cm">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * 计算并返回两个参数的和
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> */&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">return&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="cm">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * 计算并返回两个数相除的结果
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> */&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">division&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">return&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>创建测试类 CountTest .&lt;/p></description></item><item><title>4. 实例: 读取测试数据并测试弱密码</title><link>https://itest2025.pages.dev/tutorials/35-004-4-%E5%AE%9E%E4%BE%8B-%E8%AF%BB%E5%8F%96%E6%B5%8B%E8%AF%95%E6%95%B0%E6%8D%AE%E5%B9%B6%E6%B5%8B%E8%AF%95%E5%BC%B1%E5%AF%86%E7%A0%81/</link><pubDate>Tue, 07 Nov 2017 06:23:31 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/35-004-4-%E5%AE%9E%E4%BE%8B-%E8%AF%BB%E5%8F%96%E6%B5%8B%E8%AF%95%E6%95%B0%E6%8D%AE%E5%B9%B6%E6%B5%8B%E8%AF%95%E5%BC%B1%E5%AF%86%E7%A0%81/</guid><description>&lt;h3 id="背景">背景&lt;/h3>
&lt;p>接上一节的弱密码例子，我们的用例尽管运行的不错，但还是有点问题。&lt;/p>
&lt;p>假如我们需要增加一些测试数据，那么我们就必须去修改&lt;code>setUp&lt;/code>方法，在&lt;code>test_data&lt;/code>列表中增加数据，频繁修改代码以适应一些不变的测试场景，这是没有必要的开销，可以想办法去优化。&lt;/p>
&lt;p>我们可以把测试数据保存在文件里，通过读取文件的方式，每次动态从测试用例读取数据，这样数据的改变并不会影响用例，用例逻辑相对稳定，维护成本得到一定的降低。&lt;/p>
&lt;h3 id="设计测试数据">设计测试数据&lt;/h3>
&lt;p>我们可以把测试数据保存成json格式，json格式的数据在各个语言间有较好的通用性，比较适合复用。&lt;/p>
&lt;p>新建user_data.json文件，内容如下&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;jack&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;password&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;Iloverose&amp;#34;&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;rose&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;password&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;Ilovejack&amp;#34;&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;tom&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;password&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;password123&amp;#34;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>使用python的json库解析上面的json文件，可以得到如上节中&lt;code>test_data&lt;/code>一致的数据。&lt;/p>
&lt;h3 id="代码">代码&lt;/h3>
&lt;p>新建&lt;code>test_password_2.py&lt;/code>，内容如下&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">unittest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">json&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">PasswordWithJsonTeseCase&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TestCase&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data_file_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;./user_data.json&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">setUp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;set up&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">test_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">json&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">loads&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">data_file_path&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">read&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">test_week_password&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">data&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">test_data&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">passwd&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;password&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertTrue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">passwd&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">6&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">msg&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;user &lt;/span>&lt;span class="si">%s&lt;/span>&lt;span class="s2"> has a weak password&amp;#34;&lt;/span> &lt;span class="o">%&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;name&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertTrue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">passwd&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="s1">&amp;#39;password&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">msg&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertTrue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">passwd&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="s1">&amp;#39;password123&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">msg&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">test_dummy&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">pass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">main&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>跟上一节相比，最大的不同点是现在test_data通过解析json文件的方式来赋值&lt;code>self.test_data = json.loads(open(self.data_file_path).read())&lt;/code>。&lt;/p>
&lt;p>执行测试文件，结果应该与上一节一致。&lt;/p>
&lt;h3 id="发现问题">发现问题&lt;/h3>
&lt;p>上面的代码有2个测试方法:&lt;code>test_week_password&lt;/code>和&lt;code>test_dummy&lt;/code>。由于&lt;code>setUp&lt;/code>会在每个测试方法执行之前执行一次，那么setUp方法会执行2次，相应的json文件也会读取2次。如果测试方法多的话，那么反复读取json文件对性能来说是一个巨大的挑战。&lt;/p>
&lt;h3 id="优化">优化&lt;/h3>
&lt;p>对于上面的测试数据读取场景，我们可以在所有测试方法执行前读取一次数据，毕竟测试数据在所有测试方法执行过程中是保持不变的。&lt;/p>
&lt;h3 id="setupclass和teardownclass">setUpClass()和tearDownClass()&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="https://docs.python.org/2/library/unittest.html#unittest.TestCase.setUpClass" target="_blank" rel="noopener noreffer ">setUpClass&lt;/a>方法在每个测试用例类执行之前会执行一次，接收该class作为唯一的参数，并且必须使用装饰器&lt;a href="https://docs.python.org/2/library/functions.html#classmethod" target="_blank" rel="noopener noreffer ">classmethod()&lt;/a>&lt;/li>
&lt;li>tearDownClass: 在所有测试方法执行完之后被调用1次，调用方式跟上面的方法类似&lt;/li>
&lt;/ul>
&lt;h3 id="重构">重构&lt;/h3>
&lt;p>下面我们重构代码以达到只读取1次测试数据的目的，新建文件````test_password_3.py```，内容如下&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">unittest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">json&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">WeakPasswordTeseCase&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TestCase&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@classmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">setUpClass&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">kls&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data_file_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;./user_data.json&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;before all test methods&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">with&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data_file_path&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">kls&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">test_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">json&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">loads&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">read&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">test_week_password&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">data&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">test_data&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">passwd&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;password&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertTrue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">passwd&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">6&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">msg&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;user &lt;/span>&lt;span class="si">%s&lt;/span>&lt;span class="s2"> has a weak password&amp;#34;&lt;/span> &lt;span class="o">%&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;name&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertTrue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">passwd&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="s1">&amp;#39;password&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">msg&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertTrue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">passwd&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="s1">&amp;#39;password123&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">msg&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">test_dummy&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">pass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">main&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>有几点需要提及一下&lt;/p></description></item><item><title>4. 变量和名称</title><link>https://itest2025.pages.dev/tutorials/28-004-4-%E5%8F%98%E9%87%8F%E5%92%8C%E5%90%8D%E7%A7%B0/</link><pubDate>Sat, 04 Nov 2017 08:17:22 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/28-004-4-%E5%8F%98%E9%87%8F%E5%92%8C%E5%90%8D%E7%A7%B0/</guid><description>&lt;h3 id="背景">背景&lt;/h3>
&lt;p>变量是编程语言中常见的概念。变量实际上很简单，我们可以把它想象成是一个盒子，这个盒子有名字，就是变量名，盒子里面可以放东西进去，就是变量的值。&lt;/p>
&lt;p>程序员们一般使用变量让代码变得更加容易理解，因为他们的记忆力很糟糕，所以如果不取一些有意义的变量名的话，他们后来可能就看不懂自己写的代码了。&lt;/p>
&lt;p>我们对上一节的内容稍微做一些修改，加入变量的实践。&lt;/p>
&lt;h3 id="代码实现">代码实现&lt;/h3>
&lt;p>新建名为&lt;code>report_with_var.py&lt;/code>，内容如下&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 打印出本次测试的测试结果&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># A: 27/30 B: 40/40 C: 30/30&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">module_count&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">case_count_of_module_a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">30.0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">success_case_count_of_module_a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">27&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">case_count_of_module_b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">40.0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">success_case_count_of_module_b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">40&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">case_count_of_module_c&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">30.0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">success_case_count_of_module_c&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">30&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;本次测试覆盖了&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">module_count&lt;/span> &lt;span class="p">,&lt;/span>&lt;span class="s1">&amp;#39;个模块&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;测试用例总数为: &amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">case_count_of_module_a&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">case_count_of_module_b&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">case_count_of_module_c&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;执行的测试用例总数为: &amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">case_count_of_module_a&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">case_count_of_module_b&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">case_count_of_module_c&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;用例最多的模块是B模块，B模块比A模块多出的用例数为&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">case_count_of_module_b&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">case_count_of_module_a&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;A模块执行成功&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">success_case_count_of_module_a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;个用例，执行失败的用例数为&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">case_count_of_module_a&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">success_case_count_of_module_a&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;A模块用例通过率为百分之&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">success_case_count_of_module_a&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">case_count_of_module_a&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">100&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;B模块的用例全部执行通过， 通过率为百分之&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">success_case_count_of_module_b&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">case_count_of_module_b&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">100&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;C模块的用例全部执行通过， 通过率为百分之&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">success_case_count_of_module_b&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">case_count_of_module_b&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">100&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;B模块的用例比C模块多吗?&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">case_count_of_module_b&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">case_count_of_module_c&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;A模块的用例比C模块多吗?&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">case_count_of_module_a&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">case_count_of_module_c&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;B模块的用例比C模块少吗?&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">case_count_of_module_b&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">case_count_of_module_c&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 结束打印&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;回归不通过&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行">运行&lt;/h3>
&lt;p>在命令行中使用下面的命令去执行代码&lt;/p>
&lt;pre tabindex="0">&lt;code>$python report_with_var.py
&lt;/code>&lt;/pre>&lt;h3 id="你应该可以看到">你应该可以看到&lt;/h3>
&lt;p>如果没有出错的话，你应该可以看到命令行窗口显示如下的内容&lt;/p>
&lt;pre tabindex="0">&lt;code>本次测试覆盖了 3 个模块
测试用例总数为: 100.0
执行的测试用例总数为: 100.0
用例最多的模块是B模块，B模块比A模块多出的用例数为 10.0
A模块执行成功 27 个用例，执行失败的用例数为 3.0
A模块用例通过率为百分之 90.0
B模块的用例全部执行通过， 通过率为百分之 100.0
C模块的用例全部执行通过， 通过率为百分之 100.0
B模块的用例比C模块多吗? True
A模块的用例比C模块多吗? False
B模块的用例比C模块少吗? False
回归不通过
&lt;/code>&lt;/pre>&lt;h3 id="动手时间">动手时间&lt;/h3>
&lt;p>刚开始写代码的时候，我们经常会敲错，比如&lt;/p></description></item><item><title>4.Fixture</title><link>https://itest2025.pages.dev/tutorials/25-004-4fixture/</link><pubDate>Tue, 31 Oct 2017 07:22:42 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/25-004-4fixture/</guid><description>&lt;p>我们可以简单的把Fixture理解为准备测试数据和初始化测试对象的阶段。&lt;/p>
&lt;p>一般我们对测试数据和测试对象的管理有这样的一些场景&lt;/p>
&lt;ul>
&lt;li>所有用例开始之前初始化测试数据或对象&lt;/li>
&lt;li>所有用例结束之后销毁测试数据或对象&lt;/li>
&lt;li>每个用例开始之前初始化测试数据或对象&lt;/li>
&lt;li>每个用例结束之后销毁测试数据或对象&lt;/li>
&lt;li>在每个／所有module的用例开始之前初始化数据或对象&lt;/li>
&lt;li>在每个／所有module的用例开始之后销毁数据或对象&lt;/li>
&lt;li>&amp;hellip;&amp;hellip;&lt;/li>
&lt;li>&amp;hellip;&amp;hellip;&lt;/li>
&lt;/ul>
&lt;p>pytest的fixture特性可以满足上面的需求。&lt;/p>
&lt;h3 id="简单的例子">简单的例子&lt;/h3>
&lt;p>考虑这种场景，我们需要判断用户的密码中包含简单密码，规则是这样的，密码必须至少6位，满足6位的话判断用户的密码不是password123或者password之类的弱密码。&lt;/p>
&lt;p>我们将用户的信息导出成名为users.dev.json的文件，该文件如下所示&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;jack&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;password&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;Iloverose&amp;#34;&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;rose&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;password&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;Ilovejack&amp;#34;&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;tom&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;password&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;password123&amp;#34;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>新建名为test_user_password.py的文件，键入以下内容，一定要&lt;strong>保证users.dev.json文件与该文件在同一路径下&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">pytest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">json&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">TestUserPassword&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">object&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@pytest.fixture&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">users&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">json&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">loads&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;./users.dev.json&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;r&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">read&lt;/span>&lt;span class="p">())&lt;/span> &lt;span class="c1"># 读取当前路径下的users.dev.json文件，返回的结果是dict&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">test_user_password&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">users&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 遍历每条user数据&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">user&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">users&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">passwd&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;password&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">passwd&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">6&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">msg&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;user &lt;/span>&lt;span class="si">%s&lt;/span>&lt;span class="s2"> has a weak password&amp;#34;&lt;/span> &lt;span class="o">%&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;name&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="n">passwd&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="s1">&amp;#39;password&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">msg&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="n">passwd&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="s1">&amp;#39;password123&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">msg&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行">运行&lt;/h3>
&lt;p>pytest可以通过指定文件名的方式运行单个用例文件，这里我们只运行test_user_password.py文件&lt;/p>
&lt;pre tabindex="0">&lt;code>pytest test_user_password.py
&lt;/code>&lt;/pre>&lt;h3 id="运行结果">运行结果&lt;/h3>
&lt;pre tabindex="0">&lt;code>$ pytest test_user_password.py
========================================================================= test session starts =========================================================================
platform darwin -- Python 2.7.12, pytest-3.2.3, py-1.4.34, pluggy-0.4.0
rootdir: /Users/easonhan/code/testclass.net/src/pytest, inifile:
collected 1 item

test_user_password.py F

============================================================================== FAILURES ===============================================================================
_________________________________________________________________ TestUserPassword.test_user_password _________________________________________________________________

self = &amp;lt;test_user_password.TestUserPassword object at 0x1046e3290&amp;gt;
users = [{&amp;#39;name&amp;#39;: &amp;#39;jack&amp;#39;, &amp;#39;password&amp;#39;: &amp;#39;Iloverose&amp;#39;}, {&amp;#39;name&amp;#39;: &amp;#39;rose&amp;#39;, &amp;#39;password&amp;#39;: &amp;#39;Ilovejack&amp;#39;}, {&amp;#39;name&amp;#39;: &amp;#39;tom&amp;#39;, &amp;#39;password&amp;#39;: &amp;#39;password123&amp;#39;}]

 def test_user_password(self, users):
 for user in users:
 passwd = user[&amp;#39;password&amp;#39;]
 assert len(passwd) &amp;gt;= 6
 msg = &amp;#34;user %s has a weak password&amp;#34; %(user[&amp;#39;name&amp;#39;])
 assert passwd != &amp;#39;password&amp;#39;, msg
&amp;gt; assert passwd != &amp;#39;password123&amp;#39;, msg
E AssertionError: user tom has a weak password
E assert &amp;#39;password123&amp;#39; != &amp;#39;password123&amp;#39;

test_user_password.py:14: AssertionError
====================================================================== 1 failed in 0.03 seconds =======================================================================
&lt;/code>&lt;/pre>&lt;h3 id="分析">分析&lt;/h3>
&lt;ul>
&lt;li>使用@pytest.fixture装饰器可以定义feature&lt;/li>
&lt;li>在用例的参数中传递fixture的名称以便直接调用fixture，拿到fixture的返回值&lt;/li>
&lt;li>3个assert是递进关系，前1个assert断言失败后，后面的assert是不会运行的，因此重要的assert放到前面&lt;/li>
&lt;li>&lt;code> E AssertionError: user tom has a weak password&lt;/code>可以很容易的判断出是哪条数据出了问题，所以定制可读性好的错误信息是很必要的&lt;/li>
&lt;li>任何1个断言失败以后，for循环就会退出，所以上面的用例1次只能发现1条错误数据，换句话说任何1个assert失败后，用例就终止运行了&lt;/li>
&lt;/ul>
&lt;h3 id="执行顺序">执行顺序&lt;/h3>
&lt;p>pytest是这样运行上面的用例的&lt;/p></description></item><item><title>4. Finds</title><link>https://itest2025.pages.dev/tutorials/43-004-4-finds/</link><pubDate>Thu, 26 Oct 2017 06:55:26 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/43-004-4-finds/</guid><description>&lt;p>&lt;code>webium.find.Finds&lt;/code> 方法的用法跟&lt;code>Find&lt;/code>方法基本是一致的，不过返回的是&lt;code>WebElement&lt;/code>列表。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium.webdriver.common.by&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">By&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">webium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">BasePage&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Finds&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">LinksPage&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BasePage&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">links&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Finds&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">by&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TAG_NAME&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;a&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">super&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">LinksPage&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;http://itest.info&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">page&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">LinksPage&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">open&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Number of links: &amp;#39;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">links&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>我们甚至可以动态返回满足条件的一组元素。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium.webdriver.common.by&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">By&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium.webdriver.remote.webelement&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">WebElement&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">webium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">BasePage&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Finds&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Link&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">WebElement&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">is_secure&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_attribute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;href&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">startswith&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;https://&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">TypedPage&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BasePage&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">links&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Finds&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Link&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">By&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TAG_NAME&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;a&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">super&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">TypedPage&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;http://itest.info&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">get_unsecured_links&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">filter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">lambda&lt;/span> &lt;span class="n">link&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">link&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">is_secure&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">links&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">page&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">TypedPage&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">open&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Number of unsecured links: &amp;#39;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_unsecured_links&lt;/span>&lt;span class="p">())))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1507208773393-40d9fc670acf?w=300"
 data-srcset="https://images.unsplash.com/photo-1507208773393-40d9fc670acf?w=300, https://images.unsplash.com/photo-1507208773393-40d9fc670acf?w=300 1.5x, https://images.unsplash.com/photo-1507208773393-40d9fc670acf?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1507208773393-40d9fc670acf?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>收藏清单: python安全测试API测试及性能测试最全资源汇总</title><link>https://itest2025.pages.dev/tutorials/34-004-%E6%94%B6%E8%97%8F%E6%B8%85%E5%8D%95-python%E5%AE%89%E5%85%A8%E6%B5%8B%E8%AF%95api%E6%B5%8B%E8%AF%95%E5%8F%8A%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E6%9C%80%E5%85%A8%E8%B5%84%E6%BA%90%E6%B1%87%E6%80%BB/</link><pubDate>Mon, 23 Oct 2017 08:19:06 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/34-004-%E6%94%B6%E8%97%8F%E6%B8%85%E5%8D%95-python%E5%AE%89%E5%85%A8%E6%B5%8B%E8%AF%95api%E6%B5%8B%E8%AF%95%E5%8F%8A%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E6%9C%80%E5%85%A8%E8%B5%84%E6%BA%90%E6%B1%87%E6%80%BB/</guid><description>&lt;h2 id="rest-api-testing-rest-api测试">REST API Testing REST API测试&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://github.com/chitamoor/rester" target="_blank" rel="noopener noreffer ">Rester&lt;/a> - 测试RESTful API的框架&lt;/li>
&lt;li>&lt;a href="https://github.com/svanoort/pyresttest" target="_blank" rel="noopener noreffer ">pyresttest&lt;/a> - REST以及API microbenchmarking工具&lt;/li>
&lt;li>&lt;a href="http://scastillo.github.com/siesta" target="_blank" rel="noopener noreffer ">siesta&lt;/a> - Python REST 客户端&lt;/li>
&lt;/ul>
&lt;h2 id="virtual-environments-虚拟环境">Virtual environments 虚拟环境&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://pypi.python.org/pypi/virtualenv" target="_blank" rel="noopener noreffer ">virtualenv&lt;/a> - 创建隔离的python开发环境的工具&lt;/li>
&lt;li>&lt;a href="https://virtualenvwrapper.readthedocs.org/en/latest/" target="_blank" rel="noopener noreffer ">virtualenvwrapper&lt;/a> - virtualenv的一些扩展&lt;/li>
&lt;li>&lt;a href="https://pypi.python.org/pypi/tox" target="_blank" rel="noopener noreffer ">tox&lt;/a> - 虚拟环境管理，可以在不同的python版本上进行测试和截图&lt;/li>
&lt;li>&lt;a href="https://pypi.python.org/pypi/pew/" target="_blank" rel="noopener noreffer ">pew&lt;/a> - 一些管理虚拟环境的工具&lt;/li>
&lt;li>&lt;a href="https://github.com/sashahart/vex" target="_blank" rel="noopener noreffer ">Vex&lt;/a> - 在命名的虚拟环境运行命令&lt;/li>
&lt;li>&lt;a href="https://www.egenix.com/products/python/PyRun/" target="_blank" rel="noopener noreffer ">PyRun&lt;/a> - 单文件无需按照的python版本&lt;/li>
&lt;li>&lt;a href="https://github.com/yyuu/pyenv" target="_blank" rel="noopener noreffer ">pyenv&lt;/a> - 简单的python版本管理&lt;/li>
&lt;li>&lt;a href="https://tapper.github.io/Tapper/" target="_blank" rel="noopener noreffer ">Tapper&lt;/a> - all-embracing test infrastructure.&lt;/li>
&lt;/ul>
&lt;h2 id="performance--stress--load-性能测试">Performance &amp;amp; stress &amp;amp; load 性能测试&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="http://testutils.org/multi-mechanize/" target="_blank" rel="noopener noreffer ">Multi-Mechanize&lt;/a> - 开源的性能测试框架&lt;/li>
&lt;li>&lt;a href="https://github.com/locustio/locust" target="_blank" rel="noopener noreffer ">locust&lt;/a> - 可扩展的python性能测试工具&lt;/li>
&lt;li>&lt;a href="https://github.com/yandex/yandex-tank" target="_blank" rel="noopener noreffer ">Yandex.Tank&lt;/a> - 性能及benchmark工具&lt;/li>
&lt;li>&lt;a href="https://github.com/ionelmc/pytest-benchmark" target="_blank" rel="noopener noreffer ">pytest-benchmark&lt;/a> - py.test的benchmark工具&lt;/li>
&lt;li>&lt;a href="https://github.com/spacetelescope/asv" target="_blank" rel="noopener noreffer ">Airspeed Velocity&lt;/a> - 简单的Python benchmarking工具自带基于web的报告&lt;/li>
&lt;li>&lt;a href="http://grinder.sourceforge.net/" target="_blank" rel="noopener noreffer ">The Grinder&lt;/a> - 支持分布式的负载测试框架. 包含一些常规用例，比如 HTTP web servers, SOAP and REST web services, 和 application servers (CORBA, RMI, JMS, EJBs),以及定制化的协议. 测试脚本使用Jython和Clojure实现&lt;/li>
&lt;li>&lt;a href="http://tsung.erlang-projects.org/" target="_blank" rel="noopener noreffer ">Tsung&lt;/a> - 开源，支持多协议的分布式性能测试工具. 可以测试 HTTP, WebDAV, SOAP, PostgreSQL, MySQL, LDAP 和 Jabber/XMPP 服务&lt;/li>
&lt;li>&lt;a href="http://gettaurus.org" target="_blank" rel="noopener noreffer ">taurus&lt;/a> - 自动化友好的持续测试工具&lt;/li>
&lt;/ul>
&lt;h2 id="security-checking-安全扫描">Security checking 安全扫描&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="http://sparta.secforce.com/" target="_blank" rel="noopener noreffer ">sparta&lt;/a> - 支持gui的网络扫描工具&lt;/li>
&lt;li>&lt;a href="https://code.google.com/p/zaproxy/wiki/ApiPython" target="_blank" rel="noopener noreffer ">OWASP ZAP&lt;/a> - 用python实现的OWASP ZAP-features API&lt;/li>
&lt;li>&lt;a href="https://github.com/m4n3dw0lf/PytheM" target="_blank" rel="noopener noreffer ">pythem&lt;/a> - pythem是多用途的安全测试工具&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p></description></item><item><title>（四）Jenkins 配置构建执行状态</title><link>https://itest2025.pages.dev/tutorials/18-004-%E5%9B%9Bjenkins-%E9%85%8D%E7%BD%AE%E6%9E%84%E5%BB%BA%E6%89%A7%E8%A1%8C%E7%8A%B6%E6%80%81/</link><pubDate>Mon, 16 Oct 2017 13:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/18-004-%E5%9B%9Bjenkins-%E9%85%8D%E7%BD%AE%E6%9E%84%E5%BB%BA%E6%89%A7%E8%A1%8C%E7%8A%B6%E6%80%81/</guid><description>&lt;h4 id="运行构建">运行构建&lt;/h4>
&lt;hr>
&lt;p>在项目 左侧列表点击 &lt;strong>“立即构建”&lt;/strong> ，在 “Build History” 列表，你会得到一个红色的小圆点，表示构建失败。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/jenkins_build_run.png"
 data-srcset="http://img.testclass.net/jenkins_build_run.png, http://img.testclass.net/jenkins_build_run.png 1.5x, http://img.testclass.net/jenkins_build_run.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/jenkins_build_run.png"
 title="http://img.testclass.net/jenkins_build_run.png" />&lt;/p>
&lt;p>点击 构建失败的任务（红色的小圆点）。然后点击“Console Output” 就可以查看失败的 log 了。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/jenkins_control_print_error.png"
 data-srcset="http://img.testclass.net/jenkins_control_print_error.png, http://img.testclass.net/jenkins_control_print_error.png 1.5x, http://img.testclass.net/jenkins_control_print_error.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/jenkins_control_print_error.png"
 title="http://img.testclass.net/jenkins_control_print_error.png" />&lt;/p>
&lt;p>提示：&lt;code> 'python' 不是内部或外部命令，也不是可运行的程序或批处理文件。&lt;/code>&lt;/p>
&lt;p>我们明明在 Windows 提示符下运行是没有问题的。这是因为 Jenkins 缺少环境配置。&lt;/p>
&lt;h4 id="配置构建执行状态">配置构建执行状态&lt;/h4>
&lt;hr>
&lt;p>回到 Jenkins 首页，点击 &lt;strong>“构建执行状态”&lt;/strong> ,右则会列出本机信息，点击本机信息，配置 Python 的 path 环境变量。同时还需要添加浏览器驱动文件所在目录，&lt;a href="https://itest2025.pages.dev/selenium_python/selenium3-browser-driver/" rel="">参考&lt;/a> 。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/jenkins_build_run_status.png"
 data-srcset="http://img.testclass.net/jenkins_build_run_status.png, http://img.testclass.net/jenkins_build_run_status.png 1.5x, http://img.testclass.net/jenkins_build_run_status.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/jenkins_build_run_status.png"
 title="http://img.testclass.net/jenkins_build_run_status.png" />&lt;/p>
&lt;p>&lt;font color='red'> 如果你明白这块的话，说明你不懂 Python 语言，或不熟悉 Python 运行环境的配置。（不同技术的之间的配合使用存在一定的依赖关系！我们无法做到零基础。）&lt;/font>&lt;/p>
&lt;p>配置完成，点击 &lt;strong>“保存”&lt;/strong> , 再来运行 &lt;strong>“立即构建”&lt;/strong> ，这次看到 py_tests.py 自动化脚本被执行了。&lt;/p></description></item><item><title>（四）Locust no-web模式</title><link>https://itest2025.pages.dev/tutorials/38-004-%E5%9B%9Blocust-no-web%E6%A8%A1%E5%BC%8F/</link><pubDate>Mon, 16 Oct 2017 12:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/38-004-%E5%9B%9Blocust-no-web%E6%A8%A1%E5%BC%8F/</guid><description>&lt;p>熟悉 Apache ab 工具的同学都知道，它是没有界面的，通过命令行执行。 Locust 同样也提供的命令行运行，好处就是更节省客户端资源。&lt;/p>
&lt;h4 id="命令行运行-locust-测试">命令行运行 Locust 测试&lt;/h4>
&lt;hr>
&lt;p>以上一节的 baidu 首页测试（load_test.py）为例 通过 &lt;strong>no-web&lt;/strong> 模式运行测试。&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt; locust -f load_test.py --host=https://www.baidu.com --no-web -c 10 -r 2 -t 1m

[2017-10-30 22:17:30,292] DESKTOP-SMGQBBM/INFO/locust.main: Run time limit set to 60 seconds
[2017-10-30 22:17:30,302] DESKTOP-SMGQBBM/INFO/locust.main: Starting Locust 0.8
[2017-10-30 22:17:30,302] DESKTOP-SMGQBBM/INFO/locust.runners: Hatching and swarming 10 clients at the rate 2 clients/s...
 Name # reqs # fails Avg Min Max | Median req/s

....


 [2017-10-30 22:18:30,301] DESKTOP-SMGQBBM/INFO/locust.main: Time limit reached. Stopping Locust.
 [2017-10-30 22:18:30,302] DESKTOP-SMGQBBM/INFO/locust.main: Shutting down (exit code 0), bye.
 Name # reqs # fails Avg Min Max | Median req/s
 --------------------------------------------------------------------------------------------------------------------------------------------
 GET / 117 0(0.00%) 31 17 96 | 28 2.10
 --------------------------------------------------------------------------------------------------------------------------------------------
 Total 117 0(0.00%) 2.10

 Percentage of the requests completed within given times
 Name # reqs 50% 66% 75% 80% 90% 95% 98% 99% 100%
 --------------------------------------------------------------------------------------------------------------------------------------------
 GET / 117 28 30 36 37 49 62 69 72 96
 --------------------------------------------------------------------------------------------------------------------------------------------
 Total 117 28 30 36 37 49 62 69 72 96
&lt;/code>&lt;/pre>&lt;p>&lt;strong>启动参数：&lt;/strong>&lt;/p></description></item><item><title>03. 安装环境：Windows</title><link>https://itest2025.pages.dev/tutorials/37-004-03-%E5%AE%89%E8%A3%85%E7%8E%AF%E5%A2%83windows/</link><pubDate>Mon, 16 Oct 2017 10:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/37-004-03-%E5%AE%89%E8%A3%85%E7%8E%AF%E5%A2%83windows/</guid><description>&lt;h1 id="windows-系统下安装-intellij-idea">Windows 系统下安装 IntelliJ IDEA&lt;/h1>
&lt;h2 id="更新记录">更新记录&lt;/h2>
&lt;ul>
&lt;li>2016-12：IntelliJ IDEA 2016.3 版本出来之后，Windows 的安装过程增加了一个可以勾选选用 JetBrains 自己开发的一个 JRE 环境，这个建议 64 位系统的用户可以勾选上，按正常理论效果比 Oracle 应该会好。&lt;/li>
&lt;/ul>
&lt;h2 id="系统要求">系统要求&lt;/h2>
&lt;blockquote>
&lt;ul>
&lt;li>系统支持：Microsoft Windows 8 / 7 / Vista / 2003 / XP（每个系统版本的 32 位和 64 位都可以）&lt;/li>
&lt;li>JDK 版本：Oracle JDK 1.6 或以上&lt;/li>
&lt;li>内存：最低要求 1 GB，推荐 2 GB 以上&lt;/li>
&lt;li>硬盘：最低要求 2 GB&lt;/li>
&lt;li>显示器：最低要求 1024 X 768 分辨率&lt;/li>
&lt;li>更多信息可以阅读：&lt;a href="https://www.jetbrains.com/idea/download/system_requirements.jsp?os=win" target="_blank" rel="noopener noreffer ">https://www.jetbrains.com/idea/download/system_requirements.jsp?os=win&lt;/a>&lt;/li>
&lt;/ul>&lt;/blockquote>
&lt;h2 id="首次安装">首次安装&lt;/h2>
&lt;blockquote>
&lt;ul>
&lt;li>IntelliJ IDEA 的安装是非常简单的，不需要做过多的选择，可以说简单到都是 &lt;code>Next&lt;/code> 即可。&lt;/li>
&lt;/ul>&lt;/blockquote>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/iii-a-first-install-1.jpg"
 data-srcset="http://img.testclass.net/iii-a-first-install-1.jpg, http://img.testclass.net/iii-a-first-install-1.jpg 1.5x, http://img.testclass.net/iii-a-first-install-1.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/iii-a-first-install-1.jpg"
 title="首次安装步骤截图" />&lt;/p></description></item><item><title>04. 安装环境：Ubuntu</title><link>https://itest2025.pages.dev/tutorials/37-004-04-%E5%AE%89%E8%A3%85%E7%8E%AF%E5%A2%83ubuntu/</link><pubDate>Mon, 16 Oct 2017 09:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/37-004-04-%E5%AE%89%E8%A3%85%E7%8E%AF%E5%A2%83ubuntu/</guid><description>&lt;h1 id="ubuntu-系统下安装-intellij-idea">Ubuntu 系统下安装 IntelliJ IDEA&lt;/h1>
&lt;h2 id="系统要求">系统要求&lt;/h2>
&lt;blockquote>
&lt;ul>
&lt;li>系统支持：只要是支持 GNOME 或 KDE 桌面系统，建议是 Ubuntu（32位和64位都可以）&lt;/li>
&lt;li>JDK 版本：Oracle JDK 1.6 或以上&lt;/li>
&lt;li>内存：最低要求 1 GB，推荐 2 GB 以上&lt;/li>
&lt;li>硬盘：最低要求 2 GB&lt;/li>
&lt;li>显示器：最低要求 1024 X 768 分辨率&lt;/li>
&lt;li>更多信息可以阅读：&lt;a href="https://www.jetbrains.com/idea/download/system_requirements.jsp?os=linux" target="_blank" rel="noopener noreffer ">https://www.jetbrains.com/idea/download/system_requirements.jsp?os=linux&lt;/a>&lt;/li>
&lt;/ul>&lt;/blockquote>
&lt;h2 id="重要说明">重要说明&lt;/h2>
&lt;p>我这里以 Ubuntu 系统为例进行讲解。但是，在学习下面内容之前请先看下章节：&lt;a href="windows-install.md" rel="">Windows 下安装&lt;/a>&lt;/p>
&lt;p>因为它们配置流程是基本一样的，只是系统不同，开始的步骤不太一样而已，因此相同部分我这里是不会再讲的，我只讲 IntelliJ IDEA 在 Linux 安装特殊的地方。&lt;/p>
&lt;h2 id="ubuntu-下安装过程">Ubuntu 下安装过程&lt;/h2>
&lt;p>先把你下载到的 &lt;code>ideaIU-14.1.4.tar.gz&lt;/code> 移动到你平时存放软件的目录下，然后进行解压，我电脑是放在 /opt 下。&lt;/p>
&lt;blockquote>
&lt;ul>
&lt;li>终端下解压命令：&lt;code>tar xfz ideaIU-14.1.4.tar.gz&lt;/code>，解压出来的目录名称是：&lt;code>idea-IU-141.1532.4&lt;/code>&lt;/li>
&lt;li>可能在解压过程中你需要 &lt;code>sudo&lt;/code> 命令权限，或者是切换到 root 账号下。如果你是切换到 root 用户下就一定要注意，解压完记得再切回来你常用的账户，不然等下生成的 IntelliJ IDEA 配置文件是放在 &lt;code>/home/root&lt;/code> 下，这样就跟你常用的那个用户没啥关系了。&lt;/li>
&lt;/ul>&lt;/blockquote>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/iv-a-ubuntu-install-1.jpg"
 data-srcset="http://img.testclass.net/iv-a-ubuntu-install-1.jpg, http://img.testclass.net/iv-a-ubuntu-install-1.jpg 1.5x, http://img.testclass.net/iv-a-ubuntu-install-1.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/iv-a-ubuntu-install-1.jpg"
 title="Ubuntu 下安装过程" />&lt;/p></description></item><item><title>appium新手入门（4）—— java-client安装与测试</title><link>https://itest2025.pages.dev/tutorials/21-004-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A84-java-client%E5%AE%89%E8%A3%85%E4%B8%8E%E6%B5%8B%E8%AF%95/</link><pubDate>Thu, 07 Sep 2017 10:24:12 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/21-004-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A84-java-client%E5%AE%89%E8%A3%85%E4%B8%8E%E6%B5%8B%E8%AF%95/</guid><description>&lt;p>&lt;strong>关联阅读：&lt;/strong>&lt;/p>
&lt;p>&lt;a href="https://itest2025.pages.dev/appium/appium-base-summary/" rel="">appium新手入门（1）—— appium介绍&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://itest2025.pages.dev/appium/appium-base-sdk/" rel="">appium新手入门（2）—— 安装 Android SDK&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://itest2025.pages.dev/appium/appium-base-server/" rel="">appium新手入门（3）—— 安装 appium Server&lt;/a>&lt;/p>
&lt;br>
#### 前提条件
----
&lt;p>当你点击这一章时，说明你是打算使用 Java 语言编写 appium 自动化测试脚本的。&lt;/p>
&lt;p>1、安装 &lt;a href="https://itest2025.pages.dev/selenium_java/install-java/" rel="">Java 环境&lt;/a> ,我想这一步你已经搞定了&lt;/p>
&lt;p>2、安装 &lt;a href="https://itest2025.pages.dev/selenium_java/install-idea/" rel="">IntelliJ IDEA&lt;/a> , 当然，你喜欢用 Eclipse 也可以，不过，我仍然推荐 IDEA。&lt;/p>
&lt;p>3、安装 &lt;a href="https://itest2025.pages.dev/selenium_java/install-selenium/" rel="">Maven&lt;/a>, Java开发必备啊！&lt;/p>
&lt;h4 id="maven-安装-java-client">Maven 安装 Java-client&lt;/h4>
&lt;hr>
&lt;p>首先，启动IntelliJ IDEA，创建Maven项目（参考selenium java教程），然后在maven配置文件中添加Java-client配置。&lt;/p>
&lt;pre>&lt;code>&amp;lt;dependency&amp;gt;
 &amp;lt;groupId&amp;gt;io.appium&amp;lt;/groupId&amp;gt;
 &amp;lt;artifactId&amp;gt;java-client&amp;lt;/artifactId&amp;gt;
 &amp;lt;version&amp;gt;5.0.0-BETA9&amp;lt;/version&amp;gt;
 &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code>&lt;/pre>
&lt;p>最新版本号可以到 github &lt;a href="https://github.com/appium/java-client" target="_blank" rel="noopener noreffer ">Java-client开源项目&lt;/a>上查看。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/appium_idea_maven.png"
 data-srcset="http://img.testclass.net/appium_idea_maven.png, http://img.testclass.net/appium_idea_maven.png 1.5x, http://img.testclass.net/appium_idea_maven.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/appium_idea_maven.png"
 title="http://img.testclass.net/appium_idea_maven.png" />&lt;/p>
&lt;br>
#### 运行第一个Appium测试
----
* __第一步__，启动Android模拟器。
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/appium_android_system.png"
 data-srcset="http://img.testclass.net/appium_android_system.png, http://img.testclass.net/appium_android_system.png 1.5x, http://img.testclass.net/appium_android_system.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/appium_android_system.png"
 title="http://img.testclass.net/appium_android_system.png" />&lt;/p></description></item><item><title>（四）Git克隆与更新代码</title><link>https://itest2025.pages.dev/tutorials/33-004-%E5%9B%9Bgit%E5%85%8B%E9%9A%86%E4%B8%8E%E6%9B%B4%E6%96%B0%E4%BB%A3%E7%A0%81/</link><pubDate>Thu, 31 Aug 2017 02:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/33-004-%E5%9B%9Bgit%E5%85%8B%E9%9A%86%E4%B8%8E%E6%9B%B4%E6%96%B0%E4%BB%A3%E7%A0%81/</guid><description>&lt;p>请先阅读：&lt;/p>
&lt;p>&lt;a href="https://itest2025.pages.dev/git/registration-and-installation/" rel="">GitHub注册与Git安装&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://itest2025.pages.dev/git/git-commit-code/" rel="">通过Git提交代码到GitHub&lt;/a>&lt;/p>
&lt;h4 id="克隆项目">克隆项目&lt;/h4>
&lt;hr>
&lt;p>我们除了可以向GitHub上提交项目外，更多的时候是我们到上面克隆（下载）优秀的开源项目来用，当然也可以将使用过程中发现的bug，通过建立分支的方式提交给项目的原作者。
我们现在的场景是在家将项目提交到了GitHub上，现在来到公司，需要将GitHub上的项目克隆到本地，那么对于公司的电脑来说，同样需要与GitHub建立连接。&lt;/p>
&lt;p>首先，下载安装Git。&lt;/p>
&lt;p>其次，通过Git生成本地公钥，并且将公钥添加到GitHub中。&lt;/p>
&lt;p>最后，设置仓库人员的用户名和邮箱地址。&lt;/p>
&lt;p>&lt;strong>具体操作请参考前面的章节&lt;/strong>。当一切都设置完成后，就可以从GitHub上克隆项目到本地了。我们同样以Windows系统为例，打开Git Bash。&lt;/p>
&lt;pre>&lt;code>Company@MININT-IQVJFIT /d/my_test
$ git clone git@github.com:defnngj/project-name.git

Cloning into 'project-name'...
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.
Checking connectivity... done.

Company@MININT-IQVJFIT /d/my_test
$ cd project-name/

Company@MININT-IQVJFIT /d/my_test/project-name (master)
$ ls

test_case.py
&lt;/code>&lt;/pre>
&lt;p>&lt;strong>“git clone”&lt;/strong> 命令用于克隆GitHub上的项目到本地。通过“cd”命令进入项目目录，查看项目文件。&lt;/p>
&lt;p>另外，我们也可以直接通过http链接克隆项目：&lt;/p>
&lt;pre>&lt;code>$ git clone https://github.com/defnngj/project-name
&lt;/code>&lt;/pre>
&lt;h4 id="更新项目">更新项目&lt;/h4>
&lt;hr>
&lt;p>这次更新我们项目做了较大的变更，创建文件的文件与文件夹，并且删除了原有文件。&lt;/p></description></item><item><title>4.Json简介</title><link>https://itest2025.pages.dev/tutorials/40-004-4json%E7%AE%80%E4%BB%8B/</link><pubDate>Sun, 27 Aug 2017 04:41:43 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/40-004-4json%E7%AE%80%E4%BB%8B/</guid><description>&lt;h3 id="官方解释">官方解释&lt;/h3>
&lt;p>JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。 易于人阅读和编写。同时也易于机器解析和生成。 它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999的一个子集。 JSON采用完全独立于语言的文本格式，但是也使用了类似于C语言家族的习惯（包括C, C++, C#, Java, JavaScript, Perl, Python等）。 这些特性使JSON成为理想的数据交换语言。&lt;/p>
&lt;h3 id="什么是json">什么是JSON&lt;/h3>
&lt;p>首先json是字符串。&lt;/p>
&lt;p>大家都知道，字符串是用来传递信息的。json字符串实际上就是一种规定了格式的字符串，&lt;/p>
&lt;p>通过这种格式，我们可以在不同的编程语言之间互相传递信息，比如我们可以把javascript的对象转换成json传递给java，这样java可以反解析出java语言自身代表的对象；同理，我们可以把java对象转成json，通过解析json，python语言可以把json转成是自身的dict或者是list，json统一了交流的格式，使得信息可以在不同的语言间顺畅传递。&lt;/p>
&lt;h3 id="json解析的简单例子">JSON解析的简单例子&lt;/h3>
&lt;p>比如，我们可以把json字符串转成python语言的dict&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">#coding: utf-8&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">json&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">json_str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">{
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;id&amp;#34; : 90,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;name&amp;#34; : &amp;#34;python&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;url&amp;#34; : &amp;#34;http://www.v2ex.com/go/python&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;title&amp;#34; : &amp;#34;Python&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;title_alternative&amp;#34; : &amp;#34;Python&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;topics&amp;#34; : 7646,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;stars&amp;#34; : 4862,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;header&amp;#34; : &amp;#34;这里讨论各种 Python 语言编程话题，也包括 Django，Tornado 等框架的讨论。这里是一个能够帮助你解决实际问题的地方。&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;footer&amp;#34; : null,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;created&amp;#34; : 1278683336,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;avatar_mini&amp;#34; : &amp;#34;//v2ex.assets.uxengine.net/navatar/8613/985e/90_mini.png?m=1504080972&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;avatar_normal&amp;#34; : &amp;#34;//v2ex.assets.uxengine.net/navatar/8613/985e/90_normal.png?m=1504080972&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;avatar_large&amp;#34; : &amp;#34;//v2ex.assets.uxengine.net/navatar/8613/985e/90_large.png?m=1504080972&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">}
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">json&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">loads&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">json_str&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">res&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;id&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span> &lt;span class="c1"># 90&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">res&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;name&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span> &lt;span class="c1"># python&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">res&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;url&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span> &lt;span class="c1"># http://www.v2ex.com/go/python&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p></description></item><item><title>JMeter官方文档：4. 创建web测试计划</title><link>https://itest2025.pages.dev/tutorials/22-004-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A34-%E5%88%9B%E5%BB%BAweb%E6%B5%8B%E8%AF%95%E8%AE%A1%E5%88%92/</link><pubDate>Thu, 24 Aug 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/22-004-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A34-%E5%88%9B%E5%BB%BAweb%E6%B5%8B%E8%AF%95%E8%AE%A1%E5%88%92/</guid><description>&lt;p>&lt;a href="https://itest2025.pages.dev/2017/08/24/jmeter-translation-plans/" rel="">《JMeter官方文档&amp;ndash;翻译计划》&lt;/a> &lt;a href="http://jmeter.apache.org/usermanual/build-web-test-plan.html" target="_blank" rel="noopener noreffer ">原文地址&lt;/a>&lt;/p>
&lt;h2 id="4-创建web测试计划">4. 创建web测试计划&lt;/h2>
&lt;hr>
&lt;p>在这一章，我们将学习如何创建基本的&lt;a href="http://jmeter.apache.org/usermanual/build-test-plan.html" target="_blank" rel="noopener noreffer ">测试计划&lt;/a>来测试一个web网站。您将创建五个用户并发送请求到JMeter网站的两个页面。同时，设置用户运行测试两次。因此，请求的总数是（5个用户）x（2个请求）x（重复2次）＝20个HTTP请求。要构建测试计划，您将使用以下元素：&lt;a href="http://jmeter.apache.org/usermanual/test_plan.html#thread_group" target="_blank" rel="noopener noreffer ">线程组&lt;/a>、&lt;a href="http://jmeter.apache.org/usermanual/component_reference.html#HTTP_Request" target="_blank" rel="noopener noreffer ">HTTP请求&lt;/a>、&lt;a href="http://jmeter.apache.org/usermanual/component_reference.html#HTTP_Request_Defaults" target="_blank" rel="noopener noreffer ">HTTP请求默认值&lt;/a>和&lt;a href="http://jmeter.apache.org/usermanual/component_reference.html#Graph_Results" target="_blank" rel="noopener noreffer ">图表结果&lt;/a>。&lt;/p>
&lt;p>想要创建一个更深层次的测试计划，请查看&lt;a href="https://itest2025.pages.dev/jmeter/jmeter-doc-05/" rel="">建立一个更高级的web测试计划&lt;/a>。&lt;/p>
&lt;h3 id="41-添加用户">4.1 添加用户&lt;/h3>
&lt;hr>
&lt;p>做每一个测试计划之前的第一步是添加一个&lt;a href="http://jmeter.apache.org/usermanual/test_plan.html#thread_group" target="_blank" rel="noopener noreffer ">线程组&lt;/a>。在JMeter的线程组中设置要模拟的用数量，请求发送的频率，以及请求发送的次数。&lt;/p>
&lt;p>在添加线程组之前先鼠标选中测试计划，然后单击鼠标右键，选择 &lt;strong>“ 添加 → 线程组 ”&lt;/strong>。&lt;/p>
&lt;p>你现在应该看到在测试计划下的线程组元素。如果您没有看到元素，你需要单击“测试计划”来展开‘测试计划树’。&lt;/p>
&lt;p>接下来，你需要修改默认的属性。在树中选中该线程组，如果你已经选择。你现在应该在JMeter窗口右部看到线程组控制面板（见下面的图4.1）&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/http://img.testclass.net/thread_group.png"
 data-srcset="http://img.testclass.net/http://img.testclass.net/thread_group.png, http://img.testclass.net/http://img.testclass.net/thread_group.png 1.5x, http://img.testclass.net/http://img.testclass.net/thread_group.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/http://img.testclass.net/thread_group.png"
 title="http://img.testclass.net/http://img.testclass.net/thread_group.png" />
图4.1 线程组默认值&lt;/p>
&lt;p>我们为线程组提供一个更具体的描述性名称，在名称栏里输入：&lt;strong>JMeter Users&lt;/strong>。&lt;/p>
&lt;p>接下来，设置用户数量（线程数量）为5.&lt;/p>
&lt;p>在下一个字段中，设置过渡时期，保留默认值1，这个属性告诉Jmeter启动每个用户需要多长时间.例如，如果你设置过渡时期为5s，Jmeter将会在5s之内完成所有用户的启动，所以，如果你设置了5个线程数，过渡期为5s，那么启动线程之间的过渡期将是1s（5用户/5s=每秒1个用户）.如果你设置这个值为0，那么JMeter将立即开启你所有的线程，中间没有间隔。&lt;/p>
&lt;p>最后一行，选择循环2次，这个属性是告诉JMeter要重复测试多少次，如果你设置的值是1，JMeter将就跑一遍，如果选择‘永远’复选框的话，JMetre将重复运行测试计划。&lt;/p>
&lt;blockquote>
&lt;p>在大多数应用程序中，你必须手动保存才能生效，然而，在JMeter中，控制面板会在你进行更改时自动保存。如果你改变了一个元素的名称，那么在你离开控制面板上之后，新元素、就会生效（例如，当我们在选择其它树元素时）&lt;/p>&lt;/blockquote>
&lt;p>查看图4.2已经设置好的JMeter线程组&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/04_jmeter_create_web_plan.png"
 data-srcset="http://img.testclass.net/04_jmeter_create_web_plan.png, http://img.testclass.net/04_jmeter_create_web_plan.png 1.5x, http://img.testclass.net/04_jmeter_create_web_plan.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/04_jmeter_create_web_plan.png"
 title="http://img.testclass.net/04_jmeter_create_web_plan.png" />&lt;/p>
&lt;h3 id="42添加http请求默认值">4.2添加HTTP请求默认值&lt;/h3>
&lt;hr>
&lt;p>现在我们已经定义了我们的用户，是时候来定义他们将要执行的任务了。在本节中，您将指定你的HTTP请求的默认设置。然后，在第4.3节中，您将添加使用此处指定的默认设置的HTTP请求元素。&lt;/p>
&lt;p>首先选择JMeter用户（线程组）。点击你的鼠标右键来添加菜单，然后选择 &lt;strong>“添加→配置元件→HTTP请求默认值”&lt;/strong>。然后选中HTTP请求默认值以查看其控制面板（见图4.3）。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/04_jmeter_http_requestd_defaults.png"
 data-srcset="http://img.testclass.net/04_jmeter_http_requestd_defaults.png, http://img.testclass.net/04_jmeter_http_requestd_defaults.png 1.5x, http://img.testclass.net/04_jmeter_http_requestd_defaults.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/04_jmeter_http_requestd_defaults.png"
 title="http://img.testclass.net/04_jmeter_http_requestd_defaults.png" />
图4.3，HTTP请求默认值&lt;/p></description></item><item><title>appium简明教程（4）——appium client的安装</title><link>https://itest2025.pages.dev/tutorials/21-004-appium%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B4appium-client%E7%9A%84%E5%AE%89%E8%A3%85/</link><pubDate>Thu, 17 Aug 2017 07:24:12 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/21-004-appium%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B4appium-client%E7%9A%84%E5%AE%89%E8%A3%85/</guid><description>&lt;p>appium client是对webdriver原生api的一些扩展和封装。它可以帮助我们更容易的写出用例，写出更好懂的用例。&lt;/p>
&lt;p>appium client是配合原生的webdriver来使用的，因此二者必须配合使用缺一不可。&lt;/p>
&lt;p>从本节开始，教程的内容将涵盖3个语言，ruby/python/java。&lt;/p>
&lt;p>本文版权归乙醇所有，欢迎转载，但请注明作者与出处，严禁用于任何商业用途&lt;/p>
&lt;h3 id="安装appium-client">安装appium client&lt;/h3>
&lt;h4 id="ruby篇一定要在线安装">ruby篇（一定要在线安装）&lt;/h4>
&lt;p>ruby的appium client叫做appium lib，为什么是这样就不解释了，总之是历史原因。&lt;/p>
&lt;p>首先update rubygem和bundler(说老实话，真的不需要，但官方文档上这么写)&lt;/p>
&lt;pre tabindex="0">&lt;code>gem update --system ;\
gem update bundler
&lt;/code>&lt;/pre>&lt;p>然后使用gem安装&lt;/p>
&lt;pre tabindex="0">&lt;code>gem uninstall -aIx appium_lib ;\(这个也不是必须的)
gem install --no-rdoc --no-ri appium_lib
&lt;/code>&lt;/pre>&lt;h4 id="python篇尽量在线安装">python篇（尽量在线安装）&lt;/h4>
&lt;p>推荐使用pip安装&lt;/p>
&lt;pre tabindex="0">&lt;code>pip install Appium-Python-Client
&lt;/code>&lt;/pre>&lt;p>当然了也可以在Pipy上下载源码安装&lt;/p>
&lt;pre tabindex="0">&lt;code>tar -xvf Appium-Python-Client-X.X.tar.gz（windows上用7zip可以解压）
cd Appium-Python-Client-X.X
python setup.py install
&lt;/code>&lt;/pre>&lt;p>最后，也可以通过github安装（要git客户端）&lt;/p>
&lt;pre tabindex="0">&lt;code>git clone git@github.com:appium/python-client.git
cd python-client
python setup.py install
&lt;/code>&lt;/pre>&lt;h4 id="java篇在线安装">java篇（在线安装）&lt;/h4>
&lt;p>java的话用maven安装就可以了&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;lt;dependency&amp;gt;
 &amp;lt;groupId&amp;gt;io.appium&amp;lt;/groupId&amp;gt;
 &amp;lt;artifactId&amp;gt;java-client&amp;lt;/artifactId&amp;gt;
 &amp;lt;version&amp;gt;1.3.0&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code>&lt;/pre>&lt;p>当然了，也可以自己&lt;a href="http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22io.appium%22%20AND%20a%3A%22java-client%22" target="_blank" rel="noopener noreffer ">下载jar包&lt;/a>，请自行选择最新版本。&lt;/p>
&lt;p>本文版权归乙醇所有，欢迎转载，但请注明作者与出处，严禁用于任何商业用途&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1462332420958-a05d1e002413?w=300"
 data-srcset="https://images.unsplash.com/photo-1462332420958-a05d1e002413?w=300, https://images.unsplash.com/photo-1462332420958-a05d1e002413?w=300 1.5x, https://images.unsplash.com/photo-1462332420958-a05d1e002413?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1462332420958-a05d1e002413?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>性能测试基础（四）吞吐量</title><link>https://itest2025.pages.dev/tutorials/14-004-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E5%9F%BA%E7%A1%80%E5%9B%9B%E5%90%9E%E5%90%90%E9%87%8F/</link><pubDate>Fri, 11 Aug 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/14-004-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E5%9F%BA%E7%A1%80%E5%9B%9B%E5%90%9E%E5%90%90%E9%87%8F/</guid><description>&lt;br>
我们每天的生活中都在用水用电，如果我们把水龙头拧到最大，还是一滴水不出。那我们就会找物业/房东去询问情况，但一般不会想过去找自来水公司解决。我们每天都会上网，看电影很卡，需要等很久才缓冲一个几帧；打开网页很慢，IE状态条一直50%，那我们就会找电信服务器商，而不是某视频网站的客服。
&lt;p>以上的情况是正常的，这是生活常识。我想说明的是，你可能从来不关心一个自来水厂供应多少水，但供应多少水对一个自来厂来说却非常重要。你也可能从来不关心一个系统的吞吐量，但吞吐量对一个系统来说却非常重要。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/throughput.png"
 data-srcset="http://img.testclass.net/throughput.png, http://img.testclass.net/throughput.png 1.5x, http://img.testclass.net/throughput.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/throughput.png"
 title="http://img.testclass.net/throughput.png" />&lt;/p>
&lt;p>&lt;strong>吞吐量&lt;/strong>&lt;/p>
&lt;p>指在一次性能测试过程中网络上传输的数据量的总和。&lt;/p>
&lt;p>对于交互式应用来说，吞吐量指标反映的是服务器承受的压力，在容量规划的测试中，吞吐量是一个重点关注的指标，因为它能够说明系统级别的负载能力，另外，在性能调优过程中，吞吐量指标也有重要的价值。如一个大型工厂，他们的生产效率与生产速度很快，一天生产10W吨的货物，结果工厂的运输能力不行，就两辆小型三轮车一天拉2吨的货物，比喻有些夸张，但我想说明的是这个运输能力是整个系统的瓶颈。&lt;/p>
&lt;p>但是，用吞吐量来衡量一个系统的输出能力是极其不准确的，用个最简单的例子说明，一个水龙头开24小时，流出10吨水；10个水龙头开1秒钟，流出0.1吨水。当然是一个水龙头的吞吐量大。你能说1个水龙头的出水能力远超10个水龙头？所以，我们要加单位时间的限制，每秒/出水量，这就引出了一个新的概念&amp;ndash;吞吐率。&lt;/p>
&lt;p>&lt;strong>吞吐率&lt;/strong>&lt;/p>
&lt;p>单位时间内网络上传输的数据量，也可以指单位时间内处理客户请求数量。它是衡量网络性能的重要指标，通常情况下，吞吐率用“字节数/秒”来衡量，当然，你可以用“请求数/秒”和“页面数/秒”来衡量。其实，不管是一个请求还是一个页面，它的本质都是在网络上传输的数据，那么来表示数据的单位就是字节数。&lt;/p>
&lt;p>但是从业务的角度看，吞吐率也可以用“业务数/小时”、“访问人数/小时”、“页面访问量/小时”来衡量。例如，在银行卡审批系统中，可以用“千件/小时”来衡量系统的业务处理能力。那么，从用户的角度，一个表单提交可以得到一次审批。这又引出来一个概念&amp;mdash;事务。&lt;/p>
&lt;p>&lt;strong>事务&lt;/strong>&lt;/p>
&lt;p>就是用户某一步或几步操作的集合。不过，我们要保证它有一个完整意义。比如用户对某一个页面的一次请求，对某系统的一次登录，对商品的一次确认支付过程。这些我们都可以看作一个事务。那么如何衡量服务器对事务的处理能力。又引出一个概念&amp;mdash;-TPS&lt;/p>
&lt;ul>
&lt;li>TPS (Transaction Per second) &lt;/li>
&lt;/ul>
&lt;p>每秒钟系统能够处理事务或交易的数量，它是衡量系统处理能力的重要指标。&lt;/p>
&lt;ul>
&lt;li>点击率（Hit Per Second）&lt;/li>
&lt;/ul>
&lt;p>点击率可以看做是TPS的一种特定情况。点击率更能体现用户端对服务器的压力。TPS更能体现服务器对客户请求的处理能力。&lt;/p>
&lt;p>每秒钟用户向Web服务器提交的HTTP请求数。这个指标是Web 应用特有的一个指标；Web应用是“请求&amp;mdash;响应”模式，用户发一个申请，服务器就要处理一次，所以点击是Web应用能够处理的交易的最小单位。如果把每次点击定义为一个交易，点击率和TPS就是一个概念。容易看出，点击率越大。对服务器的压力也越大，点击率只是一个性能参考指标，重要的是分析点击时产生的影响。&lt;/p>
&lt;p>需要注意的是，这里的点击不能简单的看作鼠标的一次“单击”操作，也许一次“单击”操作中，客户端可能向服务器发现多个HTTP请求。&lt;/p>
&lt;br>
__吞吐量指标的作用：__
&lt;p>再次将话题回归到吞吐量上，在我们的性能测试中查看吞吐量对我们的测试有什么意义呢。&lt;/p>
&lt;p>1. 用于协助设计性能测试场景，以及衡量性能测试场景是否达到了预期的设计目标：在设计性能测试场景时，吞吐量可被用于协助设计性能测试场景，根据估算的吞吐量数据，可以对应到测试场景的事务发生频率，事务发生次数等；另外，在测试完成后，根据实际的吞吐量可以衡量测试是否达到了预期的目标。&lt;/p>
&lt;p>2. 用于协助分析性能瓶颈：吞吐量的限制是性能瓶颈的一种重要表现形式，因此，有针对性地对吞吐量设计测试，可以协助尽快定位到性能瓶颈的所在位置。&lt;/p>
&lt;br>
__扩展：__
&lt;p>RBI（rapid bottleneck identify）&lt;/p>
&lt;p>是Empirix公司提出的快速识别系统性能瓶颈的方法。该方法基于以下事实。&lt;/p>
&lt;p>    1. 发现的80%系统的性能瓶颈都由吞吐量制约；&lt;/p>
&lt;p>    2. 并发用户数和吞吐量瓶颈之间存在一定的关联；&lt;/p>
&lt;p>    3. 采用吞吐量测试可以更快速定位问题。 &lt;/p>
&lt;p>通过不断增加并发用户数和吞吐量观察系统的性能瓶颈。然后，从网络、数据库、应用服务器和代码本身4个环节确定系统的的性能瓶颈。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1435265603574-177a37a94c2f?w=300"
 data-srcset="https://images.unsplash.com/photo-1435265603574-177a37a94c2f?w=300, https://images.unsplash.com/photo-1435265603574-177a37a94c2f?w=300 1.5x, https://images.unsplash.com/photo-1435265603574-177a37a94c2f?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1435265603574-177a37a94c2f?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（四）通过id去定位页面上的元素</title><link>https://itest2025.pages.dev/tutorials/20-004-%E5%9B%9B%E9%80%9A%E8%BF%87id%E5%8E%BB%E5%AE%9A%E4%BD%8D%E9%A1%B5%E9%9D%A2%E4%B8%8A%E7%9A%84%E5%85%83%E7%B4%A0/</link><pubDate>Thu, 10 Aug 2017 07:27:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/20-004-%E5%9B%9B%E9%80%9A%E8%BF%87id%E5%8E%BB%E5%AE%9A%E4%BD%8D%E9%A1%B5%E9%9D%A2%E4%B8%8A%E7%9A%84%E5%85%83%E7%B4%A0/</guid><description>&lt;h3 id="关于定位">关于定位&lt;/h3>
&lt;p>UI的自动化测试的主要操作就是找到页面上的元素并且操作元素。找到元素一般有2个目的&lt;/p>
&lt;ul>
&lt;li>&lt;strong>操作元素:&lt;/strong> 比如点击，输入内容之类的&lt;/li>
&lt;li>&lt;strong>获取这个元素的某些属性:&lt;/strong> 比如获取一个段落元素(p)的内容，通过这个内容去验证测试是否达到了预期的效果(断言)&lt;/li>
&lt;/ul>
&lt;h3 id="定位方式">定位方式&lt;/h3>
&lt;p>selenium的javascript binding支持下面一些定位方法&lt;/p>
&lt;ul>
&lt;li>
&lt;p>By.className( name )&lt;/p>
&lt;/li>
&lt;li>
&lt;p>By.css( selector )&lt;/p>
&lt;/li>
&lt;li>
&lt;p>By.id( id )&lt;/p>
&lt;/li>
&lt;li>
&lt;p>By.js( script, &amp;hellip;var_args )&lt;/p>
&lt;/li>
&lt;li>
&lt;p>By.linkText( text )&lt;/p>
&lt;/li>
&lt;li>
&lt;p>By.name( name )&lt;/p>
&lt;/li>
&lt;li>
&lt;p>By.partialLinkText( text )&lt;/p>
&lt;/li>
&lt;li>
&lt;p>By.xpath( xpath )&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>在这些定位方式里，最简单最常用的定位方式就是通过元素的id进行定位&lt;/p>
&lt;h3 id="目的">目的&lt;/h3>
&lt;ul>
&lt;li>熟悉selenium webdriver 定位方式&lt;/li>
&lt;li>学会通过id属性去定位元素&lt;/li>
&lt;li>学会使用&lt;code>sendKeys()&lt;/code>方法&lt;/li>
&lt;/ul>
&lt;h3 id="练习对象">练习对象&lt;/h3>
&lt;p>我们使用&lt;a href="https://github.com/cbracco/html5-test-page/blob/master/index.html" target="_blank" rel="noopener noreffer ">html5-test-page&lt;/a>作为我们的练习对象。&lt;/p>
&lt;p>将html代码拷贝一份并保存到本地，文件名为&lt;code>index.html&lt;/code>。&lt;/p>
&lt;h3 id="场景">场景&lt;/h3>
&lt;p>我们将使用id定位下图所示的输入框，并输入一些内容&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://ooo.0o0.ooo/2017/06/29/5954b8e6b038a.png"
 data-srcset="https://ooo.0o0.ooo/2017/06/29/5954b8e6b038a.png, https://ooo.0o0.ooo/2017/06/29/5954b8e6b038a.png 1.5x, https://ooo.0o0.ooo/2017/06/29/5954b8e6b038a.png 2x"
 data-sizes="auto"
 alt="https://ooo.0o0.ooo/2017/06/29/5954b8e6b038a.png"
 title="https://ooo.0o0.ooo/2017/06/29/5954b8e6b038a.png" />&lt;/p>
&lt;h3 id="代码">代码&lt;/h3>
&lt;p>新建文件by_id.js，并键入下面的内容。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;path&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">webdriver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;selenium-webdriver&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">By&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">testFile&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;file://&amp;#34;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="nx">path&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">__dirname&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;index.html&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">dr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Builder&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">forBrowser&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;chrome&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">build&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">testFile&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;input__text&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;测试教程网&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;input__password&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;password&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;input__webaddress&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;http://www.itest.info&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;input__emailaddress&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;service@itest.info&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;input__phone&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;13888888888&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;input__search&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;keywords&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;input__text2&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;6666666&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;input__text3&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;should be error&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;input__text4&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;should be valid&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行结果">运行结果&lt;/h3>
&lt;p>如下图所示&lt;/p></description></item><item><title>python测试笔试题1</title><link>https://itest2025.pages.dev/tutorials/44-004-python%E6%B5%8B%E8%AF%95%E7%AC%94%E8%AF%95%E9%A2%981/</link><pubDate>Wed, 26 Jul 2017 09:30:25 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/44-004-python%E6%B5%8B%E8%AF%95%E7%AC%94%E8%AF%95%E9%A2%981/</guid><description>&lt;h3 id="哪一个方法用来返回变量类型">哪一个方法用来返回变量类型？&lt;/h3>
&lt;p>which function is usd to get type of a variable&lt;/p>
&lt;p>答案 type&lt;/p>
&lt;h3 id="哪一个方法用来列出一个类下的所有属性方法以及变量">哪一个方法用来列出一个类下的所有属性，方法，以及变量？&lt;/h3>
&lt;p>which function is used to list all names of a class&amp;rsquo;s attributes?&lt;/p>
&lt;p>答案 dir&lt;/p>
&lt;h3 id="字符串方法format是用来去掉字符串的左右空格的么">字符串方法format是用来去掉字符串的左右空格的么？&lt;/h3>
&lt;p>is the methods format used to get rid of blank space around a string?&lt;/p>
&lt;p>答案 不是&lt;/p>
&lt;h3 id="python-的类可以有多个父类么">python 的类可以有多个父类么？&lt;/h3>
&lt;p>can a class inheritance from multiple classes?&lt;/p>
&lt;p>答案 是&lt;/p>
&lt;h3 id="哪一个函数是用来获得字符串长度">哪一个函数是用来获得字符串长度？&lt;/h3>
&lt;p>which function is used to get the length of a string? len&lt;/p>
&lt;p>答案 ：len&lt;/p></description></item><item><title>（四）一个bug的生命周期</title><link>https://itest2025.pages.dev/tutorials/29-004-%E5%9B%9B%E4%B8%80%E4%B8%AAbug%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/</link><pubDate>Tue, 25 Jul 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/29-004-%E5%9B%9B%E4%B8%80%E4%B8%AAbug%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/</guid><description>&lt;br>
又一篇测试技术普及文章，希望你在被各种技术吸引的同时，能时常来整理和总结软件测试最基本的知识。
&lt;br>
#### Bug的属性
----
__Bug重现环境__
&lt;p>这个应该是我们重现bug的一个前提，如果没有这个前提，我们可能会无法重现问题，或者跟本就无从下手。&lt;/p>
&lt;ul>
&lt;li>操作系统&lt;/li>
&lt;/ul>
&lt;p>这个是一般软件运行的一大前提，基本上所有的软件都依赖于操作系统之上的，对于一个软件来说，要想在某个操作系统上运行，必须要对这个操作系统支持，这就需要有真对性的设计与开发。对于不同的操作系统，其可能存在差异（如：win xp 与 win 7）或本质的区别（如 win 7 与 CentOS linux ），所以，操作系统环境是重现问题的一个重要前提。&lt;/p>
&lt;ul>
&lt;li>浏览器&lt;/li>
&lt;/ul>
&lt;p>对于B/S系统，或面向大众的互联网产品（网站，邮箱等），浏览器的兼容性也是必须测试的一个重点，对于现在的浏览器市场，各式的浏览器都有其用户群，要想使产品大众化，必须考虑这些产品的兼容性问题。&lt;/p>
&lt;p>不同的浏览器之间（IE、 firefox、chrome、opera 等），甚至同一系列不同版本（ie6/ie7/ie8/ie9等）都可能存在兼容性问题，所以，对于这类应用，浏览器环境重现bug前提条件之一。&lt;/p>
&lt;ul>
&lt;li>其它（这个“其它”非常重要）&lt;/li>
&lt;/ul>
&lt;p>对于不同的系统发现重现问题，都会有其特定的前提，拿我测试的邮箱来说，必须要描述其是在测试线还是现网环境，而且还要附带一重现问题的帐号等。&lt;/p>
&lt;p>对于c/s软件，可能还要考虑与其它常用软的兼容等，例如，是在安装的某款软件后，对本软件的安装和使用造成影响。这些都是重现问题的必须描述的环境。&lt;/p>
&lt;p>&lt;strong>问题类型&lt;/strong>&lt;/p>
&lt;p>根据JIRA的管理系统的划分，bug 只是问题的一种，它可以用于跟踪多种不同类型的问题（其实，他只是将bug做为一子类而已）。&lt;/p>
&lt;p>JIRA系统缺省提供的问题类型（大部分的系统都可以自定义类型的，这样就增加了灵活性。）&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Bug : 测试过程、维护过程发现影响系统运行的缺陷。（这就是一般测试人员所提交的bug）&lt;/p>
&lt;/li>
&lt;li>
&lt;p>New Feature : 对系统提出的新功能。（单个的小需求可以，如果大的话，就相当于一个需求，放到这里是不合理的。）&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Task : 需要完成的一任务。（开发或测试任务指派。）&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Improvement : 对现有系统功能的改进。（一般产品经理或产品体验师做的事）&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>当然，不同的公司，他们的人员定位与职责是不太相同的，按照上面的分类，JIRA就不是简单的缺陷管理系统了，它涵盖一项目（或产品）所需要处理的任务、需求与缺陷。&lt;/p>
&lt;p>&lt;strong>Bug 类型&lt;/strong>&lt;/p>
&lt;p>这里缩小范围，单指我们测试人员在测试过程中发现的缺陷，发现产品缺陷其实就是测试人员工作的主要目的。当然，你要确定一个问题的类型，也需要对项目（或产品）有比较深的理解。是代码缺陷还是设计缺陷有时候就不太容易区分，当然，这个划分，对于开发定位问题影响很小，但对于问题类型的统计就比较重要了。&lt;/p>
&lt;p>下面看一些常见的分类：&lt;/p>
&lt;p>划分方式一：&lt;/p>
&lt;pre tabindex="0">&lt;code>　　* 代码错误

　　* 设计缺陷

　　* 界面优化

　　* 配置相关

　　* 安装部署

 * 性能问题

　　* 标准规范

　　* 测试代码

　　* 其它
&lt;/code>&lt;/pre>&lt;p>划分方式二：&lt;/p>
&lt;pre tabindex="0">&lt;code>　　* 功能类（function）

　　* 性能类（performance）

　　* 界面类（UI）

　　* 易用性类（usability）

　　* 兼容性类（compatibility）

　　* 其它（else）
&lt;/code>&lt;/pre>&lt;p>这个分类当然是可以自定义的，具我接触的缺陷管理都是可以自定义的，既然是对问题的管理，那么你当然可以拿来做特定环境下的系统来使用，或我就想用这个系统来指派任务，那么我的自定义类型为前端任务、后端任务、测试任务、配置部署&amp;hellip;&lt;/p></description></item><item><title>（四）selenium3 浏览器驱动</title><link>https://itest2025.pages.dev/tutorials/19-004-%E5%9B%9Bselenium3-%E6%B5%8F%E8%A7%88%E5%99%A8%E9%A9%B1%E5%8A%A8/</link><pubDate>Tue, 04 Jul 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/19-004-%E5%9B%9Bselenium3-%E6%B5%8F%E8%A7%88%E5%99%A8%E9%A9%B1%E5%8A%A8/</guid><description>&lt;br>
### 下载浏览器驱动
&lt;p>当selenium升级到3.0之后，对不同的浏览器驱动进行了规范。如果想使用selenium驱动不同的浏览器，必须单独下载并设置不同的浏览器驱动。&lt;/p>
&lt;p>各浏览器下载地址：&lt;/p>
&lt;p>Firefox浏览器驱动：&lt;a href="https://github.com/mozilla/geckodriver/releases" target="_blank" rel="noopener noreffer ">geckodriver&lt;/a>&lt;/p>
&lt;p>Chrome浏览器驱动：&lt;a href="https://sites.google.com/a/chromium.org/chromedriver/home" target="_blank" rel="noopener noreffer ">chromedriver&lt;/a> &lt;a href="https://npm.taobao.org/mirrors/chromedriver" target="_blank" rel="noopener noreffer ">taobao备用地址&lt;/a>&lt;/p>
&lt;p>IE浏览器驱动：&lt;a href="http://selenium-release.storage.googleapis.com/index.html" target="_blank" rel="noopener noreffer ">IEDriverServer&lt;/a>&lt;/p>
&lt;p>Edge浏览器驱动：&lt;a href="https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver" target="_blank" rel="noopener noreffer ">MicrosoftWebDriver&lt;/a>&lt;/p>
&lt;p>Opera浏览器驱动：&lt;a href="https://github.com/operasoftware/operachromiumdriver/releases" target="_blank" rel="noopener noreffer ">operadriver&lt;/a>&lt;/p>
&lt;p>PhantomJS浏览器驱动：&lt;a href="http://phantomjs.org" target="_blank" rel="noopener noreffer ">phantomjs&lt;/a>&lt;/p>
&lt;p>注：部分浏览器驱动地址需要科学上网。&lt;/p>
&lt;br>
### 设置浏览器驱动
&lt;p>设置浏览器的地址非常简单。
我们可以手动创建一个存放浏览器驱动的目录，如： C:\driver , 将下载的浏览器驱动文件（例如：chromedriver、geckodriver）丢到该目录下。&lt;/p>
&lt;p>我的电脑&amp;ndash;&amp;gt;属性&amp;ndash;&amp;gt;系统设置&amp;ndash;&amp;gt;高级&amp;ndash;&amp;gt;环境变量&amp;ndash;&amp;gt;系统变量&amp;ndash;&amp;gt;Path，将“C:\driver”目录添加到Path的值中。&lt;/p>
&lt;ul>
&lt;li>Path&lt;/li>
&lt;li>;C:\driver&lt;/li>
&lt;/ul>
&lt;br>
### 设置浏览器驱动
&lt;p>验证不同的浏览器驱动是否正常使用。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.chrome.ChromeDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.firefox.FirefoxDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.edge.EdgeDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.ie.InternetExplorerDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.opera.OperaDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.phantomjs.PhantomJSDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="err">……&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">WebDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ChromeDriver&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//Chrome浏览器&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">WebDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">FirefoxDriver&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//Firefox浏览器&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">WebDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">EdgeDriver&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//Edge浏览器&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">WebDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">InternetExplorerDriver&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// Internet Explorer浏览器&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">WebDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">OperaDriver&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//Opera浏览器&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">WebDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">PhantomJSDriver&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//PhantomJS&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="err">……&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p></description></item><item><title>（四）控制浏览器操作</title><link>https://itest2025.pages.dev/tutorials/24-004-%E5%9B%9B%E6%8E%A7%E5%88%B6%E6%B5%8F%E8%A7%88%E5%99%A8%E6%93%8D%E4%BD%9C/</link><pubDate>Tue, 27 Jun 2017 07:37:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/24-004-%E5%9B%9B%E6%8E%A7%E5%88%B6%E6%B5%8F%E8%A7%88%E5%99%A8%E6%93%8D%E4%BD%9C/</guid><description>&lt;br>
### 控制浏览器窗口大小
&lt;p>有时候我们希望能以某种浏览器尺寸打开，让访问的页面在这种尺寸下运行。例如可以将浏览器设置成移动端大小(480* 800)，然后访问移动站点，对其样式进行评估；WebDriver提供了set_window_size()方法来设置浏览器的大小。&lt;/p>
&lt;pre tabindex="0">&lt;code>from selenium import webdriver

driver = webdriver.Firefox()
driver.get(&amp;#34;http://m.baidu.com&amp;#34;)

# 参数数字为像素点
print(&amp;#34;设置浏览器宽480、高800显示&amp;#34;)
driver.set_window_size(480, 800)
driver.quit()
&lt;/code>&lt;/pre>&lt;p>在PC端执行自动化测试脚本大多的情况下是希望浏览器在全屏幕模式下执行，那么可以使用maximize_window()方法使打开的浏览器全屏显示，其用法与set_window_size() 相同，但它不需要参数。&lt;/p>
&lt;br>
### 控制浏览器后退、前进
&lt;p>在使用浏览器浏览网页时，浏览器提供了后退和前进按钮，可以方便地在浏览过的网页之间切换，WebDriver也提供了对应的back()和forward()方法来模拟后退和前进按钮。下面通过例子来演示这两个方法的使用。&lt;/p>
&lt;pre tabindex="0">&lt;code>from selenium import webdriver

driver = webdriver.Firefox()

#访问百度首页
first_url= &amp;#39;http://www.baidu.com&amp;#39;
print(&amp;#34;now access %s&amp;#34; %(first_url))
driver.get(first_url)

#访问新闻页面
second_url=&amp;#39;http://news.baidu.com&amp;#39;
print(&amp;#34;now access %s&amp;#34; %(second_url))
driver.get(second_url)

#返回（后退）到百度首页
print(&amp;#34;back to %s &amp;#34;%(first_url))
driver.back()

#前进到新闻页
print(&amp;#34;forward to %s&amp;#34;%(second_url))
driver.forward()

driver.quit()
&lt;/code>&lt;/pre>&lt;p>为了看清脚本的执行过程，下面每操作一步都通过print()来打印当前的URL地址。&lt;/p>
&lt;br>
### 刷新页面
&lt;p>有时候需要手动刷新（F5） 页面。&lt;/p>
&lt;pre tabindex="0">&lt;code>……
driver.refresh() #刷新当前页面
……
&lt;/code>&lt;/pre>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1431887773042-803ed52bed26?w=300"
 data-srcset="https://images.unsplash.com/photo-1431887773042-803ed52bed26?w=300, https://images.unsplash.com/photo-1431887773042-803ed52bed26?w=300 1.5x, https://images.unsplash.com/photo-1431887773042-803ed52bed26?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1431887773042-803ed52bed26?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>浅谈测试用例</title><link>https://itest2025.pages.dev/tutorials/13-005-%E6%B5%85%E8%B0%88%E6%B5%8B%E8%AF%95%E7%94%A8%E4%BE%8B/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/13-005-%E6%B5%85%E8%B0%88%E6%B5%8B%E8%AF%95%E7%94%A8%E4%BE%8B/</guid><description>&lt;br>
#### 一、什么是测试用例？
----
测试用例是为某个特殊目标而编制的一组测试输入、执行条件以及预期结果，以便测试某个程序路径或核实是否满足某个特定需求。
&lt;p>通俗的讲：就是把我们测试系统的操作步骤用按照一定的格式用文字描述出来。&lt;/p>
&lt;br>
#### 二、写测试用例有什么好处？
----
* 理清思路，避免遗漏
&lt;p>这里是我们认为最重要的一点，假如我们测试的项目大而复杂，我们可以把项目功能细分，根据每一个功能通过编写用例的方式来整理我们测试系统的思路，避免遗漏掉要测试的功能点。&lt;/p>
&lt;ul>
&lt;li>跟踪测试进展&lt;/li>
&lt;/ul>
&lt;p>通过编写测试用例，执行测试用例，我们可以很清楚的知道我们的测试进度。&lt;/p>
&lt;ul>
&lt;li>历史参考&lt;/li>
&lt;/ul>
&lt;p>在我们所做的项目中，也许会有很多功能是相同或相近的，我们对这类功能设计了测试用例，便于以后我们遇到类似功能的时候可以做参考依据。&lt;/p>
&lt;ul>
&lt;li>重复性&lt;/li>
&lt;/ul>
&lt;p>我们测试一个系统不是一个人测一遍就算测完的，需要多人反复的进行测试，那么我们就需要测试用例来规范和指导我们的测试行为。&lt;/p>
&lt;br>
#### 三、测试用例的方法
----
好吧，咱知道啥是测试用例了，也是知道为什么要写测试用例了，那到底应该怎么写？无从下手啊。我们在写测试用例之前，先学习几种方法，它是我们写测试用例的指导思想。
&lt;ul>
&lt;li>等价类划分&lt;/li>
&lt;/ul>
&lt;p>等价类是指某个输入域的一个特定的子集合，在该子集合中各个输入数据对于揭露程序中的错误都是等效的，也就是说，如果用这个等价类中的代表值作为测试用例未发现程序错误，那么该类中其他数据（测试用例）也不会发现程序中的错误。&lt;/p>
&lt;p>&lt;strong>有效等价类：&lt;/strong> 输入满足程序输入的要求（来自规格说明书），通俗的说就是正确的输入。&lt;/p>
&lt;p>&lt;strong>无效等价类：&lt;/strong> 输入不满足程序输入的要求，即异常输入，需要系统对此有一定的容错性。&lt;/p>
&lt;p>例如：&lt;/p>
&lt;p>一个输入框要求输入1-10000的数字&lt;/p>
&lt;p>有效等价类：可以输入1-10000之间的数来验证，如：2、5、99、8495&amp;hellip;&amp;hellip;&lt;/p>
&lt;p>无效等价类：可以输入1-10000之外的任意字符验证，如：0、10001、字母、下划线、特殊符号、空格、回车&amp;hellip;..&lt;/p>
&lt;ul>
&lt;li>边界值&lt;/li>
&lt;/ul>
&lt;p>边界值是对等价类的补充，测试工作经验告诉我们，大量的错误是出在输入输出的边界价上。我们还拿上面的例子，一个输入框要求输入1-10000之间的数。我们要测它有没有超出这个范围，如：0、-1、-2、1000、10001&amp;hellip;..等等，来判定是否超出了我们的范围。&lt;/p>
&lt;ul>
&lt;li>因果图&lt;/li>
&lt;/ul>
&lt;p>因果图方法最终生成的就是判定表，它适合于检查程序输入条件的各种组合情况。举个例子：原因：A=0，B=0，结果我就可以判定：A=B。确切的说他是一种因果关系思想。它会无形中指导这我们的测试。当然了，我们为了以免遗漏，可以把系统中的因果关系用图画出。不过系统大而复杂的话就是个体力活了。呵呵。&lt;/p>
&lt;ul>
&lt;li>错误推测法&lt;/li>
&lt;/ul>
&lt;p>基于经验和直觉推测出系统可能存在的错误，从而有针对性的设计测试用例的方法。&lt;/p>
&lt;ul>
&lt;li>其它&lt;/li>
&lt;/ul>
&lt;p>设计测试用例的方法有很多，我们常用就上面几种，其它的方法还有：状态迁移图、流程分析法、正交验证法等等。&lt;/p>
&lt;br>
#### 四、测试用例的格式与要素
----
一个测试用例应该包括：编号，标题，测试场景，测试步骤，预期结果。
&lt;p>当然还可加入一些它选项，如：优先级、测试阶段&amp;hellip;.&lt;/p>
&lt;pre tabindex="0">&lt;code>编号：

标题:

测试环境：

测试步骤：

预期结果：
&lt;/code>&lt;/pre>&lt;p>关于测试用例的存放管理：&lt;/p>
&lt;p>1、项目管理系统自带的用例管理，一般用例会与项目挂钩，有固定的格式，搜索、修改等功能，使用起来非常方便。如：禅道项目管理、QC、bugfree 等等都带的有用例管理功能。&lt;/p>
&lt;p>2、通过world\Excel文档形式管理，这样的好处就是自己定义测试用例的格式。&lt;/p>
&lt;p>面来看一个具体的测试用例。我们会有更深刻的认识。&lt;/p>
&lt;pre tabindex="0">&lt;code>编号：001

标题: 系统登录测试用例

测试环境：
Windows 10/Chrome 58


测试步骤：
1、打开浏览器，输入系统网站，打开登录页面。
2、用户名密码为空，点击登录按钮
3、输入用户名，密码为空，点击登录按钮。
4、用户名为空，输入密码，点击登录按钮。
5、用户名正确，密码错误，点击登录按钮。
....


预期结果：
1、成功打开首页。
2、系统提示：用户名密码不能为空。
3、系统提示：密码不能为空。
4、系统提示：用户名不能为空。
5、系统提示：用户名或密码错误。
....
&lt;/code>&lt;/pre>&lt;br>
__最后__ ，写好测试用例，除了掌握基本的测试方法之外，最重要的是，要去深入理解业务需求。
从需求文档中抽出测试点；另外善于总结以往测试中发现的bug，完善测试用例。
&lt;p>原始封面&lt;/p></description></item><item><title>wrk系列教程(5)lua扩展</title><link>https://itest2025.pages.dev/tutorials/15-005-wrk%E7%B3%BB%E5%88%97%E6%95%99%E7%A8%8B5lua%E6%89%A9%E5%B1%95/</link><pubDate>Sun, 03 Mar 2019 02:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/15-005-wrk%E7%B3%BB%E5%88%97%E6%95%99%E7%A8%8B5lua%E6%89%A9%E5%B1%95/</guid><description>&lt;p>&lt;a href="https://github.com/wg/wrk/blob/master/SCRIPTING" target="_blank" rel="noopener noreffer ">官方文档&lt;/a>上面对wrk的lua脚本扩展方式有详细的说明。&lt;/p>
&lt;p>lua脚本可以为wrk增加更多灵活的功能，通过代码扩展，wrk的定制能力会有很大的提升。&lt;/p>
&lt;h3 id="钩子函数">钩子函数&lt;/h3>
&lt;p>wrk提供了一些简单的钩子函数，可以实现在测试过程中对请求及场景做定制化的增强。&lt;/p>
&lt;p>这些函数分别是&lt;/p>
&lt;ul>
&lt;li>setup()&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1496851473196-e26508c21494?w=300"
 data-srcset="https://images.unsplash.com/photo-1496851473196-e26508c21494?w=300, https://images.unsplash.com/photo-1496851473196-e26508c21494?w=300 1.5x, https://images.unsplash.com/photo-1496851473196-e26508c21494?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1496851473196-e26508c21494?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>python简明教程: 5. 类</title><link>https://itest2025.pages.dev/tutorials/39-005-python%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B-5-%E7%B1%BB/</link><pubDate>Sun, 18 Nov 2018 03:23:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/39-005-python%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B-5-%E7%B1%BB/</guid><description>&lt;p>本文内容基本上翻译自&lt;a href="http://cheat.sh/python/:learn" target="_blank" rel="noopener noreffer ">http://cheat.sh/python/:learn)&lt;/a>&lt;/p>
&lt;p>&lt;strong>非原创, 非原创, 非原创!!!&lt;/strong>&lt;/p>
&lt;p>感谢原文社区作者&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">####################################################&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 5. 类&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">####################################################&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 以继承object的方式来定义1个类&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Human&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">object&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 类属性，所有类实例都共享&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">species&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;H. sapiens&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 基本的构造函数，当类实例化的时候会自动被调用&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 注意双下划线开头和结尾的变量是python保留的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 你不应该自己定义类似风格的变量&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 将参数里name赋值给同名的实例属性&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">name&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 初始化属性&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">age&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 实例方法，第一个参数必须是self&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">say&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">msg&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{0}&lt;/span>&lt;span class="s2">: &lt;/span>&lt;span class="si">{1}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">msg&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 类方法，所有实例共享&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 调用的时候第1个参数代表这个类本身&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@classmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">get_species&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">cls&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="bp">cls&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">species&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 静态方法被调用的时候是不需要传入类或实例的引用(kls,self)的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@staticmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">grunt&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s2">&amp;#34;*grunt*&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 属性有点像getter.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 这个将 age() 方法变成了同名的只读的属性(调用的时候不用加括号了)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@property&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">age&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_age&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 这样就可以允许属性被赋值了&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@age.setter&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">age&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">age&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_age&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">age&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 这样就可以允许属性被删除&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@age.deleter&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">age&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">del&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_age&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 实例化1个类&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Human&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;Ian&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">say&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;hi&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 打印出 &amp;#34;Ian: hi&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">j&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Human&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Joel&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span> &lt;span class="n">j&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">say&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;hello&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 打印出 &amp;#34;Joel: hello&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 调用类方法&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">i&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_species&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;H. sapiens&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 修改类属性&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Human&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">species&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;H. neanderthalensis&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">i&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_species&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;H. neanderthalensis&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">j&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_species&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;H. neanderthalensis&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 调用静态方法&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Human&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">grunt&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1"># =&amp;gt; &amp;#34;*grunt*&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 更新属性&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">i&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">age&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">42&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 获取属性&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">i&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">age&lt;/span> &lt;span class="c1"># =&amp;gt; 42&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 删除属性&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">del&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">age&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">i&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">age&lt;/span> &lt;span class="c1"># =&amp;gt; 抛出AttributeError异常&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p></description></item><item><title>（五）Docker 仓库</title><link>https://itest2025.pages.dev/tutorials/30-005-%E4%BA%94docker-%E4%BB%93%E5%BA%93/</link><pubDate>Mon, 22 Jan 2018 14:40:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/30-005-%E4%BA%94docker-%E4%BB%93%E5%BA%93/</guid><description>&lt;p>前面在下载镜像的适应已经用到了Docker仓库，如果是镜像的一个托管平吧。&lt;/p>
&lt;h4 id="仓库">仓库&lt;/h4>
&lt;hr>
&lt;p>一个容易混淆的概念是注册服务器（Registry）。 实际上注册服务器是管理仓库的具体服务器，每个服务器上可以有多个仓库，而每个仓库下面有多个镜像。从这方面来说， 仓库可以被认为是一个具体的项目或目录。例如对于仓库地址 	&lt;code>registry.hub.docker.com/ubuntu&lt;/code>	来说，&lt;code>registry.hub.docker.com&lt;/code>是注册服务器地址，&lt;code>ubuntu&lt;/code>是仓库名。大部分时候，并不需要严格区分这两者的概念。&lt;/p>
&lt;h5 id="docker-hub">Docker Hub&lt;/h5>
&lt;p>目前Docker官方维护了一个公共仓库 Docker Hub：https://hub.docker.com&lt;/p>
&lt;p>我们可以在Docker Hub上完成注册。这样就可以使用Docker Hub 来托管我们的镜像了。&lt;/p>
&lt;p>通过&lt;code>docker	search&lt;/code>命令来查找官方仓库中的镜像，并利用&lt;code>docker pull&lt;/code> 命令来将它下载到本地。&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo docker search ubuntu
&lt;/code>&lt;/pre>&lt;h4 id="使用国内镜像">使用国内镜像&lt;/h4>
&lt;p>参考地址：https://www.docker-cn.com/registry-mirror&lt;/p>
&lt;p>临时性的使用：&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo docker pull registry.docker-cn.com/library/ubuntu:16.04
&lt;/code>&lt;/pre>&lt;p>永久性的使用：&lt;/p>
&lt;p>修改 /etc/docker/daemon.json文件（没有的话可以手动创建，需要通过&lt;code>root&lt;/code>用户操作）并添加上 registry-mirrors 键值。&lt;/p>
&lt;pre tabindex="0">&lt;code>{
 &amp;#34;registry-mirrors&amp;#34;: [&amp;#34;https://registry.docker-cn.com&amp;#34;]
}
&lt;/code>&lt;/pre>&lt;p>修改保存后重启Docker服务以使配置生效。&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo service docker restart
&lt;/code>&lt;/pre>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1705365212953-153ebe92cce3?w=300"
 data-srcset="https://images.unsplash.com/photo-1705365212953-153ebe92cce3?w=300, https://images.unsplash.com/photo-1705365212953-153ebe92cce3?w=300 1.5x, https://images.unsplash.com/photo-1705365212953-153ebe92cce3?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1705365212953-153ebe92cce3?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（五）Java数据结构：数组和HashMap</title><link>https://itest2025.pages.dev/tutorials/16-005-%E4%BA%94java%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E6%95%B0%E7%BB%84%E5%92%8Chashmap/</link><pubDate>Wed, 17 Jan 2018 14:38:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/16-005-%E4%BA%94java%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E6%95%B0%E7%BB%84%E5%92%8Chashmap/</guid><description>&lt;p>Java的数据结构包含的数接口和类分好多种，不过，我觉得最常用的就是数组和HashMap（反正是我最常用的），所以，将他们拿出来介绍一下。&lt;/p>
&lt;h4 id="数组">数组&lt;/h4>
&lt;hr>
&lt;p>&lt;strong>数组&lt;/strong> 保存的是一组有顺序的、具有相同类型的数据。在Java的数组中，所有数据元素的数据类型都是相同的，可以通过数组的下标来访问数组。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">JavaList&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">group&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="n">5&lt;/span>&lt;span class="o">]&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">group&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="n">0&lt;/span>&lt;span class="o">]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;小明&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">group&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="o">]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;老师&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">group&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="o">]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;老王&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">group&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="n">3&lt;/span>&lt;span class="o">]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;张三&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">group&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="n">4&lt;/span>&lt;span class="o">]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;李四&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">0&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">group&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">length&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="o">++&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">group&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="o">]&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在创建数组的时候需要为其分配空间大小， 在本例子中， 通过循环将 0~4 之间的 5 个数放到的数组 group 中。&lt;/p></description></item><item><title>TDD实战（五）“井字游戏” 需求三</title><link>https://itest2025.pages.dev/tutorials/32-005-tdd%E5%AE%9E%E6%88%98%E4%BA%94%E4%BA%95%E5%AD%97%E6%B8%B8%E6%88%8F-%E9%9C%80%E6%B1%82%E4%B8%89/</link><pubDate>Mon, 08 Jan 2018 12:45:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/32-005-tdd%E5%AE%9E%E6%88%98%E4%BA%94%E4%BA%95%E5%AD%97%E6%B8%B8%E6%88%8F-%E9%9C%80%E6%B1%82%E4%B8%89/</guid><description>&lt;h3 id="需求3">需求3&lt;/h3>
&lt;hr>
&lt;p>继续实现需求3，检查所可能获胜的情况，只要满足其中一个，就宣布相应玩家获胜。&lt;/p>
&lt;blockquote>
&lt;p>最先在水平、锤直或对角线上将自己的3个标记连起来的玩家获胜。&lt;/p>&lt;/blockquote>
&lt;h4 id="测试用例1">测试用例1&lt;/h4>
&lt;hr>
&lt;p>现在我们检查是否有垂直线完全被某个玩家占据。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">whenPlayAndWholeVerticalLineThenWinner&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">ticTacToe&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">play&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//X&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">ticTacToe&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">play&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//O&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">ticTacToe&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">play&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">3&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//X&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">ticTacToe&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">play&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//O&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">ticTacToe&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">play&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//O&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">actual&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ticTacToe&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">play&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">3&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//O&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;O is the winner&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">actual&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>一个玩家的棋子占据整条垂直线就赢了。&lt;/p>
&lt;h5 id="实现代码1">实现代码1&lt;/h5>
&lt;p>这个实现和前面一个类似，前面在水平方向上做检查，现在需要在垂直方向上做同样的检查。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">private&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">boolean&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">isWin&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">playerTotal&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">lastPlayer&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">3&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">0&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">SIZE&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="o">++&lt;/span>&lt;span class="p">){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">board&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="n">0&lt;/span>&lt;span class="o">][&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="o">]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">board&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="o">][&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="o">]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">board&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="o">][&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="o">]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">==&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">playerTotal&lt;/span>&lt;span class="p">){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">return&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="k">else&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">board&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="o">][&lt;/span>&lt;span class="n">0&lt;/span>&lt;span class="o">]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">board&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="o">][&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="o">]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">board&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="o">][&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="o">]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">==&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">playerTotal&lt;/span>&lt;span class="p">){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">return&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">return&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>** &lt;strong>执行 测试用例1 检查它是否运行通过。&lt;/strong>&lt;/p></description></item><item><title>Android测试（五）：Instrumented 单元测试</title><link>https://itest2025.pages.dev/tutorials/17-005-android%E6%B5%8B%E8%AF%95%E4%BA%94instrumented-%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/</link><pubDate>Wed, 20 Dec 2017 14:35:12 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/17-005-android%E6%B5%8B%E8%AF%95%E4%BA%94instrumented-%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/</guid><description>&lt;p>原文：https://developer.android.com/training/testing/unit-testing/instrumented-unit-tests.html&lt;/p>
&lt;p>Instrumented 单元测试是在真机和模拟器上运行的测试，它可以利用Android框架API和支持的API（如Android测试支持库）。如果你的测试需要访问工具信息（例如目标应用程序的&lt;code>Context&lt;/code>），或者需要真正实现Android框架组件（如&lt;code>Parcelable&lt;/code>或&lt;code>SharedPreferences&lt;/code>对象），则应该创建Instrumented 单元测试。&lt;/p>
&lt;p>使用Instrumented单元测试还有助于减少编写和维护mock代码所需的工作量。 如果你愿意，仍然可以自由地使用一个mock框架模拟任何依赖关系。&lt;/p>
&lt;h4 id="设置测试环境">设置测试环境&lt;/h4>
&lt;hr>
&lt;p>在你的Android Studio项目中，你必须将mock测试的源文件存储在module-name/src/androidTest/java/ 中。 创建新项目时该目录已经存在，并包含示例代码。&lt;/p>
&lt;p>在开始之前，你应该下载Android测试支持库安装程序，该安装程序提供的API可让你快速构建和运行应用程序的检测代码。测试支持库包括用于功能性UI测试（Espresso和UI Automator）的JUnit 4测试运行器（AndroidJUnitRunner）和API。&lt;/p>
&lt;p>还需要为项目配置Android测试依赖项，以使用测试运行程序和测试支持库提供的规则API。 为了简化测试开发，还应该包含Hamcrest库，它可以让你使用Hamcrest匹配器API创建更灵活的断言。&lt;/p>
&lt;p>在你的App的顶级build.gradle文件中将这些库指定为依赖项：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">dependencies&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">    &lt;/span>&lt;span class="n">androidTestCompile&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">com&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">android&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">support&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">support&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">annotations&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">24&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">0&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">    &lt;/span>&lt;span class="n">androidTestCompile&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">com&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">android&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">support&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">test&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">runner&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">5&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">    &lt;/span>&lt;span class="n">androidTestCompile&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">com&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">android&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">support&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">test&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">rules&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">5&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">    &lt;/span>&lt;span class="c1">// Optional -- Hamcrest library&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">    &lt;/span>&lt;span class="n">androidTestCompile&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">org&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">hamcrest&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">hamcrest&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">library&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">3&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">    &lt;/span>&lt;span class="c1">// Optional -- UI testing with Espresso&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">    &lt;/span>&lt;span class="n">androidTestCompile&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">com&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">android&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">support&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">test&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">espresso&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">espresso&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">core&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">2&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">2&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">    &lt;/span>&lt;span class="c1">// Optional -- UI testing with UI Automator&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">    &lt;/span>&lt;span class="n">androidTestCompile&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">com&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">android&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">support&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">test&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">uiautomator&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">uiautomator&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">v18&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">1&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">2&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>警告：&lt;/strong> 如果构建配置包含support-annotations库的编译依赖项和espresso-core库的androidTestCompile依赖项，则由于依赖冲突，构建可能会失败。 请按照下面步骤更新对espresso-core的依赖关系：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">androidTestCompile&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">com&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">android&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">support&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">test&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">espresso&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">espresso&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">core&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">2&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">2&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">    &lt;/span>&lt;span class="n">exclude&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">group&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">com&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">android&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">support&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">module&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">support&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">annotations&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">})&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>要使用JUnit 4测试类，请确保将AndroidJUnitRunner指定为项目中的默认测试工具运行器，方法是在应用程序的模块级build.gradle文件中包含以下设置：&lt;/p></description></item><item><title>Fiddler（五）设置显式IP地址</title><link>https://itest2025.pages.dev/tutorials/23-005-fiddler%E4%BA%94%E8%AE%BE%E7%BD%AE%E6%98%BE%E5%BC%8Fip%E5%9C%B0%E5%9D%80/</link><pubDate>Tue, 19 Dec 2017 13:45:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/23-005-fiddler%E4%BA%94%E8%AE%BE%E7%BD%AE%E6%98%BE%E5%BC%8Fip%E5%9C%B0%E5%9D%80/</guid><description>&lt;p>在测试过程中，我们经常需要通过host在不同的环境之间切换，如果知道自己的环境是否切换成功，那么通过IP地址就很容易判断。&lt;/p>
&lt;h4 id="fiddler设置显示ip地址">Fiddler设置显示IP地址&lt;/h4>
&lt;hr>
&lt;p>打开Fiddler, 菜单栏：&lt;strong>Rules-&amp;gt;Customize Rules…&lt;/strong> 或快捷键 &lt;strong>Ctrl+R&lt;/strong> 。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/fiddler_07_1.png"
 data-srcset="http://img.testclass.net/fiddler_07_1.png, http://img.testclass.net/fiddler_07_1.png 1.5x, http://img.testclass.net/fiddler_07_1.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/fiddler_07_1.png"
 title="http://img.testclass.net/fiddler_07_1.png" />&lt;/p>
&lt;p>通过快捷键 &lt;strong>Ctrl+F&lt;/strong> ,搜索：&lt;strong>static function Main()&lt;/strong> 函数。 在函数中添加一行代码，如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-JavaScript" data-lang="JavaScript">&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// The Main() function runs everytime your FiddlerScript compiles
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kr">static&lt;/span> &lt;span class="kd">function&lt;/span> &lt;span class="nx">Main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">var&lt;/span> &lt;span class="nx">today&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nb">Date&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nb">Date&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">FiddlerObject&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">StatusText&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34; CustomRules.js was loaded at: &amp;#34;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="nx">today&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 显示IP 地址
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">FiddlerObject&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">UI&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">lvSessions&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">AddBoundColumn&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;ServerIP&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">120&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;X-HostIP&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Uncomment to add a &amp;#34;Server&amp;#34; column containing the response &amp;#34;Server&amp;#34; header, if present
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// UI.lvSessions.AddBoundColumn(&amp;#34;Server&amp;#34;, 50, &amp;#34;@response.server&amp;#34;);
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Uncomment to add a global hotkey (Win+G) that invokes the ExecAction method below...
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// UI.RegisterCustomHotkey(HotkeyModifiers.Windows, Keys.G, &amp;#34;screenshot&amp;#34;);
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>然后，点击菜单栏：&lt;strong>File &amp;ndash;&amp;gt; Save&lt;/strong> 或快捷键 &lt;strong>Ctrl+S&lt;/strong>，关闭窗口。&lt;/p></description></item><item><title>图片爬虫</title><link>https://itest2025.pages.dev/tutorials/27-005-%E5%9B%BE%E7%89%87%E7%88%AC%E8%99%AB/</link><pubDate>Thu, 14 Dec 2017 02:52:34 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/27-005-%E5%9B%BE%E7%89%87%E7%88%AC%E8%99%AB/</guid><description>&lt;h3 id="图片爬虫">图片爬虫&lt;/h3>
&lt;p>之前的例子里我们开发的都是文本爬虫，有时候我们需要去下载其他网站的图片并保存下来，这时候就需要用图片爬虫。&lt;/p>
&lt;p>图片爬虫的套路其实跟文本爬虫差不多，最大的区别就是图片爬虫会去下载需要的文件，而文本爬虫可能会做其他的一些持久化的工作。&lt;/p>
&lt;p>在这一节里，我们将实现下载&lt;a href="http://jandan.net/drawings" target="_blank" rel="noopener noreffer ">煎蛋画廊&lt;/a>第一页所有图片的功能。&lt;/p>
&lt;p>具体步骤&lt;/p>
&lt;ul>
&lt;li>访问煎蛋画廊主页，获取html文本&lt;/li>
&lt;li>分析html文本，找出所有图片的html特征&lt;/li>
&lt;li>解析html代码，拿到所有图片的src&lt;/li>
&lt;li>通过src去下载图片&lt;/li>
&lt;/ul>
&lt;h3 id="分析html代码">分析html代码&lt;/h3>
&lt;p>图片的html标签是img，所以我们只需要拿到页面上所有的img标签的src就好了。&lt;/p>
&lt;h3 id="下载文件">下载文件&lt;/h3>
&lt;p>通过下面的代码，我们可以使用requests库来下载文件。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">download_file&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Downding &lt;/span>&lt;span class="si">%s&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span> &lt;span class="o">%&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">local_filename&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">url&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;/&amp;#39;&lt;/span>&lt;span class="p">)[&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">r&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">requests&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">stream&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">with&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">local_filename&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;wb&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">chunk&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">r&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">iter_content&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">chunk_size&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">1024&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">chunk&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">chunk&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">flush&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">local_filename&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>download_file方法只需要传入具体文件的地址就可以完成下载文件的功能了。&lt;/p>
&lt;h3 id="user-agent">user agent&lt;/h3>
&lt;p>由于煎蛋做了非常简单的反爬虫处理，该站点会拒绝所有看起来像是爬虫的请求，大概的逻辑可能是如果后台发现请求的user agent异常，就返回403错误。&lt;/p>
&lt;p>这里是&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent" target="_blank" rel="noopener noreffer ">User-Agent&lt;/a>的基础知识，大家可以自行学习。&lt;/p>
&lt;p>我们可以通过requests非常方便的修改请求的user agent，从而让被访问站点的后台没有办法识别出这次请求是否异常，达到绕过反爬机制的目的。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">headers&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;user-agent&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">requests&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">headers&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">headers&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上面代码的核心思想就是通过修改http headers中user agent，达到将请求伪装成是来自普通chrome浏览器访问的目的。&lt;/p>
&lt;h3 id="代码">代码&lt;/h3>
&lt;p>新建名为&lt;code>get_images.py&lt;/code>的文件，输入下面的内容&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">requests&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">bs4&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">BeautifulSoup&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">headers&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;user-agent&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">download_file&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Downding &lt;/span>&lt;span class="si">%s&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span> &lt;span class="o">%&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">local_filename&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">url&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;/&amp;#39;&lt;/span>&lt;span class="p">)[&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">r&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">requests&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">stream&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">headers&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">headers&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">with&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">local_filename&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;wb&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">chunk&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">r&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">iter_content&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">chunk_size&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">1024&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">chunk&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">chunk&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">flush&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">local_filename&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">url&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;http://jandan.net/drawings&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">soup&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">BeautifulSoup&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">requests&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">headers&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">headers&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;html.parser&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">valid_img&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">src&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">src&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">endswith&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;jpg&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="s1">&amp;#39;img.jandan.net&amp;#39;&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">src&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">img&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">soup&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_all&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;img&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">src&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">valid_img&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">src&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">img&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;src&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">src&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">startswith&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;http&amp;#39;&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">src&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;http:&amp;#39;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">src&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">download_file&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">src&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行">运行&lt;/h3>
&lt;p>在命令行中输入&lt;/p></description></item><item><title>（五） 验证函数调用次数和顺序</title><link>https://itest2025.pages.dev/tutorials/45-005-%E4%BA%94-%E9%AA%8C%E8%AF%81%E5%87%BD%E6%95%B0%E8%B0%83%E7%94%A8%E6%AC%A1%E6%95%B0%E5%92%8C%E9%A1%BA%E5%BA%8F/</link><pubDate>Sat, 25 Nov 2017 12:45:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/45-005-%E4%BA%94-%E9%AA%8C%E8%AF%81%E5%87%BD%E6%95%B0%E8%B0%83%E7%94%A8%E6%AC%A1%E6%95%B0%E5%92%8C%E9%A1%BA%E5%BA%8F/</guid><description>&lt;h4 id="验证函数调用次数">验证函数调用次数&lt;/h4>
&lt;p>例子：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">java.util.LinkedList&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.mockito.Mockito.*&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">MockitoDemo&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">verifying_number_of_invocations&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">LinkedList&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">mock&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">LinkedList&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">class&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//using mock&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;once&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;twice&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;twice&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;three times&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;three times&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;three times&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//following two verifications work exactly the same - times(1) is used by default&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 下面的两个验证函数效果一样,因为verify默认验证的就是times(1)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">verify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="na">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;once&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">verify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">times&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;once&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//exact number of invocations verification&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 验证具体的执行次数&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">verify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">times&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;twice&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">verify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">times&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">3&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;three times&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//verification using never(). never() is an alias to times(0)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 使用never()进行验证,never相当于times(0)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">verify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">never&lt;/span>&lt;span class="p">()).&lt;/span>&lt;span class="na">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;never happened&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//verification using atLeast()/atMost()&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 使用atLeast()/atMost()&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">verify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">atLeastOnce&lt;/span>&lt;span class="p">()).&lt;/span>&lt;span class="na">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;three times&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">verify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">atLeast&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;five times&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">verify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">atMost&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">5&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;three times&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>verify函数默认验证的是执行了times(1)，也就是某个测试函数是否执行了1次.因此，times(1)通常被省略了。&lt;/p></description></item><item><title>（五）测试级别设置</title><link>https://itest2025.pages.dev/tutorials/36-005-%E4%BA%94%E6%B5%8B%E8%AF%95%E7%BA%A7%E5%88%AB%E8%AE%BE%E7%BD%AE/</link><pubDate>Sat, 25 Nov 2017 12:40:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/36-005-%E4%BA%94%E6%B5%8B%E8%AF%95%E7%BA%A7%E5%88%AB%E8%AE%BE%E7%BD%AE/</guid><description>&lt;p>在我们创建测试用例时，大概分三个层级。&lt;/p>
&lt;ul>
&lt;li>测试包（目录）&lt;/li>
&lt;li>测试类（文件）&lt;/li>
&lt;li>测试用例（&lt;code>@Test&lt;/code> 注解的方法）&lt;/li>
&lt;/ul>
&lt;p>接下来介绍，如何控制这三个级别用例的执行。当然，核心还是通过 &lt;strong>testng.mxl&lt;/strong> 文件配置。&lt;/p>
&lt;h4 id="指定运行测试包">指定运行测试包&lt;/h4>
&lt;hr>
&lt;pre tabindex="0">&lt;code>&amp;lt;!DOCTYPE suite SYSTEM &amp;#34;http://testng.org/testng-1.0.dtd&amp;#34; &amp;gt;
&amp;lt;suite name=&amp;#34;测试套件&amp;#34; verbose=&amp;#34;1&amp;#34; &amp;gt;
 &amp;lt;test name=&amp;#34;简单测试&amp;#34;&amp;gt;
 &amp;lt;packages&amp;gt;
 &amp;lt;package name=&amp;#34;test.sample&amp;#34; /&amp;gt;
 &amp;lt;package name=&amp;#34;test.sample2&amp;#34; /&amp;gt;
 &amp;lt;/packages&amp;gt;
 &amp;lt;/test&amp;gt;
&amp;lt;/suite&amp;gt;
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>&lt;code>&amp;lt;packages&amp;gt;...&amp;lt;/packages&amp;gt;&lt;/code> 定义一组测试包。&lt;/li>
&lt;li>&lt;code>&amp;lt;package.../&amp;gt;&lt;/code> 定义一个测试包。
&lt;ul>
&lt;li>name 指定测试包（目录）的名称。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h4 id="指定运行测试类">指定运行测试类&lt;/h4>
&lt;hr>
&lt;pre tabindex="0">&lt;code>&amp;lt;!DOCTYPE suite SYSTEM &amp;#34;http://testng.org/testng-1.0.dtd&amp;#34; &amp;gt;
&amp;lt;suite name=&amp;#34;测试套件&amp;#34; verbose=&amp;#34;1&amp;#34; &amp;gt;
 &amp;lt;test name=&amp;#34;简单测试&amp;#34;&amp;gt;
 &amp;lt;classes&amp;gt;
 &amp;lt;class name=&amp;#34;test.sample.FirstTest&amp;#34;/&amp;gt;
 &amp;lt;class name=&amp;#34;test.sample.SecondTest&amp;#34;/&amp;gt;
 &amp;lt;/classes&amp;gt;
 &amp;lt;/test&amp;gt;
&amp;lt;/suite&amp;gt;
&lt;/code>&lt;/pre>&lt;p>指定测试类的运行，&lt;a href="https://itest2025.pages.dev/testng/testngxml/" rel="">上一节&lt;/a>已经介绍。&lt;/p>
&lt;h4 id="指定运行测试用例">指定运行测试用例&lt;/h4>
&lt;hr>
&lt;pre tabindex="0">&lt;code>&amp;lt;!DOCTYPE suite SYSTEM &amp;#34;http://testng.org/testng-1.0.dtd&amp;#34; &amp;gt;
&amp;lt;suite name=&amp;#34;测试套件&amp;#34; verbose=&amp;#34;1&amp;#34; &amp;gt;
 &amp;lt;test name=&amp;#34;简单测试&amp;#34;&amp;gt;
 &amp;lt;classes&amp;gt;
 &amp;lt;class name=&amp;#34;test.sample.FirstTest&amp;#34;&amp;gt;
 &amp;lt;methods&amp;gt;
 &amp;lt;include name=&amp;#34;testCase&amp;#34; /&amp;gt;
 &amp;lt;/methods&amp;gt;
 &amp;lt;/class&amp;gt;
 &amp;lt;/classes&amp;gt;
 &amp;lt;/test&amp;gt;
&amp;lt;/suite&amp;gt;
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>&lt;code>&amp;lt;methods&amp;gt;...&amp;lt;/methods&amp;gt;&lt;/code> 定义一组测试方法。&lt;/li>
&lt;li>&lt;code>&amp;lt;include.../&amp;gt;&lt;/code> 指定包含的测试用例（方法）。
&lt;ul>
&lt;li>name 指定测试用例（方法）的名称。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>注意：&lt;/strong> 测试方法&lt;code>&amp;lt;methods&amp;gt;&lt;/code>必须包含在&lt;code>&amp;lt;class&amp;gt;&lt;/code>标签中。&lt;/p></description></item><item><title>（五） IntelliJ-IDEA 创建 Maven 项目</title><link>https://itest2025.pages.dev/tutorials/41-005-%E4%BA%94-intellij-idea-%E5%88%9B%E5%BB%BA-maven-%E9%A1%B9%E7%9B%AE/</link><pubDate>Sat, 25 Nov 2017 12:35:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/41-005-%E4%BA%94-intellij-idea-%E5%88%9B%E5%BB%BA-maven-%E9%A1%B9%E7%9B%AE/</guid><description>&lt;p>IntelliJ IDEA 默认集成的就有 Maven 插件，所以，我们也可以直接使用它来创建 Maven 项目。&lt;/p>
&lt;h4 id="修改-maven-配置">修改 Maven 配置&lt;/h4>
&lt;hr>
&lt;p>首先， 打开 IntelliJ IDEA 开发工具， 菜单栏： &lt;strong>“File” &amp;mdash;&amp;gt;“Settings&amp;hellip;”&lt;/strong> ， 搜索“Maven” 选项， 如下图。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/maven_idea_setting.png"
 data-srcset="http://img.testclass.net/maven_idea_setting.png, http://img.testclass.net/maven_idea_setting.png 1.5x, http://img.testclass.net/maven_idea_setting.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/maven_idea_setting.png"
 title="http://img.testclass.net/maven_idea_setting.png" />&lt;/p>
&lt;p>设置参数：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Maven home directory： 设置本地安装的 Maven 目录。 如“&lt;strong>D:/java/apache-maven-3.5.0&lt;/strong>”。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>User settings file： 选择 Maven 目录下的配置文件。 如“&lt;strong>D:\java\apache-maven-3.5.0\conf\settings.xml&lt;/strong>” ，需要勾选“&lt;strong>Override&lt;/strong>” 选项才能设置。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Locla repository： 设置本地仓库地址。 上一个选项设置好后， 该选项自动设置。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>&lt;font color="red"> &lt;strong>注：&lt;/strong> 这里也可以不用设置，直接使用 IntelliJ IDEA 的默认配置。&lt;/font>&lt;/p>
&lt;h4 id="创建-maven-项目">创建 Maven 项目&lt;/h4>
&lt;hr>
&lt;p>接下来在 IntelliJ IDEA 中创建 Maven 项目。 菜单栏： &lt;strong>“File” &amp;mdash;&amp;gt;“New” &amp;mdash;&amp;gt;“Project&amp;hellip;”&lt;/strong> ， 打开创建 Maven 。&lt;/p></description></item><item><title>requests如何自定义请求的headers?</title><link>https://itest2025.pages.dev/tutorials/42-005-requests%E5%A6%82%E4%BD%95%E8%87%AA%E5%AE%9A%E4%B9%89%E8%AF%B7%E6%B1%82%E7%9A%84headers/</link><pubDate>Wed, 22 Nov 2017 03:23:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/42-005-requests%E5%A6%82%E4%BD%95%E8%87%AA%E5%AE%9A%E4%B9%89%E8%AF%B7%E6%B1%82%E7%9A%84headers/</guid><description>&lt;p>&lt;a href="http://docs.python-requests.org/en/master/user/quickstart/#custom-headers" target="_blank" rel="noopener noreffer ">官方文档&lt;/a>&lt;/p>
&lt;p>有时候我们需要自定义一些请求的headers，比如我们可能需要将jwt的token放到headers里以完成鉴权。&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; url = &amp;#39;https://api.github.com/some/endpoint&amp;#39;
&amp;gt;&amp;gt;&amp;gt; headers = {&amp;#39;user-agent&amp;#39;: &amp;#39;my-app/0.0.1&amp;#39;}

&amp;gt;&amp;gt;&amp;gt; r = requests.get(url, headers=headers)
&lt;/code>&lt;/pre>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1432821596592-e2c18b78144f?w=300"
 data-srcset="https://images.unsplash.com/photo-1432821596592-e2c18b78144f?w=300, https://images.unsplash.com/photo-1432821596592-e2c18b78144f?w=300 1.5x, https://images.unsplash.com/photo-1432821596592-e2c18b78144f?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1432821596592-e2c18b78144f?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（五）JUnit 注解之Fixture</title><link>https://itest2025.pages.dev/tutorials/31-005-%E4%BA%94junit-%E6%B3%A8%E8%A7%A3%E4%B9%8Bfixture/</link><pubDate>Mon, 13 Nov 2017 12:40:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/31-005-%E4%BA%94junit-%E6%B3%A8%E8%A7%A3%E4%B9%8Bfixture/</guid><description>&lt;p>继续介绍 JUnit 的注解。&lt;/p>
&lt;h4 id="什么是fixture">什么是Fixture&lt;/h4>
&lt;hr>
&lt;p>Test Fixture 是指一个测试运行所需的固定环境，准确的定义：&lt;/p>
&lt;blockquote>
&lt;p>The test fixture is everything we need to have in place to exercise the SUT&lt;/p>&lt;/blockquote>
&lt;p>在进行测试时，我们通常需要把环境设置成已知状态（如创建对象、获取资源等）来创建测试，每次测试开始时都处于一个固定的初始状态；测试结果后需要将测试状态还原，所以，测试执行所需要的固定环境称为 Test Fixture。&lt;/p>
&lt;h4 id="junit-中的-fixture">JUnit 中的 Fixture&lt;/h4>
&lt;hr>
&lt;p>被测试类同样使用上一小节的 Count , 创建 TestFixture 测试类。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.Assert.*&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.*&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">TestFixture&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//在当前测试类开始时运行。&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@BeforeClass&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">beforeClass&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;-------------------beforeClass&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//在当前测试类结束时运行。&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@AfterClass&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">afterClass&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;-------------------afterClass&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//每个测试方法运行之前运行&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Before&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">before&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;=====before&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//每个测试方法运行之后运行&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@After&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">after&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;=====after&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">testAdd1&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Count&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="na">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">5&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">3&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">8&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;test Run testadd1&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">testAdd2&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Count&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="na">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">15&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">13&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">28&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;test Run testadd2&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>代码中的注释已经对 &lt;strong>@BeforeClass、 @AfterClass 、 @Before 、 @After&lt;/strong> 做了说明。&lt;/p></description></item><item><title>5. 实例: 找出所有是弱密码的用户</title><link>https://itest2025.pages.dev/tutorials/35-005-5-%E5%AE%9E%E4%BE%8B-%E6%89%BE%E5%87%BA%E6%89%80%E6%9C%89%E6%98%AF%E5%BC%B1%E5%AF%86%E7%A0%81%E7%9A%84%E7%94%A8%E6%88%B7/</link><pubDate>Mon, 06 Nov 2017 06:23:31 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/35-005-5-%E5%AE%9E%E4%BE%8B-%E6%89%BE%E5%87%BA%E6%89%80%E6%9C%89%E6%98%AF%E5%BC%B1%E5%AF%86%E7%A0%81%E7%9A%84%E7%94%A8%E6%88%B7/</guid><description>&lt;h3 id="背景">背景&lt;/h3>
&lt;p>当我们的测试数据是下面这些的时候，我们的用例是有问题的。&lt;/p>
&lt;pre tabindex="0">&lt;code>[
 {&amp;#34;name&amp;#34;:&amp;#34;jack&amp;#34;,&amp;#34;password&amp;#34;:&amp;#34;Iloverose&amp;#34;},
 {&amp;#34;name&amp;#34;:&amp;#34;rose&amp;#34;,&amp;#34;password&amp;#34;:&amp;#34;Ilovejack&amp;#34;},
 {&amp;#34;name&amp;#34;:&amp;#34;tom&amp;#34;,&amp;#34;password&amp;#34;:&amp;#34;password123&amp;#34;},
 {&amp;#34;name&amp;#34;:&amp;#34;jerry&amp;#34;,&amp;#34;password&amp;#34;:&amp;#34;password&amp;#34;}
]
&lt;/code>&lt;/pre>&lt;p>我们的用例只能找出tom是弱密码的用户，jerry这个用户会成为漏网之鱼。&lt;/p>
&lt;h3 id="为什么">为什么&lt;/h3>
&lt;p>这是因为在unittest中，一旦某个测试方法中的断言失败，后续的断言都不会被执行。&lt;/p>
&lt;p>还原一下上面的例子，当用例在断言tom失败后，for循环就退出了，测试方法也执行完毕了，后面jerry这条数据就不会被断言。&lt;/p>
&lt;h3 id="怎么办">怎么办&lt;/h3>
&lt;p>我们可以重构一下我们的用例，让整个用例只断言1次，断言失败以后就把弱密码的用户打印出来。&lt;/p>
&lt;h3 id="代码">代码&lt;/h3>
&lt;p>修改user_data.json文件，加入一些测试数据，修改后的user_data.json文件应该是&lt;/p>
&lt;pre tabindex="0">&lt;code>[
 {&amp;#34;name&amp;#34;:&amp;#34;jack&amp;#34;,&amp;#34;password&amp;#34;:&amp;#34;Iloverose&amp;#34;},
 {&amp;#34;name&amp;#34;:&amp;#34;rose&amp;#34;,&amp;#34;password&amp;#34;:&amp;#34;Ilovejack&amp;#34;},
 {&amp;#34;name&amp;#34;:&amp;#34;tom&amp;#34;,&amp;#34;password&amp;#34;:&amp;#34;password123&amp;#34;},
 {&amp;#34;name&amp;#34;:&amp;#34;jerry&amp;#34;,&amp;#34;password&amp;#34;:&amp;#34;password&amp;#34;},
 {&amp;#34;name&amp;#34;:&amp;#34;fred&amp;#34;,&amp;#34;password&amp;#34;:&amp;#34;123456&amp;#34;},
 {&amp;#34;name&amp;#34;:&amp;#34;elma&amp;#34;,&amp;#34;password&amp;#34;:&amp;#34;654321&amp;#34;}
]
&lt;/code>&lt;/pre>&lt;p>新建&lt;code>test_password_4.py&lt;/code>文件，内容如下&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">unittest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">json&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">WeakPasswordTeseCase1&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TestCase&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@classmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">setUpClass&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">kls&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data_file_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;./user_data.json&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;before all test methods&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">with&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data_file_path&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">kls&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">test_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">json&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">loads&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">read&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">test_week_password&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">msg&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">data&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">test_data&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">passwd&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;password&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tmp_res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tmp_res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tmp_res&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">passwd&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">6&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tmp_res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tmp_res&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">passwd&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="s1">&amp;#39;password&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tmp_res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tmp_res&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">passwd&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="s1">&amp;#39;password123&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">tmp_res&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">msg&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;user &lt;/span>&lt;span class="si">%s&lt;/span>&lt;span class="s2"> has a weak password &lt;/span>&lt;span class="si">%s&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="o">%&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;name&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;password&amp;#39;&lt;/span>&lt;span class="p">]))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">res&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="n">tmp_res&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertTrue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">res&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">msg&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">test_dummy&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">pass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">main&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行及结果">运行及结果&lt;/h3>
&lt;p>在命令行中运行&lt;code>python test_password_4.py&lt;/code>，结果如下&lt;/p>
&lt;pre tabindex="0">&lt;code>$ python test_password_4.py
before all test methods
.F
======================================================================
FAIL: test_week_password (__main__.WeakPasswordTeseCase1)
----------------------------------------------------------------------
Traceback (most recent call last):
 File &amp;#34;test_password_4.py&amp;#34;, line 27, in test_week_password
 self.assertTrue(res, &amp;#34;\n&amp;#34;.join(msg))
AssertionError: user tom has a weak password password123
user jerry has a weak password password

----------------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (failures=1)
&lt;/code>&lt;/pre>&lt;h3 id="我们能学到什么">我们能学到什么&lt;/h3>
&lt;ul>
&lt;li>断言一旦失败之后测试方法就会结束运行，所以一般来说1个测试方法推荐只有1个断言&lt;/li>
&lt;li>如果一个测试方法里面必须要有多个断言，那么要确保前面的断言失败之后，后面的断言就算不运行也不会影响测试的范围和结果&lt;/li>
&lt;li>for循环中的断言一旦失败，for循环就退出了&lt;/li>
&lt;li>上面演示的测试用例写法其实具备了一定的数据驱动测试的思想&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p></description></item><item><title>5. 字符串和文本</title><link>https://itest2025.pages.dev/tutorials/28-005-5-%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%92%8C%E6%96%87%E6%9C%AC/</link><pubDate>Fri, 03 Nov 2017 08:17:22 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/28-005-5-%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%92%8C%E6%96%87%E6%9C%AC/</guid><description>&lt;h3 id="什么是字符串">什么是字符串&lt;/h3>
&lt;p>目前为止我们已经打印了不少的字符串了。那么什么是字符串呢?&lt;/p>
&lt;p>在python里，字符串往往表现为用单引号&lt;code>''&lt;/code>或者是双引号&lt;code>&amp;quot;&amp;quot;&lt;/code>包裹起来的一些文字。这些文字便于人类阅读，往往可以展示给我们程序的用户阅读。&lt;/p>
&lt;p>下面代码里s1,s2都是字符串。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">s1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;本次测试覆盖了100个模块&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">s2&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;本次测试运行了100个用例&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="f-string">f-string&lt;/h3>
&lt;p>我们经常需要在字符串中包含一些变量，这样可以让字符串变得更加动态，不同变量的取值可以生成不同的字符串。&lt;/p>
&lt;p>python 3.6 之后引入了f-string的概念，可以非常方便的在字符串中包含变量。比如下面的例子。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">module_count&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;本次测试覆盖了&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">module_count&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">个模块&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>另外python还支持.format()语法，我们后面通过代码去理解&lt;/p>
&lt;h3 id="背景">背景&lt;/h3>
&lt;p>这一节里，我们把上一节的内容使用f-string来重新实现一下，逻辑和输出保持不变，用开发领域的术语来说，叫做&amp;quot;重构&amp;quot;。&lt;/p>
&lt;h3 id="代码实现">代码实现&lt;/h3>
&lt;p>新建名为&lt;code>report_with_f_string.py&lt;/code>，内容如下&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 打印出本次测试的测试结果&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># A: 27/30 B: 40/40 C: 30/30&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">module_count&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">case_count_of_module_a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">30.0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">success_case_count_of_module_a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">27&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">case_count_of_module_b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">40.0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">success_case_count_of_module_b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">40&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">case_count_of_module_c&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">30.0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">success_case_count_of_module_c&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">30&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;本次测试覆盖了&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">module_count&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">个模块&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;测试用例总数为: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">case_count_of_module_a&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">case_count_of_module_b&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">case_count_of_module_c&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;执行的测试用例总数为: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">case_count_of_module_a&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">case_count_of_module_b&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">case_count_of_module_c&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;用例最多的模块是B模块，B模块比A模块多出的用例数为: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">case_count_of_module_b&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">case_count_of_module_a&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s1">&amp;#39;A模块执行成功&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">success_case_count_of_module_a&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s1">个用例，执行失败的用例数为&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">case_count_of_module_a&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">success_case_count_of_module_a&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;A模块用例通过率为百分之&lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">success_case_count_of_module_a&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">case_count_of_module_a&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">100&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;B模块的用例全部执行通过， 通过率为百分之&lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="n">success_case_count_of_module_b&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">case_count_of_module_b&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">100&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;C模块的用例全部执行通过， 通过率为百分之&lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="n">success_case_count_of_module_b&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">case_count_of_module_b&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">100&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">test_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;回归测试&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">test_result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;不通过&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 结束打印&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">test_type&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">test_result&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行">运行&lt;/h3>
&lt;p>在命令行中使用下面的命令去执行代码&lt;/p>
&lt;pre tabindex="0">&lt;code>$python report_with_f_string.py
&lt;/code>&lt;/pre>&lt;h3 id="你应该可以看到">你应该可以看到&lt;/h3>
&lt;p>如果没有出错的话，你应该可以看到命令行窗口显示如下的内容&lt;/p>
&lt;pre tabindex="0">&lt;code>本次测试覆盖了3个模块
测试用例总数为: 100.0
执行的测试用例总数为: 100.0
用例最多的模块是B模块，B模块比A模块多出的用例数为: 10.0
A模块执行成功27个用例，执行失败的用例数为3.0
A模块用例通过率为百分之90.0
B模块的用例全部执行通过， 通过率为百分之100.0
C模块的用例全部执行通过， 通过率为百分之100.0
回归测试不通过
&lt;/code>&lt;/pre>&lt;h3 id="常见问题">常见问题&lt;/h3>
&lt;ul>
&lt;li>为什么有时候字符串用单引号有时候又用双引号？ 一般情况下用双引号就足够了，不过有时候我们需要打印出单引号，这时候把单引号放到双引号内就可以了,反之亦然。&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p></description></item><item><title>5.参数化的Fixture</title><link>https://itest2025.pages.dev/tutorials/25-005-5%E5%8F%82%E6%95%B0%E5%8C%96%E7%9A%84fixture/</link><pubDate>Mon, 30 Oct 2017 07:22:42 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/25-005-5%E5%8F%82%E6%95%B0%E5%8C%96%E7%9A%84fixture/</guid><description>&lt;h3 id="背景">背景&lt;/h3>
&lt;p>继续上一节的测试需求，在上一节里，任何1条测试数据导致断言不通过后测试用例就会停止运行，这样每次只能检查出1条不符合规范的数据，有没有什么办法可以一次性把所有的不符合结果都测出来呢？&lt;/p>
&lt;p>这时候我们就需要用到参数化的fixture特性了&lt;/p>
&lt;h3 id="更新数据文件">更新数据文件&lt;/h3>
&lt;p>新建&lt;code>users.test.json&lt;/code>文件，内容如下&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;jack&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;password&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;Iloverose&amp;#34;&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;rose&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;password&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;Ilovejack&amp;#34;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;tom&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;password&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;password123&amp;#34;&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;mike&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;password&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;password&amp;#34;&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;james&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nt">&amp;#34;password&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;AGoodPasswordWordShouldBeLongEnough&amp;#34;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>我们增加了2条用户信息，其中mike的密码是弱密码。&lt;/p>
&lt;h3 id="参数化fixture">参数化fixture&lt;/h3>
&lt;p>参数化fixture允许我们向fixture提供参数，参数可以是list，该list中有几条数据，fixture就会运行几次，相应的测试用例也会运行几次。&lt;/p>
&lt;p>参数化fixture的语法是&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@pytest.fixture&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">params&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;smtp.gmail.com&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;mail.python.org&amp;#34;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>其中&lt;code>len(params)&lt;/code>的值就是用例执行的次数&lt;/p>
&lt;p>在fixture的定义中，可以使用&lt;code>request.param&lt;/code>来获取每次传入的参数，如下:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@pytest.fixture&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">scope&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;module&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">params&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;smtp.gmail.com&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;mail.python.org&amp;#34;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">smtp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">smtp&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">smtplib&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">SMTP&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">param&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">587&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">timeout&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">yield&lt;/span> &lt;span class="n">smtp&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;finalizing &lt;/span>&lt;span class="si">%s&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">smtp&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">smtp&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">close&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>上面的代码smtp fixture会执行2次&lt;/li>
&lt;li>第1次&lt;code>request.param == 'smtp.gmail.com'&lt;/code>&lt;/li>
&lt;li>第2次&lt;code>request.param == 'mail.python.org'&lt;/code>&lt;/li>
&lt;/ul>
&lt;h3 id="实现用例">实现用例&lt;/h3>
&lt;p>我们现在使用参数化fixtures来实现一次性检查出弱密码的用例。&lt;/p>
&lt;p>新建文件&lt;code>test_user_password_with_params.py&lt;/code>，内容如下:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">pytest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">json&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">users&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">json&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">loads&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;./users.test.json&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;r&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">read&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">TestUserPasswordWithParam&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">object&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@pytest.fixture&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">params&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">users&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">user&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">request&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">param&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">test_user_password&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">passwd&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;password&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">passwd&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">6&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">msg&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;user &lt;/span>&lt;span class="si">%s&lt;/span>&lt;span class="s2"> has a weak password&amp;#34;&lt;/span> &lt;span class="o">%&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;name&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="n">passwd&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="s1">&amp;#39;password&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">msg&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="n">passwd&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="s1">&amp;#39;password123&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">msg&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上面的例子里，我们先把所有用户信息读到users变量里，注意users这时候是list类型，可以直接传入到fixture的params&lt;/p>
&lt;h3 id="运行及结果">运行及结果&lt;/h3>
&lt;p>运行&lt;/p>
&lt;pre tabindex="0">&lt;code>pytest test_user_password_with_params.py
&lt;/code>&lt;/pre>&lt;p>结果&lt;/p>
&lt;pre tabindex="0">&lt;code>$ pytest test_user_password_with_params.py
========================================================================= test session starts =========================================================================
platform darwin -- Python 2.7.12, pytest-3.2.3, py-1.4.34, pluggy-0.4.0
rootdir: /Users/easonhan/code/testclass.net/src/pytest, inifile:
collected 5 items

test_user_password_with_params.py ..FF.

============================================================================== FAILURES ===============================================================================
_________________________________________________________ TestUserPasswordWithParam.test_user_password[user2] _________________________________________________________

self = &amp;lt;test_user_password_with_params.TestUserPasswordWithParam object at 0x10de1d790&amp;gt;, user = {&amp;#39;name&amp;#39;: &amp;#39;tom&amp;#39;, &amp;#39;password&amp;#39;: &amp;#39;password123&amp;#39;}

 def test_user_password(self, user):
 passwd = user[&amp;#39;password&amp;#39;]
 assert len(passwd) &amp;gt;= 6
 msg = &amp;#34;user %s has a weak password&amp;#34; %(user[&amp;#39;name&amp;#39;])
 assert passwd != &amp;#39;password&amp;#39;, msg
&amp;gt; assert passwd != &amp;#39;password123&amp;#39;, msg
E AssertionError: user tom has a weak password
E assert &amp;#39;password123&amp;#39; != &amp;#39;password123&amp;#39;

test_user_password_with_params.py:15: AssertionError
_________________________________________________________ TestUserPasswordWithParam.test_user_password[user3] _________________________________________________________

self = &amp;lt;test_user_password_with_params.TestUserPasswordWithParam object at 0x10de1df50&amp;gt;, user = {&amp;#39;name&amp;#39;: &amp;#39;mike&amp;#39;, &amp;#39;password&amp;#39;: &amp;#39;password&amp;#39;}

 def test_user_password(self, user):
 passwd = user[&amp;#39;password&amp;#39;]
 assert len(passwd) &amp;gt;= 6
 msg = &amp;#34;user %s has a weak password&amp;#34; %(user[&amp;#39;name&amp;#39;])
&amp;gt; assert passwd != &amp;#39;password&amp;#39;, msg
E AssertionError: user mike has a weak password
E assert &amp;#39;password&amp;#39; != &amp;#39;password&amp;#39;

test_user_password_with_params.py:14: AssertionError
================================================================= 2 failed, 3 passed in 0.05 seconds ==================================================================
&lt;/code>&lt;/pre>&lt;p>稍微留意一下, 可以看出tom和mike使用了弱密码。总共运行了5个用例,3个成功,2个失败。&lt;/p></description></item><item><title>5. Containers</title><link>https://itest2025.pages.dev/tutorials/43-005-5-containers/</link><pubDate>Wed, 25 Oct 2017 06:55:26 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/43-005-5-containers/</guid><description>&lt;p>我们可以使用容器(containers)来限制定位范围，webium的containers特性可以让我们的定位代码更加干净容易理解，避免大规模的使用难懂晦涩的xpath。&lt;/p>
&lt;p>考虑下面的页面结构，为了可以遍历每一个搜索结果，我们可以使用下面的代码&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://wgnet.github.io/webium/_images/containers.png"
 data-srcset="http://wgnet.github.io/webium/_images/containers.png, http://wgnet.github.io/webium/_images/containers.png 1.5x, http://wgnet.github.io/webium/_images/containers.png 2x"
 data-sizes="auto"
 alt="http://wgnet.github.io/webium/_images/containers.png"
 title="http://wgnet.github.io/webium/_images/containers.png" />&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium.webdriver.common.by&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">By&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium.webdriver.remote.webelement&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">WebElement&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">webium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Find&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Finds&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">BasePage&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Vacancy&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">WebElement&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">title&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Find&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">by&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">CLASS_NAME&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;vacancy_title&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">profession&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Find&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">by&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">CLASS_NAME&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;vacancy_profession&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">location&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Find&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">by&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">CLASS_NAME&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;vacancy_location&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">apply_button&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Find&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">by&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">CLASS_NAME&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;vacancy_apply_button&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">VacanciesPage&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BasePage&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vacancies_list&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Finds&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Vacancy&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">By&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">XPATH&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;//div[@id=&amp;#34;careers-vacancies&amp;#34;]/div[@data-id]&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">super&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">VacanciesPage&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;http://wargaming.com/en/careers/vacancies/&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">page&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">VacanciesPage&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">open&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">vacancy&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">vacancies_list&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># search by CLASS_NAME=&amp;#39;vacancy_title&amp;#39; is performed within one node&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Title: &amp;#39;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">vacancy&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">title&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1515965885361-f1e0095517ea?w=300"
 data-srcset="https://images.unsplash.com/photo-1515965885361-f1e0095517ea?w=300, https://images.unsplash.com/photo-1515965885361-f1e0095517ea?w=300 1.5x, https://images.unsplash.com/photo-1515965885361-f1e0095517ea?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1515965885361-f1e0095517ea?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>收藏清单: python自动化测试工具最全资源汇总</title><link>https://itest2025.pages.dev/tutorials/34-005-%E6%94%B6%E8%97%8F%E6%B8%85%E5%8D%95-python%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7%E6%9C%80%E5%85%A8%E8%B5%84%E6%BA%90%E6%B1%87%E6%80%BB/</link><pubDate>Sun, 22 Oct 2017 08:19:06 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/34-005-%E6%94%B6%E8%97%8F%E6%B8%85%E5%8D%95-python%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7%E6%9C%80%E5%85%A8%E8%B5%84%E6%BA%90%E6%B1%87%E6%80%BB/</guid><description>&lt;h2 id="web-ui-test-automation-web-ui-自动化">Web UI test automation Web UI 自动化&lt;/h2>
&lt;ul>
&lt;li>libraries 各种库
&lt;ul>
&lt;li>&lt;a href="https://pypi.python.org/pypi/selenium" target="_blank" rel="noopener noreffer ">selenium webdriver&lt;/a> - 浏览器自动化工具&lt;/li>
&lt;li>&lt;a href="https://github.com/cobrateam/splinter" target="_blank" rel="noopener noreffer ">splinter&lt;/a> - 简单的web自动化工具，让元素定位，表单提交等更加容易&lt;/li>
&lt;li>&lt;a href="https://pypi.python.org/pypi/mechanize/" target="_blank" rel="noopener noreffer ">mechanize&lt;/a> - 有状态可编程的浏览器&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>frameworks and wrappers 框架和封装
&lt;ul>
&lt;li>&lt;a href="https://github.com/element-34/py.saunter" target="_blank" rel="noopener noreffer ">py.saunter&lt;/a> - 有主见的自动化测试框架，使用了selenium RC和webdriver api&lt;/li>
&lt;li>&lt;a href="https://github.com/davehunt/pytest-mozwebqa" target="_blank" rel="noopener noreffer ">moz-web-qa&lt;/a> - py.test的插件，为Mozilla的WebQA项目提供了额外功能&lt;/li>
&lt;li>&lt;a href="http://testutils.org/sst" target="_blank" rel="noopener noreffer ">testutils sst&lt;/a> - A web test framework that uses Python to generate functional browser-based tests.&lt;/li>
&lt;li>&lt;a href="https://github.com/wiredrive/wtframework" target="_blank" rel="noopener noreffer ">wtframework&lt;/a> - 让web测试可以配置的框架&lt;/li>
&lt;li>&lt;a href="https://github.com/alisaifee/holmium.core" target="_blank" rel="noopener noreffer ">holmium.core&lt;/a> - Page Object及其他工具库支持&lt;/li>
&lt;li>&lt;a href="https://github.com/rtomac/robotframework-selenium2library" target="_blank" rel="noopener noreffer ">robotframework-selenium2library&lt;/a> - Robot Framework的selenium扩展&lt;/li>
&lt;li>&lt;a href="https://pypi.python.org/pypi/gocept.selenium" target="_blank" rel="noopener noreffer ">gocept.selenium&lt;/a> - selenium RC的API, 适合编写基于WSGI, Plone, Zope 2, ZTK, or Grok 应用的测试用例&lt;/li>
&lt;li>&lt;a href="https://github.com/wgnet/webium" target="_blank" rel="noopener noreffer ">webium&lt;/a> - 基于python的一个Page Object实现&lt;/li>
&lt;li>&lt;a href="https://github.com/luisxiaomai/robotframework-anywherelibrary" target="_blank" rel="noopener noreffer ">robotframework-anywherelibrary&lt;/a> - Robot Framework的扩展库，使用selenium2测试web应用，使用appium测试移动应用&lt;/li>
&lt;li>&lt;a href="https://github.com/ncbi/robotframework-pageobjects" target="_blank" rel="noopener noreffer ">robotframework-pageobjects&lt;/a> - 一个不错的Page Object实现，可以脱离robot framework单独使用。 具体看&lt;a href="http://kahunacohen.com/2014/12/03/new-testing-paradigm-robotframework-pageobjects/" target="_blank" rel="noopener noreffer ">这里&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/actmd/elementium" target="_blank" rel="noopener noreffer ">elementium&lt;/a> - 用jQuery风格的语法糖来实现浏览器的自动化测试用例&lt;/li>
&lt;li>&lt;a href="http://www.slickqa.com/webdriver/python/" target="_blank" rel="noopener noreffer ">slickqa&lt;/a> - slick-webdriver-python 项目是python selenium binding的一个封装&lt;/li>
&lt;li>&lt;a href="https://github.com/yashaka/selene/" target="_blank" rel="noopener noreffer ">selene&lt;/a> - Concise UI 测试用例，使用python实现支持Ajax,PageObjects和Widgets&lt;/li>
&lt;li>&lt;a href="http://hitchtest.com/" target="_blank" rel="noopener noreffer ">hitch&lt;/a> - 编写基于service的应用的测试用例&lt;/li>
&lt;li>&lt;a href="http://needle.readthedocs.org/en/latest/" target="_blank" rel="noopener noreffer ">Needle&lt;/a> - Needle是基于图片比对的测试工作，它可以对web应用的一部分进行截图，然后跟预期结果的图片进行比对&lt;/li>
&lt;li>&lt;a href="https://github.com/mozilla/PyPOM" target="_blank" rel="noopener noreffer ">PyPOM&lt;/a> - PyPOM是另一个Page Object库，适用于Selenium和Splinter测试&lt;/li>
&lt;li>&lt;a href="https://github.com/schipiga/pom" target="_blank" rel="noopener noreffer ">POM&lt;/a> - POM是Page-Object-Model 微框架，目的是让Web UI测试更加简单，快速和有乐趣&lt;/li>
&lt;li>&lt;a href="https://github.com/omaciel/websmith" target="_blank" rel="noopener noreffer ">websmith&lt;/a> - Web测试的一套DSL&lt;/li>
&lt;li>&lt;a href="https://github.com/Skyscanner/pages" target="_blank" rel="noopener noreffer ">pages&lt;/a> - 轻量的page object库和组建&lt;/li>
&lt;li>&lt;a href="https://github.com/nextQE/widgetastic.core" target="_blank" rel="noopener noreffer ">widgetastic&lt;/a> - RedHat UI widget 组建框架&lt;/li>
&lt;li>&lt;a href="https://github.com/nextQE/navmazing" target="_blank" rel="noopener noreffer ">navmazing&lt;/a> - PageObjects based navigation from RedHat&lt;/li>
&lt;li>&lt;a href="https://github.com/nextQE/nightwatch" target="_blank" rel="noopener noreffer ">nightwatch&lt;/a> - 基于python和selenium的UI 自动化测试框架. 灵感来源于nightwatch.js&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>extensions 扩展
&lt;ul>
&lt;li>&lt;a href="https://github.com/SergeyPirogov/webdriver_manager" target="_blank" rel="noopener noreffer ">webdriver_manager&lt;/a> - 主要目的是让不同版本的浏览器driver管理起来更加方便&lt;/li>
&lt;li>&lt;a href="https://github.com/pytest-dev/pytest-splinter" target="_blank" rel="noopener noreffer ">pytest_splinter&lt;/a> - pytest spinter 和 selenium的集成&lt;/li>
&lt;li>&lt;a href="https://github.com/bbangert/lettuce_webdriver" target="_blank" rel="noopener noreffer ">lettuce_webdriver&lt;/a> - Selenium webdriver 的 lettuce封装&lt;/li>
&lt;li>&lt;a href="https://github.com/AutomatedTester/browsermob-proxy-py" target="_blank" rel="noopener noreffer ">Browsermob Proxy&lt;/a> - python的Browsermob Proxy封装&lt;/li>
&lt;li>&lt;a href="https://github.com/joao-carloto/FireRobot" target="_blank" rel="noopener noreffer ">FireRobot&lt;/a> - 一个Firefox的扩展,让你可以更高效的编写基于robot framework的selenium用例&lt;/li>
&lt;li>&lt;a href="https://github.com/kpodl/pytractor" target="_blank" rel="noopener noreffer ">pytractor&lt;/a> - Python的selenium扩展，以便更好的测试angular.js应用&lt;/li>
&lt;li>&lt;a href="https://github.com/cryzed/Selenium-Requests" target="_blank" rel="noopener noreffer ">Selenium-Requests&lt;/a> - 扩展 Selenium WebDriver类，包含了Requests库的一些功能，可以更方便的处理cookie和请求头&lt;/li>
&lt;li>&lt;a href="https://github.com/SerpentAI/selenium-respectful" target="_blank" rel="noopener noreffer ">selenium-respectful&lt;/a> - selenium的封装，可以并行访问站点&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="mobile-test-automation-移动端自动化测试工具">Mobile test automation 移动端自动化测试工具&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="http://appium.io/" target="_blank" rel="noopener noreffer ">appium&lt;/a> - 开源的自动化测试框架，可以测试native/hybrid/mobile web应用。核心是基于webdriver协议进行了扩展&lt;/li>
&lt;li>&lt;a href="https://github.com/2gis/Winium.StoreApps/" target="_blank" rel="noopener noreffer ">Winium.StoreApps&lt;/a> - 开源的自动化测试用具，用来测试Windows Store应用，实现了Selenium Remote WebDriver&lt;/li>
&lt;li>&lt;a href="https://github.com/lovelysystems/robotframework-androidlibrary" target="_blank" rel="noopener noreffer ">robotframework-androidlibrary&lt;/a> - Robot Framework用来测试android应用的扩展库&lt;/li>
&lt;li>&lt;a href="https://github.com/jollychang/robotframework-appiumlibrary" target="_blank" rel="noopener noreffer ">robotframework-appiumlibrary&lt;/a> - appium的RobotFramework扩展&lt;/li>
&lt;li>&lt;a href="https://github.com/lovelysystems/robotframework-ioslibrary" target="_blank" rel="noopener noreffer ">robotframework-ioslibrary&lt;/a> -Robot的ios测试扩展库&lt;/li>
&lt;li>&lt;a href="https://github.com/xiaocong/uiautomator" target="_blank" rel="noopener noreffer ">uiautomator&lt;/a> - Android uiautomator的python封装, 支持 Android 4.1+&lt;/li>
&lt;li>&lt;a href="https://github.com/NetEaseGame/ATX" target="_blank" rel="noopener noreffer ">ATX&lt;/a> - 智能机自动化测试工具. 支持 iOS, Android, WebApp 和游戏&lt;/li>
&lt;/ul>
&lt;h2 id="windows-ui-test-automation-windows的ui测试工具">Windows UI test automation Windows的UI测试工具&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://github.com/2gis/Winium.Desktop/" target="_blank" rel="noopener noreffer ">Winium.Desktop&lt;/a> - 测试Windows应用(主要是基于WinForms和WPF平台)的自动化测试工具. 实现了Selenium Remote WebDriver协议&lt;/li>
&lt;li>&lt;a href="https://pypi.python.org/pypi/PyAutoGUI" target="_blank" rel="noopener noreffer ">PyAutoGUI&lt;/a> - 跨平台的GUI测试工具，支持通过python脚本控制键盘和鼠标&lt;/li>
&lt;li>&lt;a href="https://code.google.com/p/robotframework-autoitlibrary/" target="_blank" rel="noopener noreffer ">robotframework-autoitlibrary&lt;/a> - Robot Framework的windows GUI测试扩展&lt;/li>
&lt;li>&lt;a href="https://github.com/msanders/autopy" target="_blank" rel="noopener noreffer ">autopy&lt;/a> - 简单跨平台的GUI测试工具集&lt;/li>
&lt;li>&lt;a href="https://pypi.python.org/pypi/UISoup/" target="_blank" rel="noopener noreffer ">UISoup&lt;/a> - 支持windows和MacOS平台的UI自动化(仅工作在x86平台)&lt;/li>
&lt;li>&lt;a href="http://pywinauto.github.io/" target="_blank" rel="noopener noreffer ">pywinauto&lt;/a> - 非常有python面向对象风格的GUI测试库，现已支持64位机器以及py2和py3&lt;/li>
&lt;li>&lt;a href="http://sikulix.com/" target="_blank" rel="noopener noreffer ">SikuliX&lt;/a> - 基于OpenCV的 GUI 测试框架, 使用图片识别技术，支持python2.7&lt;/li>
&lt;/ul>
&lt;h2 id="unix--linux-ui-test-automation">Unix \ Linux UI test automation&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://pypi.python.org/pypi/ldtp" target="_blank" rel="noopener noreffer ">ldtp&lt;/a> - 跨平台的linux GUI测试项目&lt;/li>
&lt;li>&lt;a href="https://github.com/01org/fMBT" target="_blank" rel="noopener noreffer ">fMBT&lt;/a> - 支持多平台的python GUI测试库&lt;/li>
&lt;li>&lt;a href="http://sikulix.com/" target="_blank" rel="noopener noreffer ">SikuliX&lt;/a> - 基于OpenCV的 GUI 测试框架, 使用图片识别技术，支持python2.7&lt;/li>
&lt;/ul>
&lt;h2 id="macos-ui-test-automation-macos-ui自动化测试工具">MacOS UI test automation MacOS UI自动化测试工具&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://github.com/pyatom/pyatom" target="_blank" rel="noopener noreffer ">ATOMac&lt;/a> - 通过Apple Accessibility API来测试Mac应用的python库&lt;/li>
&lt;li>&lt;a href="https://pypi.python.org/pypi/PyAutoGUI" target="_blank" rel="noopener noreffer ">PyAutoGUI&lt;/a> - 跨平台的GUI测试工具，支持通过python脚本控制键盘和鼠标&lt;/li>
&lt;li>&lt;a href="http://sikulix.com/" target="_blank" rel="noopener noreffer ">SikuliX&lt;/a> - 基于OpenCV的 GUI 测试框架, 使用图片识别技术，支持python2.7&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p></description></item><item><title>（五）Jenkins 设置定时任务</title><link>https://itest2025.pages.dev/tutorials/18-005-%E4%BA%94jenkins-%E8%AE%BE%E7%BD%AE%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1/</link><pubDate>Mon, 16 Oct 2017 12:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/18-005-%E4%BA%94jenkins-%E8%AE%BE%E7%BD%AE%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1/</guid><description>&lt;p>每次都手动的构建项目显然不够方便，有时候需要定时地执行自动化测试脚本。例如，每天晚上定时执行 py_tests.py 文件来运行自动化测试项目。&lt;/p>
&lt;h4 id="设置定时任务">设置定时任务&lt;/h4>
&lt;hr>
&lt;p>前面已经创建的 &lt;strong>“python test project”&lt;/strong> 项目为例，单击项目左侧的 &lt;strong>“配置”&lt;/strong> 选项，修改项目的配置。&lt;/p>
&lt;p>找到 &lt;strong>构建触发器&lt;/strong> ，勾选 &lt;strong>Build periodically&lt;/strong> 选项。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/jenkins_setting_time.png"
 data-srcset="http://img.testclass.net/jenkins_setting_time.png, http://img.testclass.net/jenkins_setting_time.png 1.5x, http://img.testclass.net/jenkins_setting_time.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/jenkins_setting_time.png"
 title="http://img.testclass.net/jenkins_setting_time.png" />&lt;/p>
&lt;p>通过查看设置说明，此处定时任务的格式遵循 cron 的语法（可以与 cron 的语法有轻微的差异）。具体格式，每行包含五个字段，通过 Tab 或空格分隔。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/jenkins_crontab.png"
 data-srcset="http://img.testclass.net/jenkins_crontab.png, http://img.testclass.net/jenkins_crontab.png 1.5x, http://img.testclass.net/jenkins_crontab.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/jenkins_crontab.png"
 title="http://img.testclass.net/jenkins_crontab.png" />&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">字段&lt;/th>
 &lt;th style="text-align: left">说明&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">MINUTE&lt;/td>
 &lt;td style="text-align: left">Minutes within the hour (0–59)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">HOUR&lt;/td>
 &lt;td style="text-align: left">The hour of the day (0–23)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">DOM&lt;/td>
 &lt;td style="text-align: left">The day of the month (1–31)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">MONTH&lt;/td>
 &lt;td style="text-align: left">The month (1–12)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">DOW&lt;/td>
 &lt;td style="text-align: left">The day of the week (0–7) where 0 and 7 are Sunday.&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>若要指定一个字段的多个值，可以使用以下运算符，按先后顺序。&lt;/p></description></item><item><title>（五）Locust 参数说明</title><link>https://itest2025.pages.dev/tutorials/38-005-%E4%BA%94locust-%E5%8F%82%E6%95%B0%E8%AF%B4%E6%98%8E/</link><pubDate>Mon, 16 Oct 2017 11:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/38-005-%E4%BA%94locust-%E5%8F%82%E6%95%B0%E8%AF%B4%E6%98%8E/</guid><description>&lt;p>最时候该讲一下 locust 工具的参数了，虽然前面几节我们已经使用了不少参数，例如 &lt;strong>“-f”&lt;/strong> 、&lt;strong>“&amp;ndash;host”&lt;/strong> 等。&lt;/p>
&lt;h4 id="locust-参数">Locust 参数&lt;/h4>
&lt;hr>
&lt;p>打开命令提示符（或Linux终端），输入 &lt;code>locust --help&lt;/code> 。&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt; locust --help
Usage: locust [options] [LocustClass [LocustClass2 ... ]]

Options:
 -h, --help show this help message and exit
 -H HOST, --host=HOST Host to load test in the following format:
 http://10.21.32.33
 --web-host=WEB_HOST Host to bind the web interface to. Defaults to &amp;#39;&amp;#39; (all
 interfaces)
 -P PORT, --port=PORT, --web-port=PORT
 Port on which to run web host
 -f LOCUSTFILE, --locustfile=LOCUSTFILE
 Python module file to import, e.g. &amp;#39;../other.py&amp;#39;.
 Default: locustfile
 --csv=CSVFILEBASE, --csv-base-name=CSVFILEBASE
 Store current request stats to files in CSV format.
 --master Set locust to run in distributed mode with this
 process as master
 --slave Set locust to run in distributed mode with this
 process as slave
 --master-host=MASTER_HOST
 Host or IP address of locust master for distributed
 load testing. Only used when running with --slave.
 Defaults to 127.0.0.1.
 --master-port=MASTER_PORT
 The port to connect to that is used by the locust
 master for distributed load testing. Only used when
 running with --slave. Defaults to 5557. Note that
 slaves will also connect to the master node on this
 port + 1.
 --master-bind-host=MASTER_BIND_HOST
 Interfaces (hostname, ip) that locust master should
 bind to. Only used when running with --master.
 Defaults to * (all available interfaces).
 --master-bind-port=MASTER_BIND_PORT
 Port that locust master should bind to. Only used when
 running with --master. Defaults to 5557. Note that
 Locust will also use this port + 1, so by default the
 master node will bind to 5557 and 5558.
 --expect-slaves=EXPECT_SLAVES
 How many slaves master should expect to connect before
 starting the test (only when --no-web used).
 --no-web Disable the web interface, and instead start running
 the test immediately. Requires -c and -r to be
 specified.
 -c NUM_CLIENTS, --clients=NUM_CLIENTS
 Number of concurrent Locust users. Only used together
 with --no-web
 -r HATCH_RATE, --hatch-rate=HATCH_RATE
 The rate per second in which clients are spawned. Only
 used together with --no-web
 -t RUN_TIME, --run-time=RUN_TIME
 Stop after the specified amount of time, e.g. (300s,
 20m, 3h, 1h30m, etc.). Only used together with --no-
 web
 -L LOGLEVEL, --loglevel=LOGLEVEL
 Choose between DEBUG/INFO/WARNING/ERROR/CRITICAL.
 Default is INFO.
 --logfile=LOGFILE Path to log file. If not set, log will go to
 stdout/stderr
 --print-stats Print stats in the console
 --only-summary Only print the summary stats
 --no-reset-stats Do not reset statistics once hatching has been
 completed
 -l, --list Show list of possible locust classes and exit
 --show-task-ratio print table of the locust classes&amp;#39; task execution
 ratio
 --show-task-ratio-json
 print json data of the locust classes&amp;#39; task execution
 ratio
 -V, --version show program&amp;#39;s version number and exit
&lt;/code>&lt;/pre>&lt;p>&lt;strong>参数说明：&lt;/strong>&lt;/p></description></item><item><title>05. 安装环境：Mac</title><link>https://itest2025.pages.dev/tutorials/37-005-05-%E5%AE%89%E8%A3%85%E7%8E%AF%E5%A2%83mac/</link><pubDate>Mon, 16 Oct 2017 08:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/37-005-05-%E5%AE%89%E8%A3%85%E7%8E%AF%E5%A2%83mac/</guid><description>&lt;h1 id="mac-系统下安装-intellij-idea">Mac 系统下安装 IntelliJ IDEA&lt;/h1>
&lt;h2 id="系统要求">系统要求&lt;/h2>
&lt;blockquote>
&lt;ul>
&lt;li>系统支持：Mac OS X 10.5 以上&lt;/li>
&lt;li>JDK 版本：Apple Java 6 或 Oracle Java 7 以上&lt;/li>
&lt;li>内存：最低要求 1 G，推荐 2 G 以上&lt;/li>
&lt;li>硬盘：最低要求 2 G&lt;/li>
&lt;li>显示器：最低要求 1024 X 768 分辨率&lt;/li>
&lt;li>更多信息可以阅读：&lt;a href="https://www.jetbrains.com/idea/download/system_requirements.jsp?os=mac" target="_blank" rel="noopener noreffer ">https://www.jetbrains.com/idea/download/system_requirements.jsp?os=mac&lt;/a>&lt;/li>
&lt;/ul>&lt;/blockquote>
&lt;h2 id="重要说明">重要说明&lt;/h2>
&lt;p>我这里以 Mac 系统为例进行讲解。但是，在学习下面内容之前请先看下章节：&lt;a href="windows-install.md" rel="">Windows 下安装&lt;/a>&lt;/p>
&lt;p>因为它们配置流程是基本一样的，只是系统不同，开始的步骤不太一样而已，因此相同部分我这里是不会再讲的，我只讲 IntelliJ IDEA 在 Mac 安装特殊的地方。&lt;/p>
&lt;h2 id="mac-下安装过程">Mac 下安装过程&lt;/h2>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/v-a-mac-install-1.jpg"
 data-srcset="http://img.testclass.net/v-a-mac-install-1.jpg, http://img.testclass.net/v-a-mac-install-1.jpg 1.5x, http://img.testclass.net/v-a-mac-install-1.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/v-a-mac-install-1.jpg"
 title="Mac 下安装过程" />&lt;/p>
&lt;blockquote>
&lt;ul>
&lt;li>运行下载到 &lt;code>ideaIU-14.1.4.dmg&lt;/code>，效果如上图所示。&lt;/li>
&lt;li>根据提示把左侧的 IntelliJ IDEA 图标拖动到右侧目录图&lt;/li>
&lt;/ul>&lt;/blockquote>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/v-a-mac-install-2.jpg"
 data-srcset="http://img.testclass.net/v-a-mac-install-2.jpg, http://img.testclass.net/v-a-mac-install-2.jpg 1.5x, http://img.testclass.net/v-a-mac-install-2.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/v-a-mac-install-2.jpg"
 title="Mac 下安装过程" />&lt;/p></description></item><item><title>（五）soapUI创建SOAP项目</title><link>https://itest2025.pages.dev/tutorials/26-005-%E4%BA%94soapui%E5%88%9B%E5%BB%BAsoap%E9%A1%B9%E7%9B%AE/</link><pubDate>Wed, 20 Sep 2017 22:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/26-005-%E4%BA%94soapui%E5%88%9B%E5%BB%BAsoap%E9%A1%B9%E7%9B%AE/</guid><description>&lt;h4 id="创建-soap-项目">创建 SOAP 项目&lt;/h4>
&lt;hr>
&lt;p>打开 soapUI 工具。创建一个SOAP项目。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/soapui_main_window.png"
 data-srcset="http://img.testclass.net/soapui_main_window.png, http://img.testclass.net/soapui_main_window.png 1.5x, http://img.testclass.net/soapui_main_window.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/soapui_main_window.png"
 title="http://img.testclass.net/soapui_main_window.png" />&lt;/p>
&lt;p>在窗口左侧导航栏，右键 &lt;strong>Projects &amp;ndash;&amp;gt; New SOAP Project&lt;/strong>。&lt;/p>
&lt;h4 id="添加soap接口">添加SOAP接口&lt;/h4>
&lt;hr>
&lt;p>以国内手机号码归属地查询接口为例：&lt;/p>
&lt;p>&lt;strong>Project Name&lt;/strong>：MobileCodeWS为项目名称。&lt;/p>
&lt;p>&lt;strong>Initial WSDL&lt;/strong>：http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl 为接口URL。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/soapui_new_soap_project.png"
 data-srcset="http://img.testclass.net/soapui_new_soap_project.png, http://img.testclass.net/soapui_new_soap_project.png 1.5x, http://img.testclass.net/soapui_new_soap_project.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/soapui_new_soap_project.png"
 title="http://img.testclass.net/soapui_new_soap_project.png" />&lt;/p>
&lt;p>点击 &lt;strong>OK&lt;/strong> 按钮，创建项目完成。&lt;/p>
&lt;p>依次展开：&lt;strong>MobileCodeWS&amp;ndash;&amp;gt;MobileCodeWSSoap&amp;ndash;&amp;gt;getMobileCodeInfo/&lt;/strong>，双击 &lt;strong>Request 1&lt;/strong>，填写接口查询的手机号。如下图。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/soapui_soap_if_data.png"
 data-srcset="http://img.testclass.net/soapui_soap_if_data.png, http://img.testclass.net/soapui_soap_if_data.png 1.5x, http://img.testclass.net/soapui_soap_if_data.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/soapui_soap_if_data.png"
 title="http://img.testclass.net/soapui_soap_if_data.png" />&lt;/p>
&lt;p>请求接口详细配置如下：&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;lt;soapenv:Envelope xmlns:soapenv=&amp;#34;http://schemas.xmlsoap.org/soap/envelope/&amp;#34; xmlns:web=&amp;#34;http://WebXml.com.cn/&amp;#34;&amp;gt;
 &amp;lt;soapenv:Header/&amp;gt;
 &amp;lt;soapenv:Body&amp;gt;
 &amp;lt;web:getMobileCodeInfo&amp;gt;
 &amp;lt;!--Optional:--&amp;gt;
 &amp;lt;web:mobileCode&amp;gt;186xxxxxxxx&amp;lt;/web:mobileCode&amp;gt;
 &amp;lt;!--Optional:--&amp;gt;
 &amp;lt;web:userID&amp;gt;&amp;lt;/web:userID&amp;gt;
 &amp;lt;/web:getMobileCodeInfo&amp;gt;
 &amp;lt;/soapenv:Body&amp;gt;
&amp;lt;/soapenv:Envelope&amp;gt;
&lt;/code>&lt;/pre>&lt;p>注：将 xxxxxxxx 替换为手机号。&lt;/p>
&lt;h4 id="运行测试">运行测试&lt;/h4>
&lt;hr>
&lt;p>点击 &lt;strong>Request 1&lt;/strong> 窗口左上角的绿色 &lt;strong>运行&lt;/strong> 按钮，发送 SOAP 请求。右侧窗口将会显示接口返回结果。&lt;/p></description></item><item><title>appium新手入门（5）—— python-client安装与测试</title><link>https://itest2025.pages.dev/tutorials/21-005-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A85-python-client%E5%AE%89%E8%A3%85%E4%B8%8E%E6%B5%8B%E8%AF%95/</link><pubDate>Thu, 07 Sep 2017 10:24:12 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/21-005-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A85-python-client%E5%AE%89%E8%A3%85%E4%B8%8E%E6%B5%8B%E8%AF%95/</guid><description>&lt;p>&lt;strong>关联阅读：&lt;/strong>&lt;/p>
&lt;p>&lt;a href="https://itest2025.pages.dev/appium/appium-base-summary/" rel="">appium新手入门（1）—— appium介绍&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://itest2025.pages.dev/appium/appium-base-sdk/" rel="">appium新手入门（2）—— 安装 Android SDK&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://itest2025.pages.dev/appium/appium-base-server/" rel="">appium新手入门（3）—— 安装 appium Server&lt;/a>&lt;/p>
&lt;br>
#### 前提条件
----
&lt;p>当你点击这一章时，说明你是打算使用 Python 语言编写 appium 自动化测试脚本的。&lt;/p>
&lt;p>1、安装 &lt;a href="https://itest2025.pages.dev/selenium_python/install-selenium/" rel="">Python 语言&lt;/a> , Python的安装相对相简单得多。&lt;/p>
&lt;p>2、Python 编辑器很多，推荐：PyCharm、Atom、Sublime text3等。这几款都是我常用的。&lt;/p>
&lt;h4 id="安装-python-client">安装 python-client&lt;/h4>
&lt;hr>
&lt;p>其实，&lt;a href="https://github.com/appium/python-client" target="_blank" rel="noopener noreffer ">python-client&lt;/a> 的项目名称叫：Appium-Python-Client。&lt;/p>
&lt;p>推荐pip安装：&lt;/p>
&lt;pre>&lt;code>(venv) λ pip install Appium-Python-Client
Collecting Appium-Python-Client
 Using cached Appium-Python-Client-0.24.tar.gz
Requirement already satisfied: selenium&amp;gt;=2.47.0 in d:\pyflask\venv\lib\site-packages (from Appium-Python-Client)
Building wheels for collected packages: Appium-Python-Client
 Running setup.py bdist_wheel for Appium-Python-Client ... done
 Stored in directory: C:\Users\fnngj\AppData\Local\pip\Cache\wheels\2e\cf\10\0e3f177c9869147b16584d402f79d9007df1139105ea3ecc2c

Successfully built Appium-Python-Client
Installing collected packages: Appium-Python-Client
Successfully installed Appium-Python-Client-0.24
&lt;/code>&lt;/pre>
&lt;br>
#### 运行第一个Appium测试
----
* __第一步__，启动Android模拟器。
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/appium_android_system.png"
 data-srcset="http://img.testclass.net/appium_android_system.png, http://img.testclass.net/appium_android_system.png 1.5x, http://img.testclass.net/appium_android_system.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/appium_android_system.png"
 title="http://img.testclass.net/appium_android_system.png" />&lt;/p></description></item><item><title>5.3A原则</title><link>https://itest2025.pages.dev/tutorials/40-005-53a%E5%8E%9F%E5%88%99/</link><pubDate>Sat, 26 Aug 2017 04:41:43 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/40-005-53a%E5%8E%9F%E5%88%99/</guid><description>&lt;p>3A原则原本是单元测试用例编写时应该遵循的基本原则，不过我们可以扩展到接口的自动化测试用例编写中来。&lt;/p>
&lt;p>我们首先看一下3A原则在每一层自动化测试中的具体应用。&lt;/p>
&lt;h3 id="单元测试用例">单元测试用例&lt;/h3>
&lt;ul>
&lt;li>Arrange: 初始化测试对象或者准备测试数据&lt;/li>
&lt;li>Act : 调用被测方法&lt;/li>
&lt;li>Assert: 断言&lt;/li>
&lt;/ul>
&lt;p>给一个例子(c#)&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-c#" data-lang="c#">&lt;span class="line">&lt;span class="cl">&lt;span class="na">[TestMethod]&lt;/span> 
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span> &lt;span class="k">void&lt;/span> &lt;span class="n">Withdraw_ValidAmount_ChangesBalance&lt;/span>&lt;span class="p">()&lt;/span> 
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span> 
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// arrange &lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">double&lt;/span> &lt;span class="n">currentBalance&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">10.0&lt;/span>&lt;span class="p">;&lt;/span> 
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">double&lt;/span> &lt;span class="n">withdrawal&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">1.0&lt;/span>&lt;span class="p">;&lt;/span> 
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">double&lt;/span> &lt;span class="n">expected&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">9.0&lt;/span>&lt;span class="p">;&lt;/span> 
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">var&lt;/span> &lt;span class="n">account&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">CheckingAccount&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;JohnDoe&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">currentBalance&lt;/span>&lt;span class="p">);&lt;/span> 
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// act &lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">account&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Withdraw&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">withdrawal&lt;/span>&lt;span class="p">);&lt;/span> 
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">double&lt;/span> &lt;span class="n">actual&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">account&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Balance&lt;/span>&lt;span class="p">;&lt;/span> 
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// assert &lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Assert&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">AreEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">expected&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">actual&lt;/span>&lt;span class="p">);&lt;/span> 
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span> 
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="服务间的接口测试用例">服务间的接口测试用例&lt;/h3>
&lt;p>服务间的接口测试实际上是黑盒测试，3A原则也适用于这种测试用例的编写&lt;/p>
&lt;ul>
&lt;li>A: arrange 初始化测试数据，就是造数据，这里的数据有我们输入的数据，也有目标接口所涉及的资源，比如hr系统中的用户信息，我们必须先有几条人员的详细信息才能去测获取人员信息的接口（当然只是正常的流程，我们有时候还需要清掉数据以便测试资源为空的情况）；&lt;/li>
&lt;li>A: act 调用接口，传入输入数据；&lt;/li>
&lt;li>A: assert 断言， 对返回的资源信息进行断言，比如获取用户信息的接口返回了用户信息之后，我们要判断返回的用户是不是我们想要的那个用户，我们获取的是李雷的信息，接口如果返回韩梅梅，那么接口的逻辑就是不对的；&lt;/li>
&lt;/ul>
&lt;p>举个例子(python)&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">test_get_task_by_id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># arrange&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">create_task_res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create_task&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;test&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;desc&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">new_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">create_task_res&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;id&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># act&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">url_for_get_by_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ip&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="s1">&amp;#39;/api/tasks/&amp;#39;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">new_id&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">requests&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;GET&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">url_for_get_by_id&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">json&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># assert&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">res&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;id&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">new_id&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="手工测试用例">手工测试用例&lt;/h3>
&lt;p>手工的功能测试用例也可以用3A原则来编写。&lt;/p>
&lt;ul>
&lt;li>Arrange: 准备被测功能相关的测试数据，比如往系统里录入一批工单以便测试工单的分页功能&lt;/li>
&lt;li>Act : 调用被测的功能，实际上这就是我们一直讲的测试步骤&lt;/li>
&lt;li>Assert: 断言&lt;/li>
&lt;/ul>
&lt;p>举个例子&lt;/p>
&lt;pre tabindex="0">&lt;code># arrange and act
打开chrome浏览器并跳转至http://localhost/wordpress/wp-login.php
在用户名文本框中输入admin
在密码文本框中输入admin
点击登陆按钮
# assert
浏览器跳转到http://localhost/wordpress/wp-admin/
右上角出现“你好，admin”字样
&lt;/code>&lt;/pre>&lt;h3 id="总结">总结&lt;/h3>
&lt;p>总之对于接口的自动化测试用例说来，遵循3A原则就意味着&lt;/p></description></item><item><title>JMeter官方文档：5. 构建一个高级web测试计划</title><link>https://itest2025.pages.dev/tutorials/22-005-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A35-%E6%9E%84%E5%BB%BA%E4%B8%80%E4%B8%AA%E9%AB%98%E7%BA%A7web%E6%B5%8B%E8%AF%95%E8%AE%A1%E5%88%92/</link><pubDate>Thu, 24 Aug 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/22-005-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A35-%E6%9E%84%E5%BB%BA%E4%B8%80%E4%B8%AA%E9%AB%98%E7%BA%A7web%E6%B5%8B%E8%AF%95%E8%AE%A1%E5%88%92/</guid><description>&lt;p>&lt;a href="https://itest2025.pages.dev/2017/08/24/jmeter-translation-plans/" rel="">《JMeter官方文档&amp;ndash;翻译计划》&lt;/a> &lt;a href="http://jmeter.apache.org/usermanual/build-adv-web-test-plan.html" target="_blank" rel="noopener noreffer ">原文地址&lt;/a>&lt;/p>
&lt;h2 id="5-构建一个高级web测试计划">5. 构建一个高级web测试计划&lt;/h2>
&lt;hr>
&lt;p>在本章，你将学习如何创建高级&lt;a href="http://jmeter.apache.org/usermanual/build-test-plan.html" target="_blank" rel="noopener noreffer ">测试计划&lt;/a>，来测试一个web网站。&lt;/p>
&lt;p>有关基础测试计划的示例，请参考&lt;a href="http://jmeter.apache.org/usermanual/build-web-test-plan.html" target="_blank" rel="noopener noreffer ">构建Web测试计划&lt;/a>&lt;/p>
&lt;h3 id="51-使用url重写用户session">5.1 使用URL重写用户session&lt;/h3>
&lt;hr>
&lt;p>如果你的 Web 应用程序，是使用URL重写而不是使用cookie保存session信息，那么你将需要做一点额外的设置来测试你的网站。&lt;/p>
&lt;p>为了争取响应URL重写，JMeter 需要解析从服务器接受的 HTML，并检索唯一的 sessionID。&lt;/p>
&lt;p>使用恰当的 &lt;a href="http://jmeter.apache.org/usermanual/component_reference.html#HTTP_URL_Re-writing_Modifier" target="_blank" rel="noopener noreffer ">HTTP URL 重写修改器&lt;/a>来完成这项工作。只需要将sessionID参数名输入到修改器，jmeter会找到它并将它添加到每个请求中。如果请求已经有这个参数值，则会替换它。如果勾选Cache Session id?复选框，那么最后找到的sessionID将被保存，如果先前的http示例不包含sessionID，则会使用它。&lt;/p>
&lt;h4 id="url重写修改器示例">URL重写修改器示例&lt;/h4>
&lt;hr>
&lt;p>下载这个示例。&lt;strong>图1&lt;/strong> 显示一个使用URL重写的测试计划。注意，URL重写修改器被添加到事务控制器中，因此它只会影响该事务控制器下的请求。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/05_http_URL_Re_writ.png"
 data-srcset="http://img.testclass.net/05_http_URL_Re_writ.png, http://img.testclass.net/05_http_URL_Re_writ.png 1.5x, http://img.testclass.net/05_http_URL_Re_writ.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/05_http_URL_Re_writ.png"
 title="http://img.testclass.net/05_http_URL_Re_writ.png" />&lt;/p>
&lt;p>图1 测试树&lt;/p>
&lt;p>在 &lt;strong>图2&lt;/strong> 中，我们看到URL重写修改器的GUI界面，它有一个字段是供用户修改指定sessionID的。还有一个复选框，用于标记sessionID是地址的一部分（由“；”分隔），而不是作为请求参数。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/05_http_URL_Re_writ2.png"
 data-srcset="http://img.testclass.net/05_http_URL_Re_writ2.png, http://img.testclass.net/05_http_URL_Re_writ2.png 1.5x, http://img.testclass.net/05_http_URL_Re_writ2.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/05_http_URL_Re_writ2.png"
 title="http://img.testclass.net/05_http_URL_Re_writ2.png" />&lt;/p>
&lt;p>图2 请求参数&lt;/p>
&lt;h3 id="52-使用头文件管理器">5.2 使用头文件管理器&lt;/h3>
&lt;hr>
&lt;p>Jmeter的 &lt;a href="http://jmeter.apache.org/usermanual/component_reference.html#HTTP_Header_Manager" target="_blank" rel="noopener noreffer ">HTTP头文件管理器&lt;/a>，允许您自定义HTTP请求头文件，这个头文件包括“User-Agent&amp;quot;，&amp;ldquo;Pragma&amp;rdquo;, &amp;ldquo;Referer&amp;quot;等属性。&lt;/p>
&lt;p>HTTP 头文件管理器，和 &lt;a href="http://jmeter.apache.org/usermanual/component_reference.html#HTTP_Cookie_Manager" target="_blank" rel="noopener noreffer ">HTTP cookie 管理器&lt;/a>类似，应该在线程组级别添加，除非出于特殊原因，您希望在测试中给某几个 &lt;a href="http://jmeter.apache.org/usermanual/component_reference.html#HTTP_Request" target="_blank" rel="noopener noreffer ">HTTP 请求&lt;/a> 设置不一样的头文件。&lt;/p></description></item><item><title>appium简明教程（5）——appium client方法一览</title><link>https://itest2025.pages.dev/tutorials/21-005-appium%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B5appium-client%E6%96%B9%E6%B3%95%E4%B8%80%E8%A7%88/</link><pubDate>Wed, 16 Aug 2017 07:30:01 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/21-005-appium%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B5appium-client%E6%96%B9%E6%B3%95%E4%B8%80%E8%A7%88/</guid><description>&lt;p>appium client扩展了原生的webdriver client方法&lt;/p>
&lt;p>下面以java代码为例，简单过一下appium client提供的适合移动端使用的新方法&lt;/p>
&lt;pre tabindex="0">&lt;code>resetApp()
getAppString()
sendKeyEvent()
currentActivity()
pullFile()
pushFile()
pullFolder()
hideKeyboard()
runAppInBackground()
performTouchAction()
performMultiTouchAction()
tap()
swipe()
pinch()
zoom()
getNamedTextField()
isAppInstalled()
installApp()
removeApp()
launchApp()
closeApp()
endTestCoverage()
lockScreen()
shake()
complexFind()
scrollTo()
scrollToExact()
openNotifications()
Context Switching: .context(), .getContextHandles(), getContext())
&lt;/code>&lt;/pre>&lt;p>新增的locator&lt;/p>
&lt;pre tabindex="0">&lt;code>findElementByAccessibilityId()
findElementsByAccessibilityId()
findElementByIosUIAutomation()
findElementsByIosUIAutomation()
findElementByAndroidUIAutomator()
findElementsByAndroidUIAutomator()
&lt;/code>&lt;/pre>&lt;p>这些方法主要覆盖了3大类：&lt;/p>
&lt;ul>
&lt;li>driver扩展：比如增加了resetApp等操作app的方法&lt;/li>
&lt;li>action扩展：增加一些移动端的特有的action（怎么描述呢，相当于是移动端 特有的操作），比如swipe，shake(嗯，有了这个方法就可以让代码帮你摇一摇了)等；&lt;/li>
&lt;li>locator扩展：增加了一些移动端专属的定位策略&lt;/li>
&lt;/ul>
&lt;p>本文版权归乙醇所有，欢迎转载，但请注明作者与出处，严禁用于任何商业用途&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1504387103978-e4ee71416c38?w=300"
 data-srcset="https://images.unsplash.com/photo-1504387103978-e4ee71416c38?w=300, https://images.unsplash.com/photo-1504387103978-e4ee71416c38?w=300 1.5x, https://images.unsplash.com/photo-1504387103978-e4ee71416c38?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1504387103978-e4ee71416c38?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>性能测试基础（五）响应时间</title><link>https://itest2025.pages.dev/tutorials/14-005-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E5%9F%BA%E7%A1%80%E4%BA%94%E5%93%8D%E5%BA%94%E6%97%B6%E9%97%B4/</link><pubDate>Fri, 11 Aug 2017 11:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/14-005-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E5%9F%BA%E7%A1%80%E4%BA%94%E5%93%8D%E5%BA%94%E6%97%B6%E9%97%B4/</guid><description>&lt;br>
站在用户角度来说，你可以将软件性能看作是软件对用户操作的响应时间。说得更明直白点，对用户来说，当单击一个按钮或链接，从用户单击开始到应用系统把本次操作的结果以用户识别的方式展示出来，这个过程所消耗的时间就是用户对软件性能的直观印象。
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/response-time.jpg"
 data-srcset="http://img.testclass.net/response-time.jpg, http://img.testclass.net/response-time.jpg 1.5x, http://img.testclass.net/response-time.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/response-time.jpg"
 title="http://img.testclass.net/response-time.jpg" />&lt;/p>
&lt;br>
#### 响应时间过程分析:
&lt;p>我们需要对这个过程进行分解，才能得到你真正想要的响应时间。我把整个过程分三个部分：呈现时间，数据传输时间和系统处理时间。&lt;/p>
&lt;p>&lt;strong>呈现时间&lt;/strong>&lt;/p>
&lt;p>其实主要说的浏览器对接收到数据的一个处理展示的过程。几年前大家都在用IE，如果页面显示比较慢，我们肯定不会怪罪IE，只会怪罪电信运营商的网速或被访问的系统（其实，大多情况我们不会考虑是被访问系统的问题）。现在Chrome来了，我们会发现同一台电脑同一个网站，通过Chrome去访问，页面的呈现速度会比IE略快。这是各种评测及大众用户的整体感受。&lt;/p>
&lt;p>当然，我说这个呈现时间不能全怪在浏览器的身上，当然还和承载它的操作系统有关，以及电脑硬件（比如CPU、 内存）。假如你有超快的浏览器，如果是一台配置很低的电脑上运行，当你多打开几个网页就有可能使电脑卡死。&lt;/p>
&lt;p>&lt;strong>数据传输时间&lt;/strong>&lt;/p>
&lt;p>千万不要忽视数据传输时间。如果你要寄信给你一个远方的朋友，你想是什么影响你朋友收到信的时间的？不是你写信的过程（如果你写的信不像书一样厚的话），也不是你朋友读信的过程，而是送信的过程。&lt;/p>
&lt;p>拿我们系统的数据传输过程来说，我们发送一个请求需要时间，系统处理完后返回给我们也需要时间。初学性能测试工具的同学喜欢拿工具去测试互联网上的一些系统，甚至不懂性能的同学认为可以用性能测试工具将互联网上的一些网站宕机。&lt;/p>
&lt;p>那么，我觉得这些同学应该补补网络知识了，你的带宽是多少？互联网是个网，就是算是相同的起点与终点，它有可能走的不同的路线。有没有考虑网络延迟？就算你的发出请求都能成功的发出，但到目的地的时候，已经不能叫并发了。&lt;/p>
&lt;p>这也是为什么我们在一般做性能测试时，一般要强调要在局域网中进行。当然，有些性能测试需要在互联网中时行。但它们重点不是验证服务器端的最大处理能力。&lt;/p>
&lt;p>&lt;strong>系统处理时间&lt;/strong>&lt;/p>
&lt;p>当系统得到请求后会对请求进行处理并将结果返回。那我进行性能测试主要就是验证系统的处理时间，因为前面的呈现时间和数据传输时间都是我们不可控制的，用户使用的电脑及浏览器千差万别，用户的网络状况千差万别。我们唯一能控制的就是将系统的处理请求的时间缩到最短。
 
一般性能测试场景&lt;/p>
&lt;p>听了上面的分析，貌似每个过程都挺“浪费”时间，那么我们如何只测试系统的处理时间呢？&lt;/p>
&lt;p>一般测试工具都屏蔽响应的呈现过程，只是模拟多用户并发请求，计算用户得到响应的时间，不会将服务器的每个响应做客户端渲染呈现。&lt;/p>
&lt;p>对于数据传输的问题，这也是我要强调的性能测试要在局域网中进行，在局域网中一般不会受到数据带宽的限制。所以，可以对数据的传输时间忽略不计。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1414438992182-69e404046f80?w=300"
 data-srcset="https://images.unsplash.com/photo-1414438992182-69e404046f80?w=300, https://images.unsplash.com/photo-1414438992182-69e404046f80?w=300 1.5x, https://images.unsplash.com/photo-1414438992182-69e404046f80?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1414438992182-69e404046f80?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（五）通过name去定位页面上的元素</title><link>https://itest2025.pages.dev/tutorials/20-005-%E4%BA%94%E9%80%9A%E8%BF%87name%E5%8E%BB%E5%AE%9A%E4%BD%8D%E9%A1%B5%E9%9D%A2%E4%B8%8A%E7%9A%84%E5%85%83%E7%B4%A0/</link><pubDate>Wed, 09 Aug 2017 01:45:25 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/20-005-%E4%BA%94%E9%80%9A%E8%BF%87name%E5%8E%BB%E5%AE%9A%E4%BD%8D%E9%A1%B5%E9%9D%A2%E4%B8%8A%E7%9A%84%E5%85%83%E7%B4%A0/</guid><description>&lt;h3 id="表单元素">表单元素&lt;/h3>
&lt;p>一般来说表单元素的标签大多出现在&lt;code>&amp;lt;form&amp;gt;&amp;lt;/form&amp;gt;&lt;/code>标签中，比如&lt;/p>
&lt;ul>
&lt;li>&lt;code>&amp;lt;input type=&amp;quot;text&amp;quot;&amp;gt;&lt;/code>: 单行文本框&lt;/li>
&lt;li>&lt;code>&amp;lt;input type=&amp;quot;checkbox&amp;quot;&amp;gt;&lt;/code>: checkbox&lt;/li>
&lt;li>&lt;code>&amp;lt;input type=&amp;quot;radio&amp;quot;&amp;gt;&lt;/code>: radio&lt;/li>
&lt;li>&lt;code>&amp;lt;select&amp;gt;&amp;lt;option&amp;gt;&amp;lt;/option&amp;gt;&amp;lt;/select&amp;gt;&lt;/code>: 下拉框&lt;/li>
&lt;li>&lt;code>&amp;lt;textarea&amp;gt;&amp;lt;/textarea&amp;gt;&lt;/code>: 多行文本&lt;/li>
&lt;/ul>
&lt;p>如果这样元素有name属性的话，建议使用name属性去定位，因为相比较其他属性，name属性更加稳定。&lt;/p>
&lt;p>有一些元素比如checkbox和radio往往有多个name属性相同的元素，如下面的html代码所示&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">ul&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;list list--bare&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;&lt;/span>&lt;span class="nt">label&lt;/span> &lt;span class="na">for&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;radio1&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;&lt;/span>&lt;span class="nt">input&lt;/span> &lt;span class="na">id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;radio1&amp;#34;&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;radio&amp;#34;&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;radio&amp;#34;&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;radio&amp;#34;&lt;/span> &lt;span class="na">checked&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;checked&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> Option 1&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">label&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;&lt;/span>&lt;span class="nt">label&lt;/span> &lt;span class="na">for&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;radio2&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;&lt;/span>&lt;span class="nt">input&lt;/span> &lt;span class="na">id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;radio2&amp;#34;&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;radio&amp;#34;&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;radio&amp;#34;&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;radio&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> Option 2&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">label&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;&lt;/span>&lt;span class="nt">label&lt;/span> &lt;span class="na">for&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;radio3&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;&lt;/span>&lt;span class="nt">input&lt;/span> &lt;span class="na">id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;radio3&amp;#34;&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;radio&amp;#34;&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;radio&amp;#34;&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;radio&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> Option 3&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">label&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">ul&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这时候也可以使用name属性定位，不过需要用到后面讲的定位一组元素的知识了。&lt;/p>
&lt;h3 id="目的">目的&lt;/h3>
&lt;ul>
&lt;li>熟悉selenium webdriver 定位方式&lt;/li>
&lt;li>学会通过name属性去定位元素&lt;/li>
&lt;/ul>
&lt;h3 id="示例代码">示例代码&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// &amp;lt;input name=&amp;#34;username&amp;#34; /&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;username&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;测试教程网&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// &amp;lt;input name=&amp;#34;password&amp;#34; type=&amp;#34;password&amp;#34; /&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;password&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;就不告诉你&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1492446190781-58ac4285911d?w=300"
 data-srcset="https://images.unsplash.com/photo-1492446190781-58ac4285911d?w=300, https://images.unsplash.com/photo-1492446190781-58ac4285911d?w=300 1.5x, https://images.unsplash.com/photo-1492446190781-58ac4285911d?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1492446190781-58ac4285911d?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>java测试笔试题1</title><link>https://itest2025.pages.dev/tutorials/44-005-java%E6%B5%8B%E8%AF%95%E7%AC%94%E8%AF%95%E9%A2%981/</link><pubDate>Wed, 26 Jul 2017 09:30:25 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/44-005-java%E6%B5%8B%E8%AF%95%E7%AC%94%E8%AF%95%E9%A2%981/</guid><description>&lt;h3 id="final关键字可以修饰类吗">final关键字可以修饰类吗？&lt;/h3>
&lt;p>can keyword final be assigned to a class? yes&lt;/p>
&lt;p>可以&lt;/p>
&lt;h3 id="java可以继承多父类么可以实现多接口么">Java可以继承多父类么？可以实现多接口么？&lt;/h3>
&lt;p>Can a java class inheritance from multiple classes? how about a java class implement multiple interfaces?&lt;/p>
&lt;p>不可以多继承，但是可以多实现&lt;/p>
&lt;h3 id="构造方法是否可以重写和重载">构造方法是否可以重写和重载？&lt;/h3>
&lt;p>Can a constructor be overrided? how about oveload?&lt;/p>
&lt;p>不可以重写，可以重载&lt;/p>
&lt;h3 id="exception类的父类是">Exception类的父类是？&lt;/h3>
&lt;p>what is the Exception class inhertanced from?&lt;/p>
&lt;p>Throwable&lt;/p>
&lt;h3 id="同一个类中静态方法如何直接调用非静态方法">同一个类中，静态方法如何直接调用非静态方法？&lt;/h3>
&lt;p>Could a static method call a non-static method in the same class?&lt;/p>
&lt;p>静态方法不可以调用非静态方法&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1531497865144-0464ef8fb9a9?w=300"
 data-srcset="https://images.unsplash.com/photo-1531497865144-0464ef8fb9a9?w=300, https://images.unsplash.com/photo-1531497865144-0464ef8fb9a9?w=300 1.5x, https://images.unsplash.com/photo-1531497865144-0464ef8fb9a9?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1531497865144-0464ef8fb9a9?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（五）浅谈测试用例</title><link>https://itest2025.pages.dev/tutorials/29-005-%E4%BA%94%E6%B5%85%E8%B0%88%E6%B5%8B%E8%AF%95%E7%94%A8%E4%BE%8B/</link><pubDate>Sat, 22 Jul 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/29-005-%E4%BA%94%E6%B5%85%E8%B0%88%E6%B5%8B%E8%AF%95%E7%94%A8%E4%BE%8B/</guid><description>&lt;br>
#### 一、什么是测试用例？
----
测试用例是为某个特殊目标而编制的一组测试输入、执行条件以及预期结果，以便测试某个程序路径或核实是否满足某个特定需求。
&lt;p>通俗的讲：就是把我们测试系统的操作步骤用按照一定的格式用文字描述出来。&lt;/p>
&lt;br>
#### 二、写测试用例有什么好处？
----
* 理清思路，避免遗漏
&lt;p>这里是我们认为最重要的一点，假如我们测试的项目大而复杂，我们可以把项目功能细分，根据每一个功能通过编写用例的方式来整理我们测试系统的思路，避免遗漏掉要测试的功能点。&lt;/p>
&lt;ul>
&lt;li>跟踪测试进展&lt;/li>
&lt;/ul>
&lt;p>通过编写测试用例，执行测试用例，我们可以很清楚的知道我们的测试进度。&lt;/p>
&lt;ul>
&lt;li>历史参考&lt;/li>
&lt;/ul>
&lt;p>在我们所做的项目中，也许会有很多功能是相同或相近的，我们对这类功能设计了测试用例，便于以后我们遇到类似功能的时候可以做参考依据。&lt;/p>
&lt;ul>
&lt;li>重复性&lt;/li>
&lt;/ul>
&lt;p>我们测试一个系统不是一个人测一遍就算测完的，需要多人反复的进行测试，那么我们就需要测试用例来规范和指导我们的测试行为。&lt;/p>
&lt;br>
#### 三、测试用例的方法
----
好吧，咱知道啥是测试用例了，也是知道为什么要写测试用例了，那到底应该怎么写？无从下手啊。我们在写测试用例之前，先学习几种方法，它是我们写测试用例的指导思想。
&lt;ul>
&lt;li>等价类划分&lt;/li>
&lt;/ul>
&lt;p>等价类是指某个输入域的一个特定的子集合，在该子集合中各个输入数据对于揭露程序中的错误都是等效的，也就是说，如果用这个等价类中的代表值作为测试用例未发现程序错误，那么该类中其他数据（测试用例）也不会发现程序中的错误。&lt;/p>
&lt;p>&lt;strong>有效等价类：&lt;/strong> 输入满足程序输入的要求（来自规格说明书），通俗的说就是正确的输入。&lt;/p>
&lt;p>&lt;strong>无效等价类：&lt;/strong> 输入不满足程序输入的要求，即异常输入，需要系统对此有一定的容错性。&lt;/p>
&lt;p>例如：&lt;/p>
&lt;p>一个输入框要求输入1-10000的数字&lt;/p>
&lt;p>有效等价类：可以输入1-10000之间的数来验证，如：2、5、99、8495&amp;hellip;&amp;hellip;&lt;/p>
&lt;p>无效等价类：可以输入1-10000之外的任意字符验证，如：0、10001、字母、下划线、特殊符号、空格、回车&amp;hellip;..&lt;/p>
&lt;ul>
&lt;li>边界值&lt;/li>
&lt;/ul>
&lt;p>边界值是对等价类的补充，测试工作经验告诉我们，大量的错误是出在输入输出的边界价上。我们还拿上面的例子，一个输入框要求输入1-10000之间的数。我们要测它有没有超出这个范围，如：0、-1、-2、1000、10001&amp;hellip;..等等，来判定是否超出了我们的范围。&lt;/p>
&lt;ul>
&lt;li>因果图&lt;/li>
&lt;/ul>
&lt;p>因果图方法最终生成的就是判定表，它适合于检查程序输入条件的各种组合情况。举个例子：原因：A=0，B=0，结果我就可以判定：A=B。确切的说他是一种因果关系思想。它会无形中指导这我们的测试。当然了，我们为了以免遗漏，可以把系统中的因果关系用图画出。不过系统大而复杂的话就是个体力活了。呵呵。&lt;/p>
&lt;ul>
&lt;li>错误推测法&lt;/li>
&lt;/ul>
&lt;p>基于经验和直觉推测出系统可能存在的错误，从而有针对性的设计测试用例的方法。&lt;/p>
&lt;ul>
&lt;li>其它&lt;/li>
&lt;/ul>
&lt;p>设计测试用例的方法有很多，我们常用就上面几种，其它的方法还有：状态迁移图、流程分析法、正交验证法等等。&lt;/p>
&lt;br>
#### 四、测试用例的格式与要素
----
一个测试用例应该包括：编号，标题，测试场景，测试步骤，预期结果。
&lt;p>当然还可加入一些它选项，如：优先级、测试阶段&amp;hellip;.&lt;/p>
&lt;pre tabindex="0">&lt;code>编号：

标题:

测试环境：

测试步骤：

预期结果：
&lt;/code>&lt;/pre>&lt;p>关于测试用例的存放管理：&lt;/p>
&lt;p>1、项目管理系统自带的用例管理，一般用例会与项目挂钩，有固定的格式，搜索、修改等功能，使用起来非常方便。如：禅道项目管理、QC、bugfree 等等都带的有用例管理功能。&lt;/p>
&lt;p>2、通过world\Excel文档形式管理，这样的好处就是自己定义测试用例的格式。&lt;/p>
&lt;p>面来看一个具体的测试用例。我们会有更深刻的认识。&lt;/p>
&lt;pre tabindex="0">&lt;code>编号：001

标题: 系统登录测试用例

测试环境：
Windows 10/Chrome 58


测试步骤：
1、打开浏览器，输入系统网站，打开登录页面。
2、用户名密码为空，点击登录按钮
3、输入用户名，密码为空，点击登录按钮。
4、用户名为空，输入密码，点击登录按钮。
5、用户名正确，密码错误，点击登录按钮。
....


预期结果：
1、成功打开首页。
2、系统提示：用户名密码不能为空。
3、系统提示：密码不能为空。
4、系统提示：用户名不能为空。
5、系统提示：用户名或密码错误。
....
&lt;/code>&lt;/pre>&lt;br>
__最后__ ，写好测试用例，除了掌握基本的测试方法之外，最重要的是，要去深入理解业务需求。
从需求文档中抽出测试点；另外善于总结以往测试中发现的bug，完善测试用例。
&lt;p>原始封面&lt;/p></description></item><item><title>（五）selenium元素定位</title><link>https://itest2025.pages.dev/tutorials/19-005-%E4%BA%94selenium%E5%85%83%E7%B4%A0%E5%AE%9A%E4%BD%8D/</link><pubDate>Tue, 04 Jul 2017 07:37:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/19-005-%E4%BA%94selenium%E5%85%83%E7%B4%A0%E5%AE%9A%E4%BD%8D/</guid><description>&lt;br>
### selenium定位方法
&lt;p>Selenium提供了8种定位方式。&lt;/p>
&lt;ul>
&lt;li>id&lt;/li>
&lt;li>name&lt;/li>
&lt;li>class name&lt;/li>
&lt;li>tag name&lt;/li>
&lt;li>link text&lt;/li>
&lt;li>partial link text&lt;/li>
&lt;li>xpath&lt;/li>
&lt;li>css selector&lt;/li>
&lt;/ul>
&lt;p>这8种定位方式在Python selenium中所对应的方法为：&lt;/p>
&lt;ul>
&lt;li>findElement(By.id())&lt;/li>
&lt;li>findElement(By.name())&lt;/li>
&lt;li>findElement(By.className())&lt;/li>
&lt;li>findElement(By.tagName())&lt;/li>
&lt;li>findElement(By.linkText())&lt;/li>
&lt;li>findElement(By.partialLinkText())&lt;/li>
&lt;li>findElement(By.xpath())&lt;/li>
&lt;li>findElement(By.cssSelector())&lt;/li>
&lt;/ul>
&lt;br>
### 定位方法的用法
&lt;p>假如我们有一个Web页面，通过前端工具（如，Firebug）查看到一个元素的属性是这样的。&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;lt;html&amp;gt;
 &amp;lt;head&amp;gt;
 &amp;lt;body link=&amp;#34;#0000cc&amp;#34;&amp;gt;
 &amp;lt;a id=&amp;#34;result_logo&amp;#34; href=&amp;#34;/&amp;#34; onmousedown=&amp;#34;return c({&amp;#39;fm&amp;#39;:&amp;#39;tab&amp;#39;,&amp;#39;tab&amp;#39;:&amp;#39;logo&amp;#39;})&amp;#34;&amp;gt;
 &amp;lt;form id=&amp;#34;form&amp;#34; class=&amp;#34;fm&amp;#34; name=&amp;#34;f&amp;#34; action=&amp;#34;/s&amp;#34;&amp;gt;
 &amp;lt;span class=&amp;#34;soutu-btn&amp;#34;&amp;gt;&amp;lt;/span&amp;gt;
 &amp;lt;input id=&amp;#34;kw&amp;#34; class=&amp;#34;s_ipt&amp;#34; name=&amp;#34;wd&amp;#34; value=&amp;#34;&amp;#34; maxlength=&amp;#34;255&amp;#34; autocomplete=&amp;#34;off&amp;#34;&amp;gt;
&lt;/code>&lt;/pre>&lt;p>我们的目的是要定位input标签的输入框。&lt;/p>
&lt;ul>
&lt;li>通过id定位:&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>driver.findElement(By.id(&amp;#34;kw&amp;#34;))
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>通过name定位:&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>driver.findElement(By.name(&amp;#34;wd&amp;#34;))
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>通过class name定位:&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>driver.findElement(By.className(&amp;#34;s_ipt&amp;#34;))
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>通过tag name定位:&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>driver.findElement(By.tagName(&amp;#34;input&amp;#34;))
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>通过xpath定位，xpath定位有N种写法，这里列几个常用写法:&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">xpath&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;//*[@id=&amp;#39;kw&amp;#39;]&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">xpath&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;//*[@name=&amp;#39;wd&amp;#39;]&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">xpath&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;//input[@class=&amp;#39;s_ipt&amp;#39;]&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">xpath&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;/html/body/form/span/input&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">xpath&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;//span[@class=&amp;#39;soutu-btn&amp;#39;]/input&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">xpath&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;//form[@id=&amp;#39;form&amp;#39;]/span/input&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">xpath&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;//input[@id=&amp;#39;kw&amp;#39; and @name=&amp;#39;wd&amp;#39;]&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>通过css定位，css定位有N种写法，这里列几个常用写法:&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">cssSelector&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;#kw&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">cssSelector&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;[name=wd]&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">cssSelector&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;.s_ipt&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">cssSelector&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;html &amp;gt; body &amp;gt; form &amp;gt; span &amp;gt; input&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">cssSelector&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;span.soutu-btn&amp;gt; input#kw&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">cssSelector&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;form#form &amp;gt; span &amp;gt; input&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>接下来，我们的页面上有一组文本链接。&lt;/p></description></item><item><title>（五）WebDriver常用方法</title><link>https://itest2025.pages.dev/tutorials/24-005-%E4%BA%94webdriver%E5%B8%B8%E7%94%A8%E6%96%B9%E6%B3%95/</link><pubDate>Mon, 26 Jun 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/24-005-%E4%BA%94webdriver%E5%B8%B8%E7%94%A8%E6%96%B9%E6%B3%95/</guid><description>&lt;br>
### 点击和输入
前面我们已经学习了定位元素， 定位只是第一步， 定位之后需要对这个元素进行操作， 或单击（按钮）
或输入（输入框） ， 下面就来认识 WebDriver 中最常用的几个方法：
&lt;ul>
&lt;li>
&lt;p>clear()： 清除文本。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>send_keys (value)： 模拟按键输入。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>click()： 单击元素。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>from selenium import webdriver

driver = webdriver.Chrome()
driver.get(&amp;#34;https://www.baidu.com&amp;#34;)

driver.find_element_by_id(&amp;#34;kw&amp;#34;).clear()
driver.find_element_by_id(&amp;#34;kw&amp;#34;).send_keys(&amp;#34;selenium&amp;#34;)
driver.find_element_by_id(&amp;#34;su&amp;#34;).click()

driver.quit()
&lt;/code>&lt;/pre>&lt;br>
### 提交
&lt;ul>
&lt;li>submit()&lt;/li>
&lt;/ul>
&lt;p>submit()方法用于提交表单。 例如， 在搜索框输入关键字之后的“回车” 操作， 就可以通过该方法模拟。&lt;/p>
&lt;pre tabindex="0">&lt;code>from selenium import webdriver

driver = webdriver.Chrome()
driver.get(&amp;#34;https://www.baidu.com&amp;#34;)

search_text = driver.find_element_by_id(&amp;#39;kw&amp;#39;)
search_text.send_keys(&amp;#39;selenium&amp;#39;)
search_text.submit()

driver.quit()
&lt;/code>&lt;/pre>&lt;p>有时候 submit()可以与 click()方法互换来使用， submit()同样可以提交一个按钮， 但 submit()的应用范围远不及 click()广泛。&lt;/p>
&lt;br>
### 其他常用方法
&lt;ul>
&lt;li>
&lt;p>size： 返回元素的尺寸。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>text： 获取元素的文本。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>get_attribute(name)： 获得属性值。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>is_displayed()： 设置该元素是否用户可见。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>from selenium import webdriver

driver = webdriver.Chrome()
driver.get(&amp;#34;http://www.baidu.com&amp;#34;)

# 获得输入框的尺寸
size = driver.find_element_by_id(&amp;#39;kw&amp;#39;).size
print(size)

# 返回百度页面底部备案信息
text = driver.find_element_by_id(&amp;#34;cp&amp;#34;).text
print(text)

# 返回元素的属性值， 可以是 id、 name、 type 或其他任意属性
attribute = driver.find_element_by_id(&amp;#34;kw&amp;#34;).get_attribute(&amp;#39;type&amp;#39;)
print(attribute)

# 返回元素的结果是否可见， 返回结果为 True 或 False
result = driver.find_element_by_id(&amp;#34;kw&amp;#34;).is_displayed()
print(result)

driver.quit()
&lt;/code>&lt;/pre>&lt;p>输出结果：&lt;/p></description></item><item><title>软件测试分工</title><link>https://itest2025.pages.dev/tutorials/13-006-%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E5%88%86%E5%B7%A5/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/13-006-%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E5%88%86%E5%B7%A5/</guid><description>&lt;p>按照本文的主题还是来谈谈软件测试人员的分工吧！主要来谈传统软件测试过程中的测试分工。&lt;/p>
&lt;h4 id="集体测试">集体测试&lt;/h4>
&lt;hr>
&lt;p>也许专业测试里讲这种方式，很可能不叫“集体测试”。因为我根据的自己的理解起了大概符合意思的名词叫集体测试“集体测试”。&lt;/p>
&lt;p>这种测试模式就是，公司里所有的测试人员抱成一团儿，来一个项目，所有测试人员就集中测试一个项目。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/focus_test.png"
 data-srcset="http://img.testclass.net/focus_test.png, http://img.testclass.net/focus_test.png 1.5x, http://img.testclass.net/focus_test.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/focus_test.png"
 title="http://img.testclass.net/focus_test.png" />&lt;/p>
&lt;p>先说这种分工方式的优点：&lt;/p>
&lt;p>1、因为测试团队的中每个成员有都有优缺，人员在工作之中相互取长补短。可以很快的找出软件中的缺陷。三个臭皮匠顶一个诸葛亮，一个经验再丰富的测试不一定有三个水平一般的测从员发现的问题多。&lt;/p>
&lt;p>2、人多的另一个好处是测试项目能可以在更快的时间内发现更多的缺陷。总结一下就是更短时间内发现更多的问题。&lt;/p>
&lt;p>再来说说这种方式的缺点：&lt;/p>
&lt;p>1、一个人员一张嘴，人力成本很高（人员工资，人员平均时间投入，测试机等硬件资源投入）。&lt;/p>
&lt;p>2、当同时需要测试多个项目中时，不好意思，按顺序来，请在后面排好队。（并发能力不足）&lt;/p>
&lt;p>3、工作重复，同样一个缺陷，很可能同时被所有测试员发现，或者叫重复率很高。&lt;/p>
&lt;p>4、人员水平难以区分，在一个项目测试过程中，有的测人员可能一个缺陷也没找到，有的测试人员却发现了几乎所有的问题。也许这个项目一个缺陷也没找到的测试员在下个项目中却发现了很多缺陷。（混入南郭先生）&lt;/p>
&lt;p>5、发现了漏测现象是整个测试团队的责任。（这也不是明确的缺点，要看团队的氛围是积极的还是消极的。）&lt;/p>
&lt;p>好吧！集体测试缺点太多，就像国家成立初期的“吃大锅饭”，肯定是阻碍发展的。那我们来看看几种分工方式。&lt;/p>
&lt;br>
#### 按测试内容分工
---
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/content_test.png"
 data-srcset="http://img.testclass.net/content_test.png, http://img.testclass.net/content_test.png 1.5x, http://img.testclass.net/content_test.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/content_test.png"
 title="http://img.testclass.net/content_test.png" />&lt;/p>
&lt;p>一个项目的测试包括文档测试，易用性测试，逻辑功能测试，界面测试，配置和兼容等多个方面。我们可以根据人员的特点为每个人员分配不同的测试内容。&lt;/p>
&lt;p>内容分工方式的优点：&lt;/p>
&lt;p>1、分工明确，每位人员都清楚自己的测试的内容重点。&lt;/p>
&lt;p>2、责任到位，通过漏测的缺陷就可明确是谁的责任。&lt;/p>
&lt;br>
#### 按测试流程划分
----
&lt;p>我们的项目测试流程一般需要，制定测试计划，编写测试用例，执行测试用例，输出测试报告等工作，我们可以根据流程中的各个阶段来进行划分。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/flow_test.png"
 data-srcset="http://img.testclass.net/flow_test.png, http://img.testclass.net/flow_test.png 1.5x, http://img.testclass.net/flow_test.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/flow_test.png"
 title="http://img.testclass.net/flow_test.png" />&lt;/p>
&lt;p>不同的测试人员负责不同测试阶段的工作。&lt;/p>
&lt;p>优点：&lt;/p>
&lt;p>1、流程清晰，就像瀑布试项目开发流程，不同阶段的工作由不同的人员担任。&lt;/p>
&lt;p>2、划分流程的每个阶段难易程度和所需要的技能。&lt;/p>
&lt;p>编写测试计划人员需要对整个项目的工作时间、资源分配，测试内容，实施过程有整体的把控能力。&lt;/p>
&lt;p>用例辨析人员，需要对项目需求，测试方法，测试点有深入的了解。&lt;/p>
&lt;p>用例执行人员需要细心，使用缺陷系统，沟通，协助研发定位缺陷。&lt;/p>
&lt;p>输出测试报告人员需要对项目的测试过程，缺陷数量，类型，分布。用例执行请况等进行统计。也可以由测试执行人员担任。&lt;/p>
&lt;br>
#### 按项目模块划分
----
![](http://img.testclass.net/module_test.png)
&lt;p>对中大型的项目，这种划分就非常必要了，项目的模块非常多，功能也非常多。不同的测试人员负责不同模块的功能测试，这样会使用测试工作变得更加清晰。&lt;/p>
&lt;p>1、人员利用率高，为什么这么说呢? 不同的人员负责的功能不一样。工作就不会存在交叉与重复。&lt;/p>
&lt;p>2、更容易挖掘深度缺陷，假如A人员今天测试这个功能，明天测试那个功能，他就不可能对被测功能内部逻辑与业务有深入有了解。找到的也只是很表面的缺陷。那么如果一个人员长期负责一个模块的功能，那么就会更容易发现更有深度的缺陷。而往往深度的缺陷是致命的。&lt;/p>
&lt;br>
#### 按照测试类型分工
----
&lt;p>我们知道软件除了功能需要测试以外，软件在编码阶段需要单元测试，接口测试等，在系统测试阶段，为提高功能测试的效率，可能对某些模块进行功能自动化，我们还要考虑软件的性能、安全性等问题。这些类型也是我项目中最常见的分类。我们可以根据这些类型为测试人员分配测试工作。当然，其专业性对测试人员的要求也比较高。&lt;/p></description></item><item><title>python简明教程: 6. 模块</title><link>https://itest2025.pages.dev/tutorials/39-006-python%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B-6-%E6%A8%A1%E5%9D%97/</link><pubDate>Sat, 17 Nov 2018 03:23:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/39-006-python%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B-6-%E6%A8%A1%E5%9D%97/</guid><description>&lt;p>本文内容基本上翻译自&lt;a href="http://cheat.sh/python/:learn" target="_blank" rel="noopener noreffer ">http://cheat.sh/python/:learn)&lt;/a>&lt;/p>
&lt;p>&lt;strong>非原创, 非原创, 非原创!!!&lt;/strong>&lt;/p>
&lt;p>感谢原文社区作者&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">####################################################&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 6. 模块&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">####################################################&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 你可以导入1个模块&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">math&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span> &lt;span class="n">math&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sqrt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">16&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; 4&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 可以从module里导入一些函数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">math&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">ceil&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">floor&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span> &lt;span class="n">ceil&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mf">3.7&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; 4.0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span> &lt;span class="n">floor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mf">3.7&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; 3.0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 可以把模块里所有的函数都导出来&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 注意: 这是不推荐的做法&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">math&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="o">*&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 模块名是可以有简写的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">math&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">m&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">math&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sqrt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">16&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sqrt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">16&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 你也可以测试这些函数是否相等&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">math&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">sqrt&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">math&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sqrt&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sqrt&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">sqrt&lt;/span> &lt;span class="c1"># =&amp;gt; True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># python的模块就是普通的python文件.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 你可以创建自己的模块，然后进行导入&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 模块就是文件的文件名&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 你可以找出模块里定义了哪些函数和属性&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">math&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">dir&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">math&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 如果你有1个名为math.py的文件&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 并且该文件跟你的脚本在同一文件夹下&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 你导入math.py的时候你将导入自己定义的版本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 而不是python标准库的math模块&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 这是因为本地文件夹的导入优先级高于标准库&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p></description></item><item><title>（六） 创建Nginx容器</title><link>https://itest2025.pages.dev/tutorials/30-006-%E5%85%AD-%E5%88%9B%E5%BB%BAnginx%E5%AE%B9%E5%99%A8/</link><pubDate>Mon, 22 Jan 2018 14:38:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/30-006-%E5%85%AD-%E5%88%9B%E5%BB%BAnginx%E5%AE%B9%E5%99%A8/</guid><description>&lt;h4 id="获取nginx镜像">获取Nginx镜像&lt;/h4>
&lt;hr>
&lt;p>最简单的方法就是通过 &lt;code>docker pull nginx&lt;/code> 命令来创建 Nginx容器。&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo docker pull nginx
&lt;/code>&lt;/pre>&lt;p>或者：&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo docker pull registry.docker-cn.com/library/nginx
&lt;/code>&lt;/pre>&lt;p>其中 &lt;code>registry.docker-cn.com&lt;/code> 为国内的官方镜像仓库，速度要好很多。&lt;/p>
&lt;h4 id="启动nginx容器">启动Nginx容器&lt;/h4>
&lt;hr>
&lt;p>查看镜像：&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo docker images

REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 2a4cca5ac898 8 days ago 111MB
registry.docker-cn.com/library/nginx latest 3f8a4339aadd 4 weeks ago 108MB
hello-world latest f2a91732366c 2 months ago 1.85kB
&lt;/code>&lt;/pre>&lt;p>启动 ngnnx 容器&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo docker run --name some-nginx -d -p 8080:80 registry.docker-cn.com/library/nginx

b5bbf1dfe86a21d641a161c05598c0f4f4d4b32fc8d756b6fdf306295067625f
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>
&lt;p>-name 指定启动容器的名称为 some-nginx。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>-d 让Docker容器在后台以守护态（Daemonized）形式运行。&lt;/p></description></item><item><title>（六）Package 和 Import</title><link>https://itest2025.pages.dev/tutorials/16-006-%E5%85%ADpackage-%E5%92%8C-import/</link><pubDate>Wed, 17 Jan 2018 14:36:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/16-006-%E5%85%ADpackage-%E5%92%8C-import/</guid><description>&lt;p>除非你写的代码超级简单，如：打印。大多数情况情，必须会导入依赖的类。这些类大体上分三类：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>由我们自己创建的类。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>由Java JDK提供的类。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>由第三方库或框架提供。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h4 id="package">package&lt;/h4>
&lt;hr>
&lt;p>其实， package 名称就像是我们的姓，而 class
名称就像是我们的名字。package 名称有很多点号“ . ”，就好像是复姓。 比如说java.lang.String，就是复姓 java.lang，名字为 String 的类别。&lt;/p>
&lt;p>Java 会使用package这种机制的原因也非常明显，就像我们取姓名一样， 光是一间学校的同一届同学中，就有可能会出现不少同名的同学，如果不取姓的话，那学校在处理学生资料，或是同学彼此之间的称呼，就会发生很大的困扰。幸运的是，Java 的套件名称我们可以自己取，不像人的姓没有太大的选择， 如果依照 Sun 的规范来取套件名称，那理论上不同人所取的套件名称不会相同 ( 请参阅 &amp;ldquo;命名惯例&amp;quot;的相关文章 )， 也就不会发生名称冲突的情况。&lt;/p>
&lt;p>如， 我们可以用下面的方法使用 Selenium 的相关包。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">JavaPackage&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">org&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">openqa&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">selenium&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">WebDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">org&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">openqa&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">selenium&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">chrome&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">ChromeDriver&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// ……&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="import">import&lt;/h4>
&lt;hr>
&lt;p>显然上面的例子使编程变得很麻烦，我想使用某个类或方法，就不得写又臭又长的“复姓” 。 于是，Sun（Sun 公司目前已被 Oracle 公司收购） 想到了一个方法用 import 来优雅的解决这个问题。这个 import 就是在程式一开头的时候，先说明程式中会用到那些类别的简称，也就是只称呼名字，不称呼他的姓。姓在程序开头声明。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.WebDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.chrome.ChromeDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">JavaImport&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ChromeDriver&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//……&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p></description></item><item><title>TDD实战（六）“井字游戏” 需求四</title><link>https://itest2025.pages.dev/tutorials/32-006-tdd%E5%AE%9E%E6%88%98%E5%85%AD%E4%BA%95%E5%AD%97%E6%B8%B8%E6%88%8F-%E9%9C%80%E6%B1%82%E5%9B%9B/</link><pubDate>Mon, 08 Jan 2018 12:40:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/32-006-tdd%E5%AE%9E%E6%88%98%E5%85%AD%E4%BA%95%E5%AD%97%E6%B8%B8%E6%88%8F-%E9%9C%80%E6%B1%82%E5%9B%9B/</guid><description>&lt;h3 id="需求4">需求4&lt;/h3>
&lt;hr>
&lt;p>如果出现平局如何处理。&lt;/p>
&lt;blockquote>
&lt;p>所有格子都占满则为平局。&lt;/p>&lt;/blockquote>
&lt;h4 id="测试用例1">测试用例1&lt;/h4>
&lt;hr>
&lt;p>可以通过填满棋盘的所有格子测试平局结果。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">whenAllBoxesAreFilledThenDraw&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">ticTacToe&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">play&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//X&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">ticTacToe&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">play&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//O&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">ticTacToe&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">play&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">3&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//X&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">ticTacToe&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">play&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//O&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">ticTacToe&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">play&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">3&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//X&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">ticTacToe&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">play&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//O&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">ticTacToe&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">play&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">3&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//X&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">ticTacToe&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">play&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">3&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">3&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//O&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">actual&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ticTacToe&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">play&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">3&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//X&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;The result is draw&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">actual&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h5 id="实现测试1">实现测试1&lt;/h5>
&lt;p>检查是否为平局非常简单 &amp;mdash; 只需要检查是否已占满整个棋盘，所以，可以通过遍历数组board实现。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">play&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">checkAxis&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">checkAxis&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">lastPlayer&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">nextPlayer&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">setBox&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">lastPlayer&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">isWin&lt;/span>&lt;span class="p">()){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">return&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">lastPlayer&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34; is the winner&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="k">else&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">isDraw&lt;/span>&lt;span class="p">()){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">return&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;The result is draw&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="k">else&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">return&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;No winner&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">private&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">boolean&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">isDraw&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">0&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">SIZE&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="o">++&lt;/span>&lt;span class="p">){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">0&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">SIZE&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="o">++&lt;/span>&lt;span class="p">){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">board&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="o">][&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="o">]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">==&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="sc">&amp;#39;\0&amp;#39;&lt;/span>&lt;span class="p">){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">return&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">return&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>** &lt;strong>执行 测试用例1 检查它是否运行通过。&lt;/strong>&lt;/p></description></item><item><title>Android测试（六）：Android UI自动化测试</title><link>https://itest2025.pages.dev/tutorials/17-006-android%E6%B5%8B%E8%AF%95%E5%85%ADandroid-ui%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95/</link><pubDate>Wed, 20 Dec 2017 14:30:12 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/17-006-android%E6%B5%8B%E8%AF%95%E5%85%ADandroid-ui%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95/</guid><description>&lt;p>原文：https://developer.android.com/training/testing/ui-testing/index.html&lt;/p>
&lt;p>用户界面（UI）测试可以确保你的应用程序满足其功能要求，并达到用户最可能成功采用的高质量标准。&lt;/p>
&lt;p>UI测试的一种方法是简单地让人类测试人员在目标应用程序上执行一组用户操作，并验证其行为是否正确。 但是，这种手动方法可能耗时、乏味、且容易出错。更有效的方法是编写您的UI测试，以便用户操作以自动方式执行。 自动化方法使您能够以可重复的方式快速可靠地运行测试。&lt;/p>
&lt;blockquote>
&lt;p>注意：强烈建议您使用Android Studio来构建测试应用程序，因为它提供了项目设置，包含库和包非常方便。 这个里假定你正在使用Android Studio。&lt;/p>&lt;/blockquote>
&lt;p>要使用Android Studio自动执行UI测试，请在单独的Android测试文件夹&lt;code>src/androidTest/java&lt;/code>中实现测试代码。针对Gradle的Android插件将根据你的测试代码构建测试应用程序，然后将测试应用程序加载到与目标应用程序相同的设备上。 在测试代码中，可以使用UI测试框架来模拟目标应用程序上的用户交互，以执行覆盖特定使用场景的测试任务。&lt;/p>
&lt;p>为了测试Android应用程序，通常会创建这些类型的UI自动化测试：&lt;/p>
&lt;p>&lt;strong>单个应用程序的UI测试：&lt;/strong> 这种类型的测试验证当用户执行特定操作或在其活动中输入特定内容时，目标验证应用程序的行为是否符合预期。它允许你检查目标应用程序是否返回正确的UI输出，以响应应用程序活动中的用户交互。像Espresso这样的UI测试框架允许以编程方式模拟用户操作并测试复杂的应用内用户交互。&lt;/p>
&lt;p>&lt;strong>跨越多个应用程序的UI测试：&lt;/strong> 这种类型的测试验证不同用户应用程序之间或用户应用程序与系统应用程序之间交互的正确行为。例如，可能想要测试你的相机应用程序与第三方社交媒体应用程序或默认的Android照片应用程序正确共享图像。支持跨应用程序交互的UI测试框架（如UI Automator）允许你为这些方案创建测试。&lt;/p>
&lt;p>本课的经验将告诉你如何使用Android测试支持库中的工具和API来构建这些类型的自动化测试。 在开始使用这些API构建测试之前，你必须安装Android测试支持库，如下载Android测试支持库中所述。&lt;/p>
&lt;h4 id="课程">课程&lt;/h4>
&lt;hr>
&lt;p>&lt;a href="https://developer.android.com/training/testing/ui-testing/espresso-testing.html" target="_blank" rel="noopener noreffer ">Testing UI for a Single App&lt;/a>（单个应用程序的UI测试）&lt;/p>
&lt;ul>
&lt;li>了解如何使用Espresso测试框架在单个应用程序中测试UI。&lt;/li>
&lt;/ul>
&lt;p>&lt;a href="https://developer.android.com/training/testing/ui-testing/uiautomator-testing.html" target="_blank" rel="noopener noreffer ">Testing UI for Multiple Apps&lt;/a> （多个应用程序的UI测试）&lt;/p>
&lt;ul>
&lt;li>了解如何使用UI Automator测试框架在多个应用程序中测试UI。&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1677727853667-86855f1ce0eb?w=300"
 data-srcset="https://images.unsplash.com/photo-1677727853667-86855f1ce0eb?w=300, https://images.unsplash.com/photo-1677727853667-86855f1ce0eb?w=300 1.5x, https://images.unsplash.com/photo-1677727853667-86855f1ce0eb?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1677727853667-86855f1ce0eb?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>爬虫对抗</title><link>https://itest2025.pages.dev/tutorials/27-006-%E7%88%AC%E8%99%AB%E5%AF%B9%E6%8A%97/</link><pubDate>Wed, 13 Dec 2017 02:52:34 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/27-006-%E7%88%AC%E8%99%AB%E5%AF%B9%E6%8A%97/</guid><description>&lt;h3 id="why">why&lt;/h3>
&lt;p>知己知彼，百战不殆。&lt;/p>
&lt;p>爬虫往往会爬取其他服务的一些核心资源，这些资源是服务提供商重点保护的资产，所以很多网站都会启用一些反爬虫策略。&lt;/p>
&lt;p>这里我们简单分析一下反爬虫的常用手段。&lt;/p>
&lt;h3 id="监控后台日志和流量模式-如果发现异常活动则限制访问">监控后台日志和流量模式; 如果发现异常活动，则限制访问&lt;/h3>
&lt;p>通过日志是可以看出一些异常访问的，比如例如来自同一个IP地址的许多类似的请求操作。我们可以通过一些措施来限制这些访问，从而达到保护己方资源的效果，具体措施如下&lt;/p>
&lt;ul>
&lt;li>访问速率限制&lt;/li>
&lt;li>检测异常活动&lt;/li>
&lt;li>不要只是通过IP地址监控和限制访问速率 —— 也可以使用其他指标，比如表单提交的速度，或者是user-agent&lt;/li>
&lt;li>使用验证码替代临时阻止访问的方案&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>反爬建议:可以使用ip池，降低访问频率或浏览器自动化工具爬虫来进行对抗&lt;/strong>&lt;/p>
&lt;h3 id="要求注册和登录">要求注册和登录&lt;/h3>
&lt;p>如果你要求客户端创建帐户和登录，那么你可以准确的跟踪用户和爬虫的操作，另外也可以适当增加爬虫实现的难度。不过需不需要注册和登录最终还要看产品的需求，以产品需求为准。&lt;/p>
&lt;p>为了避免自动化创建许多帐户的脚本，你应该做以下这些事情:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>注册时需要一个电子邮件地址，并且用户必须打开通过你所发送的链接来验证该电子邮件地址才能激活该帐户。每个电子邮件地址只允许一个帐户。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>需要在注册/帐户创建期间显示验证码，以防止自动化脚本创建帐户&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>反爬建议:爬虫可以模拟登录，另外降低访问频率，以免暴露真实意图&lt;/strong>&lt;/p>
&lt;h3 id="阻止来自云托管主机和爬虫服务的ip地址的访问">阻止来自云托管主机和爬虫服务的IP地址的访问&lt;/h3>
&lt;p>有时，爬虫会从网络托管服务（如Amazon Web Services或Google App Engine）或VPSes运行。限制（或显示验证码）来源于此类云主机服务使用的IP地址请求访问你的网站。你还可以阻止从爬虫服务使用的IP地址的访问。&lt;/p>
&lt;p>同样，你还可以限制代理或VPN提供商使用的IP地址的访问，因为爬虫可能会使用此类代理服务器来避免单个IP发出许多请求。&lt;/p>
&lt;p>&lt;strong>反爬建议:使用代理和ip池&lt;/strong>&lt;/p>
&lt;h3 id="如果你要采取阻止访问的做法请将你的错误消息进行调整">如果你要采取阻止访问的做法，请将你的错误消息进行调整&lt;/h3>
&lt;p>如果你采取了阻止/限制访问的手段，那么你应该确保不要告诉爬虫导致阻塞的实际原因，从而给爬虫制作者如何修复爬虫的线索。所以用文本显示错误页面可能是一个坏主意：&lt;/p>
&lt;ul>
&lt;li>你的IP地址请求过于频繁，请稍后再试。&lt;/li>
&lt;li>错误，User Agent不存在，非法访问！&lt;/li>
&lt;/ul>
&lt;p>相反，显示一个友好的错误消息，不要告诉爬虫是什么原因造成不能正常访问的。&lt;/p>
&lt;p>抱歉，网站出了一些问题。如果问题仍然存在，你可以联系helpdesk@example.com。&lt;/p>
&lt;p>这也是真正对用户友好的一种显示内容。你还应该考虑在后续的请求中不要直接显示验证码，以防真实用户看到这个错误消息，导致你阻止了合法用户的访问行为。&lt;/p>
&lt;p>&lt;strong>反爬建议:使用浏览器自动化工具，伪装成真实的用户&lt;/strong>&lt;/p>
&lt;h3 id="如果你的网站被爬虫访问请使用验证码">如果你的网站被爬虫访问，请使用验证码&lt;/h3>
&lt;p>验证码是双刃剑，可以非常有效的组织爬虫，但也会对真正的用户产生负面影响。&lt;/p>
&lt;p>如果需要使用验证码，那么请&lt;/p>
&lt;ul>
&lt;li>
&lt;p>不要自己实现验证码，应该使用像Google的reCaptcha这样的东西：这比自己实现一个验证码要容易得多，它比一些模糊和扭曲的文本解决方案对用户来说更友好，而且比起自己实现验证码，它能更好的解决问题&lt;/p>
&lt;/li>
&lt;li>
&lt;p>不要在HTML标记中包含验证码的解决方案：实际上我已经看到一个网站在页面中嵌入了验证码的解决方案（虽然隐藏的很好）。但是不要这样做。还是推荐使用像reCaptcha这样的服务，如果你正确使用它，就不会出现问题。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>验证码是可以批量验证的：在网上有一些低报酬的人工打码服务可以批量解决验证码的验证服务。所以，我在这里还是推荐使用reCaptcha，因为它具有很好的自我保护作用。这种服务不太可能被用于人工打码，除非你的数据真的很有价值。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>反爬建议:使用人肉打码服务&lt;/strong>&lt;/p>
&lt;h3 id="将你的文本内容转成图片">将你的文本内容转成图片&lt;/h3>
&lt;p>你可以在服务器端将文本转换成图像然后在客户端显示，这种方法可以阻碍简单的爬虫提取文本。&lt;/p>
&lt;p>记得当年起点的付费阅读的内容就全部是图片形式的。&lt;/p>
&lt;p>然而，这对于屏幕阅读器，搜索引擎，性能以及其他的一些事情都是不利的。在某些方面（比如无障碍操作，例如美国残疾人法案）也可能是非法的，并且也很容易被一些OCR技术绕过，所以最好还是不要这样做。&lt;/p>
&lt;p>&lt;strong>反爬建议:使用OCR图片识别技术&lt;/strong>&lt;/p>
&lt;h3 id="不要公开你的完整数据集">不要公开你的完整数据集&lt;/h3>
&lt;p>如果可行的话，请不要为脚本或爬虫机器人提供所有数据集的方法。例如：你有一个新闻网站，有很多单独的文章。你可以通过现场搜索来搜索这些文章，并且如果你没有列出任何网站上的所有文章及其URL，那么这些文章将只能通过使用搜索来访问特征。这意味着一个想要从你的网站上获得所有文章的脚本将不得不搜索可能出现在你的文章中的所有可能的短语，才能找到文章的全部内容，这对于爬虫来说是很耗时的，而且效率低的可怕，所以爬虫一般都会放弃爬取数据。&lt;/p>
&lt;p>如果是以下这些情况，那么这种方法将变得无效：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>爬虫机器人或脚本并不想或需要完整的数据集。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>你的文章的URL是一个看起来像 example.com/article.php?articleId=12345这种（和类似的东西）的格式，这将允许爬虫可以简单地迭代所有articleId的文章，并请求所有的文章内容。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>还有其他方式可以最终找到所有的文章，比如通过编写一个脚本来跟踪其他文章的内容中的链接。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>搜索“&amp;amp;”或“”的东西可以显示几乎所有的东西，这是一些需要注意的事情。（你只能返回前10或20个结果来避免这种情况）。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>你需要搜索引擎来查找你的内容。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>反爬建议:遍历数字型id基本可以拿到所有内容&lt;/strong>&lt;/p>
&lt;h3 id="参考资料">参考资料&lt;/h3>
&lt;p>文本大部分参考了&lt;a href="http://www.4hou.com/technology/8482.html" target="_blank" rel="noopener noreffer ">Web网页爬虫对抗指南 Part.1&lt;/a>这篇文章，在这里附上原始链接，并对原作者和译者表示衷心的感谢。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1504893524553-b855bce32c67?w=300"
 data-srcset="https://images.unsplash.com/photo-1504893524553-b855bce32c67?w=300, https://images.unsplash.com/photo-1504893524553-b855bce32c67?w=300 1.5x, https://images.unsplash.com/photo-1504893524553-b855bce32c67?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1504893524553-b855bce32c67?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（六） mockito 常用方法</title><link>https://itest2025.pages.dev/tutorials/45-006-%E5%85%AD-mockito-%E5%B8%B8%E7%94%A8%E6%96%B9%E6%B3%95/</link><pubDate>Sat, 25 Nov 2017 12:40:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/45-006-%E5%85%AD-mockito-%E5%B8%B8%E7%94%A8%E6%96%B9%E6%B3%95/</guid><description>&lt;h4 id="doreturndothrowdoanswerdonothingdocallrealmethod系列方法的运用">doReturn()、doThrow()、doAnswer()、doNothing()、doCallRealMethod()系列方法的运用&lt;/h4>
&lt;p>通过&lt;code>when(Object)&lt;/code>为无返回值的函数打桩有不同的方法,因为编译器不喜欢void函数在括号内&amp;hellip;&lt;/p>
&lt;p>使用&lt;code>doThrow(Throwable)&lt;/code> 替换&lt;code>stubVoid(Object)&lt;/code>来为void函数打桩是为了与&lt;code>doAnswer()&lt;/code>等函数族保持一致性。&lt;/p>
&lt;p>当你想为void函数打桩时使用含有一个exception 参数的&lt;code>doAnswer()&lt;/code> :&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.Test&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">java.util.LinkedList&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.mockito.Mockito.*&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">MockitoDemo&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">expected&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">RuntimeException&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">class&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">when_doThrow&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">throws&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">RuntimeException&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">LinkedList&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">mock&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">LinkedList&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">class&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">doThrow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">RuntimeException&lt;/span>&lt;span class="p">()).&lt;/span>&lt;span class="na">when&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="na">clear&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//following throws RuntimeException:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 下面的代码会抛出异常&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">mockedList&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">clear&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>当你调用&lt;code>doThrow()&lt;/code>, &lt;code>doAnswer()&lt;/code>, &lt;code>doNothing()&lt;/code>, &lt;code>doReturn()&lt;/code> 和 &lt;code>doCallRealMethod()&lt;/code> 这些函数时可以在适当的位置调用&lt;code>when()&lt;/code>函数，例如下面这些功能时这是必须的:&lt;/p>
&lt;ul>
&lt;li>测试void函数&lt;/li>
&lt;li>在受监控的对象上测试函数&lt;/li>
&lt;li>不知一次的测试为同一个函数，在测试过程中改变mock对象的行为。&lt;/li>
&lt;/ul>
&lt;p>但是在调用when()函数时你可以选择是否调用这些上述这些函数。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1604328698692-f76ea9498e76?w=300"
 data-srcset="https://images.unsplash.com/photo-1604328698692-f76ea9498e76?w=300, https://images.unsplash.com/photo-1604328698692-f76ea9498e76?w=300 1.5x, https://images.unsplash.com/photo-1604328698692-f76ea9498e76?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1604328698692-f76ea9498e76?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（六）TestNG 用例分组</title><link>https://itest2025.pages.dev/tutorials/36-006-%E5%85%ADtestng-%E7%94%A8%E4%BE%8B%E5%88%86%E7%BB%84/</link><pubDate>Sat, 25 Nov 2017 12:35:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/36-006-%E5%85%ADtestng-%E7%94%A8%E4%BE%8B%E5%88%86%E7%BB%84/</guid><description>&lt;p>有时候我们的测试用例并不想以测试包、类和用例为单位去运行。测试用例可以有多个纬度去标识。&lt;/p>
&lt;p>例如，可以根据用例的重要程度划分：&lt;/p>
&lt;ul>
&lt;li>重要程度：&lt;strong>低——&amp;gt;中——&amp;gt;高&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>或者，根据用例的类型划分：&lt;/p>
&lt;ul>
&lt;li>类型：&lt;strong>正常——&amp;gt;异常&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>TestNG 允许我们给测试用例贴标签。我们可以根据这些标签有选择地的跳过或执行这些用例。&lt;/p>
&lt;h4 id="实例">实例&lt;/h4>
&lt;hr>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.testng.annotations.Test&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.testng.AssertJUnit.assertEquals&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">groups&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s">&amp;#34;功能测试&amp;#34;&lt;/span>&lt;span class="p">})&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">TagTest&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">groups&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s">&amp;#34;高&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;正常&amp;#34;&lt;/span>&lt;span class="p">})&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">testCase1&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">4&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">groups&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s">&amp;#34;高&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;正常&amp;#34;&lt;/span>&lt;span class="p">})&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">testCase2&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">5&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">3&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">groups&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s">&amp;#34;中&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;正常&amp;#34;&lt;/span>&lt;span class="p">})&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">testCase3&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">groups&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s">&amp;#34;低&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;异常&amp;#34;&lt;/span>&lt;span class="p">})&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">testCase4&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">0&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>接下来配置 &lt;strong>testng.xml&lt;/strong> ，根据标签筛选要运行的测试用例。&lt;/p></description></item><item><title>（六） pom.xml 配置文件</title><link>https://itest2025.pages.dev/tutorials/41-006-%E5%85%AD-pomxml-%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6/</link><pubDate>Sat, 25 Nov 2017 12:30:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/41-006-%E5%85%AD-pomxml-%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6/</guid><description>&lt;p>用 Maven 来管理 Java 项目的第三方库，最主要是通过 &lt;strong>pom.xml&lt;/strong> 文件，这一小节将解释该文件的使用。&lt;/p>
&lt;h4 id="pomxml-文件">pom.xml 文件&lt;/h4>
&lt;hr>
&lt;p>以 &lt;a href="https://itest2025.pages.dev/maven/create_project/" rel="">（四）通过 mvn 命令创建 Maven 项目&lt;/a> 创建的项目为例。打开项目根目录下的 pom.xml 文件。&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;lt;project xmlns=&amp;#34;http://maven.apache.org/POM/4.0.0&amp;#34; xmlns:xsi=&amp;#34;http://www.w3.org/2001/XMLSchema-instance&amp;#34;
 xsi:schemaLocation=&amp;#34;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd&amp;#34;&amp;gt;
 &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;

 &amp;lt;groupId&amp;gt;com.myapp.pro&amp;lt;/groupId&amp;gt;
 &amp;lt;artifactId&amp;gt;myapp&amp;lt;/artifactId&amp;gt;
 &amp;lt;packaging&amp;gt;jar&amp;lt;/packaging&amp;gt;
 &amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;

 &amp;lt;name&amp;gt;myapp&amp;lt;/name&amp;gt;
 &amp;lt;url&amp;gt;http://maven.apache.org&amp;lt;/url&amp;gt;

 &amp;lt;dependencies&amp;gt;
 &amp;lt;dependency&amp;gt;
 &amp;lt;groupId&amp;gt;junit&amp;lt;/groupId&amp;gt;
 &amp;lt;artifactId&amp;gt;junit&amp;lt;/artifactId&amp;gt;
 &amp;lt;version&amp;gt;3.8.1&amp;lt;/version&amp;gt;
 &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
 &amp;lt;/dependency&amp;gt;

 &amp;lt;/dependencies&amp;gt;

&amp;lt;/project&amp;gt;
&lt;/code>&lt;/pre>&lt;p>* project：pom.xml文件中的顶层元素； &lt;/p>
&lt;p>* modelVersion：指明POM使用的对象模型的版本。这个值很少改动。&lt;/p>
&lt;p>* groupId：指明创建项目的组织或者小组的唯一标识。GroupId是项目的关键标识，典型的，此标识以组织的完全限定名来定义。比如，org.apache.maven.plugins是所有Maven插件项目指定的groupId。 &lt;/p>
&lt;p>* artifactId：指明此项目产生的主要产品的基本名称。项目的主要产品通常为一个JAR文件。第二，象源代码包通常使用artifactId作为最后名称的一部分。典型的产品名称使用这个格式：
 &lt;artifactId>- &lt;version>. &lt;extension>(比如：myapp-1.0.jar)。 &lt;/p>
&lt;p>* version：项目产品的版本号。Maven帮助你管理版本，可以经常看到SNAPSHOT这个版本，表明项目处于开发阶段。 &lt;/p>
&lt;p>* name：项目的显示名称，通常用于maven产生的文档中。 &lt;/p>
&lt;p>* url：指定项目站点，通常用于maven产生的文档中。 &lt;/p>
&lt;p>* description：描述此项目，通常用于maven产生的文档中。&lt;/p>
&lt;h4 id="管理第三方库">管理第三方库&lt;/h4>
&lt;hr>
&lt;p>对于一个第三方库的添加，下面的几个参数是我们需要关注的。&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;lt;groupId&amp;gt;junit&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;junit&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;3.8.1&amp;lt;/version&amp;gt;
&amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
&lt;/code>&lt;/pre>&lt;p>&lt;scope>&lt;/scope>，它主要管理依赖的部署。目前&lt;scope>可以使用5个值： &lt;/p>
&lt;ul>
&lt;li>compile，缺省值，适用于所有阶段，会随着项目一起发布。 &lt;/li>
&lt;li>provided，类似compile，期望JDK、容器或使用者会提供这个依赖。如servlet.jar。 &lt;/li>
&lt;li>runtime，只在运行时使用，如JDBC驱动，适用运行和测试阶段。 &lt;/li>
&lt;li>test，只在测试时使用，用于编译和运行测试代码。不会随项目发布。 &lt;/li>
&lt;li>system，类似provided，需要显式提供包含依赖的jar，Maven不会在Repository中查找它。&lt;/li>
&lt;/ul>
&lt;p>通过查看pom.xml中Junit的配置，显然版本有些旧了，我们去下载最新的Junit4，但我们又不知道Maven中的具体的版本怎么办呢？我们可以到 Maven 的中央仓库去查询。&lt;/p></description></item><item><title>requests如何构造复杂的post请求?</title><link>https://itest2025.pages.dev/tutorials/42-006-requests%E5%A6%82%E4%BD%95%E6%9E%84%E9%80%A0%E5%A4%8D%E6%9D%82%E7%9A%84post%E8%AF%B7%E6%B1%82/</link><pubDate>Wed, 22 Nov 2017 03:23:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/42-006-requests%E5%A6%82%E4%BD%95%E6%9E%84%E9%80%A0%E5%A4%8D%E6%9D%82%E7%9A%84post%E8%AF%B7%E6%B1%82/</guid><description>&lt;p>默认情况下，在post方法中使用 data 关键字参数，Requests的行为会表现的像是在发送一个html表单，比如&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; payload = {&amp;#39;key1&amp;#39;: &amp;#39;value1&amp;#39;, &amp;#39;key2&amp;#39;: &amp;#39;value2&amp;#39;}

&amp;gt;&amp;gt;&amp;gt; r = requests.post(&amp;#34;http://httpbin.org/post&amp;#34;, data=payload)
&amp;gt;&amp;gt;&amp;gt; print(r.text)
{
 ...
 &amp;#34;form&amp;#34;: {
 &amp;#34;key2&amp;#34;: &amp;#34;value2&amp;#34;,
 &amp;#34;key1&amp;#34;: &amp;#34;value1&amp;#34;
 },
 ...
}
&lt;/code>&lt;/pre>&lt;p>如果需要为多个元素使用同一key的话，可以在data中传入元组，比如&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; payload = ((&amp;#39;key1&amp;#39;, &amp;#39;value1&amp;#39;), (&amp;#39;key1&amp;#39;, &amp;#39;value2&amp;#39;))
&amp;gt;&amp;gt;&amp;gt; r = requests.post(&amp;#39;http://httpbin.org/post&amp;#39;, data=payload)
&amp;gt;&amp;gt;&amp;gt; print(r.text)
{
 ...
 &amp;#34;form&amp;#34;: {
 &amp;#34;key1&amp;#34;: [
 &amp;#34;value1&amp;#34;,
 &amp;#34;value2&amp;#34;
 ]
 },
 ...
}
&lt;/code>&lt;/pre>&lt;p>如果 data 中传的是string而不是dict的话，那么字符串将会被直接发送出去&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; import json

&amp;gt;&amp;gt;&amp;gt; url = &amp;#39;https://api.github.com/some/endpoint&amp;#39;
&amp;gt;&amp;gt;&amp;gt; payload = {&amp;#39;some&amp;#39;: &amp;#39;data&amp;#39;}

&amp;gt;&amp;gt;&amp;gt; r = requests.post(url, data=json.dumps(payload))
&lt;/code>&lt;/pre>&lt;p>因为现在很多api接受json字符串格式的post data，Requests为这种方式提供了更简单的写法&lt;/p></description></item><item><title>（六）JUnit 用例执行顺序</title><link>https://itest2025.pages.dev/tutorials/31-006-%E5%85%ADjunit-%E7%94%A8%E4%BE%8B%E6%89%A7%E8%A1%8C%E9%A1%BA%E5%BA%8F/</link><pubDate>Mon, 13 Nov 2017 12:40:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/31-006-%E5%85%ADjunit-%E7%94%A8%E4%BE%8B%E6%89%A7%E8%A1%8C%E9%A1%BA%E5%BA%8F/</guid><description>&lt;p>在运行测试的过程中，有时候需要控制用例的执行顺序。&lt;/p>
&lt;h4 id="fixmethodorder">@FixMethodOrder&lt;/h4>
&lt;hr>
&lt;p>JUnit 通过 &lt;strong>@FixMethodOrder&lt;/strong> 注解来控制测试方法的执行顺序的。&lt;strong>@FixMethodOrder&lt;/strong> 注解的参数是 &lt;strong>org.junit.runners.MethodSorters&lt;/strong> 对象,在枚举类 &lt;strong>org.junit.runners.MethodSorters&lt;/strong> 中定义了如下三种顺序类型：&lt;/p>
&lt;ul>
&lt;li>MethodSorters.JVM&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>Leaves the test methods in the order returned by the JVM. Note that the order from the JVM may vary from run to run (按照JVM得到的方法顺序，也就是代码中定义的方法顺序)&lt;/p>&lt;/blockquote>
&lt;ul>
&lt;li>MethodSorters.DEFAULT(默认的顺序)&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>Sorts the test methods in a deterministic, but not predictable, order() (以确定但不可预期的顺序执行)&lt;/p>&lt;/blockquote>
&lt;ul>
&lt;li>MethodSorters.NAME_ASCENDING&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>Sorts the test methods by the method name, in lexicographic order, with Method.toString() used as a tiebreaker (按方法名字母顺序执行)&lt;/p></description></item><item><title>6. 命令行接口</title><link>https://itest2025.pages.dev/tutorials/35-006-6-%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%8E%A5%E5%8F%A3/</link><pubDate>Sun, 05 Nov 2017 06:23:31 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/35-006-6-%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%8E%A5%E5%8F%A3/</guid><description>&lt;h3 id="背景">背景&lt;/h3>
&lt;p>unittest支持命令行接口，我们可以在命令行里指定运行具体的测试用例。&lt;/p>
&lt;h3 id="实例">实例&lt;/h3>
&lt;p>在&lt;code>test_password_1.py&lt;/code>中定义了&lt;code>PasswordTeseCase&lt;/code>用例，我们可以从命令行中指定只运行该用例。&lt;/p>
&lt;pre tabindex="0">&lt;code>$ python -m unittest test_password_1.PasswordTeseCase
set up
.set up
F
======================================================================
FAIL: test_week_password (test_password_1.PasswordTeseCase)
----------------------------------------------------------------------
Traceback (most recent call last):
 File &amp;#34;/Users/easonhan/code/testclass.net/src/pyunit/test_password_1.py&amp;#34;, line 21, in test_week_password
 self.assertTrue(passwd != &amp;#39;password123&amp;#39;, msg)
AssertionError: False is not true : user tom has a weak password

----------------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (failures=1)
&lt;/code>&lt;/pre>&lt;p>还可以使用-v参数来获得更详细的输出&lt;/p>
&lt;pre tabindex="0">&lt;code>$ python -m unittest test_password_1.PasswordTeseCase -v
test_dummy (test_password_1.PasswordTeseCase) ... set up
ok
test_week_password (test_password_1.PasswordTeseCase) ... set up
FAIL

======================================================================
FAIL: test_week_password (test_password_1.PasswordTeseCase)
----------------------------------------------------------------------
Traceback (most recent call last):
 File &amp;#34;/Users/easonhan/code/testclass.net/src/pyunit/test_password_1.py&amp;#34;, line 21, in test_week_password
 self.assertTrue(passwd != &amp;#39;password123&amp;#39;, msg)
AssertionError: False is not true : user tom has a weak password

----------------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (failures=1)
&lt;/code>&lt;/pre>&lt;p>也可以在命令行中一次指定多个测试用例类，具体的大家可以自己尝试一下。&lt;/p></description></item><item><title>6. 转义序列和多行文本</title><link>https://itest2025.pages.dev/tutorials/28-006-6-%E8%BD%AC%E4%B9%89%E5%BA%8F%E5%88%97%E5%92%8C%E5%A4%9A%E8%A1%8C%E6%96%87%E6%9C%AC/</link><pubDate>Thu, 02 Nov 2017 08:17:22 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/28-006-6-%E8%BD%AC%E4%B9%89%E5%BA%8F%E5%88%97%E5%92%8C%E5%A4%9A%E8%A1%8C%E6%96%87%E6%9C%AC/</guid><description>&lt;h3 id="转义序列">转义序列&lt;/h3>
&lt;p>python提供了一种方式让我们可以输入一些不太好通过键盘输入的字符，比如换行符缩进符之类的。这种特殊的字符组合我们可以称之为转义序列(escape sequences)，详情可以参考&lt;a href="https://docs.python.org/3/reference/lexical_analysis.html" target="_blank" rel="noopener noreffer ">官方文档&lt;/a>。&lt;/p>
&lt;p>我们经常使用的有&lt;/p>
&lt;ul>
&lt;li>\n: 换行&lt;/li>
&lt;li>\t: tab，可以当成是缩进&lt;/li>
&lt;li>\: 反斜杠&lt;/li>
&lt;li>': 单引号，可以在单引号字符串中打印出单引号&lt;/li>
&lt;li>&amp;quot;: 双引号，可以在双引号字符串中打印出双引号&lt;/li>
&lt;/ul>
&lt;h3 id="多行文本">多行文本&lt;/h3>
&lt;p>python中3个引号开头的字符串中可以包含多行文本，比如&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">my_str&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">this is the first line
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">this is the second line
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">this is the last line
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="背景">背景&lt;/h3>
&lt;p>这一节里，我们强化一下转义序列和多行文本的使用和写法。&lt;/p>
&lt;h3 id="代码实现">代码实现&lt;/h3>
&lt;p>新建名为&lt;code>print_test_case.py&lt;/code>，内容如下&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">test_scenario&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;登录场景&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">test_case_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\t&lt;/span>&lt;span class="s2">正常登录: &lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># two tabs&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\t\t&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">test_step&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">tt&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">1.打开chrome浏览器&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">tt&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">2.输入www.itest.info&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">tt&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">3.在登录表单中输入用户名:example，密码:example&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">tt&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">4.登记登录按钮&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">test_assert&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">tt&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">应该跳转到www.itest.info/login_success页面，并出现&lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s2">登录成功&lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s2">的提示&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">test_scenario&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">test_case_name&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">test_step&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">test_assert&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">test_login_failed&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 密码错误:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 1.打开chrome浏览器
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 2.输入www.itest.info
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 3.在登录表单中输入用户名:example，密码:incorrect
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 4.登记登录按钮
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 页面不发生跳转，并出现&lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s2">登录失败&lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s2">的提示
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">test_login_failed&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行">运行&lt;/h3>
&lt;p>在命令行中使用下面的命令去执行代码&lt;/p></description></item><item><title>6.Parametrize Fixture</title><link>https://itest2025.pages.dev/tutorials/25-006-6parametrize-fixture/</link><pubDate>Sun, 29 Oct 2017 07:22:42 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/25-006-6parametrize-fixture/</guid><description>&lt;h3 id="背景">背景&lt;/h3>
&lt;p>&lt;code>@pytest.mark.parametrize&lt;/code> 装饰器可以让我们每次参数化fixture的时候传入多个项目。回忆上一节，我们参数化的时候只能传入传入1个字符串或者是其他的数据对象，parametrize每次多个参数，更加灵活。&lt;/p>
&lt;h3 id="例子">例子&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">pytest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@pytest.mark.parametrize&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;test_input,expected&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;3+5&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">8&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;2+4&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">6&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;6*9&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">42&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">test_eval&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">test_input&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">expected&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="nb">eval&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">test_input&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">expected&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>test_eval方法中传入了2个参数，就如同&lt;code>@pytest.mark.parametrize&lt;/code>装饰器中定义的那样，因此简单理解，我们可以把parametrize装饰器想象成是数据表格，有表头(test_input,expected)以及具体的数据。&lt;/p>
&lt;h3 id="运行结果">运行结果&lt;/h3>
&lt;pre tabindex="0">&lt;code>$ pytest
======= test session starts ========
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y
rootdir: $REGENDOC_TMPDIR, inifile:
collected 3 items

test_expectation.py ..F

======= FAILURES ========
_______ test_eval[6*9-42] ________

test_input = &amp;#39;6*9&amp;#39;, expected = 42

 @pytest.mark.parametrize(&amp;#34;test_input,expected&amp;#34;, [
 (&amp;#34;3+5&amp;#34;, 8),
 (&amp;#34;2+4&amp;#34;, 6),
 (&amp;#34;6*9&amp;#34;, 42),
 ])
 def test_eval(test_input, expected):
&amp;gt; assert eval(test_input) == expected
E AssertionError: assert 54 == 42
E + where 54 = eval(&amp;#39;6*9&amp;#39;)

test_expectation.py:8: AssertionError
======= 1 failed, 2 passed in 0.12 seconds ========
&lt;/code>&lt;/pre>&lt;p>原始封面&lt;/p></description></item><item><title>6. Logical Containers</title><link>https://itest2025.pages.dev/tutorials/43-006-6-logical-containers/</link><pubDate>Tue, 24 Oct 2017 06:55:26 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/43-006-6-logical-containers/</guid><description>&lt;p>逻辑容器适用于这样的场景：页面上有一些元素确实存在于容器中，但这些元素都有可以唯一能够定位的属性，比如id等，而我们为了代码的可读性，往往希望将这些元素放在某个容器中。&lt;/p>
&lt;p>比如页面上的菜单元素，每个子菜单都有id属性，不过为了代码能够更好的被他人理解，我们希望将子菜单放到菜单容器里。&lt;/p>
&lt;p>逻辑容器和普通容器的区别：&lt;/p>
&lt;ul>
&lt;li>普通容器需要继承自&lt;code>WebElement&lt;/code>，而逻辑容器不需要&lt;/li>
&lt;li>定义逻辑容器时Find方法不需要by和value参数&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium.webdriver.common.by&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">By&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">webium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Find&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">BasePage&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Nav&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">object&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">class_info&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Find&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">by&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">CSS_SELECTOR&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;a[href*=&amp;#34;/newclass&amp;#34;]&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">faq&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Find&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">by&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">CSS_SELECTOR&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;a[href*=&amp;#34;/faq&amp;#34;]&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">ItestPage&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BasePage&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># here we are just grouping Header elements together without any influence on actual search&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">nav&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Find&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Nav&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">super&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">StructuredPage&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;http://itest.info&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">page&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ItestPage&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">open&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">menu&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">class_info&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">menu&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">faq&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1495465798138-718f86d1a4bc?w=300"
 data-srcset="https://images.unsplash.com/photo-1495465798138-718f86d1a4bc?w=300, https://images.unsplash.com/photo-1495465798138-718f86d1a4bc?w=300 1.5x, https://images.unsplash.com/photo-1495465798138-718f86d1a4bc?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1495465798138-718f86d1a4bc?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>收藏清单: python测试数据生成及代码扫描最全资源列表</title><link>https://itest2025.pages.dev/tutorials/34-006-%E6%94%B6%E8%97%8F%E6%B8%85%E5%8D%95-python%E6%B5%8B%E8%AF%95%E6%95%B0%E6%8D%AE%E7%94%9F%E6%88%90%E5%8F%8A%E4%BB%A3%E7%A0%81%E6%89%AB%E6%8F%8F%E6%9C%80%E5%85%A8%E8%B5%84%E6%BA%90%E5%88%97%E8%A1%A8/</link><pubDate>Fri, 20 Oct 2017 08:22:28 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/34-006-%E6%94%B6%E8%97%8F%E6%B8%85%E5%8D%95-python%E6%B5%8B%E8%AF%95%E6%95%B0%E6%8D%AE%E7%94%9F%E6%88%90%E5%8F%8A%E4%BB%A3%E7%A0%81%E6%89%AB%E6%8F%8F%E6%9C%80%E5%85%A8%E8%B5%84%E6%BA%90%E5%88%97%E8%A1%A8/</guid><description>&lt;h2 id="test-data-manipulation-测试数据的操作和处理">Test Data manipulation 测试数据的操作和处理&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="http://www.joke2k.net/faker/" target="_blank" rel="noopener noreffer ">faker&lt;/a> - 生成假数据的python库&lt;/li>
&lt;li>&lt;a href="https://github.com/emirozer/fake2db" target="_blank" rel="noopener noreffer ">fake2db&lt;/a> - 创建假数据库&lt;/li>
&lt;li>&lt;a href="https://pypi.python.org/pypi/ForgeryPy" target="_blank" rel="noopener noreffer ">ForgeryPy&lt;/a> - 使用起来很简单的假数据生成库.&lt;/li>
&lt;li>&lt;a href="https://pypi.python.org/pypi/radar" target="_blank" rel="noopener noreffer ">radar&lt;/a> - 随机生成时间&lt;/li>
&lt;li>&lt;a href="https://github.com/guykisel/robotframework-faker" target="_blank" rel="noopener noreffer ">robotframework-faker&lt;/a> - faker的Robot Framework封装&lt;/li>
&lt;li>&lt;a href="https://github.com/DRMacIver/hypothesis" target="_blank" rel="noopener noreffer ">hypothesis&lt;/a> - Library for property based testing in Python, based on the Haskell library Quickcheck.&lt;/li>
&lt;li>&lt;a href="https://github.com/FactoryBoy/factory_boy" target="_blank" rel="noopener noreffer ">factory_boy&lt;/a> - &lt;a href="https://github.com/thoughtbot/factory_girl" target="_blank" rel="noopener noreffer ">factory_girl&lt;/a>的python版本&lt;/li>
&lt;li>&lt;a href="https://github.com/omaciel/fauxfactory" target="_blank" rel="noopener noreffer ">fauxfactory&lt;/a> - 随机数据生成器&lt;/li>
&lt;/ul>
&lt;h2 id="code-analysis-代码扫描及分析">Code analysis 代码扫描及分析&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://github.com/yinwang0/pysonar2" target="_blank" rel="noopener noreffer ">pysonar2&lt;/a> - 类型推断&lt;/li>
&lt;li>&lt;a href="https://pypi.python.org/pypi/coverage" target="_blank" rel="noopener noreffer ">coverage&lt;/a> - 覆盖率&lt;/li>
&lt;li>&lt;a href="https://github.com/gak/pycallgraph" target="_blank" rel="noopener noreffer ">pycallgraph&lt;/a> - 流程可视化&lt;/li>
&lt;li>&lt;a href="https://pypi.python.org/pypi/flake8" target="_blank" rel="noopener noreffer ">Flake8&lt;/a> - The modular source code checker: pep8, pyflakes and co.&lt;/li>
&lt;li>&lt;a href="https://pylama.readthedocs.org/" target="_blank" rel="noopener noreffer ">pylama&lt;/a> - Python and JavaScript的代码审查工具&lt;/li>
&lt;li>&lt;a href="http://www.pylint.org/" target="_blank" rel="noopener noreffer ">Pylint&lt;/a> - 源代码分析器&lt;/li>
&lt;li>&lt;a href="https://github.com/openstack-dev/hacking" target="_blank" rel="noopener noreffer ">hacking&lt;/a> - OpenStack Hacking Style Checks (&lt;code>flake8&lt;/code> plugins).&lt;/li>
&lt;li>&lt;a href="https://github.com/landscapeio/prospector" target="_blank" rel="noopener noreffer ">prospector&lt;/a> - 代码分析工具，可以输出错误信息，潜在问题，不规范的代码以及代码复杂度&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p></description></item><item><title>（六）实战：构建 GitHub 项目(上)</title><link>https://itest2025.pages.dev/tutorials/18-006-%E5%85%AD%E5%AE%9E%E6%88%98%E6%9E%84%E5%BB%BA-github-%E9%A1%B9%E7%9B%AE%E4%B8%8A/</link><pubDate>Mon, 16 Oct 2017 11:55:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/18-006-%E5%85%AD%E5%AE%9E%E6%88%98%E6%9E%84%E5%BB%BA-github-%E9%A1%B9%E7%9B%AE%E4%B8%8A/</guid><description>&lt;p>Jenkins 不是一个对开发零基础的人去用的工具。不管你要构建什么样的项目，首先要有这么个项目存在，而且还要知道如何运行该项目。&lt;/p>
&lt;h4 id="快速创建-github-项目">快速创建 GitHub 项目&lt;/h4>
&lt;hr>
&lt;p>如果你想快速的使用 GitHub 来维护你的自动化测试项目，请阅读该教程。&lt;/p>
&lt;p>&lt;a href="https://itest2025.pages.dev/git/git-github-start/" rel="">（一）认识Git与GitHub&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://itest2025.pages.dev/git/registration-and-installation/" rel="">（二）GitHub注册与Git安装&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://itest2025.pages.dev/git/git-commit-code/" rel="">（三）Git提交代码到GitHub&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://itest2025.pages.dev/git/git-github-used/" rel="">（四）Git克隆与更新代码&lt;/a>&lt;/p>
&lt;h4 id="jenkins-配置-git">Jenkins 配置 Git&lt;/h4>
&lt;hr>
&lt;p>首先，登录 Jenkins ，在首页找到 “&lt;strong>系统管理 -&amp;gt; Global Tool Configuration -&amp;gt; Git&lt;/strong> ”&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/jenkins_github_git.png"
 data-srcset="http://img.testclass.net/jenkins_github_git.png, http://img.testclass.net/jenkins_github_git.png 1.5x, http://img.testclass.net/jenkins_github_git.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/jenkins_github_git.png"
 title="http://img.testclass.net/jenkins_github_git.png" />&lt;/p>
&lt;p>&lt;strong>Path to Git executable&lt;/strong> ：设置 Git 执行文件的位置。从你Git的安装目录中查看 “&lt;strong>git.exe&lt;/strong>” 可执行文件的位置。&lt;/p>
&lt;p>设置完成后点击 “&lt;strong>Save&lt;/strong>” 保存设置。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1631475012097-d074e8a92597?w=300"
 data-srcset="https://images.unsplash.com/photo-1631475012097-d074e8a92597?w=300, https://images.unsplash.com/photo-1631475012097-d074e8a92597?w=300 1.5x, https://images.unsplash.com/photo-1631475012097-d074e8a92597?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1631475012097-d074e8a92597?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（六）Locust 分布式运行</title><link>https://itest2025.pages.dev/tutorials/38-006-%E5%85%ADlocust-%E5%88%86%E5%B8%83%E5%BC%8F%E8%BF%90%E8%A1%8C/</link><pubDate>Mon, 16 Oct 2017 10:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/38-006-%E5%85%ADlocust-%E5%88%86%E5%B8%83%E5%BC%8F%E8%BF%90%E8%A1%8C/</guid><description>&lt;p>参考：&lt;a href="https://docs.locust.io/en/latest/running-locust-distributed.html" target="_blank" rel="noopener noreffer ">官方文档&lt;/a>&lt;/p>
&lt;h4 id="分布式运行locust">分布式运行Locust&lt;/h4>
&lt;hr>
&lt;p>一旦单台机器不够模拟足够多的用户时，Locust支持运行在多台机器中进行压力测试。&lt;/p>
&lt;p>为了实现这个，你应该在 master 模式中使用&lt;code>--master&lt;/code>标记来启用一个 Locust 实例。这个实例将会运行你启动测试的 Locust 交互网站并查看实时统计数据。master 节点的机器自身不会模拟任何用户。相反，你必须使用 &lt;code>--slave&lt;/code> 标记启动一台到多台 Locustslave 机器节点，与标记 &lt;code>--master-host&lt;/code> 一起使用(指出master机器的IP/hostname)。&lt;/p>
&lt;p>常用的做法是在一台独立的机器中运行master，在slave机器中每个处理器内核运行一个slave实例。&lt;/p>
&lt;blockquote>
&lt;p>注意：master 和每一台 slave 机器，在运行分布式测试时都必须要有 locust 的测试文件。&lt;/p>&lt;/blockquote>
&lt;h4 id="示例">示例&lt;/h4>
&lt;hr>
&lt;p>在 master 模式下启动 Locust:&lt;/p>
&lt;pre tabindex="0">&lt;code>locust -f my_loucstfile.py --master
&lt;/code>&lt;/pre>&lt;p>在每个 slave 中执行(192.168.0.14 替换为你 msater 的IP):&lt;/p>
&lt;pre tabindex="0">&lt;code>locust -f my_locustfile.py --slave --master-host=192.168.0.14
&lt;/code>&lt;/pre>&lt;h4 id="参数说明">参数说明&lt;/h4>
&lt;hr>
&lt;p>参数&lt;/p>
&lt;p>&amp;ndash;master&lt;/p>
&lt;p>设置 Locust 为 master 模式。网页交互会在这台节点机器中运行。&lt;/p>
&lt;p>&amp;ndash;slave&lt;/p>
&lt;p>设置 Locust 为 slave 模式。&lt;/p>
&lt;p>&amp;ndash;master-host=X.X.X.X&lt;/p>
&lt;p>可选项，与 &lt;code>--slave&lt;/code> 一起结合使用，用于设置 master 模式下的 master 机器的IP/hostname(默认设置为127.0.0.1)&lt;/p>
&lt;p>&amp;ndash;master-port=5557&lt;/p>
&lt;p>可选项，与 &lt;code>--slave&lt;/code> 一起结合使用，用于设置 master 模式下的 master 机器中 Locust 的端口(默认为5557)。注意，locust 将会使用这个指定的端口号，同时指定端口+1的号也会被占用。因此，5557 会被使用，Locust将会使用 5557 和 5558。&lt;/p></description></item><item><title>06. 安装环境总结（新用户必看）</title><link>https://itest2025.pages.dev/tutorials/37-006-06-%E5%AE%89%E8%A3%85%E7%8E%AF%E5%A2%83%E6%80%BB%E7%BB%93%E6%96%B0%E7%94%A8%E6%88%B7%E5%BF%85%E7%9C%8B/</link><pubDate>Mon, 16 Oct 2017 07:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/37-006-06-%E5%AE%89%E8%A3%85%E7%8E%AF%E5%A2%83%E6%80%BB%E7%BB%93%E6%96%B0%E7%94%A8%E6%88%B7%E5%BF%85%E7%9C%8B/</guid><description>&lt;h1 id="安装总结">安装总结&lt;/h1>
&lt;h2 id="硬件建议">硬件建议&lt;/h2>
&lt;p>从上一讲的安装教程来看，IntelliJ IDEA 对硬件的要求看上去不是很高。可是实际在开发中其实并不是这样的，特别是开发 Java Web 的项目的计算机，2G 内存是基本不够用的。&lt;/p>
&lt;p>我们现在来假设一种国内常见的开发环境：&lt;/p>
&lt;blockquote>
&lt;p>有一个在开发的 Java Web 项目，它使用的框架为主流的：Struts + Spring + Hibernate，使用这三个框架的过程中，我们要引入大量的框架 jar 包，在我们的 Web 容器启动时，这些框架架包就要占用大量的内存，而且 IntelliJ IDEA 本身功能繁多，占用的内存也不算低，再加上我们这里还没计算计算机上的其他软件应用。所以基本上 2G 内存的计算机只适合写小程序、小项目或是开发静态页面。&lt;/p>&lt;/blockquote>
&lt;p>我个人建议，如果你是开发 Java Web 项目最好的方案是 8G 内存或是以上，硬盘能再用上固态是最好的，因为 IntelliJ IDEA 有大量的缓存、索引文件，把 IntelliJ IDEA 的缓存、索引文件放在固态上，IntelliJ IDEA 流畅度也会加快很多。&lt;/p>
&lt;p>&lt;strong>如果你正在使用 Eclipse / MyEclipse，想通过 IntelliJ IDEA 来解决计算机的卡、慢等问题，我这里可以直接明白地告诉你：这基本上是不可能的，本质上你应该对自己的硬件设备进行升级&lt;/strong>。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1583508915901-b5f84c1dcde1?w=300"
 data-srcset="https://images.unsplash.com/photo-1583508915901-b5f84c1dcde1?w=300, https://images.unsplash.com/photo-1583508915901-b5f84c1dcde1?w=300 1.5x, https://images.unsplash.com/photo-1583508915901-b5f84c1dcde1?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1583508915901-b5f84c1dcde1?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（六）soapUI创建REST项目</title><link>https://itest2025.pages.dev/tutorials/26-006-%E5%85%ADsoapui%E5%88%9B%E5%BB%BArest%E9%A1%B9%E7%9B%AE/</link><pubDate>Wed, 20 Sep 2017 21:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/26-006-%E5%85%ADsoapui%E5%88%9B%E5%BB%BArest%E9%A1%B9%E7%9B%AE/</guid><description>&lt;h4 id="创建-rest-项目">创建 REST 项目&lt;/h4>
&lt;hr>
&lt;p>打开 soapUI 工具。创建一个 REST 项目。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/soapui_main_window.png"
 data-srcset="http://img.testclass.net/soapui_main_window.png, http://img.testclass.net/soapui_main_window.png 1.5x, http://img.testclass.net/soapui_main_window.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/soapui_main_window.png"
 title="http://img.testclass.net/soapui_main_window.png" />&lt;/p>
&lt;p>在窗口左侧导航栏，右键 &lt;strong>Projects &amp;ndash;&amp;gt; New REST Project&lt;/strong>。&lt;/p>
&lt;h4 id="添加rest接口">添加REST接口&lt;/h4>
&lt;hr>
&lt;p>以本地查询发布会接口为例。&lt;/p>
&lt;p>&lt;strong>URI&lt;/strong>：http://127.0.0.1:8000/events/ 为接口URI。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/soapui_new_rest_project.png"
 data-srcset="http://img.testclass.net/soapui_new_rest_project.png, http://img.testclass.net/soapui_new_rest_project.png 1.5x, http://img.testclass.net/soapui_new_rest_project.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/soapui_new_rest_project.png"
 title="http://img.testclass.net/soapui_new_rest_project.png" />&lt;/p>
&lt;p>点击 &lt;strong>OK&lt;/strong> 按钮，创建项目完成。&lt;/p>
&lt;p>依次展开：&lt;strong>REST Project 1&amp;ndash;&amp;gt;Events[/events/]&amp;ndash;&amp;gt;Events&amp;ndash;&amp;gt;Request 1&lt;/strong> , 为 REST 接口窗口。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/soapui_rest_if_window.png"
 data-srcset="http://img.testclass.net/soapui_rest_if_window.png, http://img.testclass.net/soapui_rest_if_window.png 1.5x, http://img.testclass.net/soapui_rest_if_window.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/soapui_rest_if_window.png"
 title="http://img.testclass.net/soapui_rest_if_window.png" />&lt;/p>
&lt;p>点击 &lt;strong>Request 1&lt;/strong> 窗口中左上角的绿色 &lt;strong>运行&lt;/strong> 按钮，右则窗口显示接口查询结果。&lt;/p>
&lt;h4 id="设置接口uri">设置接口URI&lt;/h4>
&lt;hr>
&lt;p>如果想查询具体的某一条发布会信息，可以在 Resource 输入框中指定发布会 id，如下图。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/soapui_rest_if_data.png"
 data-srcset="http://img.testclass.net/soapui_rest_if_data.png, http://img.testclass.net/soapui_rest_if_data.png 1.5x, http://img.testclass.net/soapui_rest_if_data.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/soapui_rest_if_data.png"
 title="http://img.testclass.net/soapui_rest_if_data.png" />&lt;/p></description></item><item><title>appium新手入门（6）—— appium-desktop</title><link>https://itest2025.pages.dev/tutorials/21-006-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A86-appium-desktop/</link><pubDate>Thu, 07 Sep 2017 10:24:12 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/21-006-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A86-appium-desktop/</guid><description>&lt;h4 id="什么是-appium-desktop">什么是 Appium-desktop？&lt;/h4>
&lt;hr>
&lt;p>项目地址：https://github.com/appium/appium-desktop&lt;/p>
&lt;p>项目描述：&lt;/p>
&lt;blockquote>
&lt;p>Appium Server and Inspector in Desktop GUIs for Mac, Windows, and Linux。&lt;/p>&lt;/blockquote>
&lt;p>Appium 移动测试中有个很重新的组件 &lt;a href="https://itest2025.pages.dev/appium/appium-base-server/" rel="">Appium-Server&lt;/a>，它主要用来监听我们的移动设备（真机或模拟器），然将不同编程语言编写的 appium 测试脚本进行解析，然后，驱动移动设备来运行测试。&lt;/p>
&lt;p>但Appium-Server有一两年没有更新了。Windows版在 2015 年底止步于的 &lt;strong>AppiumForWindows_1_4_16_1.zip&lt;/strong>&lt;/p>
&lt;p>于是，新的工具 Appium-desktop 来了！ 它来继续 Appium-Server的使命，当然， Appium-Server当前仍然是可用的。&lt;/p>
&lt;h4 id="下载与安装">下载与安装&lt;/h4>
&lt;hr>
&lt;p>appium-desktop 下载地址：&lt;a href="https://github.com/appium/appium-desktop/releases" target="_blank" rel="noopener noreffer ">这里&lt;/a>&lt;/p>
&lt;p>根据自己的平台选择相关的包进行下载。本文以 Windows 为例，所以选择 &lt;strong>appium-desktop-Setup-1.2.4.exe&lt;/strong> 文件进行下载。&lt;/p>
&lt;p>安装过程太简单了，双击 exe 文件，然后，等待安装完就好了，中间都不需要你设置任何选项。所以，这里就不贴图了。&lt;/p>
&lt;h4 id="启动运行">启动运行&lt;/h4>
&lt;hr>
&lt;p>安装完成桌面会生成一个紫色的 appium 图标，双击打开。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/appium_desktop_01.png"
 data-srcset="http://img.testclass.net/appium_desktop_01.png, http://img.testclass.net/appium_desktop_01.png 1.5x, http://img.testclass.net/appium_desktop_01.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/appium_desktop_01.png"
 title="http://img.testclass.net/appium_desktop_01.png" />&lt;/p>
&lt;p>默认显示监控的 host 和 port ，这和 Appium-Server中是一致的。点击 &lt;strong>“Start Server V 1.7.1”&lt;/strong> 按钮启动服务。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/appium_desktop_02.png"
 data-srcset="http://img.testclass.net/appium_desktop_02.png, http://img.testclass.net/appium_desktop_02.png 1.5x, http://img.testclass.net/appium_desktop_02.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/appium_desktop_02.png"
 title="http://img.testclass.net/appium_desktop_02.png" />&lt;/p></description></item><item><title>6.unittest框架</title><link>https://itest2025.pages.dev/tutorials/40-006-6unittest%E6%A1%86%E6%9E%B6/</link><pubDate>Fri, 25 Aug 2017 04:41:43 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/40-006-6unittest%E6%A1%86%E6%9E%B6/</guid><description>&lt;p>在我们真正的编写测试用例之前，我们需要了解一下测试框架。&lt;/p>
&lt;p>unittest是python自带的单元测试框架，尽管其主要是为单元测试服务的，但我们也可以用它来做接口的自动化测试。&lt;/p>
&lt;p>unittest框架为我们编写用例提供了如下的能力&lt;/p>
&lt;ul>
&lt;li>
&lt;p>定义用例的能力。unittest框架有一套固有套路，可以让我们定义测试用例时更加简单和统一&lt;/p>
&lt;/li>
&lt;li>
&lt;p>断言的能力。unittest框架提供了一系列的断言&lt;/p>
&lt;/li>
&lt;li>
&lt;p>各种执行策略。通过test suit或者扩展的方式，我们可以自定义用例执行的策略&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="简单的例子">简单的例子&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">unittest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">StringTestCase&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TestCase&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">setUp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Arrange&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">test_string&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;This is a string&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">testUpper&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Act and Assert&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;THIS IS A STRING&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">test_string&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">upper&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">main&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="剖析">剖析&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">unittest&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>导入unittest库，不导入就没办法使用，好比手机如果要使用某个app就必须先安装该app一样，是套路，记住就好。&lt;/p>
&lt;hr>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">StringTestCase&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TestCase&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>定义测试类，初学者看到这一行就害怕，其实大可不必。这还是套路，测试类的名字你可以随意取，当然了首字母最好大写，这样更符合规范一些。所有的测试类都必须直接或间接的继承自&lt;code>unittest.TestCase&lt;/code>类。总之，这还是套路，记住就好。&lt;/p>
&lt;hr>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">setUp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Arrange&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">test_string&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;This is a string&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>继续套路。&lt;code>setUp(self)&lt;/code>方法是一个钩子方法，在每个测试用例执行之前都会执行一次，是做数据初始化的好地方。&lt;/p>
&lt;p>在上面的例子里，我们为每一个测试方法都定义了被测对象，&lt;code>self.test_string&lt;/code>&lt;/p>
&lt;hr>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">testUpper&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Act and Assert&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;THIS IS A STRING&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">test_string&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">upper&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>套路继续。这里定义了一个名为&lt;code>testUpper&lt;/code>的测试方法，这个方法就是一个测试用例。&lt;/p>
&lt;p>&lt;strong>注意，只有方法名以test开头的方法才是测试用例&lt;/strong>&lt;/p>
&lt;p>&lt;code>self.assertEqual&lt;/code>是一个断言方法，作用是如果第一个参数跟第二个参数相等，那么用例通过，否则用例失败，并在测试报告中打印出错误原因。上面的例子里，我们判断&lt;code>self.test_string.upper()&lt;/code>方法会将&lt;code>&amp;quot;This is a string&amp;quot;&lt;/code>字符串转换成&lt;code>&amp;quot;THIS IS A STRING&amp;quot;&lt;/code>&lt;/p>
&lt;hr>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">main&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>最后依然是套路，上面的代码表示，如果直接执行该python文件的话，就运行所有的测试类里的测试用例，也就是运行所有的以&lt;strong>test&lt;/strong>开头的方法。&lt;/p>
&lt;h3 id="总结">总结&lt;/h3>
&lt;p>使用unittest的话需要记住下面的几点&lt;/p>
&lt;ul>
&lt;li>导入unittest&lt;/li>
&lt;li>定义继承自&lt;code>unittest.TestCase&lt;/code>的测试类&lt;/li>
&lt;li>定义以&lt;strong>test&lt;/strong>开头的测试方法，这个方法就是测试用例，你可以在一个类里定义n个测试用例&lt;/li>
&lt;li>断言&lt;/li>
&lt;li>&lt;code>unittest.main()&lt;/code>是执行测试用例最简单的方式&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p></description></item><item><title>JMeter官方文档：6. 建立数据库测试计划</title><link>https://itest2025.pages.dev/tutorials/22-006-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A36-%E5%BB%BA%E7%AB%8B%E6%95%B0%E6%8D%AE%E5%BA%93%E6%B5%8B%E8%AF%95%E8%AE%A1%E5%88%92/</link><pubDate>Thu, 24 Aug 2017 11:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/22-006-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A36-%E5%BB%BA%E7%AB%8B%E6%95%B0%E6%8D%AE%E5%BA%93%E6%B5%8B%E8%AF%95%E8%AE%A1%E5%88%92/</guid><description>&lt;p>&lt;a href="https://itest2025.pages.dev/2017/08/24/jmeter-translation-plans/" rel="">《JMeter官方文档&amp;ndash;翻译计划》&lt;/a> &lt;a href="http://jmeter.apache.org/usermanual/build-db-test-plan.html" target="_blank" rel="noopener noreffer ">原文地址&lt;/a>&lt;/p>
&lt;h2 id="6-建立数据库测试计划building-a-database-test-plan">6. 建立数据库测试计划（Building a Database Test Plan）&lt;/h2>
&lt;hr>
&lt;p>在本节中，您将学习如何创建测试数据库服务器一个简单的&lt;a href="http://jmeter.apache.org/usermanual/build-test-plan.html" target="_blank" rel="noopener noreffer ">测试计划&lt;/a>。您将创建五十个用户向数据库服务器发送2个SQL请求。并且，使这些用户运行测试100次。所以，请求的总数是（50个用户）x（2个请求）x（重复100次）= 10'000个JDBC请求。要构建测试计划，您将使用以下元素： &lt;a href="http://jmeter.apache.org/usermanual/test_plan.html#thread_group" target="_blank" rel="noopener noreffer ">线程组&lt;/a>， &lt;a href="http://jmeter.apache.org/usermanual/component_reference.html#JDBC_Request" target="_blank" rel="noopener noreffer ">JDBC请求&lt;/a>，&lt;a href="http://jmeter.apache.org/usermanual/component_reference.html#Summary_Report" target="_blank" rel="noopener noreffer ">摘要报告&lt;/a>。&lt;/p>
&lt;font color=#930000>
此示例使用MySQL数据库驱动程序。要使用此驱动程序，它包含.jar文件（例如mysql-connector-java-XXX-bin.jar）
必须复制到JMeter __./lib__ 目录（有关详细信息，请参阅[JMeter的Classpath](http://jmeter.apache.org/usermanual/get-started.html#classpath)）。
&lt;/font>
&lt;h3 id="61添加用户adding-users">6.1添加用户（Adding Users）&lt;/h3>
&lt;hr>
&lt;p>您要对每个JMeter测试计划执行的第一步是添加一个&lt;a href="http://jmeter.apache.org/usermanual/test_plan.html#thread_group" target="_blank" rel="noopener noreffer ">线程组&lt;/a>元件。线程组告诉JMeter您想要模拟的用户数量，用户应发送请求的频率以及应发送的请求数量。
继续添加线程组元件，首先选择测试计划，单击鼠标右键获取 &lt;strong>添加&lt;/strong> 菜单，然后选择 &lt;strong>添加&lt;/strong>  →  &lt;strong>线程组&lt;/strong>。&lt;/p>
&lt;p>您现在应该看到“测试计划”下的“线程组”元件。如果没有看到该元件，则通过单击“测试计划”元件,从而展开“线程组”元件。&lt;/p>
&lt;p>接下来，您需要修改默认属性。如果尚未选择它，请选择树中的线程组元件。您现在应该在JMeter窗口的右侧部分看到线程组控制面板（参见下面的图6.1）&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/06_thread_group.png"
 data-srcset="http://img.testclass.net/06_thread_group.png, http://img.testclass.net/06_thread_group.png 1.5x, http://img.testclass.net/06_thread_group.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/06_thread_group.png"
 title="http://img.testclass.net/06_thread_group.png" />&lt;/p>
&lt;p>图6.1 具有默认值的线程组&lt;/p>
&lt;p>首先为我们的线程组提供更具描述性的名称。在名称字段中，输入：JDBC users。&lt;/p>
&lt;blockquote>
&lt;p>您将需要有效的数据库，数据库表和对该表的用户级访问。在这里显示的例子中，
数据库是“guest_test”，表名是“vm_instance”。&lt;/p>&lt;/blockquote>
&lt;p>接下来，将用户数增加到50个。&lt;/p>
&lt;p>在下一个字段中，“Ramp-Up Period” 的值为10秒。此属性告诉JMeter启动每个用户需要多长时间。例如，如果您输入10秒的Ramp-Up Period时间，JMeter将在10秒之后完成所有用户的启动。所以，如果我们有50个用户和10秒的 Ramp-Up Period，则起始用户之间的延迟将是200毫秒（10秒/ 50个用户=每秒0.2个用户）。如果将值设置为0，那么JMeter将立即启动所有用户。&lt;/p>
&lt;p>最后，在循环计数字段中输入值100。此属性告诉JMeter重复测试多少次。要让JMeter循环运行测试计划，请选中“永远”复选框。&lt;/p>
&lt;blockquote>
&lt;p>在大多数应用程序中，您在控制面板中进行的更改必须点击确定按钮。但是，在JMeter中，控制面板会在您进行更改时自动保存您的更改。如果更改元素了名称，在离开控制面板后（例如，当选择另一个树形元件）时，系统将自动保存您的更改。&lt;/p>&lt;/blockquote>
&lt;p>有关完成的JDBC用户线程组，请参见图6.2。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/06_jdbc_users_group.png"
 data-srcset="http://img.testclass.net/06_jdbc_users_group.png, http://img.testclass.net/06_jdbc_users_group.png 1.5x, http://img.testclass.net/06_jdbc_users_group.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/06_jdbc_users_group.png"
 title="http://img.testclass.net/06_jdbc_users_group.png" />
图6.2 JDBC用户线程组&lt;/p></description></item><item><title>appium简明教程（6）——启动appium及android模拟器</title><link>https://itest2025.pages.dev/tutorials/21-006-appium%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B6%E5%90%AF%E5%8A%A8appium%E5%8F%8Aandroid%E6%A8%A1%E6%8B%9F%E5%99%A8/</link><pubDate>Tue, 15 Aug 2017 07:33:41 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/21-006-appium%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B6%E5%90%AF%E5%8A%A8appium%E5%8F%8Aandroid%E6%A8%A1%E6%8B%9F%E5%99%A8/</guid><description>&lt;p>一般情况下，我们都从命令行启动appium。&lt;/p>
&lt;p>windows下，dos命令窗口输入&lt;/p>
&lt;pre tabindex="0">&lt;code>appium
&lt;/code>&lt;/pre>&lt;p>如果该命令报错，那么请重装appium&lt;/p>
&lt;pre tabindex="0">&lt;code>npm install -g appium
&lt;/code>&lt;/pre>&lt;p>如果安装出错，请使用淘宝源。&lt;/p>
&lt;p>&lt;a href="http://npm.taobao.org/" target="_blank" rel="noopener noreffer ">淘宝源地址&lt;/a>&lt;/p>
&lt;p>&lt;strong>然后请打开android的模拟器，如果没有请新建一个虚拟设备。请自行解除设备锁定（手动把屏幕解锁了），以防万一。&lt;/strong>&lt;/p>
&lt;p>下面的代码以启动android原生的计算器程序为例&lt;/p>
&lt;h3 id="ruby篇">ruby篇&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ruby" data-lang="ruby">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">require&lt;/span> &lt;span class="s1">&amp;#39;appium_lib&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">caps&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="ss">caps&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="ss">platformName&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;Android&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">appActivity&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;.Calculator&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">appPackage&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;com.android.calculator2&amp;#39;&lt;/span> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="ss">appium_lib&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="ss">sauce_username&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kp">nil&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ss">sauce_access_key&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kp">nil&lt;/span> &lt;span class="p">}&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="no">Appium&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="no">Driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">new&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">caps&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">start_driver&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>讨论：可以看出ruby lib里面的Appium::Driver类实际上就是原生的webdriver类的子类，当然了，由于ruby语法灵活，也可以使用monkey patch来实现类似功能。&lt;/p>
&lt;h3 id="python篇">python篇&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">appium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">webdriver&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">desired_caps&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">desired_caps&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;platformName&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;Android&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">desired_caps&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;platformVersion&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;4.2&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">desired_caps&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;deviceName&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;Android Emulator&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">desired_caps&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;appPackage&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;com.android.calculator2&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">desired_caps&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;appActivity&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;.Calculator&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">webdriver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Remote&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;http://localhost:4723/wd/hub&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">desired_caps&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>讨论：webdriver.Remote实际上就是原生webdriver的子类，另外Remote()构造函数的第一个参数中需要显示指定appium server监听的端口&lt;/p>
&lt;h3 id="java篇">java篇&lt;/h3>
&lt;p>新建java项目时候，请注意将selenium-webdriver以及appium client的jar包导入&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">io.appium.java_client.AppiumDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.By&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.WebElement&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.remote.CapabilityType&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.remote.DesiredCapabilities&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">DesiredCapabilities&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">capabilities&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">DesiredCapabilities&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">capabilities&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">setCapability&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">CapabilityType&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">BROWSER_NAME&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="c1">//这句不是必须的&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">capabilities&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">setCapability&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;deviceName&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="s">&amp;#34;Android Emulator&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">capabilities&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">setCapability&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;platformVersion&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;4.4&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">capabilities&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">setCapability&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;platformName&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="s">&amp;#34;Android&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">capabilities&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">setCapability&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;appPackage&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;com.android.calculator2&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">capabilities&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">setCapability&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;appActivity&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;.Calculator&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">AppiumDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">AppiumDriver&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">URL&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;http://127.0.0.1:4723/wd/hub&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">capabilities&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>讨论:AppiumDrvier是原生webdriver的子类。&lt;/p></description></item><item><title>性能测试流程（一）——问清性能需求</title><link>https://itest2025.pages.dev/tutorials/14-006-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E6%B5%81%E7%A8%8B%E4%B8%80%E9%97%AE%E6%B8%85%E6%80%A7%E8%83%BD%E9%9C%80%E6%B1%82/</link><pubDate>Fri, 11 Aug 2017 08:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/14-006-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E6%B5%81%E7%A8%8B%E4%B8%80%E9%97%AE%E6%B8%85%E6%80%A7%E8%83%BD%E9%9C%80%E6%B1%82/</guid><description>&lt;br>
&lt;p>假如你一名新进公司的测试小菜鸟，在一次的早会中，领导突然分配给你了一个性能测试任务。我想此时的你是一脸的大写？？，怎么办？怎么办？
这里会提供一个通用的测试思路，照着这个思路做，你就会顺利的完成性能测试。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/what.png"
 data-srcset="http://img.testclass.net/what.png, http://img.testclass.net/what.png 1.5x, http://img.testclass.net/what.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/what.png"
 title="http://img.testclass.net/what.png" />&lt;/p>
&lt;h4 id="问清性能测试需求">问清性能测试需求&lt;/h4>
&lt;hr>
&lt;p>首先，要问本次性能测试的需求是什么，或者性能测试的目的是什么？
我把性能测试按目的分以下几种。&lt;/p>
&lt;p>&lt;strong>1）新系统能力验证&lt;/strong>&lt;/p>
&lt;p>比如，你们刚好开发了一个新系统，在上线前需要验证系统性能。这种情况比较简单；你可以有更多的自由选择测试环境、压力点和测试工具；测试策略上也比较灵活。并且如果性能测试结果没有明显的短板，也不需要进行调优。&lt;/p>
&lt;p>&lt;strong>2）客户有明确要求&lt;/strong>&lt;/p>
&lt;p>这是一个好的结果，这说明客户对性能测试有一定的了解，知道他们需要的系统要达到一个什么样的标准。如：系统要求同时满足100用户登陆，平均每个用户登陆时间不能超过5秒。这个需求很明确，当然也不排除一些不懂装懂的用户，提一些不现实的要求。&lt;/p>
&lt;p>不管怎么说，用户提要求了，这个比较容易，你可以对现系统做一次性能测试，至于，是通过优化系统还是增加硬件设备才能达到要求。就不是测试考虑的问题了。&lt;/p>
&lt;p>&lt;strong>3）找出系统性能瓶颈&lt;/strong>&lt;/p>
&lt;p>这个需求的目的就很明确了，目的就是找出系统的性能瓶颈，进行调优或硬件扩容，所以性能测试的重点在系统的架构分析和业务分析上面。&lt;/p>
&lt;p>&lt;strong>4）稳定性验证（强度测试）&lt;/strong>&lt;/p>
&lt;p>稳定性是系统的一个重要指标，因为系统一旦上线，就有可能会长期处在用户的访问状态，可能以前没发现的一些问题就会暴漏出来。比较典型的就是内存溢出，这种需求在测试策略上就要考虑性能测试的运行时长。&lt;/p>
&lt;p>&lt;strong>注意：&lt;/strong> 当拿到需求时一定要问测试的目的，一方面会显得你很专业；另一方面，我们通过测试目的可以知道后续性能测试工作的重点在哪儿？最主要的是，还可以揣摩出领导对这次测试的重视程度。^_^!&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1468127225977-85bc4aa3fe0f?w=300"
 data-srcset="https://images.unsplash.com/photo-1468127225977-85bc4aa3fe0f?w=300, https://images.unsplash.com/photo-1468127225977-85bc4aa3fe0f?w=300 1.5x, https://images.unsplash.com/photo-1468127225977-85bc4aa3fe0f?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1468127225977-85bc4aa3fe0f?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（六）通过className去定位页面上的元素</title><link>https://itest2025.pages.dev/tutorials/20-006-%E5%85%AD%E9%80%9A%E8%BF%87classname%E5%8E%BB%E5%AE%9A%E4%BD%8D%E9%A1%B5%E9%9D%A2%E4%B8%8A%E7%9A%84%E5%85%83%E7%B4%A0/</link><pubDate>Tue, 08 Aug 2017 02:28:40 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/20-006-%E5%85%AD%E9%80%9A%E8%BF%87classname%E5%8E%BB%E5%AE%9A%E4%BD%8D%E9%A1%B5%E9%9D%A2%E4%B8%8A%E7%9A%84%E5%85%83%E7%B4%A0/</guid><description>&lt;h3 id="为什么是classname">为什么是className&lt;/h3>
&lt;p>用className定位实际上是通过元素的html属性class定位，由于最早的webdriver client版本是使用java实现的，java中class是一个保留字，class不给用，所以就使用了className来替代。&lt;/p>
&lt;h3 id="复合的class属性">复合的class属性&lt;/h3>
&lt;p>selenium&lt;strong>不支持&lt;/strong>复合的class属性。比如&lt;code>class=&amp;quot;col-md-1 col-sm-2&amp;quot;&lt;/code>，我们只能通过&lt;code>col-md-1&lt;/code>或者是&lt;code>col-sm-2&lt;/code>来定位，不能同时使用这2个class进行定位。&lt;/p>
&lt;h3 id="目的">目的&lt;/h3>
&lt;ul>
&lt;li>熟悉selenium webdriver 定位方式&lt;/li>
&lt;li>学会通过class属性去定位元素&lt;/li>
&lt;/ul>
&lt;h3 id="练习对象">练习对象&lt;/h3>
&lt;p>我们使用&lt;a href="https://github.com/cbracco/html5-test-page/blob/master/index.html" target="_blank" rel="noopener noreffer ">html5-test-page&lt;/a>作为我们的练习对象。&lt;/p>
&lt;p>将html代码拷贝一份并保存到本地，文件名为&lt;code>index.html&lt;/code>。&lt;/p>
&lt;h3 id="场景">场景&lt;/h3>
&lt;p>我们将使用className定位下面html代码所示的输入框，并输入一些内容&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">label&lt;/span> &lt;span class="na">for&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;input__text3&amp;#34;&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;error&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Error&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">label&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">input&lt;/span> &lt;span class="na">id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;input__text3&amp;#34;&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;is-error&amp;#34;&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;text&amp;#34;&lt;/span> &lt;span class="na">placeholder&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;Text Input&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">label&lt;/span> &lt;span class="na">for&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;input__text4&amp;#34;&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;valid&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Valid&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">label&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">input&lt;/span> &lt;span class="na">id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;input__text4&amp;#34;&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;is-valid&amp;#34;&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;text&amp;#34;&lt;/span> &lt;span class="na">placeholder&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;Text Input&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="代码">代码&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;path&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">webdriver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;selenium-webdriver&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">By&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">testFile&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;file://&amp;#34;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="nx">path&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">__dirname&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;index.html&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">dr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Builder&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">forBrowser&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;chrome&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">build&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">testFile&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">className&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;is-error&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;should be error&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">className&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;is-valid&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;should be valid&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行结果">运行结果&lt;/h3>
&lt;p>如下图所示&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://wx3.sinaimg.cn/mw690/726a2979gy1fhb4ojpahqj20ea04ydfw.jpg"
 data-srcset="http://wx3.sinaimg.cn/mw690/726a2979gy1fhb4ojpahqj20ea04ydfw.jpg, http://wx3.sinaimg.cn/mw690/726a2979gy1fhb4ojpahqj20ea04ydfw.jpg 1.5x, http://wx3.sinaimg.cn/mw690/726a2979gy1fhb4ojpahqj20ea04ydfw.jpg 2x"
 data-sizes="auto"
 alt="http://wx3.sinaimg.cn/mw690/726a2979gy1fhb4ojpahqj20ea04ydfw.jpg"
 title="http://wx3.sinaimg.cn/mw690/726a2979gy1fhb4ojpahqj20ea04ydfw.jpg" />&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1492446190781-58ac4285911d?w=300"
 data-srcset="https://images.unsplash.com/photo-1492446190781-58ac4285911d?w=300, https://images.unsplash.com/photo-1492446190781-58ac4285911d?w=300 1.5x, https://images.unsplash.com/photo-1492446190781-58ac4285911d?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1492446190781-58ac4285911d?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>软件测试综合笔试题（1）</title><link>https://itest2025.pages.dev/tutorials/44-006-%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E7%BB%BC%E5%90%88%E7%AC%94%E8%AF%95%E9%A2%981/</link><pubDate>Wed, 26 Jul 2017 09:44:38 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/44-006-%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E7%BB%BC%E5%90%88%E7%AC%94%E8%AF%95%E9%A2%981/</guid><description>&lt;br>
1、__HTTP协议有什么特点？有哪几类状态码，分别表示什么意思？__
&lt;p>&lt;strong>特点:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>无连接：限制每次连接只处理一个请求。服务器处理完客户的请求，并收到客户的应答后，即断开连接。&lt;/li>
&lt;li>媒体独立：只要客户端和服务器知道如何处理的数据内容，任何类型的数据都可以通过HTTP发送。&lt;/li>
&lt;li>无状态：无状态是指协议对于事务处理没有记忆能力。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>状态码分类和含义:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>1xx： 指示信息：表示请求已接收， 继续处理。&lt;/li>
&lt;li>2xx： 成功：表示请求已被成功接收、 理解、 接受。&lt;/li>
&lt;li>3xx： 重定向：要完成请求必须进行更进一步的操作。&lt;/li>
&lt;li>4xx： 客户端错误：请求有语法错误或请求无法实现。&lt;/li>
&lt;li>5xx： 服务器端错误：服务器未能实现合法的请求。&lt;/li>
&lt;/ul>
&lt;br>
2、__列举出10个你常用的shell命令，并说明其作用。__
&lt;p>这个只要你平时多用Linux系统，写10个命令问题不大。
参考我的&lt;a href="http://www.cnblogs.com/fnng/archive/2012/03/19/2407162.html" target="_blank" rel="noopener noreffer ">Linux那些事儿&lt;/a>&lt;/p>
&lt;br>
3、__你认为测试工程师应该掌握哪些技术，其中有哪些是你已经掌握的？__
&lt;p>根据自己所掌握的测试技术自由发挥，参考：
&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/test_skill.png"
 data-srcset="http://img.testclass.net/test_skill.png, http://img.testclass.net/test_skill.png 1.5x, http://img.testclass.net/test_skill.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/test_skill.png"
 title="http://img.testclass.net/test_skill.png" />&lt;/p>
&lt;br>
4、__简述cookies和session是怎么工作的？__
&lt;p>&lt;strong>Cookie机制：&lt;/strong> 正统的Cookie分发是通过扩展HTTP协议来实现的，服务器通过在 HTTP 的响应头中加上一行特殊的指示以提示浏览器按照指示生成相应的Cookie。然而纯粹的客户端脚本如JavaScript 或者 VBScript也可以生成 Cookie。而Cookie的使用是由浏览器按照一定的原则在后台自动发送给服务器的。浏览器检查所有存储的Cookie，如果某个Cookie所声明的作用范围大于等于将要请求的资源所在的位置， 则把该cookie附在请求资源的HTTP请求头上发送给服务器。&lt;/p>
&lt;p>&lt;strong>Session 机制：&lt;/strong> Session 机制是一种服务器端的机制，服务器使用一种类似于散列表的结构（也可能就是使用散列表）来保存信息。&lt;/p>
&lt;br>
5、__你认为WEB测试和APP测试有什么不同？__
&lt;ul>
&lt;li>工作平台不同：Web主要运行在浏览器上面，APP的运行基于移动操作系统。&lt;/li>
&lt;li>界面开发技术不同：Web主要通过前端技术（HTML/JS/CSS）来设计页面，APP(Android)主要通过布局文件来设计界面。&lt;/li>
&lt;li>其它：你自行补充。。。&lt;/li>
&lt;/ul>
&lt;br>
6、__用你熟悉的一种编程语言，写出计算以下结果的代码。1+2+3+…+100=？__
&lt;p>以下通过Python语言实现：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">j&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">101&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">j&lt;/span> &lt;span class="o">=&lt;/span>&lt;span class="n">j&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">i&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;计算结果为：&lt;/span>&lt;span class="si">%d&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="o">%&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;br>
7、__表：UC__
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>字段&lt;/th>
 &lt;th>字段名称&lt;/th>
 &lt;th>类型&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>FID&lt;/td>
 &lt;td>用户ID&lt;/td>
 &lt;td>int&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>NAME&lt;/td>
 &lt;td>用户名称&lt;/td>
 &lt;td>Varchar&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>EMAIL&lt;/td>
 &lt;td>用户邮箱&lt;/td>
 &lt;td>Varchar&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>FBAL&lt;/td>
 &lt;td>用户金额&lt;/td>
 &lt;td>decimal(20,2)&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>写出以下功能的sql语句：&lt;/p></description></item><item><title>（六）软件测试分工</title><link>https://itest2025.pages.dev/tutorials/29-006-%E5%85%AD%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E5%88%86%E5%B7%A5/</link><pubDate>Fri, 21 Jul 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/29-006-%E5%85%AD%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E5%88%86%E5%B7%A5/</guid><description>&lt;p>按照本文的主题还是来谈谈软件测试人员的分工吧！主要来谈传统软件测试过程中的测试分工。&lt;/p>
&lt;h4 id="集体测试">集体测试&lt;/h4>
&lt;hr>
&lt;p>也许专业测试里讲这种方式，很可能不叫“集体测试”。因为我根据的自己的理解起了大概符合意思的名词叫集体测试“集体测试”。&lt;/p>
&lt;p>这种测试模式就是，公司里所有的测试人员抱成一团儿，来一个项目，所有测试人员就集中测试一个项目。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/focus_test.png"
 data-srcset="http://img.testclass.net/focus_test.png, http://img.testclass.net/focus_test.png 1.5x, http://img.testclass.net/focus_test.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/focus_test.png"
 title="http://img.testclass.net/focus_test.png" />&lt;/p>
&lt;p>先说这种分工方式的优点：&lt;/p>
&lt;p>1、因为测试团队的中每个成员有都有优缺，人员在工作之中相互取长补短。可以很快的找出软件中的缺陷。三个臭皮匠顶一个诸葛亮，一个经验再丰富的测试不一定有三个水平一般的测从员发现的问题多。&lt;/p>
&lt;p>2、人多的另一个好处是测试项目能可以在更快的时间内发现更多的缺陷。总结一下就是更短时间内发现更多的问题。&lt;/p>
&lt;p>再来说说这种方式的缺点：&lt;/p>
&lt;p>1、一个人员一张嘴，人力成本很高（人员工资，人员平均时间投入，测试机等硬件资源投入）。&lt;/p>
&lt;p>2、当同时需要测试多个项目中时，不好意思，按顺序来，请在后面排好队。（并发能力不足）&lt;/p>
&lt;p>3、工作重复，同样一个缺陷，很可能同时被所有测试员发现，或者叫重复率很高。&lt;/p>
&lt;p>4、人员水平难以区分，在一个项目测试过程中，有的测人员可能一个缺陷也没找到，有的测试人员却发现了几乎所有的问题。也许这个项目一个缺陷也没找到的测试员在下个项目中却发现了很多缺陷。（混入南郭先生）&lt;/p>
&lt;p>5、发现了漏测现象是整个测试团队的责任。（这也不是明确的缺点，要看团队的氛围是积极的还是消极的。）&lt;/p>
&lt;p>好吧！集体测试缺点太多，就像国家成立初期的“吃大锅饭”，肯定是阻碍发展的。那我们来看看几种分工方式。&lt;/p>
&lt;br>
#### 按测试内容分工
---
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/content_test.png"
 data-srcset="http://img.testclass.net/content_test.png, http://img.testclass.net/content_test.png 1.5x, http://img.testclass.net/content_test.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/content_test.png"
 title="http://img.testclass.net/content_test.png" />&lt;/p>
&lt;p>一个项目的测试包括文档测试，易用性测试，逻辑功能测试，界面测试，配置和兼容等多个方面。我们可以根据人员的特点为每个人员分配不同的测试内容。&lt;/p>
&lt;p>内容分工方式的优点：&lt;/p>
&lt;p>1、分工明确，每位人员都清楚自己的测试的内容重点。&lt;/p>
&lt;p>2、责任到位，通过漏测的缺陷就可明确是谁的责任。&lt;/p>
&lt;br>
#### 按测试流程划分
----
&lt;p>我们的项目测试流程一般需要，制定测试计划，编写测试用例，执行测试用例，输出测试报告等工作，我们可以根据流程中的各个阶段来进行划分。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/flow_test.png"
 data-srcset="http://img.testclass.net/flow_test.png, http://img.testclass.net/flow_test.png 1.5x, http://img.testclass.net/flow_test.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/flow_test.png"
 title="http://img.testclass.net/flow_test.png" />&lt;/p>
&lt;p>不同的测试人员负责不同测试阶段的工作。&lt;/p>
&lt;p>优点：&lt;/p>
&lt;p>1、流程清晰，就像瀑布试项目开发流程，不同阶段的工作由不同的人员担任。&lt;/p>
&lt;p>2、划分流程的每个阶段难易程度和所需要的技能。&lt;/p>
&lt;p>编写测试计划人员需要对整个项目的工作时间、资源分配，测试内容，实施过程有整体的把控能力。&lt;/p>
&lt;p>用例辨析人员，需要对项目需求，测试方法，测试点有深入的了解。&lt;/p>
&lt;p>用例执行人员需要细心，使用缺陷系统，沟通，协助研发定位缺陷。&lt;/p>
&lt;p>输出测试报告人员需要对项目的测试过程，缺陷数量，类型，分布。用例执行请况等进行统计。也可以由测试执行人员担任。&lt;/p>
&lt;br>
#### 按项目模块划分
----
![](http://img.testclass.net/module_test.png)
&lt;p>对中大型的项目，这种划分就非常必要了，项目的模块非常多，功能也非常多。不同的测试人员负责不同模块的功能测试，这样会使用测试工作变得更加清晰。&lt;/p>
&lt;p>1、人员利用率高，为什么这么说呢? 不同的人员负责的功能不一样。工作就不会存在交叉与重复。&lt;/p>
&lt;p>2、更容易挖掘深度缺陷，假如A人员今天测试这个功能，明天测试那个功能，他就不可能对被测功能内部逻辑与业务有深入有了解。找到的也只是很表面的缺陷。那么如果一个人员长期负责一个模块的功能，那么就会更容易发现更有深度的缺陷。而往往深度的缺陷是致命的。&lt;/p>
&lt;br>
#### 按照测试类型分工
----
&lt;p>我们知道软件除了功能需要测试以外，软件在编码阶段需要单元测试，接口测试等，在系统测试阶段，为提高功能测试的效率，可能对某些模块进行功能自动化，我们还要考虑软件的性能、安全性等问题。这些类型也是我项目中最常见的分类。我们可以根据这些类型为测试人员分配测试工作。当然，其专业性对测试人员的要求也比较高。&lt;/p></description></item><item><title>（六）控制浏览器操作</title><link>https://itest2025.pages.dev/tutorials/19-006-%E5%85%AD%E6%8E%A7%E5%88%B6%E6%B5%8F%E8%A7%88%E5%99%A8%E6%93%8D%E4%BD%9C/</link><pubDate>Mon, 03 Jul 2017 07:37:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/19-006-%E5%85%AD%E6%8E%A7%E5%88%B6%E6%B5%8F%E8%A7%88%E5%99%A8%E6%93%8D%E4%BD%9C/</guid><description>&lt;br>
### 控制浏览器窗口大小
&lt;p>有时候我们希望能以某种浏览器尺寸找开，访问的页面在这种尺寸下运行。例如可以将浏览器设置成移动端大小(480* 800)，然后访问移动站点，对其样式进行评估；WebDriver 提供了 manage().window().setSize()方法来设置浏览器的大小。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>maximize() 设置浏览器最大化&lt;/p>
&lt;/li>
&lt;li>
&lt;p>setSize() 设置浏览器宽高&lt;/p>
&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.Dimension&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.WebDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.chrome.ChromeDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">Browser&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">throws&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">InterruptedException&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ChromeDriver&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;https://www.baidu.cn&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">manage&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="na">window&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="na">maximize&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2000&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;https://m.baidu.cn&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">manage&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="na">window&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="na">setSize&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Dimension&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">480&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">800&lt;/span>&lt;span class="p">));&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2000&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">quit&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在 PC 端执行自动化测试脚本大多的情况下是希望浏览器在全屏幕模式下执行， 那么可以使用 maximize()方法使打开的浏览器全屏显示， 其用法与 setSize()相同， 但它不需要任何参数。&lt;/p>
&lt;br>
### 控制浏览器后退、前进
&lt;p>在使用浏览器浏览网页时，浏览器提供了后退和前进按钮，可以方便地在浏览过的网页之间切换，WebDriver也提供了对应的back()和forward()方法来模拟后退和前进按钮。下面通过例子来演示这两个方法的使用。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>back() 模拟浏览器后退按钮&lt;/p></description></item><item><title>（六）鼠标事件</title><link>https://itest2025.pages.dev/tutorials/24-006-%E5%85%AD%E9%BC%A0%E6%A0%87%E4%BA%8B%E4%BB%B6/</link><pubDate>Sun, 25 Jun 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/24-006-%E5%85%AD%E9%BC%A0%E6%A0%87%E4%BA%8B%E4%BB%B6/</guid><description>&lt;br>
&lt;p>在 WebDriver 中， 将这些关于鼠标操作的方法封装在 ActionChains 类提供。&lt;/p>
&lt;p>ActionChains 类提供了鼠标操作的常用方法：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>perform()： 执行所有 ActionChains 中存储的行为；&lt;/p>
&lt;/li>
&lt;li>
&lt;p>context_click()： 右击；&lt;/p>
&lt;/li>
&lt;li>
&lt;p>double_click()： 双击；&lt;/p>
&lt;/li>
&lt;li>
&lt;p>drag_and_drop()： 拖动；&lt;/p>
&lt;/li>
&lt;li>
&lt;p>move_to_element()： 鼠标悬停。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;br>
### 鼠标悬停操作
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://orru5lls3.bkt.clouddn.com/xuanting.jpg"
 data-srcset="http://orru5lls3.bkt.clouddn.com/xuanting.jpg, http://orru5lls3.bkt.clouddn.com/xuanting.jpg 1.5x, http://orru5lls3.bkt.clouddn.com/xuanting.jpg 2x"
 data-sizes="auto"
 alt="http://orru5lls3.bkt.clouddn.com/xuanting.jpg"
 title="http://orru5lls3.bkt.clouddn.com/xuanting.jpg" />&lt;/p>
&lt;pre tabindex="0">&lt;code>from selenium import webdriver
# 引入 ActionChains 类
from selenium.webdriver.common.action_chains import ActionChains

driver = webdriver.Chrome()
driver.get(&amp;#34;https://www.baidu.cn&amp;#34;)

# 定位到要悬停的元素
above = driver.find_element_by_link_text(&amp;#34;设置&amp;#34;)
# 对定位到的元素执行鼠标悬停操作
ActionChains(driver).move_to_element(above).perform()

……
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>from selenium.webdriver import ActionChains&lt;/li>
&lt;/ul>
&lt;p>导入提供鼠标操作的 ActionChains 类。&lt;/p>
&lt;ul>
&lt;li>ActionChains(driver)&lt;/li>
&lt;/ul>
&lt;p>调用 ActionChains()类， 将浏览器驱动 driver 作为参数传入。&lt;/p>
&lt;ul>
&lt;li>move_to_element(above)&lt;/li>
&lt;/ul>
&lt;p>context_click()方法用于模拟鼠标右键操作， 在调用时需要指定元素定位。&lt;/p></description></item><item><title>测试投入与产出</title><link>https://itest2025.pages.dev/tutorials/13-007-%E6%B5%8B%E8%AF%95%E6%8A%95%E5%85%A5%E4%B8%8E%E4%BA%A7%E5%87%BA/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/13-007-%E6%B5%8B%E8%AF%95%E6%8A%95%E5%85%A5%E4%B8%8E%E4%BA%A7%E5%87%BA/</guid><description>&lt;p>在&lt;a href="https://itest2025.pages.dev/software_test/test-division/" rel="">测试人员分工&lt;/a>中，我介绍了各种分工方式，在选择使用哪一种分工方式时，还需要考虑投入的人员数量，投入的时间，与发现缺陷的数量。&lt;/p>
&lt;br>
#### 投入时间与发现缺陷的关系：
----
![](http://img.testclass.net/time_and_bug.png)
&lt;p>在人员一定的情况下，投入的时间越多，发现的缺陷越多。但有一个规律，越到后期发现的新缺陷越少。假设软件总缺陷为100个，第一周发现50个问题，第二新发现20个，第二周可能只发现10个新缺陷。而且一个必然的结果是，测试不可能发现所有的缺陷。&lt;/p>
&lt;br>
#### 投入人员数量与缺陷的关系：
----
![](http://img.testclass.net/personnel_and_bug.png)
&lt;p>在时间一定有的情况下，投入的人员越多，发现的问题越多，从图中可以看出，投入的人员越多，人员发现缺陷的重叠度越高。当然，你可以说，把每个人员要测试的内容划分清晰就不会重叠了。做为一个系统的各个功能模块，他们之间肯定存在必然的联系。有可能A人员在测试时会涉及到B人员测试的功能，并且发现了问题，不管是告诉B缺陷还是A人员直接提交缺陷（当然，你也可以装作没看到，等着B去发现），这都算不可避免的重叠。&lt;/p>
&lt;p>当然，划分更清晰的任务有效的降低重叠度。同步也降低了发现缺陷的数量，提高项目风险。除非投入更多的时间测试。这之间的关系，需要测试管理者认真去权衡。&lt;/p>
&lt;p>在项目不紧急测试时间充分的情况下，可以投入更少的人员，延长测试时间发现更多的缺陷。 在项目紧急的情况下，需要投入更多的人员测试，以便尽快的发现更多的缺陷。在项目质量要求很高的情况下需要投入更多的人员与时间进行测试。在测试时间少，项目质量要求不高的情况下，可以投入较少的人员与时间进行测试。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1616531770192-6eaea74c2456?w=300"
 data-srcset="https://images.unsplash.com/photo-1616531770192-6eaea74c2456?w=300, https://images.unsplash.com/photo-1616531770192-6eaea74c2456?w=300 1.5x, https://images.unsplash.com/photo-1616531770192-6eaea74c2456?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1616531770192-6eaea74c2456?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>python简明教程: 7. 高级内容</title><link>https://itest2025.pages.dev/tutorials/39-007-python%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B-7-%E9%AB%98%E7%BA%A7%E5%86%85%E5%AE%B9/</link><pubDate>Fri, 16 Nov 2018 03:23:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/39-007-python%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B-7-%E9%AB%98%E7%BA%A7%E5%86%85%E5%AE%B9/</guid><description>&lt;p>本文内容基本上翻译自&lt;a href="http://cheat.sh/python/:learn" target="_blank" rel="noopener noreffer ">http://cheat.sh/python/:learn)&lt;/a>&lt;/p>
&lt;p>&lt;strong>非原创, 非原创, 非原创!!!&lt;/strong>&lt;/p>
&lt;p>感谢原文社区作者&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">####################################################&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 7. 高级内容&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">####################################################&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 生成器&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 生成器会动态生成一些数据，而不是在使用数据前创建数据然后把这些数据储存起来&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 下面的方法(非生成器)会将所有的值翻倍，并存在double_arr变量里&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 如果iterable很大的话，double_arr将是巨大的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">double_numbers&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">iterable&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">double_arr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">iterable&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">double_arr&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">i&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">double_arr&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 运行下面的代码意味着我们首先会将所有的值都加倍然后返回回来&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 最后再检查返回值是否符合特定条件&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">value&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">double_numbers&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1000000&lt;/span>&lt;span class="p">)):&lt;/span> &lt;span class="c1"># `test_non_generator`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span> &lt;span class="n">value&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">value&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">break&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># We could instead use a generator to &amp;#34;generate&amp;#34; the doubled value as the item&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># is being requested&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 我们可以使用生成器来动态加倍必要的值&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">double_numbers_generator&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">iterable&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">iterable&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">yield&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">i&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 使用生成器运行之前同样的代码&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 现在我们可以根据运行时逻辑一个接一个的进行加倍&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 一旦value &amp;gt; 5，代码就会break&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 这样我们就不需要把所有的值都加倍一遍了(运行速度会快很多)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">value&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">double_numbers_generator&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">xrange&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1000000&lt;/span>&lt;span class="p">)):&lt;/span> &lt;span class="c1"># `test_generator`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span> &lt;span class="n">value&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">value&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">break&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># BTW: 你注意到`range` 用在了 `test_non_generator` 而`xrange` 用在 `test_generator`里了嘛?&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 就像`double_numbers_generator` 是 `double_numbers`的生成器版本一样&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># `xrange` 是`range`的生成器版本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># `range` 会返回包含1000000个值的列表&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># `xrange` 会在我们遍历的时候动态依次创建1000000个值&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 你也可以像使用列表表达式一样使用生成器表达式&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">values&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">values&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 打印出-1 -2 -3 -4 -5&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 你也可以直接把生成器转换成列表&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">values&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">gen_to_list&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">values&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">gen_to_list&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># =&amp;gt; [-1, -2, -3, -4, -5]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 装饰器&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 装饰器是高阶函数，可以接受函数作为参数并返回函数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 简单的例子 – add_apples装饰器会将 &amp;#39;Apple&amp;#39; 元素插入 into&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 到目标函数(被装饰的函数)get_fruits返回的列表里&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">add_apples&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">func&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">get_fruits&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fruits&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">func&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fruits&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Apple&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">fruits&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">get_fruits&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@add_apples&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">get_fruits&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;Banana&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Mango&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Orange&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 打印出的结果里是包含&amp;#39;Apple&amp;#39;元素的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Banana, Mango, Orange, Apple&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span> &lt;span class="s1">&amp;#39;, &amp;#39;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">get_fruits&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 下面的例子里beg 装饰了 say&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Beg会调用say. 如果 say_please 是 True 那么 beg 会修改say的返回值&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># message&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">functools&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">wraps&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">beg&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">target_function&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@wraps&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">target_function&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">wrapper&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">**&lt;/span>&lt;span class="n">kwargs&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">msg&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">say_please&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">target_function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">**&lt;/span>&lt;span class="n">kwargs&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">say_please&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2"> &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">msg&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;Please! I am poor :(&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">msg&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">wrapper&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@beg&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">say&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">say_please&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">False&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">msg&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Can you buy me a beer?&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">msg&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">say_please&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span> &lt;span class="n">say&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1"># Can you buy me a beer?&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span> &lt;span class="n">say&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">say_please&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># Can you buy me a beer? Please! I am poor :(&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p></description></item><item><title>（七） 创建docker selenium容器</title><link>https://itest2025.pages.dev/tutorials/30-007-%E4%B8%83-%E5%88%9B%E5%BB%BAdocker-selenium%E5%AE%B9%E5%99%A8/</link><pubDate>Mon, 22 Jan 2018 14:36:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/30-007-%E4%B8%83-%E5%88%9B%E5%BB%BAdocker-selenium%E5%AE%B9%E5%99%A8/</guid><description>&lt;p>SeleniumHQ官方项目：https://github.com/seleniumHQ/docker-selenium
项目目前快速迭代中。&lt;/p>
&lt;h4 id="selenium">Selenium&lt;/h4>
&lt;hr>
&lt;p>这里主要针对的是 Selenium Grid，它用于分布式自动化测试，就是一套Selenium 代码可在不同的环境上运行。刚好，Docker可快速的创建各种环境。&lt;/p>
&lt;p>&lt;strong>Selenium Grid 有两个概念&lt;/strong>&lt;/p>
&lt;p>hub ：主节点，你可以看作 “北京总公司的测试经理”。&lt;/p>
&lt;p>node：分支节点，你可以看作 “北京总公司的测试小兵A” 和 “上海分公司的测试小兵B”，还有 “深圳分公司的测试小兵C” &amp;hellip;。&lt;/p>
&lt;p>也就是说在Selenium Grid中只能有一个主hub，但可以在本地或远程建立 N 多个分支node，测试脚本指向主hub，由主hub 分配给本地/远程node 运行测试用例。&lt;/p>
&lt;h4 id="docker-selenium-环境安装">docker selenium 环境安装&lt;/h4>
&lt;hr>
&lt;p>以Ubuntu为例，在Ubuntu下安装Docker，请参考：&lt;a href="https://itest2025.pages.dev/docker/02-install/" rel="">Docker安装（Ubuntu）&lt;/a>&lt;/p>
&lt;p>docker hub（仓库）：&lt;/p>
&lt;p>&lt;a href="https://hub.docker.com/r/selenium/hub/" target="_blank" rel="noopener noreffer ">https://hub.docker.com/r/selenium/hub/&lt;/a>&lt;/p>
&lt;p>1、下载主hub镜像（北京总公司的测试经理）&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo docker pull selenium/hub
&lt;/code>&lt;/pre>&lt;p>2、下载主node chrome 镜像（上海分公司的测试小兵B）&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo docker pull selenium/node-chrome
&lt;/code>&lt;/pre>&lt;p>3、查看镜像&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo docker images

REPOSITORY TAG IMAGE ID CREATED SIZE
selenium/node-chrome latest 1eba57bd3d79 12 days ago 823MB
selenium/hub latest d1437f7d9f87 12 days ago 285MB
&lt;/code>&lt;/pre>&lt;p>4、启动主hub容器&lt;/p></description></item><item><title>（七）类与对象</title><link>https://itest2025.pages.dev/tutorials/16-007-%E4%B8%83%E7%B1%BB%E4%B8%8E%E5%AF%B9%E8%B1%A1/</link><pubDate>Wed, 17 Jan 2018 14:35:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/16-007-%E4%B8%83%E7%B1%BB%E4%B8%8E%E5%AF%B9%E8%B1%A1/</guid><description>&lt;p>Java是一门面向对象的语言，其重要的一个思想就是 &lt;strong>“万物皆对象”&lt;/strong>。 从某中意义上讲，类是Java面向对象性的基础，Java的任何工作都要在类中进行。&lt;/p>
&lt;h4 id="类">类&lt;/h4>
&lt;hr>
&lt;p>创建一个 &lt;strong>&amp;ldquo;程序员&amp;rdquo;&lt;/strong> 类，人一般属性包括姓名、性别、年龄、住址等。他的行为吃饭、睡觉、写代码等。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">Programmer&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="cm">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> /声明各类变量来描述程序类的属性
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> */&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">sex&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">age&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">address&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">eat&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;我在吃饭！&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">sleep&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;我在睡觉！&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">code&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">printf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;我在写代码！&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>注意，这个类在创建时并没有加 &lt;code>public&lt;/code> 的修饰符，关于修饰符的权限：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>private: 只有本类可见。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>protected：本类、子类、同一包的类可见。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>default(无修饰符)：本类、同一包的类可见。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>public：对任何类可见。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>在上面的代码中，你可以用以上修饰符进行修饰。类、变量、和方法。如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">Programmer&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="cm">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> /声明各类变量来描述程序类的属性
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> */&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">protected&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">protected&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">sex&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">protected&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">age&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">protected&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">address&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">eat&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;我在吃饭！&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">sleep&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;我在睡觉！&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">code&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">printf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;我在写代码！&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="对象">对象&lt;/h4>
&lt;hr>
&lt;p>前面已经把描述对象的类抽象出来，接下来就是创建些类的实例。&lt;/p></description></item><item><title>TDD实战（七）Jacoco 代码覆盖率</title><link>https://itest2025.pages.dev/tutorials/32-007-tdd%E5%AE%9E%E6%88%98%E4%B8%83jacoco-%E4%BB%A3%E7%A0%81%E8%A6%86%E7%9B%96%E7%8E%87/</link><pubDate>Mon, 08 Jan 2018 12:35:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/32-007-tdd%E5%AE%9E%E6%88%98%E4%B8%83jacoco-%E4%BB%A3%E7%A0%81%E8%A6%86%E7%9B%96%E7%8E%87/</guid><description>&lt;p>最后一节，和TDD没有直关系，我这里要介绍代码覆盖率工具 Jacoco 。&lt;/p>
&lt;h4 id="安装-jacoco">安装 Jacoco&lt;/h4>
&lt;hr>
&lt;p>由于整个TDD项目由 Gradle构建，所以在&lt;code>build.gradle&lt;/code>文件中添加 Jacoco 插件。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">group&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">org&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">tdd&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sample&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">version&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">0&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">SNAPSHOT&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">apply&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">plugin&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">java&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">apply&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">plugin&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;jacoco&amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//Jacoco 插件&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">sourceCompatibility&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">8&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">repositories&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">mavenCentral&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">dependencies&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">testCompile&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">group&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">junit&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">junit&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">version&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">4&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">12&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="运行测试">运行测试&lt;/h4>
&lt;hr>
&lt;p>切换到TDD 项目目录。执行：&lt;/p>
&lt;pre tabindex="0">&lt;code>TDD &amp;gt; gradle clean test jacocoTestReport

BUILD SUCCESSFUL in 2s
5 actionable tasks: 5 executed
&lt;/code>&lt;/pre>&lt;h4 id="测试报告">测试报告&lt;/h4>
&lt;hr>
&lt;p>在项目&lt;code>...\TDD\build\reports\jacoco\test\html&lt;/code>目录下生成&lt;code>index.html&lt;/code>报告，通过浏览器打开。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/tdd_jacoco_report.png"
 data-srcset="http://img.testclass.net/tdd_jacoco_report.png, http://img.testclass.net/tdd_jacoco_report.png 1.5x, http://img.testclass.net/tdd_jacoco_report.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/tdd_jacoco_report.png"
 title="http://img.testclass.net/tdd_jacoco_report.png" />&lt;/p></description></item><item><title>Android测试（七）：Espresso 自动化测试</title><link>https://itest2025.pages.dev/tutorials/17-007-android%E6%B5%8B%E8%AF%95%E4%B8%83espresso-%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95/</link><pubDate>Wed, 20 Dec 2017 14:25:12 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/17-007-android%E6%B5%8B%E8%AF%95%E4%B8%83espresso-%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95/</guid><description>&lt;p>原文：https://developer.android.com/training/testing/ui-testing/espresso-testing.html&lt;/p>
&lt;p>在单个应用程序中测试用户交互有助于确保用户在与应用程序进行交互时不会遇到意外的结果，或遇到糟糕的体验。 如果需要验证应用的UI功能是否正常，则应该养成创建用户界面（UI）测试的习惯。&lt;/p>
&lt;p>Espresso 测试框架，由Android测试支持库提供，用于编写UI测试的API来模拟单个应用程序内的用户交互。Espresso测试可以在运行Android 2.3.3（API等级10）及更高版本的设备上运行。 使用Espresso的一个关键好处是，它提供了测试操作与正在测试的应用程序的用户界面的自动同步。 Espresso检测主线程是否处于空闲状态，以便能够在适当的时候运行测试命令，从而提高测试的可靠性。此功能还可以减轻在测试代码中添加任何计时变通方法如&lt;code>Thread.sleep（）&lt;/code> 的麻烦。&lt;/p>
&lt;p>Espresso测试框架基于instrumentation的API，并通过AndroidJUnitRunner运行测试。&lt;/p>
&lt;h3 id="设置espresso">设置Espresso&lt;/h3>
&lt;hr>
&lt;p>在使用Espresso构建UI测试之前，请确保配置测试源代码位置和项目依赖关系，如“ &lt;a href="http://www.testclass.net/android/fundamentals/" target="_blank" rel="noopener noreffer ">Getting Started with Testing&lt;/a>”中所述。&lt;/p>
&lt;p>在Android应用程序模块的build.gradle文件中，必须设置对Espresso库的依赖关系引用：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">dependencies&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">    &lt;/span>&lt;span class="c1">// Other dependencies ...&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">    &lt;/span>&lt;span class="n">androidTestCompile&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">com&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">android&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">support&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">test&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">espresso&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">espresso&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">core&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">2&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">2&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>关闭测试设备上的动画 - 在测试设备中打开系统动画可能会导致意外的结果，或者可能导致测试失败。 通过打开“开发人员”选项关闭“设置”中的动画，并关闭以下所有选项：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>窗口动画比例&lt;/p>
&lt;/li>
&lt;li>
&lt;p>过渡动画比例&lt;/p>
&lt;/li>
&lt;li>
&lt;p>动画师持续时间比例&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>如果你希望将项目设置为使用核心API提供的Espresso功能以外的功能，请参阅&lt;a href="https://developer.android.com/training/testing/espresso/index.html" target="_blank" rel="noopener noreffer ">此资源&lt;/a>&lt;/p>
&lt;h3 id="创建一个espresso-测试">创建一个Espresso 测试&lt;/h3>
&lt;hr>
&lt;p>要创建Espresso测试，请创建遵循此编程模型的Java类：&lt;/p>
&lt;p>1.找到想要在活动中测试的UI组件(例如，应用程序中的登录按钮)，调用onView()方法，或者调用AdapterView控件的onData()方法。&lt;/p>
&lt;p>2.通过调用ViewInteraction.perform（）或DataInteraction.perform（）方法并传入用户操作（例如，单击登录按钮），模拟特定的用户交互以在该UI组件上执行。 要在同一UI组件上对多个操作进行排序，请使用方法参数中的逗号分隔列表链接它们。&lt;/p>
&lt;p>3.根据需要重复上述步骤，模拟目标应用中多个活动的用户操作。&lt;/p>
&lt;p>4.在执行这些用户交互之后，使用&lt;code>ViewAssertions&lt;/code>方法来检查UI是否反映了期望的状态或行为。&lt;/p>
&lt;p>以下各节将详细介绍这些步骤。&lt;/p>
&lt;p>下面的代码片段显示了你的测试类可能如何调用这个基本的工作流程：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">onView&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">withId&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">id&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">my_view&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="w">            &lt;/span>&lt;span class="c1">// withId(R.id.my_view) is a ViewMatcher&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">        &lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">perform&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">click&lt;/span>&lt;span class="p">())&lt;/span>&lt;span class="w">               &lt;/span>&lt;span class="c1">// click() is a ViewAction&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">        &lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">check&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">matches&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">isDisplayed&lt;/span>&lt;span class="p">()));&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// matches(isDisplayed()) is a ViewAssertion&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="使用espresso和activitytestrule">使用Espresso和ActivityTestRule&lt;/h3>
&lt;hr>
&lt;p>以下部分介绍如何使用JUnit 4样式创建新的Espresso测试，并使用ActivityTestRule来减少需要编写的样板代码的数量。 通过使用ActivityTestRule，测试框架在每个使用&lt;code>@Test&lt;/code>注释的测试方法之前以及在使用&lt;code>@Before&lt;/code>注释的方法之前启动被测活动。测试完成后，框架处理关闭活动，所有使用&lt;code>@After&lt;/code>注释的方法都会运行。&lt;/p></description></item><item><title>另一个例子: 知乎最热问题</title><link>https://itest2025.pages.dev/tutorials/27-007-%E5%8F%A6%E4%B8%80%E4%B8%AA%E4%BE%8B%E5%AD%90-%E7%9F%A5%E4%B9%8E%E6%9C%80%E7%83%AD%E9%97%AE%E9%A2%98/</link><pubDate>Wed, 13 Dec 2017 02:52:34 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/27-007-%E5%8F%A6%E4%B8%80%E4%B8%AA%E4%BE%8B%E5%AD%90-%E7%9F%A5%E4%B9%8E%E6%9C%80%E7%83%AD%E9%97%AE%E9%A2%98/</guid><description>&lt;h3 id="需求">需求&lt;/h3>
&lt;p>在这一节里，我们将实现获取&lt;a href="https://www.zhihu.com/explore" target="_blank" rel="noopener noreffer ">知乎每日及每月最热问题&lt;/a>的功能。&lt;/p>
&lt;p>具体步骤&lt;/p>
&lt;ul>
&lt;li>访问知乎的发现的主页，获取html文本&lt;/li>
&lt;li>分析html文本，找出今日最热和本月最热的html特征&lt;/li>
&lt;li>解析html代码，拿到所有满足条件的链接&lt;/li>
&lt;li>拿到链接的文本，并打印&lt;/li>
&lt;/ul>
&lt;h3 id="分析html代码">分析html代码&lt;/h3>
&lt;pre tabindex="0">&lt;code>&amp;lt;a class=&amp;#34;question_link&amp;#34; href=&amp;#34;/question/264469853/answer/281600357&amp;#34; target=&amp;#34;_blank&amp;#34; data-id=&amp;#34;20218891&amp;#34; data-za-element-name=&amp;#34;Title&amp;#34;&amp;gt;
如何看待张召忠（局座）于12月22日在b站的《荒野行动》直播？
&amp;lt;/a&amp;gt;
&lt;/code>&lt;/pre>&lt;p>稍微分析一下可以看出，我们只需要拿到所有class=&amp;ldquo;question_link&amp;quot;的a标签就可以了。&lt;/p>
&lt;h3 id="代码">代码&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># zhihu.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">requests&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">bs4&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">BeautifulSoup&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">url&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;https://www.zhihu.com/explore&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">headers&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;user-agent&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36&amp;#39;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">soup&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">BeautifulSoup&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">requests&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">headers&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">headers&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;html.parser&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">link&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">soup&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_all&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;a&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">class_&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;question_link&amp;#39;&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">link&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行">运行&lt;/h3>
&lt;p>命令行中运行&lt;/p>
&lt;pre tabindex="0">&lt;code>python zhihu.py
&lt;/code>&lt;/pre>&lt;h3 id="预期结果">预期结果&lt;/h3>
&lt;p>由于内容是动态的，所以结果应该跟我的结果不尽相同&lt;/p>
&lt;pre tabindex="0">&lt;code>如何看待美税改通过后各大公司的发福利提最低工资追加投资等行为？


全球变暖是必然吗？


主播进行游戏直播并从中获得打赏盈利涉及侵犯版权吗？


如何看待张召忠（局座）于12月22日在b站的《荒野行动》直播？


影史上有哪些经典的即兴表演镜头？


十年坚持做一件事，是种怎样的体验？


2018 年应届硕士毕业生如何拿到知名互联网公司深度学习 offer？


迄今为止你见过的最惊艳的建筑是？


有哪些令人心碎的小故事？


有哪些轻松幽默而又不低俗的段子或图片？


为什么人会失去婴儿时期的记忆？最早记忆是几岁呢？


你最喜欢的故事是什么？


做一个可爱的女孩子是一种什么体验？
&lt;/code>&lt;/pre>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1498550744921-75f79806b8a7?w=300"
 data-srcset="https://images.unsplash.com/photo-1498550744921-75f79806b8a7?w=300, https://images.unsplash.com/photo-1498550744921-75f79806b8a7?w=300 1.5x, https://images.unsplash.com/photo-1498550744921-75f79806b8a7?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1498550744921-75f79806b8a7?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（七） 使用注解来快速模拟</title><link>https://itest2025.pages.dev/tutorials/45-007-%E4%B8%83-%E4%BD%BF%E7%94%A8%E6%B3%A8%E8%A7%A3%E6%9D%A5%E5%BF%AB%E9%80%9F%E6%A8%A1%E6%8B%9F/</link><pubDate>Sat, 25 Nov 2017 12:35:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/45-007-%E4%B8%83-%E4%BD%BF%E7%94%A8%E6%B3%A8%E8%A7%A3%E6%9D%A5%E5%BF%AB%E9%80%9F%E6%A8%A1%E6%8B%9F/</guid><description>&lt;p>在前面的测试中我们在每个测试方法里都mock了一个List对象，为了避免重复的mock，是测试类更具有可读性，我们可以使用下面的注解方式来快速模拟对象：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.Test&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.mockito.Mock&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.mockito.Mockito.*&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">java.util.List&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">MockitoDemo2&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Mock&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">private&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">List&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">mockList&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">shorthand&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">mockList&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">verify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mockList&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="na">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>运行这个测试类你会发现报&lt;code>NullPointerException&lt;/code>错，mock的对象为NULL，为此我们必须在基类中添加初始化mock的代码:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.Test&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.mockito.Mock&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.mockito.MockitoAnnotations&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.mockito.Mockito.*&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">java.util.List&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">MockitoDemo2&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Mock&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">private&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">List&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">mockList&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">MockitoDemo2&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">MockitoAnnotations&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">initMocks&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">this&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">shorthand&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">mockList&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">verify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mockList&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="na">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>或者使用built-in runner：MockitoJUnitRunner:&lt;/p></description></item><item><title>（七）TestNG 用例执行顺序</title><link>https://itest2025.pages.dev/tutorials/36-007-%E4%B8%83testng-%E7%94%A8%E4%BE%8B%E6%89%A7%E8%A1%8C%E9%A1%BA%E5%BA%8F/</link><pubDate>Sat, 25 Nov 2017 12:30:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/36-007-%E4%B8%83testng-%E7%94%A8%E4%BE%8B%E6%89%A7%E8%A1%8C%E9%A1%BA%E5%BA%8F/</guid><description>&lt;p>有时候，我们希望用例按照我们要求的顺序来执行。TestNG 同样可以满足这一点要求。&lt;/p>
&lt;h4 id="实例">实例&lt;/h4>
&lt;hr>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.testng.annotations.Test&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.testng.AssertJUnit.assertEquals&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">CaseRunTest&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">testCase1&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">4&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">testCase2&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">4&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">testCase3&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">4&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>通过 &lt;strong>testng.xml&lt;/strong> 文件修改配置。&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;lt;!DOCTYPE suite SYSTEM &amp;#34;http://testng.org/testng-1.0.dtd&amp;#34; &amp;gt;
&amp;lt;suite name=&amp;#34;测试套件&amp;#34;&amp;gt;
 &amp;lt;test name=&amp;#34;简单测试&amp;#34; preserve-order=&amp;#34;false&amp;#34;&amp;gt;
 &amp;lt;classes&amp;gt;
 &amp;lt;class name=&amp;#34;test.sample.CaseRunTest&amp;#34;&amp;gt;
 &amp;lt;methods&amp;gt;
 &amp;lt;include name=&amp;#34;testCase3&amp;#34; /&amp;gt;
 &amp;lt;include name=&amp;#34;testCase1&amp;#34; /&amp;gt;
 &amp;lt;include name=&amp;#34;testCase2&amp;#34; /&amp;gt;
 &amp;lt;/methods&amp;gt;
 &amp;lt;/class&amp;gt;
 &amp;lt;/classes&amp;gt;
 &amp;lt;/test&amp;gt;
&amp;lt;/suite&amp;gt;
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>preserve-order 参数用于控制测试用例的执行顺序。如果为：&lt;strong>true&lt;/strong>，测试用例的顺序为：testCase &amp;gt; testCase1 &amp;gt; testCase2。如果为:&lt;strong>false&lt;/strong> ，那么默认会按照用例的名称的有字母/数字的顺序执行：testCase1 &amp;gt; testCase2 &amp;gt; testCase3。&lt;/li>
&lt;/ul>
&lt;p>不设置的情况下默认为 &lt;strong>true&lt;/strong> 。&lt;/p></description></item><item><title>requests如何在url中传递参数?</title><link>https://itest2025.pages.dev/tutorials/42-007-requests%E5%A6%82%E4%BD%95%E5%9C%A8url%E4%B8%AD%E4%BC%A0%E9%80%92%E5%8F%82%E6%95%B0/</link><pubDate>Wed, 22 Nov 2017 03:23:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/42-007-requests%E5%A6%82%E4%BD%95%E5%9C%A8url%E4%B8%AD%E4%BC%A0%E9%80%92%E5%8F%82%E6%95%B0/</guid><description>&lt;p>&lt;a href="http://docs.python-requests.org/en/master/user/quickstart/#passing-parameters-in-urls" target="_blank" rel="noopener noreffer ">官方文档&lt;/a>&lt;/p>
&lt;p>我们经常需要在请求中加参数，比如一些分页信息，每页返回的资源数量等。&lt;/p>
&lt;p>如果我们手工去构造这些参数的话，我们会在url后面接&lt;code>?&lt;/code>，然后传入key/value对，比如&lt;code>httpbin.org/get?key=val&lt;/code>。多个key/value对以&lt;code>&amp;amp;&lt;/code>分隔。&lt;/p>
&lt;p>在Requests里，我们一般使用&lt;code>params&lt;/code>关键字参数的方式，传入dict来传递url参数。比如，假设我们想传递&lt;code>key1=value1&lt;/code>和&lt;code>key2=value2&lt;/code>这2个参数，我们可以用下面的代码&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;gt;&amp;gt;&amp;gt;&lt;/span> &lt;span class="n">payload&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;key1&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;value1&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;key2&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;value2&amp;#39;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;gt;&amp;gt;&amp;gt;&lt;/span> &lt;span class="n">r&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">requests&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;http://httpbin.org/get&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">params&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">payload&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>可以通过url方法来查看requests帮我们构造的编码后的url&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; print(r.url)
http://httpbin.org/get?key2=value2&amp;amp;key1=value1
&lt;/code>&lt;/pre>&lt;p>我们还可以为同一个key传递一组数据，比如&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; payload = {&amp;#39;key1&amp;#39;: &amp;#39;value1&amp;#39;, &amp;#39;key2&amp;#39;: [&amp;#39;value2&amp;#39;, &amp;#39;value3&amp;#39;]}

&amp;gt;&amp;gt;&amp;gt; r = requests.get(&amp;#39;http://httpbin.org/get&amp;#39;, params=payload)
&amp;gt;&amp;gt;&amp;gt; print(r.url)
http://httpbin.org/get?key1=value1&amp;amp;key2=value2&amp;amp;key2=value3
&lt;/code>&lt;/pre>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1416339442236-8ceb164046f8?w=300"
 data-srcset="https://images.unsplash.com/photo-1416339442236-8ceb164046f8?w=300, https://images.unsplash.com/photo-1416339442236-8ceb164046f8?w=300 1.5x, https://images.unsplash.com/photo-1416339442236-8ceb164046f8?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1416339442236-8ceb164046f8?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（七）JUnit 断言方法</title><link>https://itest2025.pages.dev/tutorials/31-007-%E4%B8%83junit-%E6%96%AD%E8%A8%80%E6%96%B9%E6%B3%95/</link><pubDate>Mon, 13 Nov 2017 12:35:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/31-007-%E4%B8%83junit-%E6%96%AD%E8%A8%80%E6%96%B9%E6%B3%95/</guid><description>&lt;h4 id="junit-断言方法">JUnit 断言方法&lt;/h4>
&lt;hr>
&lt;p>JUnit 所提供的断言方法:&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">方法&lt;/th>
 &lt;th style="text-align: left">说明&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">assertArrayEquals(expecteds, actuals)&lt;/td>
 &lt;td style="text-align: left">查看两个数组是否相等。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">assertEquals(expected, actual)&lt;/td>
 &lt;td style="text-align: left">查看两个对象是否相等。类似于字符串比较使用的equals()方法。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">assertNotEquals(first, second)&lt;/td>
 &lt;td style="text-align: left">查看两个对象是否不相等。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">assertNull(object)&lt;/td>
 &lt;td style="text-align: left">查看对象是否为空。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">assertNotNull(object)&lt;/td>
 &lt;td style="text-align: left">查看对象是否不为空。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">assertSame(expected, actual)&lt;/td>
 &lt;td style="text-align: left">查看两个对象的引用是否相等。类似于使用“==”比较两个对象。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">assertNotSame(unexpected, actual)&lt;/td>
 &lt;td style="text-align: left">查看两个对象的引用是否不相等。类似于使用“!=”比较两个对象。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">assertTrue(condition)&lt;/td>
 &lt;td style="text-align: left">查看运行结果是否为true。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">assertFalse(condition)&lt;/td>
 &lt;td style="text-align: left">查看运行结果是否为false。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">assertThat(actual, matcher)&lt;/td>
 &lt;td style="text-align: left">查看实际值是否满足指定的条件。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">fail()&lt;/td>
 &lt;td style="text-align: left">让测试失败。&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h4 id="例子">例子&lt;/h4>
&lt;hr>
&lt;p>关于断言方法，我们前面用得最多的是 &lt;strong>assertEquals&lt;/strong> ，用于断言两个对象是否相等。这里再介绍一个 &lt;strong>assertTrue&lt;/strong> 的使用。&lt;/p>
&lt;p>创建 AssertTest 测试类（包了含被测试方法）：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.*&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.Assert.*&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">AssertTest&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="cm">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * 判断一个数是否为素数
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> */&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Boolean&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">Prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Math&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sqrt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="o">++&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">%&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">==&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">0&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">return&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">return&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">testPrime&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">7&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertTrue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">AssertTest&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">Prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">));&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Prime()&lt;/strong> 方法用于判断一个数是否为素数（只能被1和它本身整除的数），并返回 True 或 False ，在测试用例中通过 &lt;strong>assertTrue&lt;/strong> 来断言结果。&lt;/p></description></item><item><title>7. 各种断言方法</title><link>https://itest2025.pages.dev/tutorials/35-007-7-%E5%90%84%E7%A7%8D%E6%96%AD%E8%A8%80%E6%96%B9%E6%B3%95/</link><pubDate>Sat, 04 Nov 2017 06:23:31 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/35-007-7-%E5%90%84%E7%A7%8D%E6%96%AD%E8%A8%80%E6%96%B9%E6%B3%95/</guid><description>&lt;h3 id="背景">背景&lt;/h3>
&lt;p>unittest支持各种断言方法。&lt;/p>
&lt;h3 id="断言列表">断言列表&lt;/h3>
&lt;p>&lt;a href="https://docs.python.org/2/library/unittest.html" target="_blank" rel="noopener noreffer ">官方文档&lt;/a>&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>方法&lt;/th>
 &lt;th>检查点&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>assertEqual(a, b)&lt;/td>
 &lt;td>a == b&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>assertNotEqual(a, b)&lt;/td>
 &lt;td>a != b&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>assertTrue(x)&lt;/td>
 &lt;td>bool(x) is True&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>assertFalse(x)&lt;/td>
 &lt;td>bool(x) is False&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>assertIs(a, b)&lt;/td>
 &lt;td>a is b&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>assertIsNot(a, b)&lt;/td>
 &lt;td>a is not b&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>assertIsNone(x)&lt;/td>
 &lt;td>x is None&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>assertIsNotNone(x)&lt;/td>
 &lt;td>x is not None&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>assertIn(a, b)&lt;/td>
 &lt;td>a in b&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>assertNotIn(a, b)&lt;/td>
 &lt;td>a not in b&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>assertIsInstance(a, b)&lt;/td>
 &lt;td>isinstance(a, b)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>assertNotIsInstance(a, b)&lt;/td>
 &lt;td>not isinstance(a, b)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>assertRaises(exc, fun, *args, **kwds)&lt;/td>
 &lt;td>fun(*args, **kwds) raises exc&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>assertRaisesRegexp(exc, r, fun, *args, **kwds)&lt;/td>
 &lt;td>fun(*args, **kwds) raises exc and the message matches regex r&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>assertAlmostEqual(a, b)&lt;/td>
 &lt;td>round(a-b, 7) == 0&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>assertNotAlmostEqual(a, b)&lt;/td>
 &lt;td>round(a-b, 7) != 0&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>assertGreater(a, b)&lt;/td>
 &lt;td>a &amp;gt; b	2.7&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>assertGreaterEqual(a, b)&lt;/td>
 &lt;td>a &amp;gt;= b&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>assertLess(a, b)&lt;/td>
 &lt;td>a &amp;lt; b&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>assertLessEqual(a, b)&lt;/td>
 &lt;td>a &amp;lt;= b&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>assertRegexpMatches(s, r)&lt;/td>
 &lt;td>r.search(s)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>assertNotRegexpMatches(s, r)&lt;/td>
 &lt;td>not r.search(s)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>assertItemsEqual(a, b)&lt;/td>
 &lt;td>sorted(a) == sorted(b) 也支持unhashable对象&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>assertDictContainsSubset(a, b)&lt;/td>
 &lt;td>a里面所有的键值对都在b中存在&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h3 id="自己动手">自己动手&lt;/h3>
&lt;p>大家可以自己动手亲自尝试使用这些断言方法。&lt;/p></description></item><item><title>7. 获取用户输入</title><link>https://itest2025.pages.dev/tutorials/28-007-7-%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E8%BE%93%E5%85%A5/</link><pubDate>Wed, 01 Nov 2017 08:17:22 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/28-007-7-%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E8%BE%93%E5%85%A5/</guid><description>&lt;h3 id="获取用户的输入">获取用户的输入&lt;/h3>
&lt;p>大部分的软件可能都需要接收用户的输入，比如&lt;/p>
&lt;ul>
&lt;li>登录的功能，需要用户输入用户名密码之类&lt;/li>
&lt;li>发微信，需要用户输入发送的信息&lt;/li>
&lt;li>美化图片，需要用户选择滤镜等&lt;/li>
&lt;/ul>
&lt;p>这一节里我们将学习怎么从命令行里获取用户的输入。&lt;/p>
&lt;p>在python里，我们可以简单的使用&lt;code>input()&lt;/code>函数来获取用户输入的信息，并保存在变量里。&lt;/p>
&lt;p>在调用&lt;code>input(message)&lt;/code>函数时，我们可以在命令行将message打印出来展示给用户。&lt;/p>
&lt;h3 id="背景">背景&lt;/h3>
&lt;p>我们实现个简单的用例生成器，通过提示用户输入用例的相应部分，最后组合成1个完整的用例。&lt;/p>
&lt;h3 id="代码实现">代码实现&lt;/h3>
&lt;p>新建名为&lt;code>gen_test_case.py&lt;/code>，内容如下&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">case_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">input&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;请输入用例名称:&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">test_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">input&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;请输入用到的测试数据，比如: 测试站点=www.itest.info:&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">test_steps&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">input&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;请输入测试步骤:&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">test_assert&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">input&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;请输入测试断言(预期结果):&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">formatter&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">用例名称: &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">测试数据: &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">测试步骤: &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">测试断言: &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">formatter&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">case_name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">test_data&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">test_steps&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">test_assert&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行">运行&lt;/h3>
&lt;p>在命令行中使用下面的命令去执行代码&lt;/p>
&lt;pre tabindex="0">&lt;code>$python gen_test_case.py
&lt;/code>&lt;/pre>&lt;h3 id="你应该可以看到">你应该可以看到&lt;/h3>
&lt;p>按照下面展示的情况进行输入，如果没有出错的话，你应该可以看到命令行窗口显示如下的内容&lt;/p>
&lt;pre tabindex="0">&lt;code>请输入用例名称:
正常登录
请输入用到的测试数据，比如: 测试站点=www.itest.info:
用户名=example;密码=example
请输入测试步骤:
略
请输入测试断言(预期结果):
测试断言: 应该跳转到www.itest.info/login_success页面，并出现&amp;#34;登录成功&amp;#34;的提示

用例名称: 正常登录
测试数据: 用户名=example;密码=example
测试步骤: 略
测试断言: 测试断言: 应该跳转到www.itest.info/login_success页面，并出现&amp;#34;登录成功&amp;#34;的提示
&lt;/code>&lt;/pre>&lt;h3 id="动手时间">动手时间&lt;/h3>
&lt;ul>
&lt;li>在命令行里输入&lt;code>python -m pydoc input&lt;/code>，看一下输出的结果是什么&lt;/li>
&lt;li>在查看pydoc的时候，按&lt;code>q&lt;/code>可以退出&lt;/li>
&lt;li>去网络上搜索一下pydoc的作用是什么&lt;/li>
&lt;li>使用pydoc去了解一下open, file, os和sys的作用&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1573164574511-73c773193279?w=300"
 data-srcset="https://images.unsplash.com/photo-1573164574511-73c773193279?w=300, https://images.unsplash.com/photo-1573164574511-73c773193279?w=300 1.5x, https://images.unsplash.com/photo-1573164574511-73c773193279?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1573164574511-73c773193279?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>7.常见套路</title><link>https://itest2025.pages.dev/tutorials/25-007-7%E5%B8%B8%E8%A7%81%E5%A5%97%E8%B7%AF/</link><pubDate>Sat, 28 Oct 2017 07:22:42 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/25-007-7%E5%B8%B8%E8%A7%81%E5%A5%97%E8%B7%AF/</guid><description>&lt;p>在使用pytest的时候，下面这些问题我们可能会经常遇到，这里给出官方的解决方案，按照套路来执行就可以了。&lt;/p>
&lt;h3 id="基础用法">基础用法&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="https://docs.pytest.org/en/latest/example/simple.html#pass-different-values-to-a-test-function-depending-on-command-line-options" target="_blank" rel="noopener noreffer ">把命令行参数传入到用例&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.pytest.org/en/latest/example/simple.html#dynamically-adding-command-line-options" target="_blank" rel="noopener noreffer ">动态添加命令行参数&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.pytest.org/en/latest/example/simple.html#control-skipping-of-tests-according-to-command-line-option" target="_blank" rel="noopener noreffer ">根据命令行参数来忽略用例执行&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.pytest.org/en/latest/example/simple.html#writing-well-integrated-assertion-helpers" target="_blank" rel="noopener noreffer ">编写集成度更好的辅助断言&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.pytest.org/en/latest/example/simple.html#detect-if-running-from-within-a-pytest-run" target="_blank" rel="noopener noreffer ">判断是否由pytest执行&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.pytest.org/en/latest/example/simple.html#adding-info-to-test-report-header" target="_blank" rel="noopener noreffer ">在测试报告的头部添加内容&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.pytest.org/en/latest/example/simple.html#profiling-test-duration" target="_blank" rel="noopener noreffer ">统计用例运行时间&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.pytest.org/en/latest/example/simple.html#profiling-test-duration" target="_blank" rel="noopener noreffer ">定义测试步骤，也就是让用例按照一定的顺序执行&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.pytest.org/en/latest/example/simple.html#package-directory-level-fixtures-setups" target="_blank" rel="noopener noreffer ">Package/Directory-level fixtures (setups)&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.pytest.org/en/latest/example/simple.html#post-process-test-reports-failures" target="_blank" rel="noopener noreffer ">在报告和用例失败之前添加钩子&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.pytest.org/en/latest/example/simple.html#making-test-result-information-available-in-fixtures" target="_blank" rel="noopener noreffer ">在fixtures中访问测试结果&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.pytest.org/en/latest/example/simple.html#pytest-current-test-environment-variable" target="_blank" rel="noopener noreffer ">PYTEST_CURRENT_TEST环境变量&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.pytest.org/en/latest/example/simple.html#freezing-pytest" target="_blank" rel="noopener noreffer ">冻结pytest&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="参数化">参数化&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="https://docs.pytest.org/en/latest/example/parametrize.html#generating-parameters-combinations-depending-on-command-line" target="_blank" rel="noopener noreffer ">根据命令行参数来组合测试参数&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.pytest.org/en/latest/example/parametrize.html#generating-parameters-combinations-depending-on-command-line" target="_blank" rel="noopener noreffer ">配置test ID&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.pytest.org/en/latest/example/parametrize.html#a-quick-port-of-testscenarios" target="_blank" rel="noopener noreffer ">快速创建测试场景的功能&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.pytest.org/en/latest/example/parametrize.html#deferring-the-setup-of-parametrized-resources" target="_blank" rel="noopener noreffer ">延迟参数资源加载&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.pytest.org/en/latest/example/parametrize.html#apply-indirect-on-particular-arguments" target="_blank" rel="noopener noreffer ">间接参数&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.pytest.org/en/latest/example/parametrize.html#parametrizing-test-methods-through-per-class-configuration" target="_blank" rel="noopener noreffer ">为不同的方法设置不同的参数&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.pytest.org/en/latest/example/parametrize.html#indirect-parametrization-with-multiple-fixtures" target="_blank" rel="noopener noreffer ">在多个fixture中使用间接参数&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.pytest.org/en/latest/example/parametrize.html#indirect-parametrization-of-optional-implementations-imports" target="_blank" rel="noopener noreffer ">Indirect parametrization of optional implementations/imports&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.pytest.org/en/latest/example/parametrize.html#set-marks-or-test-id-for-individual-parametrized-test" target="_blank" rel="noopener noreffer ">单独的为每个参数化用例设置标记和ID&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p></description></item><item><title>7. 判断元素是否存在</title><link>https://itest2025.pages.dev/tutorials/43-007-7-%E5%88%A4%E6%96%AD%E5%85%83%E7%B4%A0%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8/</link><pubDate>Tue, 24 Oct 2017 06:55:26 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/43-007-7-%E5%88%A4%E6%96%AD%E5%85%83%E7%B4%A0%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8/</guid><description>&lt;h3 id="is_element_present">is_element_present&lt;/h3>
&lt;p>判断元素是否存在。所有的容器类(BasePage, Container和Logical Container)都有&lt;code>is_element_present&lt;/code>方法，如果对应名称的元素在页面上存在，该方法返回true。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium.webdriver.common.by&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">By&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">webium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">BasePage&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Find&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">PresencePage&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BasePage&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">class_info&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Find&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">by&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">CSS_SELECTOR&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;a[href*=&amp;#34;/newclass&amp;#34;]&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">faq&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Find&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">by&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">CSS_SELECTOR&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;a[href*=&amp;#34;/faq&amp;#34;]&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">super&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">PresencePage&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;http://itest.info&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">page&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PresencePage&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">open&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;This should be True: &amp;#39;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">is_element_present&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;class_info&amp;#39;&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;This should be False: &amp;#39;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">is_element_present&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;no_such_link&amp;#39;&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>注意：如果是通过Finds去定位的一组元素，我们也可以调用&lt;code>is_element_present&lt;/code>方法来判断这组元素的存在性。如果这一组元素全部存在，返回True,如果有任意1个元素不存在，返回False。&lt;/p>
&lt;h3 id="just_in_dom">just_in_dom&lt;/h3>
&lt;p>默认情况下，&lt;code>is_element_prasent&lt;/code>方法只有在这个元素可见的时候返回True。如果我们需要元素存在于dom中就返回True的话，那么设置&lt;code>just_in_dom=True&lt;/code>&lt;/p>
&lt;h3 id="timeout">timeout&lt;/h3>
&lt;p>timeout是等待&lt;code>is_element_prasent&lt;/code>返回True的时间，单位是秒。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;This should be True: &amp;#39;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">page&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">is_element_present&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;class_info&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">just_in_dom&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">timeout&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1501556466850-7c9fa1fccb4c?w=300"
 data-srcset="https://images.unsplash.com/photo-1501556466850-7c9fa1fccb4c?w=300, https://images.unsplash.com/photo-1501556466850-7c9fa1fccb4c?w=300 1.5x, https://images.unsplash.com/photo-1501556466850-7c9fa1fccb4c?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1501556466850-7c9fa1fccb4c?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>收藏清单: python测试框架最全资源汇总</title><link>https://itest2025.pages.dev/tutorials/34-007-%E6%94%B6%E8%97%8F%E6%B8%85%E5%8D%95-python%E6%B5%8B%E8%AF%95%E6%A1%86%E6%9E%B6%E6%9C%80%E5%85%A8%E8%B5%84%E6%BA%90%E6%B1%87%E6%80%BB/</link><pubDate>Fri, 20 Oct 2017 08:19:06 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/34-007-%E6%94%B6%E8%97%8F%E6%B8%85%E5%8D%95-python%E6%B5%8B%E8%AF%95%E6%A1%86%E6%9E%B6%E6%9C%80%E5%85%A8%E8%B5%84%E6%BA%90%E6%B1%87%E6%80%BB/</guid><description>&lt;h2 id="xunit-frameworks单元测试框架">xUnit frameworks(单元测试框架)&lt;/h2>
&lt;ul>
&lt;li>frameworks 框架
&lt;ul>
&lt;li>&lt;a href="https://docs.python.org/library/unittest.html" target="_blank" rel="noopener noreffer ">unittest&lt;/a> - python自带的单元测试库，开箱即用&lt;/li>
&lt;li>&lt;a href="https://pypi.python.org/pypi/unittest2" target="_blank" rel="noopener noreffer ">unittest2&lt;/a> - 加强版的单元测试框架，适用于Python 2.7以及后续版本&lt;/li>
&lt;li>&lt;a href="http://pytest.org/" target="_blank" rel="noopener noreffer ">pytest&lt;/a> - 成熟且功能强大的单元测试框架&lt;/li>
&lt;li>&lt;a href="http://plugincompat.herokuapp.com/" target="_blank" rel="noopener noreffer ">plugincompat&lt;/a> - pytest的执行及兼容性插件&lt;/li>
&lt;li>&lt;a href="https://nose.readthedocs.org/en/latest/" target="_blank" rel="noopener noreffer ">nosetests&lt;/a> - 让python测试更容易一点&lt;/li>
&lt;li>&lt;a href="https://github.com/slash-testing/slash" target="_blank" rel="noopener noreffer ">slash&lt;/a> - python实现的单元测试框架&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>extensions 扩展
&lt;ul>
&lt;li>&lt;a href="https://pythonhosted.org/proboscis/" target="_blank" rel="noopener noreffer ">proboscis&lt;/a> - 仿TestNG扩展了unittest模块以及Nose的功能&lt;/li>
&lt;li>&lt;a href="https://github.com/wgnet/grail" target="_blank" rel="noopener noreffer ">grail&lt;/a> - 可以让你一步一步编写测试用例的库&lt;/li>
&lt;li>&lt;a href="https://github.com/Yelp/Testify/" target="_blank" rel="noopener noreffer ">testify&lt;/a> - 单元测试框架，提供了加强型fixture，用例切割并行运行，testrunner高亮及详尽的log和report功能&lt;/li>
&lt;li>&lt;a href="http://twistedmatrix.com/trac/wiki/TwistedTrial" target="_blank" rel="noopener noreffer ">trial&lt;/a> - unittest模块的扩展，提供了命令行的testrunner工具以及代码覆盖率的整合，跟nose差不多&lt;/li>
&lt;li>&lt;a href="https://launchpad.net/subunit" target="_blank" rel="noopener noreffer ">subunit&lt;/a> - 提供了unittest在另一个进程执行用例并汇总测试数据的能力&lt;/li>
&lt;li>&lt;a href="https://launchpad.net/testresources" target="_blank" rel="noopener noreffer ">testresources&lt;/a> - 提供了多用例间管理测试数据的机制，兼容unittest&lt;/li>
&lt;li>&lt;a href="https://launchpad.net/testtools" target="_blank" rel="noopener noreffer ">testtools&lt;/a> - 为Twisted和Bazaar提供的unittest扩展&lt;/li>
&lt;li>&lt;a href="https://www.mems-exchange.org/software/DurusWorks/" target="_blank" rel="noopener noreffer ">Sancho&lt;/a> - 运行用例，并为失败的用例提供报告，但仅限于此&lt;/li>
&lt;li>&lt;a href="https://pypi.python.org/pypi/zope.testing" target="_blank" rel="noopener noreffer ">zope.testing&lt;/a> - testrunner，提供了不错的debuge能力，并且集成了代码覆盖率。可以跟zope项目使用，也可以用在非zope项目上&lt;/li>
&lt;li>&lt;a href="http://pythoscope.org/" target="_blank" rel="noopener noreffer ">pythoscope&lt;/a> - 自动或半自动为遗留的python系统创建测试用例的工具&lt;/li>
&lt;li>&lt;a href="http://www.logilab.org/project/logilab-common/" target="_blank" rel="noopener noreffer ">testlib&lt;/a> - 更强大的unittest，更多的断言，支持module级的setup/teardown，skip test等&amp;hellip;&lt;/li>
&lt;li>&lt;a href="https://pypi.python.org/pypi/dutest" target="_blank" rel="noopener noreffer ">dutest&lt;/a> - An object oriented interface to retrieve unittest test cases out of doctests. Hides initialization from doctests by allowing setUp and tearDown for each interactive example. Allows control over all the options provided by doctest. Specialized classes allow selective test discovery across a package hierarchy.&lt;/li>
&lt;li>&lt;a href="https://github.com/CleanCut/green" target="_blank" rel="noopener noreffer ">green&lt;/a> - Green是一个简洁多彩的testrunner，跟nose很像&lt;/li>
&lt;li>&lt;a href="https://github.com/txels/ddt" target="_blank" rel="noopener noreffer ">ddt&lt;/a> - 让unittest 支持 Data-Driven&lt;/li>
&lt;li>&lt;a href="https://github.com/kpodl/pytractor" target="_blank" rel="noopener noreffer ">pytractor&lt;/a> Selenium python bindings的扩展. 目的是让angular项目的测试更简单&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="tdd--atdd--bdd">TDD \ ATDD \ BDD&lt;/h2>
&lt;ul>
&lt;li>BDD
&lt;ul>
&lt;li>&lt;a href="https://pypi.python.org/pypi/behave" target="_blank" rel="noopener noreffer ">behave&lt;/a> - BDD 框架&lt;/li>
&lt;li>&lt;a href="http://lettuce.it/" target="_blank" rel="noopener noreffer ">lettuce&lt;/a> - 又一个BDD框架
&lt;ul>
&lt;li>&lt;a href="https://github.com/telefonicaid/lettuce-tools" target="_blank" rel="noopener noreffer ">lettuce-tools&lt;/a> - 一整套lettuce扩展，让BDD更加简单&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="https://github.com/benjamin-hodgson/Contexts" target="_blank" rel="noopener noreffer ">contexts&lt;/a> - Python的描述性测试工具&lt;/li>
&lt;li>&lt;a href="http://nestorsalceda.github.io/mamba/" target="_blank" rel="noopener noreffer ">mamba&lt;/a> - python的definitive testing 工具&lt;/li>
&lt;li>&lt;a href="http://heynemann.github.io/pyvows/" target="_blank" rel="noopener noreffer ">pyvows&lt;/a> - 异步的行为驱动开发测试工具&lt;/li>
&lt;li>&lt;a href="https://github.com/pytest-dev/pytest-bdd" target="_blank" rel="noopener noreffer ">pytest-bdd&lt;/a> - py.test runner的BDD库&lt;/li>
&lt;li>&lt;a href="http://robotframework.org/" target="_blank" rel="noopener noreffer ">robotframework&lt;/a> - 最有名的acceptance test-driven development (ATDD)测试框架
&lt;ul>
&lt;li>&lt;a href="https://github.com/fkromer/awesome-robotframework" target="_blank" rel="noopener noreffer ">awesome-robotframework&lt;/a> - 各种rf的扩展库&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="https://github.com/radish-bdd/radish" target="_blank" rel="noopener noreffer ">radish-bdd&lt;/a> - BDD框架，支持gherkin语言&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Assertions 断言
&lt;ul>
&lt;li>&lt;a href="https://github.com/drslump/pyshould" target="_blank" rel="noopener noreffer ">pyshould&lt;/a> - 基于pyhamcrest的Should style断言&lt;/li>
&lt;li>&lt;a href="https://github.com/hamcrest/PyHamcrest" target="_blank" rel="noopener noreffer ">pyhamcrest&lt;/a> - python版的Hamcrest matchers&lt;/li>
&lt;li>&lt;a href="https://github.com/gabrielfalcao/sure" target="_blank" rel="noopener noreffer ">sure&lt;/a> -python实现的测试库,提供了强大灵活的断言&lt;/li>
&lt;li>&lt;a href="https://github.com/ActivisionGameScience/assertpy" target="_blank" rel="noopener noreffer ">assertpy&lt;/a> - 巨简单的python单元测试断言库，提供了优雅流利的API. 支持Python 2 和 3.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Mocking
&lt;ul>
&lt;li>&lt;a href="https://pypi.python.org/pypi/mock" target="_blank" rel="noopener noreffer ">mock&lt;/a> - python实现的Mocking和Patching库&lt;/li>
&lt;li>&lt;a href="http://github.com/nsigustavo/ludibrio/" target="_blank" rel="noopener noreffer ">Ludibrio&lt;/a> - 用python实现的优雅的test doubles框架(mocks, stubs, spy, and dummies).&lt;/li>
&lt;li>&lt;a href="https://github.com/dropbox/responses" target="_blank" rel="noopener noreffer ">responses&lt;/a> - mock请求的 Python测试工具库&lt;/li>
&lt;li>&lt;a href="https://pypi.python.org/pypi/doublex" target="_blank" rel="noopener noreffer ">doublex&lt;/a> - 强大的 test doubles 框架&lt;/li>
&lt;li>&lt;a href="https://github.com/spulec/freezegun" target="_blank" rel="noopener noreffer ">freezegun&lt;/a> - 通过mocking datetime模块实现时光穿梭&lt;/li>
&lt;li>&lt;a href="http://falcao.it/HTTPretty/" target="_blank" rel="noopener noreffer ">httpretty&lt;/a> - HTTP请求的mock工具&lt;/li>
&lt;li>&lt;a href="https://github.com/patrys/httmock" target="_blank" rel="noopener noreffer ">httmock&lt;/a> - requests的mock工具，支持Python 2.6+ and 3.2+.&lt;/li>
&lt;li>&lt;a href="https://github.com/pretenders/pretenders" target="_blank" rel="noopener noreffer ">pretenders&lt;/a> - 测试用的fake server&lt;/li>
&lt;li>&lt;a href="https://github.com/tomashanacek/mock-server" target="_blank" rel="noopener noreffer ">mock-server&lt;/a> - 简单的mock sever，支持REST and XML-RPC API，还有基于tornado的管理界面&lt;/li>
&lt;li>&lt;a href="https://github.com/kevin1024/vcrpy" target="_blank" rel="noopener noreffer ">VCR.py&lt;/a> - 自动 mock HTTP 交互 让测试更简单快速&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p></description></item><item><title>（七）实战：构建 GitHub 项目(中)</title><link>https://itest2025.pages.dev/tutorials/18-007-%E4%B8%83%E5%AE%9E%E6%88%98%E6%9E%84%E5%BB%BA-github-%E9%A1%B9%E7%9B%AE%E4%B8%AD/</link><pubDate>Mon, 16 Oct 2017 11:50:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/18-007-%E4%B8%83%E5%AE%9E%E6%88%98%E6%9E%84%E5%BB%BA-github-%E9%A1%B9%E7%9B%AE%E4%B8%AD/</guid><description>&lt;p>前提工作已经完成，接下来创建 GitHub 的项目构建。&lt;/p>
&lt;h2 id="创建-github-项目的构建">创建 GitHub 项目的构建&lt;/h2>
&lt;hr>
&lt;h4 id="1新建项目">1、新建项目&lt;/h4>
&lt;hr>
&lt;p>在 Jenkins 首页，点击 “&lt;strong>新建&lt;/strong>”。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/jenkins_github_project.png"
 data-srcset="http://img.testclass.net/jenkins_github_project.png, http://img.testclass.net/jenkins_github_project.png 1.5x, http://img.testclass.net/jenkins_github_project.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/jenkins_github_project.png"
 title="http://img.testclass.net/jenkins_github_project.png" />&lt;/p>
&lt;p>设置项目名称：GitHub project&lt;/p>
&lt;p>选择“&lt;strong>构建一个自由风格的软件项目&lt;/strong>”&lt;/p>
&lt;h4 id="2添加-github-上的项目">2、添加 GitHub 上的项目&lt;/h4>
&lt;hr>
&lt;p>勾选 &lt;strong>* GitHub Project&lt;/strong> 选项&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/jenkins_github_project2.png"
 data-srcset="http://img.testclass.net/jenkins_github_project2.png, http://img.testclass.net/jenkins_github_project2.png 1.5x, http://img.testclass.net/jenkins_github_project2.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/jenkins_github_project2.png"
 title="http://img.testclass.net/jenkins_github_project2.png" />&lt;/p>
&lt;ul>
&lt;li>Project url ：设置 github 的项目地址。&lt;/li>
&lt;/ul>
&lt;h4 id="3设置git">3、设置Git&lt;/h4>
&lt;hr>
&lt;p>勾选 &lt;strong>* Git&lt;/strong> 选项&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/jenkins_github_git_setting.png"
 data-srcset="http://img.testclass.net/jenkins_github_git_setting.png, http://img.testclass.net/jenkins_github_git_setting.png 1.5x, http://img.testclass.net/jenkins_github_git_setting.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/jenkins_github_git_setting.png"
 title="http://img.testclass.net/jenkins_github_git_setting.png" />&lt;/p>
&lt;ul>
&lt;li>Repository URL: 填写 GitHub 项目地址&lt;/li>
&lt;li>credentials ： 设置资格证书，听过 &lt;strong>add&lt;/strong> 添加账号。&lt;/li>
&lt;li>Branch Specifier(blank for &amp;lsquo;any&amp;rsquo;) ： 默认 &lt;code>*/master&lt;/code> 不用修改。&lt;/li>
&lt;/ul>
&lt;h4 id="4设置触发条件">4、设置触发条件&lt;/h4>
&lt;hr>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/jenkins_github_building_time.png"
 data-srcset="http://img.testclass.net/jenkins_github_building_time.png, http://img.testclass.net/jenkins_github_building_time.png 1.5x, http://img.testclass.net/jenkins_github_building_time.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/jenkins_github_building_time.png"
 title="http://img.testclass.net/jenkins_github_building_time.png" />&lt;/p></description></item><item><title>（七）Locust 的类和方法</title><link>https://itest2025.pages.dev/tutorials/38-007-%E4%B8%83locust-%E7%9A%84%E7%B1%BB%E5%92%8C%E6%96%B9%E6%B3%95/</link><pubDate>Mon, 16 Oct 2017 09:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/38-007-%E4%B8%83locust-%E7%9A%84%E7%B1%BB%E5%92%8C%E6%96%B9%E6%B3%95/</guid><description>&lt;p>针对你的业务，你如何进行测试测试，需要通过编写性能测试脚本实现。所以，我们要熟悉 Locust 提供了哪些类和方法，它们分别实现什么操作。&lt;/p>
&lt;h4 id="httplocust-类">HttpLocust 类&lt;/h4>
&lt;hr>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">locust&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">HttpLocust&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">TaskSet&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">task&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">UserTask&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">TaskSet&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@task&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">tc_index&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">client&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;/&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">UserOne&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">HttpLocust&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">task_set&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">UserTask&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">weight&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">min_wait&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1000&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_wait&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">3000&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">stop_timeout&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">5&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">host&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;https://www.baidu.com&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">UserTwo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">HttpLocust&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">weight&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">task_set&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">UserTask&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">host&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;https://www.baidu.com&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>每一个模拟的用户可以看做一个 HttpLocust 类的实例，HttpLocust 类有如下属性：&lt;/p>
&lt;ul>
&lt;li>task_set&lt;/li>
&lt;/ul>
&lt;p>指向一个 TaskSet 类，TaskSet 类定义了每个用户的行为。&lt;/p>
&lt;ul>
&lt;li>min_wait&lt;/li>
&lt;/ul>
&lt;p>用户执行任务之间等待时间的下界，单位：毫秒。如果TaskSet类中有覆盖，以TaskSet 中的定义为准。&lt;/p>
&lt;ul>
&lt;li>max_wait&lt;/li>
&lt;/ul>
&lt;p>用户执行任务之间等待时间的上界，单位：毫秒。如果TaskSet类中有覆盖，以TaskSet中的定义为准。&lt;/p>
&lt;ul>
&lt;li>host&lt;/li>
&lt;/ul>
&lt;p>如果是 Web 服务的测试，host 相当于是提供 URL 前缀的默认值，但是如果在命令行中指定了 &lt;code>--host&lt;/code> 选项，则以命令行中指定的为准。如果不是 Web 服务测试，使用默认的 None 就好。&lt;/p>
&lt;ul>
&lt;li>stop_timeout&lt;/li>
&lt;/ul>
&lt;p>设置 Locust 多少秒后超时，如果为 &lt;strong>None&lt;/strong> ,则不会超时。&lt;/p>
&lt;ul>
&lt;li>weight&lt;/li>
&lt;/ul>
&lt;p>一个Locust实例被挑选执行的权重，数值越大，执行频率越高。在一个 locustfile.py 文件中可以同时定义多个 HttpLocust 子类，然后分配他们的执行权重，例如：&lt;/p>
&lt;p>然后在终端启动测试：&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt; locust -f load_test.py UserOne UserTwo
&lt;/code>&lt;/pre>&lt;h4 id="taskset-类">TaskSet 类&lt;/h4>
&lt;hr>
&lt;p>TaskSet类定义了每个用户的任务集合，测试任务开始后，每个 Locust 用户会从 TaskSet 中随机挑选一个任务执行，然后随机等待 HttpLocust 类中定义的 min_wait和 max_wait 之间的一段时间，执行下一个任务。&lt;/p></description></item><item><title>07. 首次运行向导（新用户必看）</title><link>https://itest2025.pages.dev/tutorials/37-007-07-%E9%A6%96%E6%AC%A1%E8%BF%90%E8%A1%8C%E5%90%91%E5%AF%BC%E6%96%B0%E7%94%A8%E6%88%B7%E5%BF%85%E7%9C%8B/</link><pubDate>Mon, 16 Oct 2017 07:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/37-007-07-%E9%A6%96%E6%AC%A1%E8%BF%90%E8%A1%8C%E5%90%91%E5%AF%BC%E6%96%B0%E7%94%A8%E6%88%B7%E5%BF%85%E7%9C%8B/</guid><description>&lt;h1 id="首次运行">首次运行&lt;/h1>
&lt;h2 id="向导功能">向导功能&lt;/h2>
&lt;blockquote>
&lt;ul>
&lt;li>假如你计算机上在过去已经有安装过 IntelliJ IDEA 14 的版本，且你在卸载 IntelliJ IDEA 的过程中，IntelliJ IDEA 的配置文件目录都没有删除，那安装新版本之后是不会有首次运行的功能向导的。&lt;/li>
&lt;li>假如你计算机上没有安装过 IntelliJ IDEA，或是 卸载 IntelliJ IDEA 过程中你删除了 IntelliJ IDEA 的配置文件目录，则当你双击运行桌面上的 IntelliJ IDEA 快捷图标，将进入下面介绍的向导过程。&lt;/li>
&lt;/ul>&lt;/blockquote>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/vii-a-first-run-wizard-1.jpg"
 data-srcset="http://img.testclass.net/vii-a-first-run-wizard-1.jpg, http://img.testclass.net/vii-a-first-run-wizard-1.jpg 1.5x, http://img.testclass.net/vii-a-first-run-wizard-1.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/vii-a-first-run-wizard-1.jpg"
 title="向导步骤截图" />&lt;/p>
&lt;blockquote>
&lt;ul>
&lt;li>上图第一个单选按钮表示 IntelliJ IDEA 识别到我计算机上有 IntelliJ IDEA 13 版本的旧配置，如果我选择了该选项，则 IntelliJ IDEA 将自动把旧版本的配置文件转移到新版本的配置文件目录上。如果你计算机上首次安装一般是没有该选项的。&lt;/li>
&lt;li>上图第二个单选按钮表示你可以指定 IntelliJ IDEA 导入你计算机上存在其他目录的 IntelliJ IDEA 配置文件目录，如果你有的话。&lt;/li>
&lt;li>上图第三个单选按钮表示你没有任何早期版本的 IntelliJ IDEA 配置，你不导入任何配置，让 IntelliJ IDEA 生成一份新的配置。&lt;/li>
&lt;/ul>&lt;/blockquote>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/vii-a-first-run-wizard-2.jpg"
 data-srcset="http://img.testclass.net/vii-a-first-run-wizard-2.jpg, http://img.testclass.net/vii-a-first-run-wizard-2.jpg 1.5x, http://img.testclass.net/vii-a-first-run-wizard-2.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/vii-a-first-run-wizard-2.jpg"
 title="向导步骤截图" />&lt;/p></description></item><item><title>（七）soapUI设置Auth</title><link>https://itest2025.pages.dev/tutorials/26-007-%E4%B8%83soapui%E8%AE%BE%E7%BD%AEauth/</link><pubDate>Wed, 20 Sep 2017 20:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/26-007-%E4%B8%83soapui%E8%AE%BE%E7%BD%AEauth/</guid><description>&lt;br>
#### 设置用户认证（Auth）
----
当我们请求一个接口时，一般需要认证，认证是判断用户是否有请求权限的常用手段。
&lt;p>参考前面学习的添加 SOAP 和 REST 请求。&lt;/p>
&lt;p>点击 &lt;strong>“Request 1”&lt;/strong> 窗口左下角 &lt;strong>“Auth”&lt;/strong> 按钮，Authoriaztion 选项中选择 &lt;strong>“add New Authoriaztion”&lt;/strong> ，在弹出的窗口中 Type 选择 &lt;strong>“Basic”&lt;/strong> 选项，点击 &lt;strong>“OK”&lt;/strong> 按钮，如下图。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/sopaui_add_auth.png"
 data-srcset="http://img.testclass.net/sopaui_add_auth.png, http://img.testclass.net/sopaui_add_auth.png 1.5x, http://img.testclass.net/sopaui_add_auth.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/sopaui_add_auth.png"
 title="http://img.testclass.net/sopaui_add_auth.png" />&lt;/p>
&lt;p>添加认证用户,如下图。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/sopaui_setting_auth.png"
 data-srcset="http://img.testclass.net/sopaui_setting_auth.png, http://img.testclass.net/sopaui_setting_auth.png 1.5x, http://img.testclass.net/sopaui_setting_auth.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/sopaui_setting_auth.png"
 title="http://img.testclass.net/sopaui_setting_auth.png" />&lt;/p>
&lt;p>填写用户认证 Username 和 Password ，勾选 &lt;strong>“Authenticate pre-emptvely”&lt;/strong> 选项。&lt;/p>
&lt;p>Username：用于填写基本认证的用户名。&lt;/p>
&lt;p>Password：用于填写基本认证的密码。&lt;/p>
&lt;p>Domain：域名是基本认证的可选项，设置为空。&lt;/p>
&lt;p>Pre-emptive auth：设置定义认证的行为。&lt;/p>
&lt;ul>
&lt;li>Use global preference ：用于定义HTTP设置为全局首选项。&lt;/li>
&lt;li>Authenticate pre-emptively：仅适用于此请求，不需要等待身份验证质询时发送凭据。&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1524219726159-3cbf91ce4b70?w=300"
 data-srcset="https://images.unsplash.com/photo-1524219726159-3cbf91ce4b70?w=300, https://images.unsplash.com/photo-1524219726159-3cbf91ce4b70?w=300 1.5x, https://images.unsplash.com/photo-1524219726159-3cbf91ce4b70?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1524219726159-3cbf91ce4b70?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>appium新手入门（7）—— Desired Capabilities</title><link>https://itest2025.pages.dev/tutorials/21-007-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A87-desired-capabilities/</link><pubDate>Thu, 07 Sep 2017 10:24:12 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/21-007-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A87-desired-capabilities/</guid><description>&lt;p>&lt;font color="blue">从后台统计来看，appium 系列的教程很受欢迎！于是，我继续更新，也希望你把这个教程推荐给更多学习 appium 的小伙伴！&lt;/font>&lt;/p>
&lt;h4 id="desired-capabilities">Desired Capabilities&lt;/h4>
&lt;hr>
&lt;p>Desired Capabilities 在启动 session 的时候是必须提供的。&lt;/p>
&lt;p>Desired Capabilities 本质上是以 key value 字典的方式存放，客户端将这些键值对发给服务端，告诉服务端我们想要怎么测试。它告诉 appium Server这样一些事情：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>本次测试是启动浏览器还是启动移动设备。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>是启动Andorid还是启动iOS。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>启动Android时，app的package是什么。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>启动Android时，app的activity是什么。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&amp;hellip;&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h4 id="desired-capabilities-配置">Desired Capabilities 配置&lt;/h4>
&lt;hr>
&lt;p>Appium 的 Desired Capabilities 基本配置如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">DesiredCapabilities&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">capabilities&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">DesiredCapabilities&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">capabilities&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">setCapability&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;deviceName&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;Android Emulator&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">capabilities&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">setCapability&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;automationName&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;Appium&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">capabilities&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">setCapability&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;platformName&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;Android&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">capabilities&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">setCapability&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;platformVersion&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;5.1&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">capabilities&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">setCapability&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;appPackage&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;com.android.calculator2&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">capabilities&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">setCapability&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;appActivity&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;.Calculator&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">WebDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">AndroidDriver&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">URL&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;http://127.0.0.1:4723/wd/hub&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">capabilities&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>
&lt;p>deviceName：启动哪种设备，是真机还是模拟器？iPhone Simulator，iPad Simulator，iPhone Retina 4-inch，Android Emulator，Galaxy S4&amp;hellip;&lt;/p>
&lt;/li>
&lt;li>
&lt;p>automationName：使用哪种自动化引擎。appium（默认）还是Selendroid。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>platformName：使用哪种移动平台。iOS, Android, orFirefoxOS。&lt;/p></description></item><item><title>JMeter官方文档：7. 创建FTP测试计划</title><link>https://itest2025.pages.dev/tutorials/22-007-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A37-%E5%88%9B%E5%BB%BAftp%E6%B5%8B%E8%AF%95%E8%AE%A1%E5%88%92/</link><pubDate>Thu, 24 Aug 2017 10:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/22-007-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A37-%E5%88%9B%E5%BB%BAftp%E6%B5%8B%E8%AF%95%E8%AE%A1%E5%88%92/</guid><description>&lt;p>&lt;a href="https://itest2025.pages.dev/2017/08/24/jmeter-translation-plans/" rel="">《JMeter官方文档&amp;ndash;翻译计划》&lt;/a> &lt;a href="http://jmeter.apache.org/usermanual/build-ftp-test-plan.html" target="_blank" rel="noopener noreffer ">原文地址&lt;/a>&lt;/p>
&lt;h2 id="7创建ftp测试计划">7.创建FTP测试计划&lt;/h2>
&lt;hr>
&lt;p>在这一章，你将学习如何创建一个基础的&lt;a href="http://jmeter.apache.org/usermanual/build-test-plan.html" target="_blank" rel="noopener noreffer ">测试计划&lt;/a>来测试FTP站点。你将在一个FTP站点上的两个文件中创建四个用户来发送请求。并且，你将告诉用户运行测试两次。所以，总的请求数是（4个用户）x（2个请求）x（重复2次）=16 FTP请求。&lt;/p>
&lt;p>为了构造测试计划，你需使用以下元件：&lt;a href="http://jmeter.apache.org/usermanual/test_plan.html#thread_group" target="_blank" rel="noopener noreffer ">线程组&lt;/a>，&lt;a href="http://jmeter.apache.org/usermanual/component_reference.html#FTP_Request" target="_blank" rel="noopener noreffer ">FTP请求&lt;/a>，&lt;a href="http://jmeter.apache.org/usermanual/component_reference.html#FTP_Request_Defaults" target="_blank" rel="noopener noreffer ">FTP默认请求&lt;/a>和&lt;a href="http://jmeter.apache.org/usermanual/component_reference.html#View_Results_in_Table" target="_blank" rel="noopener noreffer ">用表格察看结果&lt;/a>。&lt;/p>
&lt;h3 id="71-添加用户">7.1 添加用户&lt;/h3>
&lt;hr>
&lt;p>你要进行每一个JMeter测试计划的第一步是添加一个线程组元件。线程组告诉JMeter你想要模拟的用户数量，用户应该发送请求的频率，以及他们应该发送多少个请求。
继续添加线程组元件，首先选择测试计划，点击鼠标右键添加菜单，然后选择 &lt;strong>添加→线程组&lt;/strong>。&lt;/p>
&lt;p>现在你应该看到 &lt;strong>测试计划&lt;/strong> 下的 &lt;strong>线程组&lt;/strong> 元件。如果没有看到元件，单击测试计划元件“展开”测试计划树。&lt;/p>
&lt;p>接下来，你需要修改默认配置。如果你还没有选择 &lt;strong>线程组&lt;/strong> 元件，在测试计划树里选择它。现在你应该在JMeter窗口右侧看到线程组控制面板(请参见下面的图7.1)&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/thread_group.png"
 data-srcset="http://img.testclass.net/thread_group.png, http://img.testclass.net/thread_group.png 1.5x, http://img.testclass.net/thread_group.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/thread_group.png"
 title="http://img.testclass.net/thread_group.png" />&lt;/p>
&lt;p>图7.1 默认值的线程组&lt;/p>
&lt;p>首先为我们的线程组取一个更具描述性的名称。在名称文本域中，输入“FTP用户”。&lt;/p>
&lt;p>接下来将用户数（线程数）增加到4。&lt;/p>
&lt;p>在下一个文本域中，Ramp-Up Period（in seconds），使用默认值0秒。这个属性告诉JMeter在启动每个用户之间的时间间隔。例如，如果你在Ramp-Up Period（in seconds）中输入5秒，JMeter将在5秒内完成所有用户的启动。因此，如果我们有5个用户和一个5秒的Ramp-Up Period，那么启动用户之间的时间间隔将是1秒(5个用户/ 5秒= 1个用户每秒)。如果将值设置为0，则JMeter将立即启动所有用户。&lt;/p>
&lt;p>最后，在循环次数中输入值2。这个属性告诉JMeter重复测试的次数。要让JMeter重复一直运行你的测试计划，勾选永远的复选框。&lt;/p>
&lt;blockquote>
&lt;p>在大多数应用中你必须手动的保存你在控制面板中的改动。但是在JMeter中，控制面板能自动的保存你做的改动。比如你修改了一个元件的名称，在你离开控制面板后测试计划树会以新的文本来更新（比如选择另一个树元件时）。&lt;/p>&lt;/blockquote>
&lt;p>看下图7.2 中完整的FTP Users线程组。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/07_FTP_users_thread_group.png"
 data-srcset="http://img.testclass.net/07_FTP_users_thread_group.png, http://img.testclass.net/07_FTP_users_thread_group.png 1.5x, http://img.testclass.net/07_FTP_users_thread_group.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/07_FTP_users_thread_group.png"
 title="http://img.testclass.net/07_FTP_users_thread_group.png" />&lt;/p>
&lt;p>图7.2 FTP Users线程组&lt;/p>
&lt;h3 id="72-添加默认ftp请求配置">7.2 添加默认FTP请求配置&lt;/h3>
&lt;hr>
&lt;p>既然我们已经定义了我们的用户，那么是时候定义他们要执行的任务了。在本节中，你将为你的FTP请求指定默认设置。然后，在7.3节中，使用你在这里指定的一些默认设置中添加 &lt;strong>FTP请求&lt;/strong> 元件。&lt;/p></description></item><item><title>Google测试工师的一道面试题目</title><link>https://itest2025.pages.dev/tutorials/44-007-google%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%B8%88%E7%9A%84%E4%B8%80%E9%81%93%E9%9D%A2%E8%AF%95%E9%A2%98%E7%9B%AE/</link><pubDate>Thu, 24 Aug 2017 09:44:38 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/44-007-google%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%B8%88%E7%9A%84%E4%B8%80%E9%81%93%E9%9D%A2%E8%AF%95%E9%A2%98%E7%9B%AE/</guid><description>&lt;p>最近重读《Google软件测试之道》，其中有一道面向软件测试工程师的面试题非常考验测试人员的思维。拿来与你们分享，看看这样一道题，你能想到多少个测试点。&lt;/p>
&lt;p>题目：&lt;/p>
&lt;p>在一个Web测试页面上，有一个输入框，一个计数器（count）按钮，用于计算一个文本字符串中字母a出现的个数。这里的问题是，请设计一系列字符串用以测试这个Web页面。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/google_test_subject.png"
 data-srcset="http://img.testclass.net/google_test_subject.png, http://img.testclass.net/google_test_subject.png 1.5x, http://img.testclass.net/google_test_subject.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/google_test_subject.png"
 title="http://img.testclass.net/google_test_subject.png" />&lt;/p>
&lt;p>题目非常简单，看到这个题目不要上来就开始设计用例，最好能有一些思考，这样看起来更加“专业”。&lt;/p>
&lt;p>（题外话，我在参加产品需求评审的时候也会问许多问题，尤其是产品需求并没完全确定下来的时候，站在用户的角度，我也是用户啊，我是否喜欢这个功能？）&lt;/p>
&lt;p>所以，我第一个想到的是设计这个功能的背景，因为同样一个功能，在不同的背景下，测试需要考虑的点可能是不一样的。例如，同样是一个搜索功能，百度的搜索和淘宝的搜索就有很大不同，因为用户的使用场景完全不同，输入搜索的关键字和预期结果也不一样。&lt;/p>
&lt;p>当然，这只是一道题，你根据题目回答就好了。&lt;/p>
&lt;p>不过，我们仍然可以就题目本身来提一些问题：大写还是小写？只是英文么？计算完成后文本会被清除码？多次按下按钮会发生什么事情？…..&lt;/p>
&lt;p>接下来你假装有条不紊的设计用例（思考一会儿，然后再输入一串字符，然后再思考…），而不是看起来像monkey试图破坏软件（拼命的敲击键盘…）。&lt;/p>
&lt;ul>
&lt;li>“banana”：3（一个合法的英文字）。&lt;/li>
&lt;li>“A” 和“a”：1（一个简单有正常结果的合法输入）。&lt;/li>
&lt;li>“”：0（一个简单的结果为0的合法输入）。&lt;/li>
&lt;li>Null：0（简单的错误输入）。&lt;/li>
&lt;li>“AA” 和“aa”：2（个数大于1并且所有字符都为a/A的输入）。&lt;/li>
&lt;li>“b”：0（一个简单的非空合法输入，结果为0）。&lt;/li>
&lt;li>“aba”：2（目标字符出现在开头和结尾，以寻找循环边界错误）。&lt;/li>
&lt;li>“bab”：1（目标字符出现在中间）。&lt;/li>
&lt;li>space/tabs：N（空白字符与N个a的混合）。&lt;/li>
&lt;li>不包含a的长字符串：N（N大于0）。&lt;/li>
&lt;li>包含a的长字符串：N（N是a的倍数）。&lt;/li>
&lt;li>{java/C/HTML/JavaScript}：N是a出现的个数（可执行字符，或错误，或代码解释）。&lt;/li>
&lt;li>&amp;hellip;&lt;/li>
&lt;/ul>
&lt;p>更优秀的测试工程师，应该跳出输入本身，设计以下用例。&lt;/p>
&lt;ul>
&lt;li>质疑界面的外观、调色板和对比度（这与相关应用风格一致么？）&lt;/li>
&lt;li>文本框太小了，建议加长以便显示更长的输入字符串&lt;/li>
&lt;li>这个应用能否在同一台服务器上运行多个实例，多个用户同时使用是否会有问题。&lt;/li>
&lt;li>是否会根据用户的输入自动匹配内容？&lt;/li>
&lt;li>建议使用真实的数据，如从词典或书中选择输入内容。&lt;/li>
&lt;li>提出疑问：“输入的数据是否会被保存”，输入字符串可能包含地址或其他身份信息。&lt;/li>
&lt;li>输入HTML和JavaScrip，看是否会破坏页面渲染。&lt;/li>
&lt;li>尝试复制/粘贴字符串。&lt;/li>
&lt;li>提出疑问：“计算足够快么？在大并发下使用”。&lt;/li>
&lt;li>提出提问：“用户怎么找到该页面？”&lt;/li>
&lt;/ul>
&lt;p>还有一些测试点，只有经验丰富的测试工程师才会想到。&lt;/p>
&lt;ul>
&lt;li>意识到计算会通过URL-encodedHTTP GET请求传递到服务器，字符串可能会在网络传输时被截断，因此，无法保证支持多长的URL。&lt;/li>
&lt;li>建议将此功能参数化，为什么只对字母a计算呢？&lt;/li>
&lt;li>考虑计算其它语言中的a（α，Alpha）。&lt;/li>
&lt;li>考虑到该应用是否应该国际化。&lt;/li>
&lt;li>考虑编写脚本或者手工采样来探知字符串长度的上限，然后确保在此区间内功能正常。&lt;/li>
&lt;li>考虑背后的实现和代码。也许已经有一个计数器遍历该字符串。&lt;/li>
&lt;li>提出疑问：“HTTP POST方法和参数会被黑掉码？也许有安全漏洞？”&lt;/li>
&lt;li>用脚本创建各种有趣的排列组合和字符串特性，如长度、a的个数等，自动生成测试输入和验证。&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1552664730-d307ca884978?w=300"
 data-srcset="https://images.unsplash.com/photo-1552664730-d307ca884978?w=300, https://images.unsplash.com/photo-1552664730-d307ca884978?w=300 1.5x, https://images.unsplash.com/photo-1552664730-d307ca884978?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1552664730-d307ca884978?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>7.requests库</title><link>https://itest2025.pages.dev/tutorials/40-007-7requests%E5%BA%93/</link><pubDate>Thu, 24 Aug 2017 04:41:43 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/40-007-7requests%E5%BA%93/</guid><description>&lt;p>&lt;a href="http://docs.python-requests.org/en/master/" target="_blank" rel="noopener noreffer ">requests&lt;/a>库可以极大的简化我们发送http请求及获取响应的代码，简洁而优雅。&lt;/p>
&lt;h3 id="简单示例">简单示例&lt;/h3>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; import requests
&amp;gt;&amp;gt;&amp;gt; r = requests.get(&amp;#39;https://api.github.com/user&amp;#39;, auth=(&amp;#39;user&amp;#39;, &amp;#39;pass&amp;#39;))
&amp;gt;&amp;gt;&amp;gt; r.status_code
200
&amp;gt;&amp;gt;&amp;gt; r.headers[&amp;#39;content-type&amp;#39;]
&amp;#39;application/json; charset=utf8&amp;#39;
&amp;gt;&amp;gt;&amp;gt; r.encoding
&amp;#39;utf-8&amp;#39;
&amp;gt;&amp;gt;&amp;gt; r.text
u&amp;#39;{&amp;#34;type&amp;#34;:&amp;#34;User&amp;#34;...&amp;#39;
&amp;gt;&amp;gt;&amp;gt; r.json()
{u&amp;#39;private_gists&amp;#39;: 419, u&amp;#39;total_private_repos&amp;#39;: 77, ...}
&lt;/code>&lt;/pre>&lt;p>上面的例子相信大家很容易看明白，在我们做接口自动化测试的时候，我们往往使用requests的提供的接口发送请求和获取响应，并根据响应类型将响应转换成python自建的数据结构。比如上面的例子里，我们将响应的json字符串转换成了python的dict。&lt;/p>
&lt;h3 id="安装">安装&lt;/h3>
&lt;p>&lt;a href="http://docs.python-requests.org/en/master/user/install/" target="_blank" rel="noopener noreffer ">官方文档&lt;/a>
&lt;a href="http://docs.python-requests.org/zh_CN/latest/user/install.html" target="_blank" rel="noopener noreffer ">中文文档&lt;/a>&lt;/p>
&lt;h3 id="快速开始">快速开始&lt;/h3>
&lt;p>&lt;a href="http://docs.python-requests.org/en/master/user/quickstart/" target="_blank" rel="noopener noreffer ">官方文档&lt;/a>
&lt;a href="http://docs.python-requests.org/zh_CN/latest/user/quickstart.html" target="_blank" rel="noopener noreffer ">中文文档&lt;/a>&lt;/p>
&lt;h3 id="划重点">划重点&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="http://docs.python-requests.org/en/master/user/quickstart/#make-a-request" target="_blank" rel="noopener noreffer ">发请求&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://docs.python-requests.org/en/master/user/quickstart/#passing-parameters-in-urls" target="_blank" rel="noopener noreffer ">传参&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://docs.python-requests.org/en/master/user/quickstart/#response-content" target="_blank" rel="noopener noreffer ">获取响应&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://docs.python-requests.org/en/master/user/quickstart/#json-response-content" target="_blank" rel="noopener noreffer ">解析json&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://docs.python-requests.org/en/master/user/quickstart/#custom-headers" target="_blank" rel="noopener noreffer ">自定义header&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://docs.python-requests.org/en/master/user/quickstart/#response-status-codes" target="_blank" rel="noopener noreffer ">响应状态码&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://docs.python-requests.org/en/master/user/quickstart/#response-headers" target="_blank" rel="noopener noreffer ">响应headers&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://docs.python-requests.org/en/master/user/quickstart/#more-complicated-post-requests" target="_blank" rel="noopener noreffer ">post&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>英文不好的同学可以参考&lt;a href="http://docs.python-requests.org/zh_CN/latest/user/quickstart.html" target="_blank" rel="noopener noreffer ">中文文档&lt;/a>的相关章节。&lt;/p></description></item><item><title>appium简明教程（7）——Desired Capabilities详解</title><link>https://itest2025.pages.dev/tutorials/21-007-appium%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B7desired-capabilities%E8%AF%A6%E8%A7%A3/</link><pubDate>Mon, 14 Aug 2017 08:01:35 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/21-007-appium%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B7desired-capabilities%E8%AF%A6%E8%A7%A3/</guid><description>&lt;p>Desired Capabilities在启动session的时候是必须提供的。&lt;/p>
&lt;p>Desired Capabilities本质上是key value的对象，它告诉appium server这样一些事情：&lt;/p>
&lt;ul>
&lt;li>本次测试是启动浏览器还是启动移动设备？&lt;/li>
&lt;li>是启动andorid还是启动ios？&lt;/li>
&lt;li>启动android时，app的package是什么？&lt;/li>
&lt;li>启动android时，app的activity是什么？&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Appium的Desired Capabilities是扩展了webdriver的Desired Capabilities的，下面的一些通用配置是需要指定的：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>automationName：使用哪种自动化引擎。appium（默认）还是Selendroid？&lt;/li>
&lt;li>platformName：使用哪种移动平台。iOS, Android, orFirefoxOS？&lt;/li>
&lt;li>deviceName：启动哪种设备，是真机还是模拟器？iPhone Simulator, iPad Simulator, iPhone Retina 4-inch, Android Emulator, Galaxy S4, etc&amp;hellip;&lt;/li>
&lt;li>app：应用的绝对路径，注意一定是绝对路径。如果指定了appPackage和appActivity的话，这个属性是可以不设置的。另外这个属性和browserName属性是冲突的。&lt;/li>
&lt;li>browserName：移动浏览器的名称。比如Safari&amp;rsquo; for iOS and &amp;lsquo;Chrome&amp;rsquo;, &amp;lsquo;Chromium&amp;rsquo;, or &amp;lsquo;Browser&amp;rsquo; for Android；与app属性互斥。&lt;/li>
&lt;li>udid：物理机的id。比如1ae203187fc012g。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>下面这些属性是android平台特定的：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>appActivity：待测试的app的Activity名字。比如MainActivity, .Settings。注意，原生app的话要在activity前加个&amp;quot;.&amp;quot;。&lt;/li>
&lt;li>appPackage：待测试的app的java package。比如com.example.android.myApp, com.android.settings。&lt;/li>
&lt;/ul>
&lt;p>本文主要讨论android平台的appium测试方法和技巧，因此在这里就不列出ios设备特定的属性了。&lt;/p>
&lt;p>更多信息请参考&lt;a href="https://github.com/appium/appium/blob/master/docs/en/caps.md" target="_blank" rel="noopener noreffer ">官方文档&lt;/a>&lt;/p>
&lt;p>在这里我们发现，我们经常要获取app的package和activity名字，那么有什么工具可以让我们方便的获取到这些信息呢？下一节讲回答这个问题。&lt;/p>
&lt;p>本文版权归乙醇所有，欢迎转载，但请注明作者与出处，严禁用于任何商业用途&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1447433553548-2fc162393482?w=300"
 data-srcset="https://images.unsplash.com/photo-1447433553548-2fc162393482?w=300, https://images.unsplash.com/photo-1447433553548-2fc162393482?w=300 1.5x, https://images.unsplash.com/photo-1447433553548-2fc162393482?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1447433553548-2fc162393482?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>性能测试流程（二）——了解系统架构</title><link>https://itest2025.pages.dev/tutorials/14-007-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E6%B5%81%E7%A8%8B%E4%BA%8C%E4%BA%86%E8%A7%A3%E7%B3%BB%E7%BB%9F%E6%9E%B6%E6%9E%84/</link><pubDate>Fri, 11 Aug 2017 07:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/14-007-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E6%B5%81%E7%A8%8B%E4%BA%8C%E4%BA%86%E8%A7%A3%E7%B3%BB%E7%BB%9F%E6%9E%B6%E6%9E%84/</guid><description>&lt;p>系统架构对于测试新手来是最难的；先来了解系统所使用的技术和框架，在环境搭建阶段，你需要了解项目的部署；在性能分析与调优阶段，更要深入这些技术的细节去分析。&lt;/p>
&lt;p>下面看一个基本的系统架构：&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/response-time.jpg"
 data-srcset="http://img.testclass.net/response-time.jpg, http://img.testclass.net/response-time.jpg 1.5x, http://img.testclass.net/response-time.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/response-time.jpg"
 title="http://img.testclass.net/response-time.jpg" />&lt;/p>
&lt;p>&lt;strong>表示层&lt;/strong>&lt;/p>
&lt;p>表示层（浏览器）通过前端技术（HTML5/JavaScript/CSS3）将系统功能和数据展示给用户，并与用户实现交互。通过TCP/HTTP协议与业务层系统通信，向应用层系统发送请求报文，并接收应用层系统返回的响应报文。&lt;/p>
&lt;p>&lt;strong>业务逻辑层&lt;/strong>&lt;/p>
&lt;p>业务逻辑层作为中间层实现核心业务逻辑服务。&lt;/p>
&lt;p>应用服务器主要运行中间件系统，中间件系统系统作为一个容器来运行各种应用软件系统。前台发来的请求报文通过中间件传递给应用程序，应用程序在处理的过程中调用数据层的数据服务器，数据服务器将查询的数据返回给应用程序，应用软件处理完成后通过中间件系统返回给客户端。&lt;/p>
&lt;p>在大型的系统中，可以对应用系统进行拆分，比如拆分成交易服务，查询服务；或者通过负载均衡技术，来分散客户端发来的请求，使其能承受更大的用户访问量。&lt;/p>
&lt;p>&lt;strong>数据层&lt;/strong>&lt;/p>
&lt;p>数据层运行在数据库主机上，负责整个系统中数据信息的存储。运行数据库服务程序，查询通过JDBC与应用程序进行通信，主要用于存储数据与提供数据查询等服务。&lt;/p>
&lt;p>数据库集群技术就是对大型系统应用非常广泛的一种解决方案。&lt;/p>
&lt;hr>
&lt;p>前面介绍了一般系统的架构，那么一个大型的系统在设计中使用了哪些手段或技术来提高系统的性能呢？下面通过一张图来了解一下。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/complex_architecture.png"
 data-srcset="http://img.testclass.net/complex_architecture.png, http://img.testclass.net/complex_architecture.png 1.5x, http://img.testclass.net/complex_architecture.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/complex_architecture.png"
 title="http://img.testclass.net/complex_architecture.png" />&lt;/p>
&lt;p>常用的系统架构:&lt;/p>
&lt;p>· Linux + Apache + PHP + MySQL&lt;/p>
&lt;p>· Linux + Nginx + Redis +  PHP + MySQL&lt;/p>
&lt;p>· Linux + Apache + Tomcat + Java+ Oracle&lt;/p>
&lt;p>· Windows Server 2003/2008 + IIS + C#/ASP.NET + 数据库&lt;/p>
&lt;p>· Window Server 2003/2008 + tomcat + MySql/Oracle/ + Java&lt;/p></description></item><item><title>（七）通过linkText去定位页面上的元素</title><link>https://itest2025.pages.dev/tutorials/20-007-%E4%B8%83%E9%80%9A%E8%BF%87linktext%E5%8E%BB%E5%AE%9A%E4%BD%8D%E9%A1%B5%E9%9D%A2%E4%B8%8A%E7%9A%84%E5%85%83%E7%B4%A0/</link><pubDate>Mon, 07 Aug 2017 02:59:32 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/20-007-%E4%B8%83%E9%80%9A%E8%BF%87linktext%E5%8E%BB%E5%AE%9A%E4%BD%8D%E9%A1%B5%E9%9D%A2%E4%B8%8A%E7%9A%84%E5%85%83%E7%B4%A0/</guid><description>&lt;h3 id="链接的定位">链接的定位&lt;/h3>
&lt;p>链接可以使用By.linkText和By.partialLinkText的方式去定位。&lt;/p>
&lt;p>链接的html标签是&lt;code>&amp;lt;a&amp;gt;&amp;lt;/a&amp;gt;&lt;/code>。&lt;/p>
&lt;p>看这个html代码&lt;code>&amp;lt;a href=&amp;quot;http://www.itet.info&amp;quot;&amp;gt;这就是linkText&amp;lt;a&amp;gt;&lt;/code>，这里**[这就是linkText]** 便是这个链接的linkText，partialLinkText指的是部分的链接文本，如果链接的文本过长的时候，使用partialLinkText会起到简化代码的作用。&lt;/p>
&lt;h3 id="目的">目的&lt;/h3>
&lt;ul>
&lt;li>熟悉selenium webdriver 定位方式&lt;/li>
&lt;li>学会通过linkText和partialLinkText属性去定位元素&lt;/li>
&lt;li>学会使用&lt;code>getAttribute()&lt;/code>方法获取html元素的属性&lt;/li>
&lt;li>学会使用&lt;code>then()&lt;/code>方法传入回调函数来搞定Thenable的Promise&lt;/li>
&lt;/ul>
&lt;h3 id="练习对象">练习对象&lt;/h3>
&lt;p>我们使用&lt;a href="https://github.com/cbracco/html5-test-page/blob/master/index.html" target="_blank" rel="noopener noreffer ">html5-test-page&lt;/a>作为我们的练习对象。&lt;/p>
&lt;p>将html代码拷贝一份并保存到本地，文件名为&lt;code>index.html&lt;/code>。&lt;/p>
&lt;h3 id="场景">场景&lt;/h3>
&lt;p>定位下面html代码所示的a元素，并打印这些元素的href属性&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">ul&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;&lt;/span>&lt;span class="nt">a&lt;/span> &lt;span class="na">href&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;#text__headings&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Headings&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">a&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;&lt;/span>&lt;span class="nt">a&lt;/span> &lt;span class="na">href&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;#text__paragraphs&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Paragraphs&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">a&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;&lt;/span>&lt;span class="nt">a&lt;/span> &lt;span class="na">href&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;#text__blockquotes&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Blockquotes&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">a&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;&lt;/span>&lt;span class="nt">a&lt;/span> &lt;span class="na">href&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;#text__lists&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Lists&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">a&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;&lt;/span>&lt;span class="nt">a&lt;/span> &lt;span class="na">href&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;#text__hr&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Horizontal rules&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">a&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;&lt;/span>&lt;span class="nt">a&lt;/span> &lt;span class="na">href&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;#text__tables&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Tabular data&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">a&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;&lt;/span>&lt;span class="nt">a&lt;/span> &lt;span class="na">href&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;#text__code&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Code&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">a&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;&lt;/span>&lt;span class="nt">a&lt;/span> &lt;span class="na">href&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;#text__inline&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Inline elements&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">a&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">ul&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="代码">代码&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;path&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">webdriver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;selenium-webdriver&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">By&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">testFile&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;file://&amp;#34;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="nx">path&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">__dirname&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;index.html&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">dr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Builder&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">forBrowser&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;chrome&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">build&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">testFile&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">linkText&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Headings&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">getAttribute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;href&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">then&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">href&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">href&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">linkText&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Paragraphs&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">getAttribute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;href&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">then&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">href&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">href&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">linkText&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Blockquotes&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">getAttribute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;href&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">then&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">href&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">href&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">linkText&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Lists&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">getAttribute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;href&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">then&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">href&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">href&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">linkText&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Horizontal rules&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">getAttribute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;href&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">then&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">href&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">href&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">linkText&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Tabular data&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">getAttribute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;href&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">then&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">href&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">href&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">linkText&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Code&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">getAttribute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;href&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">then&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">href&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">href&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">partialLinkText&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Inline&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">getAttribute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;href&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">then&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">href&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">href&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">quit&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行结果">运行结果&lt;/h3>
&lt;p>xxxx代表你的本机index.html的路径&lt;/p></description></item><item><title>（七）测试投入与产出</title><link>https://itest2025.pages.dev/tutorials/29-007-%E4%B8%83%E6%B5%8B%E8%AF%95%E6%8A%95%E5%85%A5%E4%B8%8E%E4%BA%A7%E5%87%BA/</link><pubDate>Thu, 20 Jul 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/29-007-%E4%B8%83%E6%B5%8B%E8%AF%95%E6%8A%95%E5%85%A5%E4%B8%8E%E4%BA%A7%E5%87%BA/</guid><description>&lt;p>在&lt;a href="https://itest2025.pages.dev/software_test/test-division/" rel="">测试人员分工&lt;/a>中，我介绍了各种分工方式，在选择使用哪一种分工方式时，还需要考虑投入的人员数量，投入的时间，与发现缺陷的数量。&lt;/p>
&lt;br>
#### 投入时间与发现缺陷的关系：
----
![](http://img.testclass.net/time_and_bug.png)
&lt;p>在人员一定的情况下，投入的时间越多，发现的缺陷越多。但有一个规律，越到后期发现的新缺陷越少。假设软件总缺陷为100个，第一周发现50个问题，第二新发现20个，第二周可能只发现10个新缺陷。而且一个必然的结果是，测试不可能发现所有的缺陷。&lt;/p>
&lt;br>
#### 投入人员数量与缺陷的关系：
----
![](http://img.testclass.net/personnel_and_bug.png)
&lt;p>在时间一定有的情况下，投入的人员越多，发现的问题越多，从图中可以看出，投入的人员越多，人员发现缺陷的重叠度越高。当然，你可以说，把每个人员要测试的内容划分清晰就不会重叠了。做为一个系统的各个功能模块，他们之间肯定存在必然的联系。有可能A人员在测试时会涉及到B人员测试的功能，并且发现了问题，不管是告诉B缺陷还是A人员直接提交缺陷（当然，你也可以装作没看到，等着B去发现），这都算不可避免的重叠。&lt;/p>
&lt;p>当然，划分更清晰的任务有效的降低重叠度。同步也降低了发现缺陷的数量，提高项目风险。除非投入更多的时间测试。这之间的关系，需要测试管理者认真去权衡。&lt;/p>
&lt;p>在项目不紧急测试时间充分的情况下，可以投入更少的人员，延长测试时间发现更多的缺陷。 在项目紧急的情况下，需要投入更多的人员测试，以便尽快的发现更多的缺陷。在项目质量要求很高的情况下需要投入更多的人员与时间进行测试。在测试时间少，项目质量要求不高的情况下，可以投入较少的人员与时间进行测试。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1496180470114-6ef490f3ff22?w=300"
 data-srcset="https://images.unsplash.com/photo-1496180470114-6ef490f3ff22?w=300, https://images.unsplash.com/photo-1496180470114-6ef490f3ff22?w=300 1.5x, https://images.unsplash.com/photo-1496180470114-6ef490f3ff22?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1496180470114-6ef490f3ff22?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（七）WebDriver常用方法</title><link>https://itest2025.pages.dev/tutorials/19-007-%E4%B8%83webdriver%E5%B8%B8%E7%94%A8%E6%96%B9%E6%B3%95/</link><pubDate>Sun, 02 Jul 2017 07:37:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/19-007-%E4%B8%83webdriver%E5%B8%B8%E7%94%A8%E6%96%B9%E6%B3%95/</guid><description>&lt;p>前面我们已经学习了定位元素， 定位只是第一步， 定位之后需要对这个元素进行操作， 或单击（按钮） 或
输入（输入框） ， 下面就来认识这些最常用的方法。
&lt;br>&lt;/p>
&lt;h3 id="webdriver-常用方法">WebDriver 常用方法&lt;/h3>
&lt;p>下面先来认识 WebDriver 中最常用的几个方法：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>clear() 清除文本。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>sendKeys(*value) 模拟按键输入。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>click() 单击元素&lt;/p>
&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.By&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.WebDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.WebElement&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.chrome.ChromeDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">BaiduDemo&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ChromeDriver&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;https://www.baidu.com/&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebElement&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">search_text&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;kw&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebElement&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">search_button&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;su&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">search_text&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Java&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">search_text&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">clear&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">search_text&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Selenium&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">search_button&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">click&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">quit&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>clear()方法用于清除文本输入框中的内容。&lt;/p></description></item><item><title>（七）键盘事件</title><link>https://itest2025.pages.dev/tutorials/24-007-%E4%B8%83%E9%94%AE%E7%9B%98%E4%BA%8B%E4%BB%B6/</link><pubDate>Sat, 24 Jun 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/24-007-%E4%B8%83%E9%94%AE%E7%9B%98%E4%BA%8B%E4%BB%B6/</guid><description>&lt;br>
Keys()类提供了键盘上几乎所有按键的方法。 前面了解到， send_keys()方法可以用来模拟键盘输入， 除此
之外， 我们还可以用它来输入键盘上的按键， 甚至是组合键， 如 Ctrl+A、 Ctrl+C 等。
&lt;pre tabindex="0">&lt;code>from selenium import webdriver
# 引入 Keys 模块
from selenium.webdriver.common.keys import Keys

driver = webdriver.Chrome()
driver.get(&amp;#34;http://www.baidu.com&amp;#34;)

# 输入框输入内容
driver.find_element_by_id(&amp;#34;kw&amp;#34;).send_keys(&amp;#34;seleniumm&amp;#34;)

# 删除多输入的一个 m
driver.find_element_by_id(&amp;#34;kw&amp;#34;).send_keys(Keys.BACK_SPACE)


# 输入空格键+“教程”
driver.find_element_by_id(&amp;#34;kw&amp;#34;).send_keys(Keys.SPACE)
driver.find_element_by_id(&amp;#34;kw&amp;#34;).send_keys(&amp;#34;教程&amp;#34;)

# ctrl+a 全选输入框内容
driver.find_element_by_id(&amp;#34;kw&amp;#34;).send_keys(Keys.CONTROL, &amp;#39;a&amp;#39;)

# ctrl+x 剪切输入框内容
driver.find_element_by_id(&amp;#34;kw&amp;#34;).send_keys(Keys.CONTROL, &amp;#39;x&amp;#39;)

# ctrl+v 粘贴内容到输入框
driver.find_element_by_id(&amp;#34;kw&amp;#34;).send_keys(Keys.CONTROL, &amp;#39;v&amp;#39;)

# 通过回车键来代替单击操作
driver.find_element_by_id(&amp;#34;su&amp;#34;).send_keys(Keys.ENTER)
driver.quit()
&lt;/code>&lt;/pre>&lt;p>需要说明的是， 上面的脚本没有什么实际意义， 仅向我们展示模拟键盘各种按键与组合键的用法。&lt;/p>
&lt;ul>
&lt;li>from selenium.webdriver.common.keys import Keys&lt;/li>
&lt;/ul>
&lt;p>在使用键盘按键方法前需要先导入 keys 类。&lt;/p>
&lt;br>
&lt;p>以下为常用的键盘操作：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>send_keys(Keys.BACK_SPACE) 删除键（BackSpace）&lt;/p>
&lt;/li>
&lt;li>
&lt;p>send_keys(Keys.SPACE) 空格键(Space)&lt;/p></description></item><item><title>软件测试流程</title><link>https://itest2025.pages.dev/tutorials/13-008-%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E6%B5%81%E7%A8%8B/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/13-008-%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E6%B5%81%E7%A8%8B/</guid><description>&lt;p>如果想让测试在公司的项目中发挥出它最大的价值，并不是招两个测试技术高手，或引入几个测试技术，而是测试技术对项目流程的渗透，以及测试流程的改进与完善。虽然，当然测试行业前景乐观，许多中小企业也都在引入测试，但一百个公司就有一百种测试，每个公司对测试的看法不同，公司对测试的定位也不完全一样。&lt;/p>
&lt;br>
#### 简陋的测试流程
&lt;p>先说我入职的第一个家公司，我是第一个入职的专职测试人员，相信一两个测试的公司还是不少的，入职后各种项目都在进行当中，上面给我的定位是并没完全融入到项目中去。而通过指派任务的方式。&lt;/p>
&lt;p>下面是简陋的流程图：&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/testing_process01.png"
 data-srcset="http://img.testclass.net/testing_process01.png, http://img.testclass.net/testing_process01.png 1.5x, http://img.testclass.net/testing_process01.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/testing_process01.png"
 title="http://img.testclass.net/testing_process01.png" />&lt;/p>
&lt;p>&lt;strong>需求分析与架构设计：&lt;/strong>&lt;/p>
&lt;p>我们做的是某一移动公司内部使用的项目，需求分析与架构全部由项目经理完成，之后由项目经理给具体某个开发人员分配任务，具体对某个功能模块的实现。这个对项目经理的经验与技术要求很高，他既然担任了需求分析师，又担任架构师的角色。&lt;/p>
&lt;p>&lt;strong>程序员编码：&lt;/strong>&lt;/p>
&lt;p>因为我们开发语言用的是JAVA 语言，IDE用MyEclipse中自带的CVS版本管理工具，开发人员完成代码后，提交到版本库中。&lt;/p>
&lt;p>&lt;strong>测试：&lt;/strong>&lt;/p>
&lt;p>我入职后的第一个任务是搭建缺陷管理工具，禅道项目管理，通过推广对发现的问题进行跟踪。后来正明效果并不好，因为对于一个六七人的开发团队项目，开发人员更喜欢测试人员能当面反馈，这样更能提高效率。对一个小 bug 通过当面交流的方式就可以将问题修复。&lt;/p>
&lt;p>对于当时的环境，并没有测试环境。开发人员在本机上将项目进行部署运行。测试人员通过局域网访问开发人员的机子进行测试。或在测试人员本机上进行部署测试。这也是一个致命的缺点。因为开发人员测试人员使用的电脑存在太多不稳定因素，这些都会造成问题的出现，有时候难以判定是系统问题还是环境问题。&lt;/p>
&lt;p>&lt;strong>上线：&lt;/strong>&lt;/p>
&lt;p>经过测试人员测试通过后，开发人员部署上线。&lt;/p>
&lt;p>&lt;strong>A程序员流程&lt;/strong>&lt;/p>
&lt;p>你会发现在流程图中，A程序员是先发上线之后，再进行测试。这是我们一个面向大众用户的网站，上面给于测试人员的定位是测试兼用户体验，测试将发现的bug和体验问题提交到缺陷管理系统，由经理对问题进行分析，指派开发人员解决。定期对系统进行更新。&lt;/p>
&lt;p>&lt;strong>流程分析：&lt;/strong>&lt;/p>
&lt;p>这个流程唯一的优点，就是能快速的发现并修复问题。&lt;/p>
&lt;p>缺点就非常多了，相信许多小软件公司也有类似的流程。&lt;/p>
&lt;p>这个流程中，项目经理是核心，项目经理也确实是有多年开发与项目经验的牛人，他喜欢不定期分享上些前沿的技术。&lt;/p>
&lt;p>对于测试来说，需求很不明确，测试文档与用例也是可有可无的产物，没有需求文档，或非常简陋，根据需求文档根本无法编写用例。我只能收集一些通用的测试用例，如登录、文件上传下载、列表翻页、日期选择、输入框验证、搜索等有一些“通用型”用例，以便在测试过程中做参考。功能测试的多了，拿到一个功能，测试思路也就出来了。&lt;/p>
&lt;br>
#### 规范的测试流程
----
&lt;p>放弃上份悠闲的工作，感谢那个带我入行公司，我想了解真正的测试在公作中如何进行的。所以，来到了现在这家公司。我很欣喜的是这测试有自己的团队，专业（对当时的我来说）的流程，以及与开发等同的地位。&lt;/p>
&lt;p>现在的测试流程：&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/testing_process02.png"
 data-srcset="http://img.testclass.net/testing_process02.png, http://img.testclass.net/testing_process02.png 1.5x, http://img.testclass.net/testing_process02.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/testing_process02.png"
 title="http://img.testclass.net/testing_process02.png" />&lt;/p>
&lt;p>&lt;strong>需求分析：&lt;/strong>&lt;/p>
&lt;p>需求分析由产品人员制定，他们要做的不是一份简单的文档，而是细化每一个功能的细节，每一个按钮的位置，对于稍大或复杂一点的需求都进行建模。&lt;/p>
&lt;p>&lt;strong>需求评审：&lt;/strong>&lt;/p>
&lt;p>这里会叫上所有参与项目人员进行，开发人员、测试人员、QA人员。测试人员提出需求，开发人员考虑功能实现的方案与可行性、当然开发负责人也是要参与的。测试人员主要是对需求的理解提出疑问，以便才能根据需求写用例。QA人员是最终对软件质量进行验证的人，所以也需要了解需求&lt;/p>
&lt;p>&lt;strong>开发人员编写排期：&lt;/strong>&lt;/p>
&lt;p>开发人员需要根据需求功能点进行排期。然后将开计划转交给测试人员。&lt;/p>
&lt;p>&lt;strong>测试计划排期：&lt;/strong>&lt;/p>
&lt;p>测试人员根据开发计划，对测试具体测试时间，也就是开发功能完成后的时间，进行几轮测试等。然后，把项目的开发与测试计划发送给各部门负责人及参与项目的所有人员。&lt;/p>
&lt;p>&lt;strong>编写测试用例：&lt;/strong>&lt;/p>
&lt;p>根据详细的需求分档，开始进行用例的编写。&lt;/p>
&lt;p>&lt;strong>用例评审：&lt;/strong>&lt;/p>
&lt;p>在用例进行评审期间，先以邮件形式将用例发送给相关人员，以便他们事先了解用例对哪些功能进行验证以及验证的细节。&lt;/p>
&lt;p>然后，测试人员组进行用例评审，开发人员对用例与实际功能不符合有哪些，产品人员对会通过用例对功能的具体实现进行把握等等。&lt;/p>
&lt;p>&lt;strong>提交基线：&lt;/strong>&lt;/p>
&lt;p>开发人员完成所有功能后，会对自己的功能进行一个自测。自测完成后提交测试人员进行基线。&lt;/p>
&lt;p>&lt;strong>具体测试流程：&lt;/strong>&lt;/p>
&lt;p>开发人员对于基到测试线的功能进行测式，发现的问题通过缺陷管理工具进行反馈，开发人员对问题进行修复，然后，准备第二轮基线。&lt;/p>
&lt;p>测试人员完成第一轮测试后，需要写测试结论，发到相关人员。然后对基线后的第二轮进行测试，第二轮会对第一轮中发现的问题进行重点回归。&lt;/p>
&lt;p>&lt;strong>测试通过：&lt;/strong>&lt;/p>
&lt;p>经过两到三轮或四轮的测试后，直到没发现新的问题，或暂时无法解决，或不紧急的问题。通过上级确认，可以通过。编写测试报告与验收方案。&lt;/p>
&lt;p>验收方案是交由QA进行验证的。在现公司的流程中是将测试与QA分开的，测试人员重点关注的是功能是否可以正常运行。QA关注的是整个流程的质量以及最终用户的质量。有些公司QA与测试是不区分的，但这对测试的要求会更高，除了关心功能，还需要关心整体流程与质量。&lt;/p>
&lt;p>&lt;strong>流程分析：&lt;/strong>&lt;/p>
&lt;p>对于刚接触这个流程的我来说，这个流程是规范的，测试真正融入了整个流程，而且还担任了很重的角色，从而也有效的保证了软件产品的整体质量。&lt;/p></description></item><item><title>（八）Docker Dockerfile</title><link>https://itest2025.pages.dev/tutorials/30-008-%E5%85%ABdocker-dockerfile/</link><pubDate>Mon, 22 Jan 2018 14:32:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/30-008-%E5%85%ABdocker-dockerfile/</guid><description>&lt;p>虽然，前面已经会 使用 Nginx 和 docker selenium 来启动容器，但也仅仅是会使用，Dcoker 中还有许多概念和细节需要我们继续学习。&lt;/p>
&lt;h5 id="dockerfile-文件分析">Dockerfile 文件分析&lt;/h5>
&lt;hr>
&lt;p>Dockerfile	由一行行命令语句组成，并且支持以 &lt;code>#&lt;/code> 开头的注释行。&lt;/p>
&lt;p>一般的 Dockerfile	分为四部分：&lt;strong>基础镜像信息&lt;/strong>、 &lt;strong>维护者信息&lt;/strong>、 &lt;strong>镜像操作指令&lt;/strong> 和 &lt;strong>容器启动时执行指令&lt;/strong> 。&lt;/p>
&lt;p>以Selenium/Hub 的 &lt;a href="https://github.com/SeleniumHQ/docker-selenium/blob/master/Hub/Dockerfile" target="_blank" rel="noopener noreffer ">Dockerfile&lt;/a> 文件为例:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-C" data-lang="C">&lt;span class="line">&lt;span class="cl">&lt;span class="cp"># !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"># NOTE: DO *NOT* EDIT THIS FILE. IT IS GENERATED.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"># PLEASE UPDATE Dockerfile.txt INSTEAD OF THIS FILE
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"># !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>&lt;span class="n">FROM&lt;/span> &lt;span class="n">selenium&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="nl">base&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mf">3.8.1&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">erbium&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">LABEL&lt;/span> &lt;span class="n">authors&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">SeleniumHQ&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">USER&lt;/span> &lt;span class="n">seluser&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#========================
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"># Selenium Configuration
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#========================
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">EXPOSE&lt;/span> &lt;span class="mi">4444&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"># As integer, maps to &amp;#34;maxSession&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>&lt;span class="n">ENV&lt;/span> &lt;span class="n">GRID_MAX_SESSION&lt;/span> &lt;span class="mi">5&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"># In milliseconds, maps to &amp;#34;newSessionWaitTimeout&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>&lt;span class="n">ENV&lt;/span> &lt;span class="n">GRID_NEW_SESSION_WAIT_TIMEOUT&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"># As a boolean, maps to &amp;#34;throwOnCapabilityNotPresent&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>&lt;span class="n">ENV&lt;/span> &lt;span class="n">GRID_THROW_ON_CAPABILITY_NOT_PRESENT&lt;/span> &lt;span class="nb">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"># As an integer
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>&lt;span class="n">ENV&lt;/span> &lt;span class="n">GRID_JETTY_MAX_THREADS&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"># In milliseconds, maps to &amp;#34;cleanUpCycle&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>&lt;span class="n">ENV&lt;/span> &lt;span class="n">GRID_CLEAN_UP_CYCLE&lt;/span> &lt;span class="mi">5000&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"># In seconds, maps to &amp;#34;browserTimeout&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>&lt;span class="n">ENV&lt;/span> &lt;span class="n">GRID_BROWSER_TIMEOUT&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"># In seconds, maps to &amp;#34;timeout&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>&lt;span class="n">ENV&lt;/span> &lt;span class="n">GRID_TIMEOUT&lt;/span> &lt;span class="mi">30&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"># Debug
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>&lt;span class="n">ENV&lt;/span> &lt;span class="n">GRID_DEBUG&lt;/span> &lt;span class="nb">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"># As integer, maps to &amp;#34;port&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>&lt;span class="n">ENV&lt;/span> &lt;span class="n">GRID_HUB_PORT&lt;/span> &lt;span class="mi">4444&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">COPY&lt;/span> &lt;span class="n">generate_config&lt;/span> \
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">entry_point&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">sh&lt;/span> \
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">/&lt;/span>&lt;span class="n">opt&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">bin&lt;/span>&lt;span class="o">/&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"># Running this command as sudo just to avoid the message:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"># To run a command as administrator (user &amp;#34;root&amp;#34;), use &amp;#34;sudo &amp;lt;command&amp;gt;&amp;#34;. See &amp;#34;man sudo_root&amp;#34; for details.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"># When logging into the container
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>&lt;span class="n">RUN&lt;/span> &lt;span class="o">/&lt;/span>&lt;span class="n">opt&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">bin&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">generate_config&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="o">/&lt;/span>&lt;span class="n">opt&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">selenium&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">config&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">json&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">CMD&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s">&amp;#34;/opt/bin/entry_point.sh&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>FROM&lt;/li>
&lt;/ul>
&lt;p>Dockerfile 都必须以 &lt;code>FROM&lt;/code> 命令开始。 &lt;code>FROM&lt;/code>命令会指定镜像基于哪个基础镜像创建，接下来的命令也会基于这个基础镜像。&lt;/p></description></item><item><title>（八）构造方法</title><link>https://itest2025.pages.dev/tutorials/16-008-%E5%85%AB%E6%9E%84%E9%80%A0%E6%96%B9%E6%B3%95/</link><pubDate>Wed, 17 Jan 2018 14:32:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/16-008-%E5%85%AB%E6%9E%84%E9%80%A0%E6%96%B9%E6%B3%95/</guid><description>&lt;h4 id="构造方法">构造方法&lt;/h4>
&lt;hr>
&lt;p>构造方法用于初始化一个新建的对象， 如果你没有定议任何构造方法的形式， 程式会为你取一个不带任何参数的构造函数， 那么你产生类的对像时只能用不带参数的方法。&lt;/p>
&lt;ul>
&lt;li>1.构造器必须与类同名（如果一个源文件中有多个类， 那么构造器必须与公共类同名）&lt;/li>
&lt;li>2.每个类可以有一个以上的构造器&lt;/li>
&lt;li>3.构造器可以有 0 个、 1 个或 1 个以上的参数&lt;/li>
&lt;li>4.构造器没有返回值&lt;/li>
&lt;li>5.构造器总是伴随着 new 操作一起调用&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">Father&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">Father&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;调用了无参的构造函数.&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">Father&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">msg&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;调用了有参的构造函数： &amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">msg&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="o">[]&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Father&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">f1&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Father&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Father&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">f2&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Father&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Hello&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>运行结果：&lt;/p>
&lt;pre tabindex="0">&lt;code>调用了无参的构造函数.
调用了有参的构造函数： Hello
&lt;/code>&lt;/pre>&lt;h5 id="构造函数中super用法">构造函数中&amp;quot;super&amp;quot;用法&lt;/h5>
&lt;p>构造方法和普通方法都用会关键字 &lt;code>super&lt;/code> 指向父类，但是用的方法不一样。在构造方法中，调用父类中的某一个构造函数。在构造方法中的用法。&lt;/p></description></item><item><title>Android测试（八）：UI Automator 自动化测试</title><link>https://itest2025.pages.dev/tutorials/17-008-android%E6%B5%8B%E8%AF%95%E5%85%ABui-automator-%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95/</link><pubDate>Wed, 20 Dec 2017 14:20:12 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/17-008-android%E6%B5%8B%E8%AF%95%E5%85%ABui-automator-%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95/</guid><description>&lt;p>原文：https://developer.android.com/training/testing/ui-testing/uiautomator-testing.html&lt;/p>
&lt;p>涉及跨多个应用程序的用户交互的用户界面（UI）测试可以验证应用程序在用户流量跨越其他应用程序或进入系统UI时的行为。 这种用户流程的一个例子是一个消息应用程序，它允许用户输入文本消息，启动Android联系人选择器，以便用户可以选择收件人发送消息，然后将控制权返回给用户的原始应用程序并提交消息。&lt;/p>
&lt;p>这一小节介绍如何使用Android测试支持库提供的UI Automator测试框架编写此类UI测试。 UI Automator API可让你与设备上的可见元素进行交互，而不管哪个Activity处于焦点。你的测试可以使用方便的描述符（如该组件中显示的文本或其内容描述）查找UI组件。 UI Automator测试可以在运行Android 4.3（API级别18）或更高版本的设备上运行。&lt;/p>
&lt;p>UI Automator测试框架是基于 instrumentation的API，并与AndroidJUnitRunner测试运行器一起使用。&lt;/p>
&lt;h3 id="设置ui-automator">设置UI Automator&lt;/h3>
&lt;hr>
&lt;p>在使用UI Automator构建UI测试之前，请确保配置测试源代码位置和项目依赖关系，如前面章节中所述。&lt;/p>
&lt;p>在Android应用程序模块的build.gradle文件中，必须设置对UI Automator库的依赖关系引用：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">dependencies&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">    &lt;/span>&lt;span class="p">...&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">    &lt;/span>&lt;span class="n">androidTestCompile&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">com&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">android&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">support&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">test&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">uiautomator&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">uiautomator&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">v18&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">1&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">1&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>为了优化您的UI Automator测试，您应该首先检查目标应用程序的UI组件，并确保它们可以访问。 这些优化技巧将在下面两节中介绍。&lt;/p>
&lt;h4 id="查看设备上的ui">查看设备上的UI&lt;/h4>
&lt;p>在设计您的测试之前，检查设备上可见的UI组件。 为确保您的UI Automator测试可以访问这些组件，请检查这些组件是否具有可见的文本标签、&lt;code>android:contentDescription&lt;/code> 值。&lt;/p>
&lt;p>uiautomatorviewer工具提供了一个方便的可视化界面来检查布局层次结构，并查看设备前台中可见的UI组件的属性。这个信息可以让你使用UI Automator创建更细致的测试。例如，可以创建一个匹配特定可见属性的UI选择器。&lt;/p>
&lt;p>启动uiautomatorviewer工具：&lt;/p>
&lt;p>1.在物理设备上启动目标应用程序。&lt;/p>
&lt;p>2.将设备连接到你的开发机器。&lt;/p>
&lt;p>3.打开终端窗口并导航到&lt;code>&amp;lt;android-sdk&amp;gt; / tools /&lt;/code>目录。&lt;/p>
&lt;p>4.使用以下命令运行该工具：&lt;/p>
&lt;pre tabindex="0">&lt;code>$ uiautomatorviewer
&lt;/code>&lt;/pre>&lt;p>要查看您的应用程序的UI属性：&lt;/p>
&lt;p>1.在uiautomatorviewer界面中，点击 &lt;strong>Device Screensho&lt;/strong> 按钮。&lt;/p>
&lt;p>2.将鼠标悬停在左侧面板中的快照上，查看由uiautomatorviewer工具标识的UI组件。 属性列在右下方的面板中，右上方的布局层次中列出。&lt;/p>
&lt;p>3.或者，单击 &lt;strong>Toggle NAF Nodes&lt;/strong> 按钮以查看UI Automator无法访问的UI组件。 这些组件只有有限的信息可用。&lt;/p>
&lt;h4 id="确保你的activity是可访问的">确保你的Activity是可访问的&lt;/h4>
&lt;p>UI Automator测试框架对已实施Android辅助功能的应用程序执行得更好。当你使用View类型的UI元素或SDK或Support Library中的View的子类时，不需要实现可访问性支持，因为这些类已经为你完成了。&lt;/p>
&lt;p>但是，有些应用程序使用自定义UI元素来提供更丰富的用户体验。 这些元素不会提供自动的可访问性支持。如果你的应用程序包含不是来自SDK或支持库的View子类的实例，请确保通过完成以下步骤将可访问性功能添加到这些元素：&lt;/p>
&lt;p>1.创建一个扩展&lt;code>ExploreByTouchHelper&lt;/code>的具体类。&lt;/p>
&lt;p>2.通过调用&lt;code>setAccessibilityDelegate（）&lt;/code>将新类的实例与特定的自定义UI元素相关联。&lt;/p>
&lt;p>有关将辅助功能添加到自定义视图元素的其他指导，请参阅构建可访问自定义视图要详细了解Android上可访问性的一般最佳实践，请参阅使应用程序更易于访问。&lt;/p></description></item><item><title>推荐资源</title><link>https://itest2025.pages.dev/tutorials/27-008-%E6%8E%A8%E8%8D%90%E8%B5%84%E6%BA%90/</link><pubDate>Mon, 11 Dec 2017 02:52:34 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/27-008-%E6%8E%A8%E8%8D%90%E8%B5%84%E6%BA%90/</guid><description>&lt;p>为了大家能够更好的学习爬虫，扩大视野，这里给大家推荐一些其他的资源&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://blog.thankbabe.com/2017/09/25/spider/" target="_blank" rel="noopener noreffer ">大话爬虫的基本套路&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://blog.fundebug.com/2017/11/01/guide-to-automating-scraping-the-web-with-js/" target="_blank" rel="noopener noreffer ">Puppeteer之爬虫入门&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.zhihu.com/question/27621722/answer/51254997" target="_blank" rel="noopener noreffer ">利用爬虫技术能做到哪些很酷很有趣很有用的事情？&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://www.4hou.com/technology/8482.html" target="_blank" rel="noopener noreffer ">Web网页爬虫对抗指南 Part.1&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://zhuanlan.zhihu.com/p/21479334" target="_blank" rel="noopener noreffer ">如何学习python爬虫&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/facert/awesome-spider" target="_blank" rel="noopener noreffer ">各种爬虫实例, 强烈推荐&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1477346611705-65d1883cee1e?w=300"
 data-srcset="https://images.unsplash.com/photo-1477346611705-65d1883cee1e?w=300, https://images.unsplash.com/photo-1477346611705-65d1883cee1e?w=300 1.5x, https://images.unsplash.com/photo-1477346611705-65d1883cee1e?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1477346611705-65d1883cee1e?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（八）TestNG 用例依赖</title><link>https://itest2025.pages.dev/tutorials/36-008-%E5%85%ABtestng-%E7%94%A8%E4%BE%8B%E4%BE%9D%E8%B5%96/</link><pubDate>Sat, 25 Nov 2017 12:25:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/36-008-%E5%85%ABtestng-%E7%94%A8%E4%BE%8B%E4%BE%9D%E8%B5%96/</guid><description>&lt;p>当某一条用例运行失败时，其它用例必然也会失败，所以，我们就没有必要再运行其它用例了，这个时候我们就可以设置用例之间的依赖。&lt;/p>
&lt;h4 id="测试方法依赖">测试方法依赖&lt;/h4>
&lt;hr>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.testng.annotations.Test&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.testng.AssertJUnit.assertEquals&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">DependentMethodsTest&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">testAdd1&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">3&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">5&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dependsOnMethods&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s">&amp;#34;testAdd1&amp;#34;&lt;/span>&lt;span class="p">})&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">testAdd2&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">3&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">5&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>dependsOnMethods 来设置用例的依赖，当 testAdd1() 运行失败时，则 testAdd2() 不再被执行。&lt;/li>
&lt;/ul>
&lt;h4 id="测试组依赖">测试组依赖&lt;/h4>
&lt;hr>
&lt;pre tabindex="0">&lt;code>import org.testng.annotations.Test;
import static org.testng.AssertJUnit.assertEquals;


public class DependentGroupsTest {

 @Test(groups={&amp;#34;funtest&amp;#34;})
 public void testAdd1(){
 assertEquals(3+1, 5);
 }

 @Test(groups={&amp;#34;funtest&amp;#34;})
 public void testAdd2(){
 assertEquals(3+2, 5);
 }

 @Test(dependsOnGroups = {&amp;#34;funtest&amp;#34;})
 public void testAdd3(){
 assertEquals(3+2, 5);
 }

}
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>dependsOnGroups 来设置组的依赖，testAdd1()和 testAdd2() 同属于于 funtest组，testAdd3() 依赖于funtest组，该组有中有一条用例运行失败，则testAdd3() 不再执行。&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p></description></item><item><title>requests如何获取响应的状态码?</title><link>https://itest2025.pages.dev/tutorials/42-008-requests%E5%A6%82%E4%BD%95%E8%8E%B7%E5%8F%96%E5%93%8D%E5%BA%94%E7%9A%84%E7%8A%B6%E6%80%81%E7%A0%81/</link><pubDate>Wed, 22 Nov 2017 03:23:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/42-008-requests%E5%A6%82%E4%BD%95%E8%8E%B7%E5%8F%96%E5%93%8D%E5%BA%94%E7%9A%84%E7%8A%B6%E6%80%81%E7%A0%81/</guid><description>&lt;p>使用&lt;code>status_code&lt;/code> 就可以了。&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; r = requests.get(&amp;#39;http://httpbin.org/get&amp;#39;)
&amp;gt;&amp;gt;&amp;gt; r.status_code
200
&lt;/code>&lt;/pre>&lt;p>为方便引用，Requests还附带了一个内置的状态码查询对象：&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; r.status_code == requests.codes.ok
True
&lt;/code>&lt;/pre>&lt;p>如果发送了一个错误请求(一个 4XX 客户端错误，或者 5XX 服务器错误响应)，我们可以通过 Response.raise_for_status() 来抛出异常：&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; bad_r = requests.get(&amp;#39;http://httpbin.org/status/404&amp;#39;)
&amp;gt;&amp;gt;&amp;gt; bad_r.status_code
404

&amp;gt;&amp;gt;&amp;gt; bad_r.raise_for_status()
Traceback (most recent call last):
 File &amp;#34;requests/models.py&amp;#34;, line 832, in raise_for_status
 raise http_error
requests.exceptions.HTTPError: 404 Client Error
&lt;/code>&lt;/pre>&lt;p>如果在测试用例中直接使用&lt;code>raise_for_status()&lt;/code>方法，如果有异常抛出的话，用例会自动失败。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1507919909716-c8262e491cde?w=300"
 data-srcset="https://images.unsplash.com/photo-1507919909716-c8262e491cde?w=300, https://images.unsplash.com/photo-1507919909716-c8262e491cde?w=300 1.5x, https://images.unsplash.com/photo-1507919909716-c8262e491cde?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1507919909716-c8262e491cde?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（八）JUnit 测试批量运行</title><link>https://itest2025.pages.dev/tutorials/31-008-%E5%85%ABjunit-%E6%B5%8B%E8%AF%95%E6%89%B9%E9%87%8F%E8%BF%90%E8%A1%8C/</link><pubDate>Mon, 13 Nov 2017 12:30:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/31-008-%E5%85%ABjunit-%E6%B5%8B%E8%AF%95%E6%89%B9%E9%87%8F%E8%BF%90%E8%A1%8C/</guid><description>&lt;p>前面测试用例的运行 主要针对单个测试类进行的，当然，在 IntelliJ IDEA 中也可以选择单个的方法执行。那如果我们想运行所有的用例的文件呢？&lt;/p>
&lt;h4 id="intellij-idea-中设置运行">IntelliJ IDEA 中设置运行&lt;/h4>
&lt;hr>
&lt;p>&lt;strong>设置&lt;/strong>&lt;/p>
&lt;p>在 IntelliJ IDEA 中，菜单栏：&lt;strong>Run菜单 &amp;ndash;&amp;gt; Edit Configurations&amp;hellip;选项&lt;/strong>。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/junit_run_all_config.png"
 data-srcset="http://img.testclass.net/junit_run_all_config.png, http://img.testclass.net/junit_run_all_config.png 1.5x, http://img.testclass.net/junit_run_all_config.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/junit_run_all_config.png"
 title="http://img.testclass.net/junit_run_all_config.png" />&lt;/p>
&lt;p>在 Junit 目录下，选择任意一个用例文件。&lt;/p>
&lt;ul>
&lt;li>Test Kind : 选择用例的运行类型/级别。&lt;/li>
&lt;li>packages : 选择用例运行的目录，即你的测试用例目录。&lt;/li>
&lt;/ul>
&lt;p>设置完成后，点击 &lt;strong>“OK”&lt;/strong> 按钮。&lt;/p>
&lt;p>&lt;strong>运行&lt;/strong>&lt;/p>
&lt;p>点击 IntelliJ IDEA 工具栏上的运行按钮，来运行 test 目录下的所有用例。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/junit_run_button.png"
 data-srcset="http://img.testclass.net/junit_run_button.png, http://img.testclass.net/junit_run_button.png 1.5x, http://img.testclass.net/junit_run_button.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/junit_run_button.png"
 title="http://img.testclass.net/junit_run_button.png" />&lt;/p>
&lt;p>运行结果：&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/junit_run_result_4.png"
 data-srcset="http://img.testclass.net/junit_run_result_4.png, http://img.testclass.net/junit_run_result_4.png 1.5x, http://img.testclass.net/junit_run_result_4.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/junit_run_result_4.png"
 title="http://img.testclass.net/junit_run_result_4.png" />&lt;/p>
&lt;h4 id="通过测试套件运行">通过测试套件运行&lt;/h4>
&lt;hr>
&lt;p>这种方法引入一种 &lt;strong>“测试套件”&lt;/strong> 的概念，JUnit 提供了一种批量运行测试类的方法，叫测试套件。&lt;/p>
&lt;p>测试套件的写法需要遵循以下原则：&lt;/p></description></item><item><title>8. 断言异常</title><link>https://itest2025.pages.dev/tutorials/35-008-8-%E6%96%AD%E8%A8%80%E5%BC%82%E5%B8%B8/</link><pubDate>Thu, 02 Nov 2017 06:23:31 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/35-008-8-%E6%96%AD%E8%A8%80%E5%BC%82%E5%B8%B8/</guid><description>&lt;h3 id="背景">背景&lt;/h3>
&lt;p>我们有时候需要断言一些方法会抛出异常，这些异常需要符合我们的预期。&lt;/p>
&lt;h3 id="代码">代码&lt;/h3>
&lt;p>新建&lt;code>test_exception.py&lt;/code>文件，内容如下&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">unittest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">DivZeroTestCase&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TestCase&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">test_should_raise_exception&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">with&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertRaises&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="ne">ZeroDivisionError&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="mi">1&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">main&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行及结果">运行及结果&lt;/h3>
&lt;pre tabindex="0">&lt;code>$ python test_exception.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK
&lt;/code>&lt;/pre>&lt;h3 id="我们能学到什么">我们能学到什么&lt;/h3>
&lt;ul>
&lt;li>上面的例子断言了当0作为除数的时候会抛出&lt;code>ZeroDivisionError&lt;/code>&lt;/li>
&lt;li>断言异常是有套路的，使用&lt;code>with&lt;/code>语句加&lt;code>assertRaises&lt;/code>，assertRaises的参数中传入预期的异常(这些异常可能需要先import进来)，在with的子句中放上会抛出异常的语句或表达式&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1573496130407-57329f01f769?w=300"
 data-srcset="https://images.unsplash.com/photo-1573496130407-57329f01f769?w=300, https://images.unsplash.com/photo-1573496130407-57329f01f769?w=300 1.5x, https://images.unsplash.com/photo-1573496130407-57329f01f769?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1573496130407-57329f01f769?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>8. 命令行参数与unpack</title><link>https://itest2025.pages.dev/tutorials/28-008-8-%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%8F%82%E6%95%B0%E4%B8%8Eunpack/</link><pubDate>Tue, 31 Oct 2017 08:17:22 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/28-008-8-%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%8F%82%E6%95%B0%E4%B8%8Eunpack/</guid><description>&lt;h3 id="背景">背景&lt;/h3>
&lt;p>我们先稍微的修改一下上一节的用例生成器，加入接收命令行参数的功能。&lt;/p>
&lt;p>作为测试用例的执行者，我们希望在创建用例的时候可以指定用例编号，以便能够更加系统的管理测试用例。&lt;/p>
&lt;h3 id="代码实现">代码实现&lt;/h3>
&lt;p>新建名为&lt;code>gen_test_case_with_id.py&lt;/code>，内容如下&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">sys&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">argv&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">script&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">case_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">argv&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;创建测试用例&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">用例编号: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">case_id&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">case_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">input&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;请输入用例名称:&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">test_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">input&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;请输入用到的测试数据，比如: 测试站点=www.itest.info:&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">test_steps&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">input&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;请输入测试步骤:&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">test_assert&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">input&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;请输入测试断言(预期结果):&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">formatter&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">用例编号: &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">用例名称: &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">测试数据: &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">测试步骤: &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">测试断言: &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">formatter&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">case_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">case_name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">test_data&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">test_steps&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">test_assert&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行">运行&lt;/h3>
&lt;p>在命令行中使用下面的命令去执行代码&lt;/p>
&lt;pre tabindex="0">&lt;code>$python gen_test_case_with_id.py itest_001
&lt;/code>&lt;/pre>&lt;p>&lt;strong>注意： 我们在脚本名称后面加上了itest_001，这就是我们指定的用例编号，千万不要忘记传入这个参数，否则代码将会报如下的错误&lt;/strong>&lt;/p>
&lt;pre tabindex="0">&lt;code>Traceback (most recent call last):
 File &amp;#34;gen_test_case_with_id.py&amp;#34;, line 3, in &amp;lt;module&amp;gt;
 script, case_id = argv
ValueError: not enough values to unpack (expected 2, got 1)
&lt;/code>&lt;/pre>&lt;h3 id="你应该可以看到">你应该可以看到&lt;/h3>
&lt;p>按照下面展示的情况进行输入，如果没有出错的话，你应该可以看到命令行窗口显示如下的内容&lt;/p>
&lt;pre tabindex="0">&lt;code>创建测试用例
用例编号: itest_001
请输入用例名称:
登录成功
请输入用到的测试数据，比如: 测试站点=www.itest.info:
无
请输入测试步骤:
略
请输入测试断言(预期结果):
跳转到www.itest.info

用例编号: itest_001
用例名称: 登录成功
测试数据: 无
测试步骤: 略
测试断言: 跳转到www.itest.info
&lt;/code>&lt;/pre>&lt;h3 id="import">import&lt;/h3>
&lt;p>python给我们预置了很多常用的功能，这些功能以module的形式组织起来，使用&lt;code>import&lt;/code>关键字就可以把我们需要的内容导入进来，从而在脚本里使用。&lt;/p></description></item><item><title>8.使用pytest做简单的接口测试</title><link>https://itest2025.pages.dev/tutorials/25-008-8%E4%BD%BF%E7%94%A8pytest%E5%81%9A%E7%AE%80%E5%8D%95%E7%9A%84%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95/</link><pubDate>Fri, 27 Oct 2017 07:22:42 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/25-008-8%E4%BD%BF%E7%94%A8pytest%E5%81%9A%E7%AE%80%E5%8D%95%E7%9A%84%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95/</guid><description>&lt;h3 id="背景">背景&lt;/h3>
&lt;p>我们现在需要测试&lt;a href="http://www.v2ex.com" target="_blank" rel="noopener noreffer ">v2ex&lt;/a>网站的查看论坛节点信息的api。具体如下:&lt;/p>
&lt;pre tabindex="0">&lt;code>节点信息

获得指定节点的名字，简介，URL 及头像图片的地址。

https://www.v2ex.com/api/nodes/show.json

Method: GET
Authentication: None
接受参数：

name: 节点名（V2EX 的节点名全是半角英文或者数字）
例如：

https://www.v2ex.com/api/nodes/show.json?name=python

接口返回

{
 &amp;#34;id&amp;#34; : 90,
 &amp;#34;name&amp;#34; : &amp;#34;python&amp;#34;,
 &amp;#34;url&amp;#34; : &amp;#34;http://www.v2ex.com/go/python&amp;#34;,
 &amp;#34;title&amp;#34; : &amp;#34;Python&amp;#34;,
 &amp;#34;title_alternative&amp;#34; : &amp;#34;Python&amp;#34;,
 &amp;#34;topics&amp;#34; : 7963,
 &amp;#34;stars&amp;#34; : 5138,

 &amp;#34;header&amp;#34; : &amp;#34;这里讨论各种 Python 语言编程话题，也包括 Django，Tornado 等框架的讨论。这里是一个能够帮助你解决实际问题的地方。&amp;#34;,


 &amp;#34;footer&amp;#34; : null,

 &amp;#34;created&amp;#34; : 1278683336,
 &amp;#34;avatar_mini&amp;#34; : &amp;#34;//v2ex.assets.uxengine.net/navatar/8613/985e/90_mini.png?m=1509941286&amp;#34;,
 &amp;#34;avatar_normal&amp;#34; : &amp;#34;//v2ex.assets.uxengine.net/navatar/8613/985e/90_normal.png?m=1509941286&amp;#34;,
 &amp;#34;avatar_large&amp;#34; : &amp;#34;//v2ex.assets.uxengine.net/navatar/8613/985e/90_large.png?m=1509941286&amp;#34;
}
&lt;/code>&lt;/pre>&lt;h3 id="需求分析">需求分析&lt;/h3>
&lt;p>该接口是获取数据的接口，一般来说，这种接口我们的测试重点是验证数据的准确性。&lt;/p>
&lt;p>根据&lt;a href="https://itest2025.pages.dev/interface/3a/" rel="">3A原则&lt;/a>，我们可以设计如下的&lt;a href="https://itest2025.pages.dev/interface/first_case/" rel="">用例&lt;/a>&lt;/p>
&lt;ul>
&lt;li>测试数据: 节点的名称:python&lt;/li>
&lt;li>接口地址: &lt;a href="https://www.v2ex.com/api/nodes/show.json" target="_blank" rel="noopener noreffer ">https://www.v2ex.com/api/nodes/show.json&lt;/a>&lt;/li>
&lt;li>断言: 返回的结果里，id必须是90,name必须等于python，大家想一想为什么？&lt;/li>
&lt;/ul>
&lt;h3 id="代码">代码&lt;/h3>
&lt;p>新建名为&lt;code>v2ex_api_test.py&lt;/code>的文件，键入如下内容&lt;/p></description></item><item><title>8. 其他</title><link>https://itest2025.pages.dev/tutorials/43-008-8-%E5%85%B6%E4%BB%96/</link><pubDate>Mon, 23 Oct 2017 06:55:26 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/43-008-8-%E5%85%B6%E4%BB%96/</guid><description>&lt;h3 id="wait">wait&lt;/h3>
&lt;p>&lt;code>webium.wait.wait()&lt;/code>是&lt;a href="https://pypi.python.org/pypi/waiting" target="_blank" rel="noopener noreffer ">python wait&lt;/a>库的简单封装。&lt;/p>
&lt;p>具体实现看&lt;a href="https://github.com/wgnet/webium/blob/ccb09876a201e75f5c5810392d4db7a8708b90cb/webium/wait.py#L7" target="_blank" rel="noopener noreffer ">这里&lt;/a>&lt;/p>
&lt;h3 id="settings">settings&lt;/h3>
&lt;p>可以看成是webium的全局配置，有下面的一些配置项目，具体看&lt;a href="https://github.com/wgnet/webium/blob/ccb09876a201e75f5c5810392d4db7a8708b90cb/webium/settings.py#L1" target="_blank" rel="noopener noreffer ">这里&lt;/a>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver_class&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Firefox&lt;/span> &lt;span class="c1"># 默认的driver&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">implicit_timeout&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">30&lt;/span> &lt;span class="c1"># 默认的隐式等待时间&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">wait_timeout&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">30&lt;/span> &lt;span class="c1"># 等待超时时间&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">default_search_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">By&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ID&lt;/span> &lt;span class="c1"># 默认的定位策略&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>具体例子&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">webium.settings&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium.webdriver&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Chrome&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">webium&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">settings&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">implicit_timeout&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">webium&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">settings&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">driver_class&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Chrome&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1573164574397-dd250bc8a598?w=300"
 data-srcset="https://images.unsplash.com/photo-1573164574397-dd250bc8a598?w=300, https://images.unsplash.com/photo-1573164574397-dd250bc8a598?w=300 1.5x, https://images.unsplash.com/photo-1573164574397-dd250bc8a598?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1573164574397-dd250bc8a598?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（八）实战：构建 GitHub 项目(下)</title><link>https://itest2025.pages.dev/tutorials/18-008-%E5%85%AB%E5%AE%9E%E6%88%98%E6%9E%84%E5%BB%BA-github-%E9%A1%B9%E7%9B%AE%E4%B8%8B/</link><pubDate>Mon, 16 Oct 2017 11:45:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/18-008-%E5%85%AB%E5%AE%9E%E6%88%98%E6%9E%84%E5%BB%BA-github-%E9%A1%B9%E7%9B%AE%E4%B8%8B/</guid><description>&lt;p>其实，到些为止，整个项目已经创建完成。这一小节，只是为了验证创建的项目是否有效。&lt;/p>
&lt;h4 id="提交项目版本">提交项目版本&lt;/h4>
&lt;hr>
&lt;p>修改 &lt;a href="https://github.com/defnngj/pyse" target="_blank" rel="noopener noreffer ">pyse&lt;/a> 开源项目,并提交代码到 GitHub .&lt;/p>
&lt;pre tabindex="0">&lt;code>D:\git\pyse (master)
λ git commit -m &amp;#34;verison 0.0.8&amp;#34;

[master 270de98] verison 0.0.8
 6 files changed, 36 insertions(+), 32 deletions(-)
 create mode 100644 test_report.png

 D:\git\pyse (master)
 λ git push origin master

 Counting objects: 12, done.
 Delta compression using up to 4 threads.
 Compressing objects: 100% (11/11), done.
 Writing objects: 100% (12/12), 33.80 KiB | 11.27 MiB/s, done.
 Total 12 (delta 5), reused 0 (delta 0)
 remote: Resolving deltas: 100% (5/5), completed with 5 local objects.
 To https://github.com/defnngj/pyse
 c5b4c8a..270de98 master -&amp;gt; master
&lt;/code>&lt;/pre>&lt;h4 id="查看构建日志">查看构建日志&lt;/h4>
&lt;hr>
&lt;p>通过 Jenkins 查看项目构建历史。&lt;/p></description></item><item><title>（八）Locust 设置断言</title><link>https://itest2025.pages.dev/tutorials/38-008-%E5%85%ABlocust-%E8%AE%BE%E7%BD%AE%E6%96%AD%E8%A8%80/</link><pubDate>Mon, 16 Oct 2017 08:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/38-008-%E5%85%ABlocust-%E8%AE%BE%E7%BD%AE%E6%96%AD%E8%A8%80/</guid><description>&lt;p>性能测试也需要设置断言么？ 某些情况下是需要，比如你在请求一个页面时，就可以通过状态来判断返回的 HTTP 状态码是不是 200。&lt;/p>
&lt;h4 id="设置响应断言">设置响应断言&lt;/h4>
&lt;hr>
&lt;p>这里同样以测试百度首页为例。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">locust&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">HttpLocust&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">TaskSet&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">task&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">UserTask&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">TaskSet&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@task&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">job&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">with&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">client&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;/&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">catch_response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status_code&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">200&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">failure&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Failed!&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">success&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">User&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">HttpLocust&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">task_set&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">UserTask&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">min_wait&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1000&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_wait&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">3000&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">host&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;https://www.baidu.com&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>catch_response = True ：布尔类型，如果设置为 True, 允许该请求被标记为失败。&lt;/p>
&lt;p>通过 client.get() 方法发送请求，将整个请求的给 response， 通过 response.status_code 得请求响应的 HTTP 状态码。如果不为 200 则通过 response.failure(&amp;lsquo;Failed!&amp;rsquo;) 打印失败！&lt;/p>
&lt;p>&lt;strong>启动测试，运行情况：&lt;/strong>&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/locust_run_fail.png"
 data-srcset="http://img.testclass.net/locust_run_fail.png, http://img.testclass.net/locust_run_fail.png 1.5x, http://img.testclass.net/locust_run_fail.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/locust_run_fail.png"
 title="http://img.testclass.net/locust_run_fail.png" />&lt;/p>
&lt;p>至于，我上面的测试脚本为什么为失败，你自个分析一下吧！原因很简单。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1513470270416-d3ff6f16b22f?w=300"
 data-srcset="https://images.unsplash.com/photo-1513470270416-d3ff6f16b22f?w=300, https://images.unsplash.com/photo-1513470270416-d3ff6f16b22f?w=300 1.5x, https://images.unsplash.com/photo-1513470270416-d3ff6f16b22f?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1513470270416-d3ff6f16b22f?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>08. 安装后生成的目录说明、VM 设置（新用户必看）</title><link>https://itest2025.pages.dev/tutorials/37-008-08-%E5%AE%89%E8%A3%85%E5%90%8E%E7%94%9F%E6%88%90%E7%9A%84%E7%9B%AE%E5%BD%95%E8%AF%B4%E6%98%8Evm-%E8%AE%BE%E7%BD%AE%E6%96%B0%E7%94%A8%E6%88%B7%E5%BF%85%E7%9C%8B/</link><pubDate>Mon, 16 Oct 2017 05:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/37-008-08-%E5%AE%89%E8%A3%85%E5%90%8E%E7%94%9F%E6%88%90%E7%9A%84%E7%9B%AE%E5%BD%95%E8%AF%B4%E6%98%8Evm-%E8%AE%BE%E7%BD%AE%E6%96%B0%E7%94%A8%E6%88%B7%E5%BF%85%E7%9C%8B/</guid><description>&lt;h1 id="intellij-idea-相关核心文件和目录介绍">IntelliJ IDEA 相关核心文件和目录介绍&lt;/h1>
&lt;h2 id="安装目录介绍">安装目录介绍&lt;/h2>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/viii-a-installation-directory-1.jpg"
 data-srcset="http://img.testclass.net/viii-a-installation-directory-1.jpg, http://img.testclass.net/viii-a-installation-directory-1.jpg 1.5x, http://img.testclass.net/viii-a-installation-directory-1.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/viii-a-installation-directory-1.jpg"
 title="安装目录介绍" />&lt;/p>
&lt;blockquote>
&lt;ul>
&lt;li>IntelliJ IDEA 的安装目录并不复杂，上图为最常改动的 bin 目录，经常会改动的文件或是必须介绍就是如图红色框中的几个。&lt;/li>
&lt;li>&lt;code>idea.exe&lt;/code> 文件是 IntelliJ IDEA 32 位的可行执行文件，IntelliJ IDEA 安装完默认发送到桌面的也就是这个执行文件的快捷方式。&lt;/li>
&lt;li>&lt;code>idea.exe.vmoptions&lt;/code> 文件是 IntelliJ IDEA 32 位的可执行文件的 VM 配置文件，具体配置修改会下面进行专门讲解。&lt;/li>
&lt;li>&lt;code>idea64.exe&lt;/code> 文件是 IntelliJ IDEA 64 位的可行执行文件，要求必须电脑上装有 JDK 64 位版本。64 位的系统也是建议使用该文件。&lt;/li>
&lt;li>&lt;code>idea64.exe.vmoptions&lt;/code> 文件是 IntelliJ IDEA 64 位的可执行文件的 VM 配置文件，具体配置修改会下面进行专门讲解。&lt;/li>
&lt;li>&lt;code>idea.properties&lt;/code> 文件是 IntelliJ IDEA 的一些属性配置文件，具体配置修改会下面进行专门讲解。&lt;/li>
&lt;/ul>&lt;/blockquote>
&lt;p>强烈推荐&lt;strong>不要&lt;/strong>直接修改安装目录下的这几个配置文件，因为 IDEA 升级/重装可能会导致修改完全失效！
强烈推荐使用 IDEA 自带菜单中的 &lt;code>Help -&amp;gt; Edit Custom VM Options&lt;/code> 和 &lt;code>Help -&amp;gt; Edit Custom Properties&lt;/code> 来进行个性化配置！&lt;/p></description></item><item><title>（八）soapUI创建性能测试</title><link>https://itest2025.pages.dev/tutorials/26-008-%E5%85%ABsoapui%E5%88%9B%E5%BB%BA%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/</link><pubDate>Wed, 20 Sep 2017 20:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/26-008-%E5%85%ABsoapui%E5%88%9B%E5%BB%BA%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/</guid><description>&lt;br>
&lt;p>这一节我们来介绍性能测试，以前面添加的 SOAP 项目为例。&lt;/p>
&lt;p>&lt;a href="https://itest2025.pages.dev/soapui/create-soap-project/" rel="">（五）soapUI创建SOAP项目&lt;/a>&lt;/p>
&lt;h4 id="创建测试用例">创建测试用例&lt;/h4>
&lt;hr>
&lt;p>右键点击 &lt;strong>“requests 1”&lt;/strong> 请求，选择 &lt;strong>“Add to TestCase”&lt;/strong> &amp;hellip;，如下图。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/soapui_add_to_TestCase.png"
 data-srcset="http://img.testclass.net/soapui_add_to_TestCase.png, http://img.testclass.net/soapui_add_to_TestCase.png 1.5x, http://img.testclass.net/soapui_add_to_TestCase.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/soapui_add_to_TestCase.png"
 title="http://img.testclass.net/soapui_add_to_TestCase.png" />&lt;/p>
&lt;p>第一步，默认设置测试套件名为：TestSuite 1。&lt;/p>
&lt;p>第二步，默认设置测试用例名为：TestCase 1。&lt;/p>
&lt;p>第三步，添加 Requests 到 测试用例，如下图。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/soapui_add_requests_to_TestCase.png"
 data-srcset="http://img.testclass.net/soapui_add_requests_to_TestCase.png, http://img.testclass.net/soapui_add_requests_to_TestCase.png 1.5x, http://img.testclass.net/soapui_add_requests_to_TestCase.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/soapui_add_requests_to_TestCase.png"
 title="http://img.testclass.net/soapui_add_requests_to_TestCase.png" />&lt;/p>
&lt;p>点击 &lt;strong>“OK”&lt;/strong> 完整测试用例的创建，如下图。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/soapui_add_LoadTest.png"
 data-srcset="http://img.testclass.net/soapui_add_LoadTest.png, http://img.testclass.net/soapui_add_LoadTest.png 1.5x, http://img.testclass.net/soapui_add_LoadTest.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/soapui_add_LoadTest.png"
 title="http://img.testclass.net/soapui_add_LoadTest.png" />&lt;/p>
&lt;br>
#### 创建性能测试用例 &amp; 运行
----
&lt;p>接下来，创建性能测试用例，右键点击 &lt;strong>“Load Tests (1)” &amp;ndash;&amp;gt; “New LoadTest”&lt;/strong> , 创建完成，参考上图，多出来一个 &lt;strong>“LoadTest 1”&lt;/strong> 的选项。&lt;/p>
&lt;p>最后，运行性能测试。在 &lt;strong>“LoadTest 1”&lt;/strong> 窗口，点解右上角的绿色按钮，运行性能测试。&lt;/p></description></item><item><title>appium新手入门（8）—— 定位控件</title><link>https://itest2025.pages.dev/tutorials/21-008-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A88-%E5%AE%9A%E4%BD%8D%E6%8E%A7%E4%BB%B6/</link><pubDate>Thu, 07 Sep 2017 10:24:12 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/21-008-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A88-%E5%AE%9A%E4%BD%8D%E6%8E%A7%E4%BB%B6/</guid><description>&lt;p>appium 通过 uiautomatorviewer.bat 工具来查看控件的属性。该工具位于 &lt;a href="https://itest2025.pages.dev/appium/appium-base-sdk/" rel="">Android SDK&lt;/a> 的 &lt;strong>/tools/bin/&lt;/strong> 目录下。&lt;/p>
&lt;h4 id="id-定位">id 定位&lt;/h4>
&lt;hr>
&lt;p>通过uiautomatorviewer.bat 工具可以查看对象的id属性。&lt;/p>
&lt;p>如果目标设备的API Level低于18则UIAutomatorViewer不能获得对应的Resource ID，只有等于大于18的时候才能使用。&lt;/p>
&lt;p>打开uiautomatorviewer.bat工具：&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/appium_find_element_id.png"
 data-srcset="http://img.testclass.net/appium_find_element_id.png, http://img.testclass.net/appium_find_element_id.png 1.5x, http://img.testclass.net/appium_find_element_id.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/appium_find_element_id.png"
 title="http://img.testclass.net/appium_find_element_id.png" />&lt;/p>
&lt;p>resource-id 就是我们理解的id属性了。&lt;/p>
&lt;p>&lt;em>&lt;strong>使用方法：&lt;/strong>&lt;/em>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;com.android.calculator2:id/formula&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="name-定位">name 定位&lt;/h4>
&lt;hr>
&lt;p>打开uiautomatorviewer.bat工具：&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/appium_find_element_class.png"
 data-srcset="http://img.testclass.net/appium_find_element_class.png, http://img.testclass.net/appium_find_element_class.png 1.5x, http://img.testclass.net/appium_find_element_class.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/appium_find_element_class.png"
 title="http://img.testclass.net/appium_find_element_class.png" />&lt;/p>
&lt;p>text就是我们要查找的name了，为什么在命名上毫无关联啊！&lt;/p>
&lt;p>&lt;em>&lt;strong>使用方法：&lt;/strong>&lt;/em>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;9&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="class-name-定位">class name 定位&lt;/h3>
&lt;hr>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/appium_find_element_class_name.png"
 data-srcset="http://img.testclass.net/appium_find_element_class_name.png, http://img.testclass.net/appium_find_element_class_name.png 1.5x, http://img.testclass.net/appium_find_element_class_name.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/appium_find_element_class_name.png"
 title="http://img.testclass.net/appium_find_element_class_name.png" />&lt;/p>
&lt;p>计算器界面上的的class属性是：android.widget.Button。
&lt;em>&lt;strong>使用方法：&lt;/strong>&lt;/em>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">WebElement&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">button&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">className&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;android.widget.Button&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>使用 Class Name 一般获得的 view 都不止一个，所以应该需要遍历一遍得到的 views，然后缩小搜索条件来获得目标控件。&lt;/p>
&lt;h4 id="xpath定位">XPath定位&lt;/h4>
&lt;hr>
&lt;p>在 WebDriver 上 XPath 定位是功能强大的一种定位方式。我个人惯用于此方法来定位Web页面上的元素。下面看看在 Android 上 XPath 定位的用法。&lt;/p></description></item><item><title>面试官问：说一个你工作中有价值的bug</title><link>https://itest2025.pages.dev/tutorials/44-008-%E9%9D%A2%E8%AF%95%E5%AE%98%E9%97%AE%E8%AF%B4%E4%B8%80%E4%B8%AA%E4%BD%A0%E5%B7%A5%E4%BD%9C%E4%B8%AD%E6%9C%89%E4%BB%B7%E5%80%BC%E7%9A%84bug/</link><pubDate>Thu, 24 Aug 2017 09:44:38 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/44-008-%E9%9D%A2%E8%AF%95%E5%AE%98%E9%97%AE%E8%AF%B4%E4%B8%80%E4%B8%AA%E4%BD%A0%E5%B7%A5%E4%BD%9C%E4%B8%AD%E6%9C%89%E4%BB%B7%E5%80%BC%E7%9A%84bug/</guid><description>&lt;br>
&lt;p>这其实是前两天测试论坛上一个同学的问题，也是我以前面试时被问到一个问题，看到这个问题后，我的大脑开始搜索过去遇到的印象深刻或有价值的bug。&lt;/p>
&lt;p>表面看这是一个非常简单的一个问题，做测试辣么久，发现的bug无数，随便从中挑选一个比较“特别”的一个bug说说就可以了啊！&lt;/p>
&lt;p>但其实，越是从习以为常的事情中找“特别”越困难，比如，我每天中午都是楼下随便找一家快餐店吃饭，如果有人问我：说说你印象深刻的一次吃快餐的经历。除非我哪天吃出了苍蝇，否则怎么会对每天吃的快餐印象深刻。&lt;/p>
&lt;p>同类的还有小学作文：《记最难忘的一件事》就很难写，别说对于小学生，对于成年人来说也一样，这其实跟你的文笔没太大关系。&lt;/p>
&lt;p>但如果换一个问题： 说说你如何测试面前的这把椅子？ 这个问题就简单太多了。&lt;/p>
&lt;p>为什么前面让你描述一个bug就那么难，对一把椅子写测试用例就很简单呢？ 明明两个都是工作最常用的“知识”。&lt;/p>
&lt;p>因为第一个问题太发散了嘛！我还要把以往有印象的bug在大脑中搜索一遍&amp;hellip; 前几天测试的时候发现页面上有一个错别字，然后让开发改了，不行不行，这个太简单了，我要说这个bug，面试官会不会直接把我赶出来！？&lt;/p>
&lt;p>继续想&amp;hellip;.&lt;/p>
&lt;p>我们换位思考一下，面试官问这个问题的目的是什么？&lt;/p>
&lt;p>其实，它并不关心你描述的这个bug是否真的有价值，或有多曲折离奇？他只是：&lt;/p>
&lt;ul>
&lt;li>了解你平时工作中的测试能力&lt;/li>
&lt;/ul>
&lt;p>所以，这就要求的你平时工作中遇到bug时试着自己去定位，定位bug的过程远比你的单纯的执行测试用例有“价值”（自我技能提高的价值），在定位bug的过程中你需要掌握和运用更多知识。&lt;/p>
&lt;p>另外，建议你平时养成总结的好习惯，发现的bug，开发解决了，最好问问他原因以及解决的方法，这样再遇到类似问题时，自己也可以试着定位解决。遇到难解决的bug，也可以把最终的解决过程记录下来。（这不是就有素材了）&lt;/p>
&lt;ul>
&lt;li>考察你的表达能力&lt;/li>
&lt;/ul>
&lt;p>我们搞技术的有许多属于闷骚性格（我也是！），让我们和技术打交道游刃有余。在QQ群里聊天，也风趣、幽默、机智、博学&amp;hellip;. 因为网络段子看多了嘛，再加上有百度加持。但面对公司会议或者和陌生人交流时，语言表达能力比较欠缺。&lt;/p>
&lt;p>所以，建议你平时可以主动要求去分享一些自己工作中用到或学习的技术。或者多去参加集体活动，加强自己的表达能力。&lt;/p>
&lt;ul>
&lt;li>也许就是想抛一个问题给你，自己好有时间继续看你的简历。&lt;/li>
&lt;/ul>
&lt;p>好了，大概了解的面试官的目的，那么可以在面试前事先思考一下这个问题，从工作中总结一些记忆深刻和有价值的bug。&lt;/p>
&lt;p>如果，一时想不起来，可以这么切入，找一个自己工作中很熟悉的项目，然后，谈谈你是如何对这个项目进行测试的，然后，在某一个版本测试中，发现xxx，开发也xxxx，前端也xxxx，运维也xxxx，最后终于发现原来是xxx引起的xxxx 。&lt;/p>
&lt;p>把你工作过程中的测试方法和步骤描述清楚了，那么这个bug有没有价值或是否印象深刻就不那么重要了。&lt;/p>
&lt;p>如果你刚好去面试，加油！祝你好运！&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1554902843-260acd0993f8?w=300"
 data-srcset="https://images.unsplash.com/photo-1554902843-260acd0993f8?w=300, https://images.unsplash.com/photo-1554902843-260acd0993f8?w=300 1.5x, https://images.unsplash.com/photo-1554902843-260acd0993f8?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1554902843-260acd0993f8?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>8.第一个用例</title><link>https://itest2025.pages.dev/tutorials/40-008-8%E7%AC%AC%E4%B8%80%E4%B8%AA%E7%94%A8%E4%BE%8B/</link><pubDate>Wed, 23 Aug 2017 04:41:43 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/40-008-8%E7%AC%AC%E4%B8%80%E4%B8%AA%E7%94%A8%E4%BE%8B/</guid><description>&lt;p>前面铺垫了很多的基础知识，掌握基础知识是做基于http接口自动化测试的前提，不建议直接跳过。&lt;/p>
&lt;h3 id="前提条件">前提条件&lt;/h3>
&lt;p>学习本节需要有一些前提条件&lt;/p>
&lt;ul>
&lt;li>安装了postman&lt;/li>
&lt;li>安装了python&lt;/li>
&lt;li>安装了requests&lt;/li>
&lt;/ul>
&lt;h3 id="用例描述">用例描述&lt;/h3>
&lt;p>在&lt;a href="https://itest2025.pages.dev/interface/test_object/" rel="">认识测试对象&lt;/a>这一节里有过描述。&lt;/p>
&lt;pre tabindex="0">&lt;code>
获得指定节点的名字，简介，URL 及头像图片的地址。

https://www.v2ex.com/api/nodes/show.json

Method: GET
Authentication: None
接受参数：

name: 节点名（V2EX 的节点名全是半角英文或者数字）
例如：

https://www.v2ex.com/api/nodes/show.json?name=python

# 响应

{
 &amp;#34;id&amp;#34; : 90,
 &amp;#34;name&amp;#34; : &amp;#34;python&amp;#34;,
 &amp;#34;url&amp;#34; : &amp;#34;http://www.v2ex.com/go/python&amp;#34;,
 &amp;#34;title&amp;#34; : &amp;#34;Python&amp;#34;,
 &amp;#34;title_alternative&amp;#34; : &amp;#34;Python&amp;#34;,
 &amp;#34;topics&amp;#34; : 7669,
 &amp;#34;stars&amp;#34; : 4870,

 &amp;#34;header&amp;#34; : &amp;#34;这里讨论各种 Python 语言编程话题，也包括 Django，Tornado 等框架的讨论。这里是一个能够帮助你解决实际问题的地方。&amp;#34;,


 &amp;#34;footer&amp;#34; : null,

 &amp;#34;created&amp;#34; : 1278683336,
 &amp;#34;avatar_mini&amp;#34; : &amp;#34;//v2ex.assets.uxengine.net/navatar/8613/985e/90_mini.png?m=1504279401&amp;#34;,
 &amp;#34;avatar_normal&amp;#34; : &amp;#34;//v2ex.assets.uxengine.net/navatar/8613/985e/90_normal.png?m=1504279401&amp;#34;,
 &amp;#34;avatar_large&amp;#34; : &amp;#34;//v2ex.assets.uxengine.net/navatar/8613/985e/90_large.png?m=1504279401&amp;#34;
}
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>测试数据: 节点的名称:python&lt;/li>
&lt;li>接口地址: &lt;a href="https://www.v2ex.com/api/nodes/show.json" target="_blank" rel="noopener noreffer ">https://www.v2ex.com/api/nodes/show.json&lt;/a>&lt;/li>
&lt;li>断言: 返回的结果里，id必须是90,name必须等于python，大家想一想为什么？&lt;/li>
&lt;/ul>
&lt;h3 id="使用postman调试接口">使用postman调试接口&lt;/h3>
&lt;p>在写用例之前，我们先在postman里把接口调通，大家可以参考&lt;a href="https://itest2025.pages.dev/interface/install_postman/" rel="">之前这篇&lt;/a>&lt;/p></description></item><item><title>appium简明教程（8）——那些工具</title><link>https://itest2025.pages.dev/tutorials/21-008-appium%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B8%E9%82%A3%E4%BA%9B%E5%B7%A5%E5%85%B7/</link><pubDate>Sun, 13 Aug 2017 08:07:13 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/21-008-appium%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B8%E9%82%A3%E4%BA%9B%E5%B7%A5%E5%85%B7/</guid><description>&lt;p>正所谓工欲善其事必先利其器，对于appium实战android来说，下面的这些工具(以windows系统为例)是必须熟练使用的。&lt;/p>
&lt;p>&lt;strong>monitor.bat（hierarchyviewer.bat已经不赞成继续使用了）&lt;/strong>&lt;/p>
&lt;p>该文件位于your_andriod_sdk_path\tools下面。以乙醇的机器为例，其位于E:\adt-bundle-windows-x86-20131030\sdk\tools下。&lt;/p>
&lt;p>该工具可以帮我们找到android控件的content-description，为以后的find_element_by_accessibility_id 定位方法做参数使用。&lt;/p>
&lt;p>关于什么是content-description，可以参考&lt;a href="http://developer.android.com/training/accessibility/accessible-app.html" target="_blank" rel="noopener noreffer ">官方文档&lt;/a>。&lt;/p>
&lt;p>好，露个脸。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://oriphg3yh.bkt.clouddn.com/tool1.png"
 data-srcset="http://oriphg3yh.bkt.clouddn.com/tool1.png, http://oriphg3yh.bkt.clouddn.com/tool1.png 1.5x, http://oriphg3yh.bkt.clouddn.com/tool1.png 2x"
 data-sizes="auto"
 alt="http://oriphg3yh.bkt.clouddn.com/tool1.png"
 title="http://oriphg3yh.bkt.clouddn.com/tool1.png" />&lt;/p>
&lt;p>&lt;strong>uiautomatorviewer.bat&lt;/strong>&lt;/p>
&lt;p>该文件位于your_andriod_sdk_path\tools下面。以乙醇的机器为例，其位于E:\adt-bundle-windows-x86-20131030\sdk\tools下。&lt;/p>
&lt;p>该工具主要用来查看控件的属性，比如resource id，class name等。&lt;/p>
&lt;p>该工具也可查看被测app的appPackage（Desired Capabilities中使用）。&lt;/p>
&lt;p>爆照。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://oriphg3yh.bkt.clouddn.com/tool2.png"
 data-srcset="http://oriphg3yh.bkt.clouddn.com/tool2.png, http://oriphg3yh.bkt.clouddn.com/tool2.png 1.5x, http://oriphg3yh.bkt.clouddn.com/tool2.png 2x"
 data-sizes="auto"
 alt="http://oriphg3yh.bkt.clouddn.com/tool2.png"
 title="http://oriphg3yh.bkt.clouddn.com/tool2.png" />&lt;/p>
&lt;p>好了，是不是感觉还缺了点什么呢？&lt;/p>
&lt;p>确实如此，被测app的appActivity怎么获取呢？&lt;/p>
&lt;p>下一讲我们详细讲解如何获取被测app的appActivity。&lt;/p>
&lt;p>本文版权归乙醇所有，欢迎转载，但请注明作者与出处，严禁用于任何商业用途&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1589517628174-5698bcf47311?w=300"
 data-srcset="https://images.unsplash.com/photo-1589517628174-5698bcf47311?w=300, https://images.unsplash.com/photo-1589517628174-5698bcf47311?w=300 1.5x, https://images.unsplash.com/photo-1589517628174-5698bcf47311?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1589517628174-5698bcf47311?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>性能测试流程（三）——分析测试点</title><link>https://itest2025.pages.dev/tutorials/14-008-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E6%B5%81%E7%A8%8B%E4%B8%89%E5%88%86%E6%9E%90%E6%B5%8B%E8%AF%95%E7%82%B9/</link><pubDate>Fri, 11 Aug 2017 06:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/14-008-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E6%B5%81%E7%A8%8B%E4%B8%89%E5%88%86%E6%9E%90%E6%B5%8B%E8%AF%95%E7%82%B9/</guid><description>&lt;p>当你了解你的系统架构之后，接下来可以好好的分析一下性能测试点。因为这关系到你测试工具的选型。&lt;/p>
&lt;p>&lt;strong>性能测试点的选取&lt;/strong>&lt;/p>
&lt;p>*　发生频率非常高的（例如：某邮箱核心业务系统中的登录、收发邮件等业务，它们在每天的业务总量中占到90%以上）&lt;/p>
&lt;p>*　关键程度非常高的（产品经理认为绝对不能出现问题的，如登录等）&lt;/p>
&lt;p>*　资源占用非常严重的（导致磁盘I/O非常大的，例如某个业务进行结果提交时需要向数十个表存取数据，或者一个查询提交请求时会检索出大量的数据记录）&lt;/p>
&lt;p>&lt;strong>对性能需求点的描述&lt;/strong> &lt;/p>
&lt;ul>
&lt;li>准确&lt;/li>
&lt;/ul>
&lt;p>如**系统必须在不超过 10 秒的响应时间内，处理 20 起登录任务。再如发邮件时间最大不超过5秒以及平均时间在2秒以内。&lt;/p>
&lt;ul>
&lt;li>一致&lt;/li>
&lt;/ul>
&lt;p>用户和性能测试工程师对有关术语的理解要一致，如:并发用户数、在线用户数、注册用户数: &lt;/p>
&lt;ul>
&lt;li>特定&lt;/li>
&lt;/ul>
&lt;p>性能测试的需求一定是有条件的。&lt;/p>
&lt;p>检查系统后台关键业务数据10G、操作数据量为20K，1500 个用户、500 个并发用户运行的负载下，连续运行12小时过程中，业务操作是否满足性能需求。&lt;/p>
&lt;p>&lt;strong>一般性能需求描述&lt;/strong>&lt;/p>
&lt;p>1、Web首页打开速度5s以下，Web登陆速度 15s以下。&lt;/p>
&lt;p>2、邮件服务支持50万个在线用户&lt;/p>
&lt;p>3、计费话单成功率达到99.999%以上。&lt;/p>
&lt;p>4、在100个并发用户的高峰期，邮箱的基本功能，处理能力至少达到10QPS(TPS).          QPS(TPS)&amp;ndash;每秒钟请求/事物 数量&lt;/p>
&lt;p>5、系统能在高于实际系统运行压力1倍的情况下，稳定的运行12小时。&lt;/p>
&lt;p>6、这个系统能否支撑200万的VU（每天登录系统的人次）          VU&amp;ndash;Virtual user(虚拟用户) &lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1485368647436-ff0fb9990605?w=300"
 data-srcset="https://images.unsplash.com/photo-1485368647436-ff0fb9990605?w=300, https://images.unsplash.com/photo-1485368647436-ff0fb9990605?w=300 1.5x, https://images.unsplash.com/photo-1485368647436-ff0fb9990605?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1485368647436-ff0fb9990605?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（八）通过css选择器去定位页面上的元素</title><link>https://itest2025.pages.dev/tutorials/20-008-%E5%85%AB%E9%80%9A%E8%BF%87css%E9%80%89%E6%8B%A9%E5%99%A8%E5%8E%BB%E5%AE%9A%E4%BD%8D%E9%A1%B5%E9%9D%A2%E4%B8%8A%E7%9A%84%E5%85%83%E7%B4%A0/</link><pubDate>Sun, 06 Aug 2017 03:41:18 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/20-008-%E5%85%AB%E9%80%9A%E8%BF%87css%E9%80%89%E6%8B%A9%E5%99%A8%E5%8E%BB%E5%AE%9A%E4%BD%8D%E9%A1%B5%E9%9D%A2%E4%B8%8A%E7%9A%84%E5%85%83%E7%B4%A0/</guid><description>&lt;h3 id="css选择器">css选择器&lt;/h3>
&lt;p>火狐的&lt;a href="https://developer.mozilla.org/zh-CN/docs/Learn/CSS" target="_blank" rel="noopener noreffer ">css教程&lt;/a>应该是比较权威的css入门教程了。&lt;/p>
&lt;p>对于selenium自动化测试来说，大家只需要掌握一些必备的&lt;a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/Introduction_to_CSS/Selectors" target="_blank" rel="noopener noreffer ">css选择器&lt;/a>知识就好了。&lt;/p>
&lt;h3 id="目的">目的&lt;/h3>
&lt;ul>
&lt;li>熟悉selenium webdriver 定位方式&lt;/li>
&lt;li>学会通过css选择器去定位元素&lt;/li>
&lt;/ul>
&lt;h3 id="练习对象">练习对象&lt;/h3>
&lt;p>我们使用&lt;a href="https://github.com/cbracco/html5-test-page/blob/master/index.html" target="_blank" rel="noopener noreffer ">html5-test-page&lt;/a>作为我们的练习对象。&lt;/p>
&lt;p>将html代码拷贝一份并保存到本地，文件名为&lt;code>index.html&lt;/code>。&lt;/p>
&lt;h3 id="场景">场景&lt;/h3>
&lt;p>定位下面html代码所示的输入框，并使用sendKeys输入一些内容。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">label&lt;/span> &lt;span class="na">for&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;input__search&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Search&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">label&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">input&lt;/span> &lt;span class="na">id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;input__search&amp;#34;&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;search&amp;#34;&lt;/span> &lt;span class="na">placeholder&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;Enter Search Term&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">label&lt;/span> &lt;span class="na">for&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;input__text2&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Number Input&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">label&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">input&lt;/span> &lt;span class="na">id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;input__text2&amp;#34;&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;number&amp;#34;&lt;/span> &lt;span class="na">placeholder&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;Enter a Number&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">label&lt;/span> &lt;span class="na">for&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;input__text3&amp;#34;&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;error&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Error&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">label&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">input&lt;/span> &lt;span class="na">id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;input__text3&amp;#34;&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;is-error&amp;#34;&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;text&amp;#34;&lt;/span> &lt;span class="na">placeholder&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;Text Input&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">label&lt;/span> &lt;span class="na">for&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;input__text4&amp;#34;&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;valid&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Valid&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">label&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">input&lt;/span> &lt;span class="na">id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;input__text4&amp;#34;&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;is-valid&amp;#34;&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;text&amp;#34;&lt;/span> &lt;span class="na">placeholder&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;Text Input&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="代码">代码&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;path&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">webdriver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;selenium-webdriver&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">By&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">testFile&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;file://&amp;#34;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="nx">path&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">__dirname&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;index.html&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">dr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Builder&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">forBrowser&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;chrome&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">build&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">testFile&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// id selector
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">css&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;#input__search&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;测试教程网&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// attribute selector
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">css&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;input[type=&amp;#34;number&amp;#34;]&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;66666&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// class selector
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">css&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;.is-error&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;should be error&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// class selector
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">css&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;.is-valid&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;should be valid&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行结果">运行结果&lt;/h3>
&lt;p>如下图所示&lt;/p></description></item><item><title>（八）软件测试流程</title><link>https://itest2025.pages.dev/tutorials/29-008-%E5%85%AB%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E6%B5%81%E7%A8%8B/</link><pubDate>Thu, 20 Jul 2017 10:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/29-008-%E5%85%AB%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E6%B5%81%E7%A8%8B/</guid><description>&lt;p>如果想让测试在公司的项目中发挥出它最大的价值，并不是招两个测试技术高手，或引入几个测试技术，而是测试技术对项目流程的渗透，以及测试流程的改进与完善。虽然，当然测试行业前景乐观，许多中小企业也都在引入测试，但一百个公司就有一百种测试，每个公司对测试的看法不同，公司对测试的定位也不完全一样。&lt;/p>
&lt;br>
#### 简陋的测试流程
&lt;p>先说我入职的第一个家公司，我是第一个入职的专职测试人员，相信一两个测试的公司还是不少的，入职后各种项目都在进行当中，上面给我的定位是并没完全融入到项目中去。而通过指派任务的方式。&lt;/p>
&lt;p>下面是简陋的流程图：&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/testing_process01.png"
 data-srcset="http://img.testclass.net/testing_process01.png, http://img.testclass.net/testing_process01.png 1.5x, http://img.testclass.net/testing_process01.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/testing_process01.png"
 title="http://img.testclass.net/testing_process01.png" />&lt;/p>
&lt;p>&lt;strong>需求分析与架构设计：&lt;/strong>&lt;/p>
&lt;p>我们做的是某一移动公司内部使用的项目，需求分析与架构全部由项目经理完成，之后由项目经理给具体某个开发人员分配任务，具体对某个功能模块的实现。这个对项目经理的经验与技术要求很高，他既然担任了需求分析师，又担任架构师的角色。&lt;/p>
&lt;p>&lt;strong>程序员编码：&lt;/strong>&lt;/p>
&lt;p>因为我们开发语言用的是JAVA 语言，IDE用MyEclipse中自带的CVS版本管理工具，开发人员完成代码后，提交到版本库中。&lt;/p>
&lt;p>&lt;strong>测试：&lt;/strong>&lt;/p>
&lt;p>我入职后的第一个任务是搭建缺陷管理工具，禅道项目管理，通过推广对发现的问题进行跟踪。后来正明效果并不好，因为对于一个六七人的开发团队项目，开发人员更喜欢测试人员能当面反馈，这样更能提高效率。对一个小 bug 通过当面交流的方式就可以将问题修复。&lt;/p>
&lt;p>对于当时的环境，并没有测试环境。开发人员在本机上将项目进行部署运行。测试人员通过局域网访问开发人员的机子进行测试。或在测试人员本机上进行部署测试。这也是一个致命的缺点。因为开发人员测试人员使用的电脑存在太多不稳定因素，这些都会造成问题的出现，有时候难以判定是系统问题还是环境问题。&lt;/p>
&lt;p>&lt;strong>上线：&lt;/strong>&lt;/p>
&lt;p>经过测试人员测试通过后，开发人员部署上线。&lt;/p>
&lt;p>&lt;strong>A程序员流程&lt;/strong>&lt;/p>
&lt;p>你会发现在流程图中，A程序员是先发上线之后，再进行测试。这是我们一个面向大众用户的网站，上面给于测试人员的定位是测试兼用户体验，测试将发现的bug和体验问题提交到缺陷管理系统，由经理对问题进行分析，指派开发人员解决。定期对系统进行更新。&lt;/p>
&lt;p>&lt;strong>流程分析：&lt;/strong>&lt;/p>
&lt;p>这个流程唯一的优点，就是能快速的发现并修复问题。&lt;/p>
&lt;p>缺点就非常多了，相信许多小软件公司也有类似的流程。&lt;/p>
&lt;p>这个流程中，项目经理是核心，项目经理也确实是有多年开发与项目经验的牛人，他喜欢不定期分享上些前沿的技术。&lt;/p>
&lt;p>对于测试来说，需求很不明确，测试文档与用例也是可有可无的产物，没有需求文档，或非常简陋，根据需求文档根本无法编写用例。我只能收集一些通用的测试用例，如登录、文件上传下载、列表翻页、日期选择、输入框验证、搜索等有一些“通用型”用例，以便在测试过程中做参考。功能测试的多了，拿到一个功能，测试思路也就出来了。&lt;/p>
&lt;br>
#### 规范的测试流程
----
&lt;p>放弃上份悠闲的工作，感谢那个带我入行公司，我想了解真正的测试在公作中如何进行的。所以，来到了现在这家公司。我很欣喜的是这测试有自己的团队，专业（对当时的我来说）的流程，以及与开发等同的地位。&lt;/p>
&lt;p>现在的测试流程：&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/testing_process02.png"
 data-srcset="http://img.testclass.net/testing_process02.png, http://img.testclass.net/testing_process02.png 1.5x, http://img.testclass.net/testing_process02.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/testing_process02.png"
 title="http://img.testclass.net/testing_process02.png" />&lt;/p>
&lt;p>&lt;strong>需求分析：&lt;/strong>&lt;/p>
&lt;p>需求分析由产品人员制定，他们要做的不是一份简单的文档，而是细化每一个功能的细节，每一个按钮的位置，对于稍大或复杂一点的需求都进行建模。&lt;/p>
&lt;p>&lt;strong>需求评审：&lt;/strong>&lt;/p>
&lt;p>这里会叫上所有参与项目人员进行，开发人员、测试人员、QA人员。测试人员提出需求，开发人员考虑功能实现的方案与可行性、当然开发负责人也是要参与的。测试人员主要是对需求的理解提出疑问，以便才能根据需求写用例。QA人员是最终对软件质量进行验证的人，所以也需要了解需求&lt;/p>
&lt;p>&lt;strong>开发人员编写排期：&lt;/strong>&lt;/p>
&lt;p>开发人员需要根据需求功能点进行排期。然后将开计划转交给测试人员。&lt;/p>
&lt;p>&lt;strong>测试计划排期：&lt;/strong>&lt;/p>
&lt;p>测试人员根据开发计划，对测试具体测试时间，也就是开发功能完成后的时间，进行几轮测试等。然后，把项目的开发与测试计划发送给各部门负责人及参与项目的所有人员。&lt;/p>
&lt;p>&lt;strong>编写测试用例：&lt;/strong>&lt;/p>
&lt;p>根据详细的需求分档，开始进行用例的编写。&lt;/p>
&lt;p>&lt;strong>用例评审：&lt;/strong>&lt;/p>
&lt;p>在用例进行评审期间，先以邮件形式将用例发送给相关人员，以便他们事先了解用例对哪些功能进行验证以及验证的细节。&lt;/p>
&lt;p>然后，测试人员组进行用例评审，开发人员对用例与实际功能不符合有哪些，产品人员对会通过用例对功能的具体实现进行把握等等。&lt;/p>
&lt;p>&lt;strong>提交基线：&lt;/strong>&lt;/p>
&lt;p>开发人员完成所有功能后，会对自己的功能进行一个自测。自测完成后提交测试人员进行基线。&lt;/p>
&lt;p>&lt;strong>具体测试流程：&lt;/strong>&lt;/p>
&lt;p>开发人员对于基到测试线的功能进行测式，发现的问题通过缺陷管理工具进行反馈，开发人员对问题进行修复，然后，准备第二轮基线。&lt;/p>
&lt;p>测试人员完成第一轮测试后，需要写测试结论，发到相关人员。然后对基线后的第二轮进行测试，第二轮会对第一轮中发现的问题进行重点回归。&lt;/p>
&lt;p>&lt;strong>测试通过：&lt;/strong>&lt;/p>
&lt;p>经过两到三轮或四轮的测试后，直到没发现新的问题，或暂时无法解决，或不紧急的问题。通过上级确认，可以通过。编写测试报告与验收方案。&lt;/p>
&lt;p>验收方案是交由QA进行验证的。在现公司的流程中是将测试与QA分开的，测试人员重点关注的是功能是否可以正常运行。QA关注的是整个流程的质量以及最终用户的质量。有些公司QA与测试是不区分的，但这对测试的要求会更高，除了关心功能，还需要关心整体流程与质量。&lt;/p>
&lt;p>&lt;strong>流程分析：&lt;/strong>&lt;/p>
&lt;p>对于刚接触这个流程的我来说，这个流程是规范的，测试真正融入了整个流程，而且还担任了很重的角色，从而也有效的保证了软件产品的整体质量。&lt;/p></description></item><item><title>（八）模拟鼠标操作</title><link>https://itest2025.pages.dev/tutorials/19-008-%E5%85%AB%E6%A8%A1%E6%8B%9F%E9%BC%A0%E6%A0%87%E6%93%8D%E4%BD%9C/</link><pubDate>Sun, 02 Jul 2017 07:37:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/19-008-%E5%85%AB%E6%A8%A1%E6%8B%9F%E9%BC%A0%E6%A0%87%E6%93%8D%E4%BD%9C/</guid><description>&lt;br>
通过前面例子了解到，可以使用click()来模拟鼠标的单击操作，现在的Web产品中提供了更丰富的鼠标交互方式， 例如鼠标右击、双击、悬停、甚至是鼠标拖动等功能。在WebDriver中，将这些关于鼠标操作的方法封装在ActionChains类提供。
&lt;p>Actions 类提供了鼠标操作的常用方法：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>contextClick() 右击&lt;/p>
&lt;/li>
&lt;li>
&lt;p>clickAndHold() 鼠标点击并控制&lt;/p>
&lt;/li>
&lt;li>
&lt;p>doubleClick() 双击&lt;/p>
&lt;/li>
&lt;li>
&lt;p>dragAndDrop() 拖动&lt;/p>
&lt;/li>
&lt;li>
&lt;p>release() 释放鼠标&lt;/p>
&lt;/li>
&lt;li>
&lt;p>perform() 执行所有Actions中存储的行为&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>百度首页设置悬停下拉菜单。
&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://orru5lls3.bkt.clouddn.com/xuanting.jpg"
 data-srcset="http://orru5lls3.bkt.clouddn.com/xuanting.jpg, http://orru5lls3.bkt.clouddn.com/xuanting.jpg 1.5x, http://orru5lls3.bkt.clouddn.com/xuanting.jpg 2x"
 data-sizes="auto"
 alt="http://orru5lls3.bkt.clouddn.com/xuanting.jpg"
 title="http://orru5lls3.bkt.clouddn.com/xuanting.jpg" />&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.By&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.WebDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.WebElement&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.chrome.ChromeDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.interactions.Actions&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">MouseDemo&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ChromeDriver&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;https://www.baidu.com/&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebElement&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">search_setting&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">linkText&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;设置&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Actions&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">action&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Actions&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">action&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">clickAndHold&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">search_setting&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="na">perform&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">quit&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>import org.openqa.selenium.interactions.Actions;&lt;/li>
&lt;/ul>
&lt;p>导入提供鼠标操作的 ActionChains 类&lt;/p></description></item><item><title>（八）获取断言信息</title><link>https://itest2025.pages.dev/tutorials/24-008-%E5%85%AB%E8%8E%B7%E5%8F%96%E6%96%AD%E8%A8%80%E4%BF%A1%E6%81%AF/</link><pubDate>Fri, 23 Jun 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/24-008-%E5%85%AB%E8%8E%B7%E5%8F%96%E6%96%AD%E8%A8%80%E4%BF%A1%E6%81%AF/</guid><description>&lt;br>
不管是在做功能测试还是自动化测试，最后一步需要拿实际结果与预期进行比较。这个比较的称之为__断言__。
&lt;p>我们通常可以通过获取title 、URL和text等信息进行断言。text方法在前面已经讲过，它用于获取标签对之间的文本信息。
下面同样以百度为例，介绍如何获取这些信息。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">webdriver&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">time&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">sleep&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">webdriver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Firefox&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;https://www.baidu.com&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Before search================&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 打印当前页面title&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">title&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">title&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">title&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 打印当前页面URL&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">now_url&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">current_url&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">now_url&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_element_by_id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;kw&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">send_keys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;selenium&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_element_by_id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;su&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">click&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;After search================&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 再次打印当前页面title&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">title&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">title&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">title&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 打印当前页面URL&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">now_url&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">current_url&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">now_url&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 获取结果数目&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">user&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_element_by_class_name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;nums&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">quit&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>脚本运行结果如下：&lt;/p>
&lt;pre tabindex="0">&lt;code>Before search================
百度一下，你就知道
https://www.baidu.com/
After search================
selenium_百度搜索
https://www.baidu.com/s?ie=utf-8&amp;amp;f=8&amp;amp;rsv_bp=0&amp;amp;rsv_idx...
搜索工具
百度为您找到相关结果约5,380,000个
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>title：用于获得当前页面的标题。&lt;/li>
&lt;li>current_url：用户获得当前页面的URL。&lt;/li>
&lt;li>text：获取搜索条目的文本信息。&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1485470733090-0aae1788d5af?w=300"
 data-srcset="https://images.unsplash.com/photo-1485470733090-0aae1788d5af?w=300, https://images.unsplash.com/photo-1485470733090-0aae1788d5af?w=300 1.5x, https://images.unsplash.com/photo-1485470733090-0aae1788d5af?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1485470733090-0aae1788d5af?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>软件测试人员定位</title><link>https://itest2025.pages.dev/tutorials/13-009-%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E4%BA%BA%E5%91%98%E5%AE%9A%E4%BD%8D/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/13-009-%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E4%BA%BA%E5%91%98%E5%AE%9A%E4%BD%8D/</guid><description>&lt;p>工作已将近三年了，虽然这三个年头里我都在积极的学习着与测试相关的技术；但是能沉淀的东西很少。相信测试同学都有类似的感觉。&lt;/p>
&lt;h4 id="不要为了测试而测试">不要为了测试而测试&lt;/h4>
&lt;p>前几天做一个测试的PPT，就是讲项目中要用到的测试技术，总结了半天其实实际的产品中没用到什么技术含量的技能，熟悉需求，并转化成用例，待项目上线后验证功能就 OK了；对一个自身质量要求不高的项目，我们有时候为了体现自己价值，非要在一些不痛不养的问题上用力过猛。&lt;/p>
&lt;p>举个不恰当例子，某钢琴高手开了一个补习班教钢琴，家长送来一孩子目的只是让孩子学学钢琴；钢琴高手为了体验自己的价值（牛B），硬是按照贝多芬的标准去培养，孩子弹不会《XX交响曲》不让孩子走。先不说孩子有没有贝多芬的钢琴天资，也许孩子压根就不想成为贝多芬。&lt;/p>
&lt;p>当然了，如果你办的是“中国音乐家钢琴协会”，你有责任要求会员达到国际超一流水平，为国家和个人赢得荣誉。&lt;/p>
&lt;p>有时候不要为了测试去测试，或为了体现自己的价值去做一些对整个项目贡献不大的事儿。当然，我在这里不是让测试人员放弃自己的原则。要知道不管是产品、开发、测试都是围绕着产品的发展贡献。&lt;/p>
&lt;p>为贡献产品的发展测试远比为了测试了测试所带来的价值大得多；所以站在产品的发展上去看待测试工作更能体现自己的价值。&lt;/p>
&lt;p>记得去年的总结自己对 &lt;a href="https://itest2025.pages.dev/software_test/testing-process/" rel="">测试流程&lt;/a> 的理解。随着工作年龄的加长对这些问题也有进一步的看法；所以，再拿来炒一炒，希望能炒出新的味道。&lt;/p>
&lt;h4 id="没有最好的开发测试流程只有最适合项目的开发测试的流程">没有最好的开发测试流程，只有最适合项目的开发测试的流程；&lt;/h4>
&lt;hr>
&lt;p>去年的一篇说软件测试流程，严格规范的测试流程一定比没流程好，敏捷的流程一定比传统的瀑布流程先进。这个观点没有大的错误，但是我们忽略了所做的产品这个“对象”；忽略了产品的特点与阶段。&lt;/p>
&lt;p>例如两三个开发合伙开发一个项目（或产品），这时你让他们建立一套规范的流程，按流程实施，显然是不现实，我想摆在他们面前最主要的问题是，如何快速的把客户需要的功能开发出来换成money ，维持生计以及公司运作。&lt;/p>
&lt;p>例如一个各种功能已经成熟的项目，有着庞大的用户群，以维护为主的更新，它的版本功能的上线必须要建立严格的发布流程，经过充分的测试才能上线；用户群越大，暴露的问题越多，问题带来的影响也会越大。&lt;/p>
&lt;p>同样是一个Web产品，笔者目前所做的项目流程完全不是这样；我们的发布流程很简单，测试流程也很简单，不去写的规范又复杂的测试用例，放弃了使用缺陷管理工具来反馈问题；&lt;/p>
&lt;p>沟通变得尤为重要；我不否认这样做会给产品带来了一定的风险；对于严重的问题，我们可以通过快速的版本回滚，对于轻微的问题，我们很快会在下个版本迭代中修复。是不是有点敏捷的味道在里面。&lt;/p>
&lt;p>为什么会这样？因为这个产品属于前期开发阶段，很多功能还没上线。整个团队都在贡献着产品的发展；需要快速的将需求转化成功能给用户使用。&lt;/p>
&lt;p>所以，没有最好的开发测试流程，只有最适合项目与阶段的开发测试的流程。&lt;/p>
&lt;br>
#### 产品质量与用户容忍度
----
&lt;p>之前看过不少人讨论到底需不需要测试人员；我想说测试人员N年后不管是被重视了还是被淘汰了“测试的行为”永远不会消失；因为没有质量的产品基本上等于没有价值（也就是说没存在的意义），至于对产品质量的要求是由用户容忍度决定的。&lt;/p>
&lt;p>Facebook 没有测试人员！但是测试行为一直都在。开发找需求，开发、自测、发布，获得用户反馈，决定功能下线还是上新的功能&amp;mdash;相当于一条龙的服务。因为用户的容忍度允许他这么做。&lt;/p>
&lt;p>微软不能这么干，修复一个 Windows 的 bug 成本很高，而且用户是花钱买的，也许用户是用来创造价值的（办室、存储、管理），也许一个文件丢失，系统崩溃会给用户带来巨大损失；所以，微软需要很多的测试员。&lt;/p>
&lt;p>拿修复成本与用户容忍度做标准，Web 产品优于客户端产品；在 Web 产品中也要分行业；用户对银行系统、火车票、购物网站的容忍度显然要低一些，反过来说也就是对产品的质量要求更高，因为与钱挂钩。就算同一个产品，会员与免费用户的容忍度也是不一样的；因为会员用户有权得到更好质量与服务。&lt;/p>
&lt;p>所以，关注分析用户的容忍度的测试才不会把自己变得格格不入。&lt;/p>
&lt;br>
#### 提升自己的贡献
----
&lt;p>前面的东西貌似都在“弱化”测试存在的价值；俺本来就不被重视，所以俺就需要更加认真和努力找问题来提升自己存在的价值，你现在说，有些产品不需要太指着的去测试；那你说俺还能干啥？&lt;/p>
&lt;p>当我们把测试看成是为开发和产品服务时，也许情况会完全不一样。我们可以提供哪些服务？&lt;/p>
&lt;ul>
&lt;li>用测试发现产品的不可以测试性&lt;/li>
&lt;/ul>
&lt;p>前面已经提到队团不管是否有测试人员，但测试行为一定会存在；如果一个产品都不可测试，如何去发现并修复bug ，如何去维护与扩展？尤其对于web产品来讲，不可维护与扩展的产品无疑是致命的。（可以通过项目重构再解决）&lt;/p>
&lt;ul>
&lt;li>建立产品质量的评估方法&lt;/li>
&lt;/ul>
&lt;p>为项目团队提供每个版本的bug趋势分析数据，让项目中的每个人都了解项目当前的状态&lt;/p>
&lt;p>通过分析bug数据来建立或完善各种 Checklist，帮助项目团队更好的完成需求评审、设计评审以及代码评审，减少bug出现的机会。同时，可以定期将多个项目的Checklist进行合并，使单个项目的经验可以通过Test Team快速的流动起来，及时的作用于其他项目&lt;/p>
&lt;p>主动为Architect Team提供每个项目的性能测试数据，帮助他们获取更多的实际项目信息，减少踏入“陷阱”的几率&lt;/p>
&lt;ul>
&lt;li>建立可持续运行的测试框架&lt;/li>
&lt;/ul>
&lt;p>建立自动化测试测试框架；构建持续集成，使版本的迭代与更新得到快速的反馈。&lt;/p>
&lt;ul>
&lt;li>建立关注开发质量的开发文化&lt;/li>
&lt;/ul>
&lt;p>没有测试人员自测节省人力的了，尤其在单元测试层面。产品的质量应该由开发与测试共同承担。（现实中的责任到人，让团队很难形成这种文化）&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1613759612065-d5971d32ca49?w=300"
 data-srcset="https://images.unsplash.com/photo-1613759612065-d5971d32ca49?w=300, https://images.unsplash.com/photo-1613759612065-d5971d32ca49?w=300 1.5x, https://images.unsplash.com/photo-1613759612065-d5971d32ca49?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1613759612065-d5971d32ca49?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（九）创建 Docker 镜像</title><link>https://itest2025.pages.dev/tutorials/30-009-%E4%B9%9D%E5%88%9B%E5%BB%BA-docker-%E9%95%9C%E5%83%8F/</link><pubDate>Mon, 22 Jan 2018 14:30:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/30-009-%E4%B9%9D%E5%88%9B%E5%BB%BA-docker-%E9%95%9C%E5%83%8F/</guid><description>&lt;p>创建镜像有很多方法，用户可以从 Docker Hub 获取已有镜像并更新，也可以利用本地文件系统创建一个。&lt;/p>
&lt;h4 id="修改已有的镜像">修改已有的镜像&lt;/h4>
&lt;hr>
&lt;p>查看已有的镜像：&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 2a4cca5ac898 9 days ago 111MB
&lt;/code>&lt;/pre>&lt;p>下面进入到ubuntu容器中:&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo docker run -t -i ubuntu /bin/bash
root@543a324ea841:/#
&lt;/code>&lt;/pre>&lt;p>&lt;strong>注意：&lt;/strong> 记住容器的	ID，稍后还会用到。&lt;/p>
&lt;p>在容器中添加 添加 &lt;code>Python3&lt;/code> 开发环境。&lt;/p>
&lt;pre tabindex="0">&lt;code>root@543a324ea841:/# apt update // 更新软件源

root@543a324ea841:/# apt install python3 // 安装 python3

root@543a324ea841:/# exit // 退出 Ubuntu 容器
exit
&lt;/code>&lt;/pre>&lt;p>当结束后，我们使用	&lt;code>exit&lt;/code> 来退出，现在我们的容器已经被我们改变了，使用 &lt;code>docker	commit&lt;/code>	命令来提交更新后的副本。&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo docker commit -m &amp;#34;Add python3&amp;#34; -a &amp;#34;Docker Newbee&amp;#34; 543a324ea841 ubuntu

sha256:7c0cf1cc5ef36a86252e94eea39c645f53be7dfda87bdcded6d2999917190ffd
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>
&lt;p>-m	来指定提交的说明信息，跟我们使用的版本控制工具一样；&lt;/p></description></item><item><title>selenium爬虫</title><link>https://itest2025.pages.dev/tutorials/27-009-selenium%E7%88%AC%E8%99%AB/</link><pubDate>Mon, 11 Dec 2017 02:52:34 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/27-009-selenium%E7%88%AC%E8%99%AB/</guid><description>&lt;h3 id="why">why&lt;/h3>
&lt;p>从上一节的反爬虫建议来看，降低访问频率和将爬虫伪装成真实的用户访问可以对抗大部分的反爬虫策略。&lt;/p>
&lt;p>因为selenium是完全操作真实的浏览器，所以发爬虫策略比较难察觉异常，对于一些反爬虫策略非常严酷的网站，用selenium爬虫有时候会起到意想不到的效果。&lt;/p>
&lt;p>但是selenium爬虫也有一些局限性，比如效率低下等。&lt;/p>
&lt;h3 id="需求">需求&lt;/h3>
&lt;p>我们使用selenium爬虫来获取&lt;a href="https://www.zhihu.com/explore" target="_blank" rel="noopener noreffer ">知乎今日最热&lt;/a>的问题列表。跟之前的知乎爬虫差不多。&lt;/p>
&lt;h3 id="搭建开发环境">搭建开发环境&lt;/h3>
&lt;p>我们需要使用selenium和chrome driver，具体的安装方式请参考&lt;a href="http://www.testclass.net/selenium_python/install-selenium/" target="_blank" rel="noopener noreffer ">这里&lt;/a>&lt;/p>
&lt;h3 id="代码">代码&lt;/h3>
&lt;p>在这里我们就不分析html代码了，打开页面用开发者工具可以看到，今日最热的内容实际上就是找到&lt;code>data-type=&amp;quot;daily&amp;quot;&lt;/code>的div下，所有的&lt;code>class=question_link&lt;/code>的a元素。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># se_zhihu.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">webdriver&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">url&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;https://www.zhihu.com/explore&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">dr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">webdriver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Chrome&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">dr&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">daily_div&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">dr&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_element_by_css_selector&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;div[data-type=&amp;#34;daily&amp;#34;]&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">link&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">daily_div&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_elements_by_css_selector&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;.question_link&amp;#39;&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">link&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">dr&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">quit&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行">运行&lt;/h3>
&lt;p>命令行中直接运行&lt;/p>
&lt;pre tabindex="0">&lt;code>python se_zhihu.py
&lt;/code>&lt;/pre>&lt;h3 id="结果">结果&lt;/h3>
&lt;p>由于动态内容的关系，结果可能不尽相同。&lt;/p>
&lt;pre tabindex="0">&lt;code>如何看待美税改通过后各大公司的发福利提最低工资追加投资等行为？


全球变暖是必然吗？


主播进行游戏直播并从中获得打赏盈利涉及侵犯版权吗？


如何看待张召忠（局座）于12月22日在b站的《荒野行动》直播？


影史上有哪些经典的即兴表演镜头？
&lt;/code>&lt;/pre>&lt;h3 id="我们可以学到什么">我们可以学到什么&lt;/h3>
&lt;ul>
&lt;li>selenium操作浏览器可以实现一些爬虫行为&lt;/li>
&lt;li>selenium爬虫的效率很低&lt;/li>
&lt;li>可以使用headless(无界面的浏览器)来提升selenium爬虫的效率&lt;/li>
&lt;li>如果你对selenium的api不熟悉，可以直接使用Puppeteer来做爬虫，详情请看&lt;a href="https://blog.fundebug.com/2017/11/01/guide-to-automating-scraping-the-web-with-js/" target="_blank" rel="noopener noreffer ">这篇文章&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1464983953574-0892a716854b?w=300"
 data-srcset="https://images.unsplash.com/photo-1464983953574-0892a716854b?w=300, https://images.unsplash.com/photo-1464983953574-0892a716854b?w=300 1.5x, https://images.unsplash.com/photo-1464983953574-0892a716854b?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1464983953574-0892a716854b?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（九）TestNG 用例参数化</title><link>https://itest2025.pages.dev/tutorials/36-009-%E4%B9%9Dtestng-%E7%94%A8%E4%BE%8B%E5%8F%82%E6%95%B0%E5%8C%96/</link><pubDate>Sat, 25 Nov 2017 12:20:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/36-009-%E4%B9%9Dtestng-%E7%94%A8%E4%BE%8B%E5%8F%82%E6%95%B0%E5%8C%96/</guid><description>&lt;p>参数化也测试用例中常用的技巧之一，它可以增加用例的可配置性和减少相同用例的编写。&lt;/p>
&lt;h4 id="通过-parameters-实现参数化">通过 @Parameters 实现参数化&lt;/h4>
&lt;hr>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.testng.annotations.Parameters&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.testng.annotations.Test&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.testng.AssertJUnit.assertEquals&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">DataProviderTest&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Parameters&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="s">&amp;#34;add1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="s">&amp;#34;add2&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="s">&amp;#34;result&amp;#34;&lt;/span>&lt;span class="p">})&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">testAdd1&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">add1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">add2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">add1&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">add2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>@Parameters 获取参数化数据，作为 testAdd1() 测试方法的参数。&lt;/li>
&lt;/ul>
&lt;p>具体的测试数据在 &lt;strong>testng.mxl&lt;/strong> 文件中设置。&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;lt;!DOCTYPE suite SYSTEM &amp;#34;http://testng.org/testng-1.0.dtd&amp;#34; &amp;gt;
&amp;lt;suite name=&amp;#34;测试套件&amp;#34;&amp;gt;
 &amp;lt;test name=&amp;#34;简单测试&amp;#34;&amp;gt;
 &amp;lt;parameter name=&amp;#34;add1&amp;#34; value=&amp;#34;3&amp;#34;/&amp;gt;
 &amp;lt;parameter name=&amp;#34;add2&amp;#34; value=&amp;#34;2&amp;#34;/&amp;gt;
 &amp;lt;parameter name=&amp;#34;result&amp;#34; value=&amp;#34;5&amp;#34;/&amp;gt;
 &amp;lt;classes&amp;gt;
 &amp;lt;class name=&amp;#34;test.sample.DataProviderTest&amp;#34; /&amp;gt;
 &amp;lt;/classes&amp;gt;
 &amp;lt;/test&amp;gt;
&amp;lt;/suite&amp;gt;
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>&lt;code>&amp;lt;parameter.../&amp;gt;&lt;/code> 定义测试数据&lt;/li>
&lt;li>name 定义数据的名字，在测试用例中通过该名字来获取对应的vlaue。&lt;/li>
&lt;li>value 定义测试数据，通过对应的name来获取该值。&lt;/li>
&lt;/ul>
&lt;h4 id="通过-dataprovider-实现参数化">通过 @DataProvider 实现参数化&lt;/h4>
&lt;hr>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.testng.annotations.DataProvider&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.testng.annotations.Test&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.testng.AssertJUnit.assertEquals&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">DataProviderTest&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 定义对象数组&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@DataProvider&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;add&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Object&lt;/span>&lt;span class="o">[][]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">Users&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">return&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Object&lt;/span>&lt;span class="o">[][]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">3&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">5&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">},&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">4&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">},&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">3&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">3&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">7&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">},&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">};&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dataProvider&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;add&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">testAdd2&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">add1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">add2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">add1&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="n">add2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>@DataProvider 定义对象数组，数组的名称为：add 。&lt;/li>
&lt;/ul>
&lt;p>在 testAdd2() 中通过 &lt;code>dataProvider=&amp;quot;add&amp;quot;&lt;/code> 调用定义的对象数组，并通过参数获取相应的测试数据。&lt;/p></description></item><item><title>requests如何查看响应内容?</title><link>https://itest2025.pages.dev/tutorials/42-009-requests%E5%A6%82%E4%BD%95%E6%9F%A5%E7%9C%8B%E5%93%8D%E5%BA%94%E5%86%85%E5%AE%B9/</link><pubDate>Wed, 22 Nov 2017 03:23:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/42-009-requests%E5%A6%82%E4%BD%95%E6%9F%A5%E7%9C%8B%E5%93%8D%E5%BA%94%E5%86%85%E5%AE%B9/</guid><description>&lt;p>&lt;code>text&lt;/code> 方法会拿到请求的响应内容，比如以再github的timeline接口为例&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; import requests

&amp;gt;&amp;gt;&amp;gt; r = requests.get(&amp;#39;https://api.github.com/events&amp;#39;)
&amp;gt;&amp;gt;&amp;gt; r.text
u&amp;#39;[{&amp;#34;repository&amp;#34;:{&amp;#34;open_issues&amp;#34;:0,&amp;#34;url&amp;#34;:&amp;#34;https://github.com/...
&lt;/code>&lt;/pre>&lt;p>Requests会自动去解码server端返回的内容，大部分的unicode字符集都会被无缝解码。&lt;/p>
&lt;p>当你发送请求的时候，Requests会根据HTTP headers来推断编码，并在&lt;code>r.text&lt;/code>调用的时候使用。我们可以查看和修改Requests的编码，比如&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; r.encoding
&amp;#39;utf-8&amp;#39;
&amp;gt;&amp;gt;&amp;gt; r.encoding = &amp;#39;ISO-8859-1&amp;#39;
&lt;/code>&lt;/pre>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1488998527040-85054a85150e?w=300"
 data-srcset="https://images.unsplash.com/photo-1488998527040-85054a85150e?w=300, https://images.unsplash.com/photo-1488998527040-85054a85150e?w=300 1.5x, https://images.unsplash.com/photo-1488998527040-85054a85150e?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1488998527040-85054a85150e?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（九）JUnit5 介绍与安装</title><link>https://itest2025.pages.dev/tutorials/31-009-%E4%B9%9Djunit5-%E4%BB%8B%E7%BB%8D%E4%B8%8E%E5%AE%89%E8%A3%85/</link><pubDate>Mon, 13 Nov 2017 12:25:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/31-009-%E4%B9%9Djunit5-%E4%BB%8B%E7%BB%8D%E4%B8%8E%E5%AE%89%E8%A3%85/</guid><description>&lt;p>官方网址：http://junit.org/junit5/&lt;/p>
&lt;p>Junit5 已经不算是新的版本了，2016 年推出非正式版，相比较 JUnit4 安装和使用都有一定的差异。&lt;/p>
&lt;h4 id="junit5-介绍">JUnit5 介绍&lt;/h4>
&lt;hr>
&lt;blockquote>
&lt;p>The new major version of the programmer-friendly testing framework for Java 8&lt;/p>&lt;/blockquote>
&lt;p>一个新的重要版本，程序员更友的测试框架，基于 Java8。&lt;/p>
&lt;p>&lt;strong>关于&lt;/strong>&lt;/p>
&lt;p>JUnit5 是 JUnit 的下一代。我们的目标是为 JVM 上的开发人员端测试创建一个最新的基础。这包括针对 Java 8 及以上，以及使许多不同风格的测试。&lt;/p>
&lt;p>&lt;strong>Junit5 组成&lt;/strong>&lt;/p>
&lt;p>先看来个公式：&lt;/p>
&lt;p>&lt;font color="red">&lt;strong>JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage&lt;/strong>&lt;/font>&lt;/p>
&lt;p>这看上去比 Junit4 复杂，实际上在导入包时也会复杂一些。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>JUnit Platform 是在JVM上启动测试框架的基础。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>JUnit Jupiter 是JUnit5扩展的新的编程模型和扩展模型，用来编写测试用例。Jupiter子项目为在平台上运行Jupiter的测试提供了一个TestEngine （测试引擎）。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>JUnit Vintage 提供了一个在平台上运行 JUnit3 和 JUnit4 的 TestEngine 。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h4 id="maven-安装">Maven 安装&lt;/h4>
&lt;hr>
&lt;p>首先，你需要通过 IntelliJ IDEA 创建一个 Maven 项目，IntelliJ IDEA 集成的有 Maven，所以，你很容易做到这一点。通过 Maven 的 pom.xml 文件，添加 Junit5 。&lt;/p></description></item><item><title>9. 读取文件</title><link>https://itest2025.pages.dev/tutorials/28-009-9-%E8%AF%BB%E5%8F%96%E6%96%87%E4%BB%B6/</link><pubDate>Mon, 30 Oct 2017 08:17:22 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/28-009-9-%E8%AF%BB%E5%8F%96%E6%96%87%E4%BB%B6/</guid><description>&lt;h3 id="背景">背景&lt;/h3>
&lt;p>这一节里我们来学习如何使用python来读取文本文件中的内容。&lt;/p>
&lt;p>我们将实现一个简单的读取测试用例文件的脚本，脚本运行时候接收1个参数，用来指定需要读取的用例文件。&lt;/p>
&lt;h3 id="创建用例文件">创建用例文件&lt;/h3>
&lt;p>新建名为&lt;code>case001.txt&lt;/code>的文本文件，内容如下:&lt;/p>
&lt;pre tabindex="0">&lt;code>用例编号: itest001
用例名称: 登录成功
测试数据: 用户名:example;密码:example
测试步骤: 略
测试断言: 应该可以正确跳转到www.itest.info
&lt;/code>&lt;/pre>&lt;h3 id="代码实现">代码实现&lt;/h3>
&lt;p>新建名为&lt;code>read_case.py&lt;/code>，内容如下&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">sys&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">argv&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">script&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">file_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">argv&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;读取文件: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">file_path&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">file_obj&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file_path&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file_obj&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">read&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">file_obj&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">close&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行">运行&lt;/h3>
&lt;p>在命令行中使用下面的命令去执行代码&lt;/p>
&lt;pre tabindex="0">&lt;code>$python read_case.py case001.txt
&lt;/code>&lt;/pre>&lt;p>&lt;strong>注意：请确保先创建了用例文件case001.txt&lt;/strong>&lt;/p>
&lt;p>&lt;strong>注意：请确保用例文件case001.txt跟脚本文件read_case.py在同一个文件目录下&lt;/strong>&lt;/p>
&lt;p>&lt;strong>注意： 我们在脚本名称后面加上了case001.txt，这就是我们指定的用例文件名称，千万不要忘记传入这个参数，否则代码将会报如下的错误&lt;/strong>&lt;/p>
&lt;pre tabindex="0">&lt;code>Traceback (most recent call last):
 File &amp;#34;read_case.py&amp;#34;, line 3, in &amp;lt;module&amp;gt;
 script, file_path = argv
ValueError: not enough values to unpack (expected 2, got 1)
&lt;/code>&lt;/pre>&lt;h3 id="你应该可以看到">你应该可以看到&lt;/h3>
&lt;p>按照下面展示的情况进行输入，如果没有出错的话，你应该可以看到命令行窗口显示如下的内容&lt;/p>
&lt;pre tabindex="0">&lt;code>读取文件: case001.txt

用例编号: itest001
用例名称: 登录成功
测试数据: 用户名:example;密码:example
测试步骤: 略
测试断言: 应该可以正确跳转到www.itest.info
&lt;/code>&lt;/pre>&lt;h3 id="常见问题">常见问题&lt;/h3>
&lt;p>&lt;code>file_obj = open(file_path)&lt;/code> 这一行中，file_obj究竟是什么？&lt;/p></description></item><item><title>9.使用fixture参数化接口入参</title><link>https://itest2025.pages.dev/tutorials/25-009-9%E4%BD%BF%E7%94%A8fixture%E5%8F%82%E6%95%B0%E5%8C%96%E6%8E%A5%E5%8F%A3%E5%85%A5%E5%8F%82/</link><pubDate>Thu, 26 Oct 2017 07:22:42 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/25-009-9%E4%BD%BF%E7%94%A8fixture%E5%8F%82%E6%95%B0%E5%8C%96%E6%8E%A5%E5%8F%A3%E5%85%A5%E5%8F%82/</guid><description>&lt;h3 id="背景">背景&lt;/h3>
&lt;p>接上一节&lt;a href="http://www.v2ex.com" target="_blank" rel="noopener noreffer ">v2ex&lt;/a>网站的查看论坛节点信息的api。具体如下:&lt;/p>
&lt;pre tabindex="0">&lt;code>节点信息

获得指定节点的名字，简介，URL 及头像图片的地址。

https://www.v2ex.com/api/nodes/show.json

Method: GET
Authentication: None
接受参数：

name: 节点名（V2EX 的节点名全是半角英文或者数字）
例如：

https://www.v2ex.com/api/nodes/show.json?name=python
&lt;/code>&lt;/pre>&lt;p>我们试一下，通过传入不同的name，我们可以获取不同的节点信息。上面例子里我们获取了python讨论区的信息。现在我们把name改成java，该接口会返回java讨论区节点的信息，如下所示&lt;/p>
&lt;pre tabindex="0">&lt;code>https://www.v2ex.com/api/nodes/show.json?name=python

{
 &amp;#34;id&amp;#34; : 63,
 &amp;#34;name&amp;#34; : &amp;#34;java&amp;#34;,
 &amp;#34;url&amp;#34; : &amp;#34;http://www.v2ex.com/go/java&amp;#34;,
 &amp;#34;title&amp;#34; : &amp;#34;Java&amp;#34;,
 &amp;#34;title_alternative&amp;#34; : &amp;#34;Java&amp;#34;,
 &amp;#34;topics&amp;#34; : 1219,
 &amp;#34;stars&amp;#34; : 1547,

 &amp;#34;header&amp;#34; : &amp;#34;The most popular programming language.&amp;#34;,


 &amp;#34;footer&amp;#34; : null,

 &amp;#34;created&amp;#34; : 1272669207,
 &amp;#34;avatar_mini&amp;#34; : &amp;#34;//v2ex.assets.uxengine.net/navatar/03af/dbd6/63_mini.png?m=1509589840&amp;#34;,
 &amp;#34;avatar_normal&amp;#34; : &amp;#34;//v2ex.assets.uxengine.net/navatar/03af/dbd6/63_normal.png?m=1509589840&amp;#34;,
 &amp;#34;avatar_large&amp;#34; : &amp;#34;//v2ex.assets.uxengine.net/navatar/03af/dbd6/63_large.png?m=1509589840&amp;#34;
}
&lt;/code>&lt;/pre>&lt;p>那么新的需求来了，现在我们要测试给定的几个节点名称(python/java/go/nodejs)，v2ex的节点api可以正确返回节点的名字&lt;/p>
&lt;h3 id="需求分析">需求分析&lt;/h3>
&lt;p>根据&lt;a href="https://itest2025.pages.dev/interface/3a/" rel="">3A原则&lt;/a>，我们可以设计如下的用例&lt;/p>
&lt;ul>
&lt;li>测试数据: 节点的名称:python/java/go/nodejs&lt;/li>
&lt;li>接口地址: &lt;a href="https://www.v2ex.com/api/nodes/show.json" target="_blank" rel="noopener noreffer ">https://www.v2ex.com/api/nodes/show.json&lt;/a>&lt;/li>
&lt;li>断言: 返回的结果里，name字段的值必须等于传入的节点名称&lt;/li>
&lt;/ul>
&lt;h3 id="代码">代码&lt;/h3>
&lt;p>在&lt;code>v2ex_api_test.py&lt;/code>的文件中添加如下内容&lt;/p></description></item><item><title>（九）Locust 参数化</title><link>https://itest2025.pages.dev/tutorials/38-009-%E4%B9%9Dlocust-%E5%8F%82%E6%95%B0%E5%8C%96/</link><pubDate>Mon, 16 Oct 2017 07:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/38-009-%E4%B9%9Dlocust-%E5%8F%82%E6%95%B0%E5%8C%96/</guid><description>&lt;p>使用 LoadRunner 和 JMeter 的同学都知道，性能测试工具设置参数化颇为麻烦，但对于 Python 来说，生成点数据再简单不过了。&lt;/p>
&lt;h4 id="参数化系统登录">参数化系统登录&lt;/h4>
&lt;hr>
&lt;p>这里以某系统登录为例，简单介绍登录用户名密码的参数化实现&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">locust&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">HttpLocust&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">TaskSet&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">task&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">random&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">randint&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Web性能测试&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">UserBehavior&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">TaskSet&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">on_start&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">login&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 随机返回登录用户&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">login_user&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">users&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;user1&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">123456&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="s2">&amp;#34;user2&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">123123&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="s2">&amp;#34;user3&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">111222&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">randint&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">username&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;user&amp;#34;&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">password&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">users&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">username&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">username&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">password&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@task&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">login&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">username&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">password&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">login_user&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">client&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">post&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;/login_action&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;username&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">username&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;password&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">password&lt;/span>&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">User&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">HttpLocust&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">task_set&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">UserTask&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">min_wait&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1000&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_wait&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">3000&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">host&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;http://www.xxx.com&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>创建 login_user() 方法，定义登录字典 users , 通过randint 随机获取字典中的用户数据。&lt;/p>
&lt;p>在 login() 登录任务中，调用 login_user() 方法实现 随机用户的登录。&lt;/p>
&lt;p>关于参数化方式很多，这里起一个抛砖引玉作用。&lt;/p>
&lt;hr>
&lt;p>&lt;font color="red">关于 Locust 工具就介绍到这里，能否把 Locust 在工作中用好，取决于你对性能测试业务的理解，其次是灵活的运行 python 语言。&lt;/font>&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1507679799987-c73779587ccf?w=300"
 data-srcset="https://images.unsplash.com/photo-1507679799987-c73779587ccf?w=300, https://images.unsplash.com/photo-1507679799987-c73779587ccf?w=300 1.5x, https://images.unsplash.com/photo-1507679799987-c73779587ccf?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1507679799987-c73779587ccf?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>09. UI 界面（新用户必看）</title><link>https://itest2025.pages.dev/tutorials/37-009-09-ui-%E7%95%8C%E9%9D%A2%E6%96%B0%E7%94%A8%E6%88%B7%E5%BF%85%E7%9C%8B/</link><pubDate>Mon, 16 Oct 2017 04:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/37-009-09-ui-%E7%95%8C%E9%9D%A2%E6%96%B0%E7%94%A8%E6%88%B7%E5%BF%85%E7%9C%8B/</guid><description>&lt;h1 id="intellij-idea-界面介绍">IntelliJ IDEA 界面介绍&lt;/h1>
&lt;h2 id="首次打开">首次打开&lt;/h2>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/ix-interface-introduce-1.jpg"
 data-srcset="http://img.testclass.net/ix-interface-introduce-1.jpg, http://img.testclass.net/ix-interface-introduce-1.jpg 1.5x, http://img.testclass.net/ix-interface-introduce-1.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/ix-interface-introduce-1.jpg"
 title="首次打开" />&lt;/p>
&lt;blockquote>
&lt;ul>
&lt;li>&lt;strong>重点说明：&lt;/strong> IntelliJ IDEA 是没有类似 Eclipse 的工作空间的概念（&lt;code>Workspaces&lt;/code> ），最大单元就是 &lt;code>Project&lt;/code>。如果你同时观察多个项目的情况，IntelliJ IDEA 提供的解决方案是打开多个项目实例，你可以理解为开多个项目窗口。&lt;/li>
&lt;li>命令 &lt;code>Create New Project&lt;/code> 创建一个新项目。&lt;/li>
&lt;li>命令 &lt;code>Import Project&lt;/code> 导入一个已有项目。&lt;/li>
&lt;li>命令 &lt;code>Open&lt;/code> 打开一个已有项目，可以直接打开 Eclipse 项目，但是由于两者 IDE 下的项目配置不一样，所以项目还是需要配置的。&lt;/li>
&lt;li>命令 &lt;code>Check out from Version Control&lt;/code> 可以通过服务器上的项目地址 Checkout Github 上面项目或是其他 Git 托管服务器上的项目。&lt;/li>
&lt;li>为了介绍 IntelliJ IDEA 界面，我们这里创建一个新 HTML 项目。&lt;/li>
&lt;/ul>&lt;/blockquote>
&lt;h2 id="新建-html-项目">新建 HTML 项目&lt;/h2>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/ix-interface-introduce-2.jpg"
 data-srcset="http://img.testclass.net/ix-interface-introduce-2.jpg, http://img.testclass.net/ix-interface-introduce-2.jpg 1.5x, http://img.testclass.net/ix-interface-introduce-2.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/ix-interface-introduce-2.jpg"
 title="新建 HTML 项目" />&lt;/p></description></item><item><title>appium新手入门（9）—— appium API 之应用操作</title><link>https://itest2025.pages.dev/tutorials/21-009-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A89-appium-api-%E4%B9%8B%E5%BA%94%E7%94%A8%E6%93%8D%E4%BD%9C/</link><pubDate>Thu, 07 Sep 2017 10:24:12 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/21-009-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A89-appium-api-%E4%B9%8B%E5%BA%94%E7%94%A8%E6%93%8D%E4%BD%9C/</guid><description>&lt;p>本小节的所罗列的方法主要针对应用的操作，如应用的安装、卸载、关闭、启动等。&lt;/p>
&lt;h4 id="1安装应用">1、安装应用&lt;/h4>
&lt;hr>
&lt;p>方法：&lt;/p>
&lt;ul>
&lt;li>installApp()&lt;/li>
&lt;/ul>
&lt;p>安装应用到设备中去。需要apk包的路径。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">installApp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;path/to/my.apk&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">installApp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;D:\\android\\apk\\ContactManager.apk&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="2卸载应用">2、卸载应用&lt;/h4>
&lt;p>方法：&lt;/p>
&lt;ul>
&lt;li>removeApp()&lt;/li>
&lt;/ul>
&lt;p>从设备中删除一个应用。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">removeApp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;com.example.android.apis&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="3关闭应用">3、关闭应用&lt;/h4>
&lt;hr>
&lt;p>方法：&lt;/p>
&lt;ul>
&lt;li>closeApp()&lt;/li>
&lt;/ul>
&lt;p>关闭打开的应用，默认关闭当前打开的应用，所以不需要入参。这个方法并非真正的关闭应用，相当于按home键将应用置于后台，可以通过launchApp()再次启动。&lt;/p>
&lt;h4 id="4启动应用">4、启动应用&lt;/h4>
&lt;hr>
&lt;p>方法：&lt;/p>
&lt;ul>
&lt;li>launchApp()&lt;/li>
&lt;/ul>
&lt;p>启动应用。你一定很迷惑，不是在初始化的配置信息已经指定了应用，脚本运行的时候就需要启动应用，为什么还要有这个方法去启动应用呢？重新启动应用也是一个测试点，该方法需要配合closeApp()使用的。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">closeApp&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">launchApp&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="5检查应用是否安装">5、检查应用是否安装&lt;/h4>
&lt;hr>
&lt;p>方法：&lt;/p>
&lt;ul>
&lt;li>isAppInstalled()&lt;/li>
&lt;/ul>
&lt;p>检查应用是否已经安装。需要传参应用包的名字。返回结果为Ture或False。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">isAppInstalled&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">com&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">example&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">android&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">apis&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="6将应用置于后台">6、将应用置于后台&lt;/h4>
&lt;hr>
&lt;p>方法：&lt;/p>
&lt;ul>
&lt;li>runAppInBackground()&lt;/li>
&lt;/ul>
&lt;p>将当前活跃的应用程序发送到后台。这个方法需要入参，需要指定应用置于后台的时长。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">runAppInBackground&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="7应用重置">7、应用重置&lt;/h4>
&lt;hr>
&lt;p>方法：&lt;/p>
&lt;ul>
&lt;li>resetApp()&lt;/li>
&lt;/ul>
&lt;p>重置当前被测程序到出始化状态。该方法不需要入参。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">resetApp&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1495490311930-678c8ecdd120?w=300"
 data-srcset="https://images.unsplash.com/photo-1495490311930-678c8ecdd120?w=300, https://images.unsplash.com/photo-1495490311930-678c8ecdd120?w=300 1.5x, https://images.unsplash.com/photo-1495490311930-678c8ecdd120?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1495490311930-678c8ecdd120?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>JMeter官方文档：9. 构建 WebService 测试计划</title><link>https://itest2025.pages.dev/tutorials/22-009-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A39-%E6%9E%84%E5%BB%BA-webservice-%E6%B5%8B%E8%AF%95%E8%AE%A1%E5%88%92/</link><pubDate>Thu, 24 Aug 2017 09:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/22-009-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A39-%E6%9E%84%E5%BB%BA-webservice-%E6%B5%8B%E8%AF%95%E8%AE%A1%E5%88%92/</guid><description>&lt;p>&lt;a href="https://itest2025.pages.dev/2017/08/24/jmeter-translation-plans/" rel="">《JMeter官方文档&amp;ndash;翻译计划》&lt;/a> &lt;a href="http://jmeter.apache.org/usermanual/build-ws-test-plan.html" target="_blank" rel="noopener noreffer ">原文地址&lt;/a>&lt;/p>
&lt;h3 id="9-构建-webservice-测试计划">9. 构建 WebService 测试计划&lt;/h3>
&lt;hr>
&lt;p>在本章节，你将学习如何创建一个 &lt;a href="http://jmeter.apache.org/usermanual/build-test-plan.html" target="_blank" rel="noopener noreffer ">测试计划&lt;/a> 去测试 WebService。先创建5个用户请求同一个页面，同时每个请求重复2次，因此总数为（5个用户）X（1次请求）X（重复请求）= 10 次 HTTP 请求。构建测试计划过程中，会使用到以下几个元素：&lt;a href="http://jmeter.apache.org/usermanual/test_plan.html#thread_group" target="_blank" rel="noopener noreffer ">线程组&lt;/a>、&lt;a href="http://jmeter.apache.org/usermanual/component_reference.html#HTTP_Request" target="_blank" rel="noopener noreffer ">HTTP 请求&lt;/a>、&lt;a href="http://jmeter.apache.org/usermanual/component_reference.html#Aggregate_Graph" target="_blank" rel="noopener noreffer ">聚合报告&lt;/a>&lt;/p>
&lt;p>如果采样器使用Web服务时出现错误，请仔细检查 SOAP 消息，并确保格式正确。 特别要确保 &lt;strong>xmlns&lt;/strong> 属性与WSDL完全相同。 如果xml命名空间不同，则 webservice 可能会返回错误。&lt;/p>
&lt;h3 id="91-构建-webservice-测试计划">9.1 构建 WebService 测试计划&lt;/h3>
&lt;hr>
&lt;p>在测试计划中，将会用到 .NET 语言写的web服务，在此就不详细介绍web 服务的编写方法了。如果不会，请自行谷歌 web 服务并尝试用 java 或 .NET熟练起来。必须强调的是，使用 .NET 和 Java 实现 web 服务是有较大差别。该主题太广泛无法写到用户手册里，所以想了解具体差异可参考其他资料。&lt;/p>
&lt;blockquote>
&lt;p>Jmeter是按照树状的排列方式去发送请求的&lt;/p>&lt;/blockquote>
&lt;p>找到菜单中的 &lt;strong>文件 → Templates&lt;/strong> , Select Template 中的 &lt;strong>“Building a SOAP Webservice Test Plan”&lt;/strong>，点击 &lt;strong>“Creat”&lt;/strong> 按钮。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/09_ws_template.png"
 data-srcset="http://img.testclass.net/09_ws_template.png, http://img.testclass.net/09_ws_template.png 1.5x, http://img.testclass.net/09_ws_template.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/09_ws_template.png"
 title="图9.1.0 WebService 模版" />
图9.1.0 WebService 模版&lt;/p></description></item><item><title>9.什么是mock server</title><link>https://itest2025.pages.dev/tutorials/40-009-9%E4%BB%80%E4%B9%88%E6%98%AFmock-server/</link><pubDate>Tue, 22 Aug 2017 04:41:43 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/40-009-9%E4%BB%80%E4%B9%88%E6%98%AFmock-server/</guid><description>&lt;h3 id="使用场景">使用场景&lt;/h3>
&lt;p>前端客户端团队和后端服务端团队往往节奏是不一致的。前端很多情况下需要等待后台的api开发完成后才能进行开发联调和测试，这种前后端不对称就造成了前后端团队节奏不一致，从而造成整个项目/产品交付/发布延期。&lt;/p>
&lt;p>有一种解决方案的思路是前后端先&lt;strong>约定&lt;/strong>好后端提供的api接口的细节，前端人员自行先模拟出这些后端的实现，当然这些实现是假的，不过前端可以去调用这些假的实现，而且能拿到返回，这样一来前端就不需要等待后端开发完成才开始工作了。&lt;/p>
&lt;p>但是这样还是会有问题，前端实现的假的api没办法迅速反映出后端的变化。简单来说就是后端可能在&lt;strong>约定&lt;/strong>好的api接口上进行了些许修改，而没有知会前端人员，这样前端的假的api实现并没有相应更新，在正式联调时就会出现问题。&lt;/p>
&lt;p>像这种假的api实现，不管是前端实现的还是后端去实现的，我们可以称之为mock server。&lt;/p>
&lt;ul>
&lt;li>mock表示这个api返回的数据是假的，仅作为测试用的&lt;/li>
&lt;li>server表示需要启动服务，说到底这是一个服务程序&lt;/li>
&lt;/ul>
&lt;h3 id="契约测试">契约测试&lt;/h3>
&lt;p>由于前后端往往有一些信息不对称，导致约定的api可能在前后端都会发生变化，所以保证前后端的一致性就成了一个挑战。&lt;/p>
&lt;p>这时候有人提出了契约测试，大致思想是前后端共用一份契约，约定了api的细节，前后端的任何变化都需要先修改契约，然后通过契约去通知前后端团队，统一更新实现。这也是契约精神的表现。&lt;/p>
&lt;p>如果为契约测试设置一种测试工具的话，我会规划下面一些特性&lt;/p>
&lt;ul>
&lt;li>
&lt;p>契约的描述工具：也就是契约长什么样子，用什么工具去定义才能让前后端团队秒懂&lt;/p>
&lt;/li>
&lt;li>
&lt;p>通过契约自动生成mock server实现，这样前端团队就可以拿来即用了，如果契约修改了，那么前端团队也很容易感知到&lt;/p>
&lt;/li>
&lt;li>
&lt;p>通过契约自动生成接口测试用例，这样通过持续运行这些接口测试用例，后端团队就可以第一时间发现契约的修改&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1542744173-8e7e53415bb0?w=300"
 data-srcset="https://images.unsplash.com/photo-1542744173-8e7e53415bb0?w=300, https://images.unsplash.com/photo-1542744173-8e7e53415bb0?w=300 1.5x, https://images.unsplash.com/photo-1542744173-8e7e53415bb0?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1542744173-8e7e53415bb0?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>appium简明教程（9）——如何获取android app的Activity</title><link>https://itest2025.pages.dev/tutorials/21-009-appium%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B9%E5%A6%82%E4%BD%95%E8%8E%B7%E5%8F%96android-app%E7%9A%84activity/</link><pubDate>Sat, 12 Aug 2017 08:11:31 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/21-009-appium%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B9%E5%A6%82%E4%BD%95%E8%8E%B7%E5%8F%96android-app%E7%9A%84activity/</guid><description>&lt;p>有时候在appium的Desired Capabilities中需要指定被测app的appActivity，下面的方法可能会对你有所帮助。&lt;/p>
&lt;p>&lt;strong>方法一&lt;/strong>&lt;/p>
&lt;p>如有你有待测项目的源码，那么直接查看源码就好。如果没有，那么请联系有源码的同学，这是推荐方法。&lt;/p>
&lt;p>&lt;strong>方法二&lt;/strong>&lt;/p>
&lt;p>如果你没有代码，那么可以反编译该app。&lt;/p>
&lt;p>这里将用到2个工具，分别是dex2jar和jd-gui。你可以在这里下载目前为止的最新版本以及示例apk。&lt;/p>
&lt;p>我们以工具包里的ContactManager.apk为例，简单介绍一下反编译的流程。&lt;/p>
&lt;ul>
&lt;li>1，重命名ContactManager.apk为ContactManager.zip并解压得到文件classes.dex；&lt;/li>
&lt;li>2，解压dex2jar-0.0.9.15.zip，并从命令行进入该文件夹；&lt;/li>
&lt;li>3，运行命令&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>d2j-dex2jar.bat path_to\classes.dex
在当前文件夹下得到classes-dex2jar.jar；
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>4，解压jd-gui-0.3.6.windows.zip得到文件jd-gui.exe；&lt;/li>
&lt;li>5，使用jd-gui.exe打开classes-dex2jar.jar；&lt;/li>
&lt;/ul>
&lt;p>嗯，好了，可以尽情欣赏了。上图。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://oriphg3yh.bkt.clouddn.com/get_activity.png"
 data-srcset="http://oriphg3yh.bkt.clouddn.com/get_activity.png, http://oriphg3yh.bkt.clouddn.com/get_activity.png 1.5x, http://oriphg3yh.bkt.clouddn.com/get_activity.png 2x"
 data-sizes="auto"
 alt="http://oriphg3yh.bkt.clouddn.com/get_activity.png"
 title="http://oriphg3yh.bkt.clouddn.com/get_activity.png" />&lt;/p>
&lt;p>上图所示的ContactManager就是待测app的main activity。&lt;/p>
&lt;p>&lt;strong>方法三&lt;/strong>&lt;/p>
&lt;p>参考testerhome的&lt;a href="http://testerhome.com/topics/1030" target="_blank" rel="noopener noreffer ">这个帖子&lt;/a>&lt;/p>
&lt;p>使用log查看大法(嗯，windows上没grep不幸福，好在有powershell的Select-String，可以拿来勉强一用)，直接搬砖。&lt;/p>
&lt;ul>
&lt;li>a、启动待测apk&lt;/li>
&lt;li>b、开启日志输出：adb logcat&amp;gt;D:/log.txt&lt;/li>
&lt;li>c、关闭日志输出：ctrl+c&lt;/li>
&lt;li>d、查看日志&lt;/li>
&lt;/ul>
&lt;p>找寻：&lt;/p>
&lt;pre tabindex="0">&lt;code>Displayed com.mm.android.hsy/.ui.LoginActivity: +3s859ms
appPackage = com.mm.android.hsy
appActivity = .ui.LoginActivity
&lt;/code>&lt;/pre>&lt;p>好了，准备活动做的差不多了。下一节乙醇带大家进行控件定位之旅。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1566352207769-3a591a2c9567?w=300"
 data-srcset="https://images.unsplash.com/photo-1566352207769-3a591a2c9567?w=300, https://images.unsplash.com/photo-1566352207769-3a591a2c9567?w=300 1.5x, https://images.unsplash.com/photo-1566352207769-3a591a2c9567?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1566352207769-3a591a2c9567?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>性能测试流程（四）——测试工具选型</title><link>https://itest2025.pages.dev/tutorials/14-009-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E6%B5%81%E7%A8%8B%E5%9B%9B%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7%E9%80%89%E5%9E%8B/</link><pubDate>Fri, 11 Aug 2017 05:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/14-009-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E6%B5%81%E7%A8%8B%E5%9B%9B%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7%E9%80%89%E5%9E%8B/</guid><description>&lt;p>根据对系统性能测试点的分析，我们选择合适的工作。不是所有的性能需求都要用LoadRunner或Jmeter来进行的。只要能满足需求就可以了，我个人倾向于轻量级的性能工具，或自己动手写代码。&lt;/p>
&lt;h4 id="测试工具的比较">测试工具的比较：&lt;/h4>
&lt;p>软件性能测试工具分为三类，商业收费工具、开源免费工具、自主开发工具。&lt;/p>
&lt;p>表：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>&amp;ndash;&lt;/th>
 &lt;th style="text-align: left">商业工具&lt;/th>
 &lt;th style="text-align: left">开源工具&lt;/th>
 &lt;th style="text-align: left">自研工具&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>优点&lt;/td>
 &lt;td style="text-align: left">功能强大且简单易用；提供丰富的功能，支持更多协议和并发用户数，丰富的计数器和测试结果；自动生成脚本，学习成本较低；很强的稳定性和可靠性。&lt;/td>
 &lt;td style="text-align: left">轻量灵活容易扩展；可免费下载使用，可查看工具源代码，根须需求容易扩展。&lt;/td>
 &lt;td style="text-align: left">贴近需求，开发出更适合需求的工具，较开源工具学习成本低。可形成特有的工具体系。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>缺点&lt;/td>
 &lt;td style="text-align: left">依赖工具本身提供的功能，较难扩展。 工具体积大，购买成本高。&lt;/td>
 &lt;td style="text-align: left">学习成本高，不能完全满足性能测试需求，需要功能扩展。功能相对比较简陋。&lt;/td>
 &lt;td style="text-align: left">工具开发成本高，需要专业的工具开发人员或团队，工具成本也会存在不确定。&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>通过上面的比较分析，很难判别对某类工具的取舍，各自有其明显的优势，当然也有明显的缺点，如何更好选择工具，这里就要结合实际性能的需求了。&lt;/p>
&lt;h4 id="需要考虑以下几个方面">需要考虑以下几个方面:&lt;/h4>
&lt;ul>
&lt;li>性能需求：&lt;/li>
&lt;/ul>
&lt;p>首先要考虑的是否满足性能需求，例如系统的协议不支持，无法创建脚本，系统的模拟用户数达不到，或都某此特殊功能无法测试，如流媒体性能测试等。一些有性能工具是无法满足这些需求的，那当然要首先排除。&lt;/p>
&lt;ul>
&lt;li>购买成本&lt;/li>
&lt;/ul>
&lt;p>对于商业工具的购买成本也是我们需要考虑的问题，其实，这个问题也是老板需要考虑的问题，对性能测试成本的整体预算等。当然了，在满足性能需求的前提下，当然一切从简。正版LoadRunner的服务费用非常的高。
那么开源软件呢？ 开源的性能测试工具其实非常的多，因为它们都分别适合在不同的需求场景下，所以，它们的体积相比商业软件会小很大，当然功能也相对简陋。但是他们在某些情况下可以完全满足某些性能需求，或者可以通过几款开源工具配合满足，或者通过对开源工具进行扩展进行满足。对开源工具进行扩展，对测试人员的要求较高。需要测试人员对工具的原理及源代码有相当有研究。这里对测试人员自动能力的提升非常有帮助。
或者你的性能测试项目特殊，找遍市面上的所有性能工具无一款满意，商业定制成本过高。或者你想构建自己有工具体系。处于公司需求的特殊性与长期性考虑，可以自主开发一个性能测试工具来用。一次开发，永久收益（当然也需要维护与升级、扩展等），而且更贴近自已的需求。目前很多知名的大公司都有自己的性能测试工具，用于内部使用。 &lt;/p>
&lt;ul>
&lt;li>人员学习成本：&lt;/li>
&lt;/ul>
&lt;p>最后要提到的就是人员对工具的学习成本，其实，测试人员在选择性能测试工具时最先考虑的就是从自己会使用的工具入手，这样可以最低的控制学习成生，如果整一个工具，测试人员单学测试脚本就学了半年，老板早让你走人了。这也是对性能测试人员要求较高的地方。所以，对于性能测试人员，你最好熟悉一款流程的商业性能工具，一款开源免费性能具，还需要熟悉常见的性能脚本开发语言等，这是基本要求。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1529664084480-627210605cc7?w=300"
 data-srcset="https://images.unsplash.com/photo-1529664084480-627210605cc7?w=300, https://images.unsplash.com/photo-1529664084480-627210605cc7?w=300 1.5x, https://images.unsplash.com/photo-1529664084480-627210605cc7?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1529664084480-627210605cc7?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（九）通过xpath去定位页面上的元素</title><link>https://itest2025.pages.dev/tutorials/20-009-%E4%B9%9D%E9%80%9A%E8%BF%87xpath%E5%8E%BB%E5%AE%9A%E4%BD%8D%E9%A1%B5%E9%9D%A2%E4%B8%8A%E7%9A%84%E5%85%83%E7%B4%A0/</link><pubDate>Sat, 05 Aug 2017 02:49:18 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/20-009-%E4%B9%9D%E9%80%9A%E8%BF%87xpath%E5%8E%BB%E5%AE%9A%E4%BD%8D%E9%A1%B5%E9%9D%A2%E4%B8%8A%E7%9A%84%E5%85%83%E7%B4%A0/</guid><description>&lt;h3 id="xpath教程">xpath教程&lt;/h3>
&lt;p>&lt;a href="http://www.w3school.com.cn/xpath/" target="_blank" rel="noopener noreffer ">自学xpath&lt;/a>&lt;/p>
&lt;h3 id="xpath语法要点">xpath语法要点&lt;/h3>
&lt;ul>
&lt;li>&lt;code>nodename&lt;/code>	选取此节点的所有子节点。&lt;/li>
&lt;li>&lt;code>/&lt;/code>	从根节点选取。&lt;/li>
&lt;li>&lt;code>//&lt;/code>	从匹配选择的当前节点选择文档中的节点，而不考虑它们的位置。&lt;/li>
&lt;li>&lt;code>.&lt;/code>	选取当前节点。&lt;/li>
&lt;li>&lt;code>..&lt;/code>	选取当前节点的父节点。&lt;/li>
&lt;li>&lt;code>@&lt;/code>	选取属性。&lt;/li>
&lt;/ul>
&lt;h3 id="示例代码">示例代码&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// &amp;lt;input id=&amp;#34;input__text2&amp;#34; type=&amp;#34;number&amp;#34; placeholder=&amp;#34;Enter a Number&amp;#34;&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">xpath&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;//input[@type=&amp;#34;number&amp;#34;]&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;66666&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="总结">总结&lt;/h3>
&lt;p>css和xpath选择器大家只需要精通其中一种就可以了。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1447433693259-c8549e937d62?w=300"
 data-srcset="https://images.unsplash.com/photo-1447433693259-c8549e937d62?w=300, https://images.unsplash.com/photo-1447433693259-c8549e937d62?w=300 1.5x, https://images.unsplash.com/photo-1447433693259-c8549e937d62?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1447433693259-c8549e937d62?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（九）软件测试人员定位</title><link>https://itest2025.pages.dev/tutorials/29-009-%E4%B9%9D%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E4%BA%BA%E5%91%98%E5%AE%9A%E4%BD%8D/</link><pubDate>Thu, 20 Jul 2017 07:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/29-009-%E4%B9%9D%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E4%BA%BA%E5%91%98%E5%AE%9A%E4%BD%8D/</guid><description>&lt;br>
工作已将近三年了，虽然这三个年头里我都在积极的学习着与测试相关的技术；但是能沉淀的东西很少。相信测试同学都有类似的感觉。
&lt;h4 id="不要为了测试而测试">不要为了测试而测试&lt;/h4>
&lt;p>前几天做一个测试的PPT，就是讲项目中要用到的测试技术，总结了半天其实实际的产品中没用到什么技术含量的技能，熟悉需求，并转化成用例，待项目上线后验证功能就 OK了；对一个自身质量要求不高的项目，我们有时候为了体现自己价值，非要在一些不痛不养的问题上用力过猛。&lt;/p>
&lt;p>举个不恰当例子，某钢琴高手开了一个补习班教钢琴，家长送来一孩子目的只是让孩子学学钢琴；钢琴高手为了体验自己的价值（牛B），硬是按照贝多芬的标准去培养，孩子弹不会《XX交响曲》不让孩子走。先不说孩子有没有贝多芬的钢琴天资，也许孩子压根就不想成为贝多芬。&lt;/p>
&lt;p>当然了，如果你办的是“中国音乐家钢琴协会”，你有责任要求会员达到国际超一流水平，为国家和个人赢得荣誉。&lt;/p>
&lt;p>有时候不要为了测试去测试，或为了体现自己的价值去做一些对整个项目贡献不大的事儿。当然，我在这里不是让测试人员放弃自己的原则。要知道不管是产品、开发、测试都是围绕着产品的发展贡献。&lt;/p>
&lt;p>为贡献产品的发展测试远比为了测试了测试所带来的价值大得多；所以站在产品的发展上去看待测试工作更能体现自己的价值。&lt;/p>
&lt;p>记得去年的总结自己对 &lt;a href="https://itest2025.pages.dev/software_test/testing-process/" rel="">测试流程&lt;/a> 的理解。随着工作年龄的加长对这些问题也有进一步的看法；所以，再拿来炒一炒，希望能炒出新的味道。&lt;/p>
&lt;h4 id="没有最好的开发测试流程只有最适合项目的开发测试的流程">没有最好的开发测试流程，只有最适合项目的开发测试的流程；&lt;/h4>
&lt;hr>
&lt;p>去年的一篇说软件测试流程，严格规范的测试流程一定比没流程好，敏捷的流程一定比传统的瀑布流程先进。这个观点没有大的错误，但是我们忽略了所做的产品这个“对象”；忽略了产品的特点与阶段。&lt;/p>
&lt;p>例如两三个开发合伙开发一个项目（或产品），这时你让他们建立一套规范的流程，按流程实施，显然是不现实，我想摆在他们面前最主要的问题是，如何快速的把客户需要的功能开发出来换成money ，维持生计以及公司运作。&lt;/p>
&lt;p>例如一个各种功能已经成熟的项目，有着庞大的用户群，以维护为主的更新，它的版本功能的上线必须要建立严格的发布流程，经过充分的测试才能上线；用户群越大，暴露的问题越多，问题带来的影响也会越大。&lt;/p>
&lt;p>同样是一个Web产品，笔者目前所做的项目流程完全不是这样；我们的发布流程很简单，测试流程也很简单，不去写的规范又复杂的测试用例，放弃了使用缺陷管理工具来反馈问题；&lt;/p>
&lt;p>沟通变得尤为重要；我不否认这样做会给产品带来了一定的风险；对于严重的问题，我们可以通过快速的版本回滚，对于轻微的问题，我们很快会在下个版本迭代中修复。是不是有点敏捷的味道在里面。&lt;/p>
&lt;p>为什么会这样？因为这个产品属于前期开发阶段，很多功能还没上线。整个团队都在贡献着产品的发展；需要快速的将需求转化成功能给用户使用。&lt;/p>
&lt;p>所以，没有最好的开发测试流程，只有最适合项目与阶段的开发测试的流程。&lt;/p>
&lt;br>
#### 产品质量与用户容忍度
----
&lt;p>之前看过不少人讨论到底需不需要测试人员；我想说测试人员N年后不管是被重视了还是被淘汰了“测试的行为”永远不会消失；因为没有质量的产品基本上等于没有价值（也就是说没存在的意义），至于对产品质量的要求是由用户容忍度决定的。&lt;/p>
&lt;p>Facebook 没有测试人员！但是测试行为一直都在。开发找需求，开发、自测、发布，获得用户反馈，决定功能下线还是上新的功能&amp;mdash;相当于一条龙的服务。因为用户的容忍度允许他这么做。&lt;/p>
&lt;p>微软不能这么干，修复一个 Windows 的 bug 成本很高，而且用户是花钱买的，也许用户是用来创造价值的（办室、存储、管理），也许一个文件丢失，系统崩溃会给用户带来巨大损失；所以，微软需要很多的测试员。&lt;/p>
&lt;p>拿修复成本与用户容忍度做标准，Web 产品优于客户端产品；在 Web 产品中也要分行业；用户对银行系统、火车票、购物网站的容忍度显然要低一些，反过来说也就是对产品的质量要求更高，因为与钱挂钩。就算同一个产品，会员与免费用户的容忍度也是不一样的；因为会员用户有权得到更好质量与服务。&lt;/p>
&lt;p>所以，关注分析用户的容忍度的测试才不会把自己变得格格不入。&lt;/p>
&lt;br>
#### 提升自己的贡献
----
&lt;p>前面的东西貌似都在“弱化”测试存在的价值；俺本来就不被重视，所以俺就需要更加认真和努力找问题来提升自己存在的价值，你现在说，有些产品不需要太指着的去测试；那你说俺还能干啥？&lt;/p>
&lt;p>当我们把测试看成是为开发和产品服务时，也许情况会完全不一样。我们可以提供哪些服务？&lt;/p>
&lt;ul>
&lt;li>用测试发现产品的不可以测试性&lt;/li>
&lt;/ul>
&lt;p>前面已经提到队团不管是否有测试人员，但测试行为一定会存在；如果一个产品都不可测试，如何去发现并修复bug ，如何去维护与扩展？尤其对于web产品来讲，不可维护与扩展的产品无疑是致命的。（可以通过项目重构再解决）&lt;/p>
&lt;ul>
&lt;li>建立产品质量的评估方法&lt;/li>
&lt;/ul>
&lt;p>为项目团队提供每个版本的bug趋势分析数据，让项目中的每个人都了解项目当前的状态&lt;/p>
&lt;p>通过分析bug数据来建立或完善各种 Checklist，帮助项目团队更好的完成需求评审、设计评审以及代码评审，减少bug出现的机会。同时，可以定期将多个项目的Checklist进行合并，使单个项目的经验可以通过Test Team快速的流动起来，及时的作用于其他项目&lt;/p>
&lt;p>主动为Architect Team提供每个项目的性能测试数据，帮助他们获取更多的实际项目信息，减少踏入“陷阱”的几率&lt;/p>
&lt;ul>
&lt;li>建立可持续运行的测试框架&lt;/li>
&lt;/ul>
&lt;p>建立自动化测试测试框架；构建持续集成，使版本的迭代与更新得到快速的反馈。&lt;/p>
&lt;ul>
&lt;li>建立关注开发质量的开发文化&lt;/li>
&lt;/ul>
&lt;p>没有测试人员自测节省人力的了，尤其在单元测试层面。产品的质量应该由开发与测试共同承担。（现实中的责任到人，让团队很难形成这种文化）&lt;/p>
&lt;ul>
&lt;li>贡献产品发展&lt;/li>
&lt;/ul>
&lt;p>旧病成医，测试的产品多了自然会对产品有自己的理解，产品的定位，用户习惯与体验； 可以从测试的角度贡献产品的发展。（这个由产品的特点，公司文化决定）&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1497366216548-37526070297c?w=300"
 data-srcset="https://images.unsplash.com/photo-1497366216548-37526070297c?w=300, https://images.unsplash.com/photo-1497366216548-37526070297c?w=300 1.5x, https://images.unsplash.com/photo-1497366216548-37526070297c?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1497366216548-37526070297c?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（九）模拟键盘操作</title><link>https://itest2025.pages.dev/tutorials/19-009-%E4%B9%9D%E6%A8%A1%E6%8B%9F%E9%94%AE%E7%9B%98%E6%93%8D%E4%BD%9C/</link><pubDate>Sat, 01 Jul 2017 07:37:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/19-009-%E4%B9%9D%E6%A8%A1%E6%8B%9F%E9%94%AE%E7%9B%98%E6%93%8D%E4%BD%9C/</guid><description>&lt;br>
Keys()类提供了键盘上几乎所有按键的方法。 前面了解到， sendKeys()方法可以用来模拟键盘输入， 除此之
外， 我们还可以用它来输入键盘上的按键， 甚至是组合键， 如 Ctrl+A、 Ctrl+C 等。
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.WebElement&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.WebDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.chrome.ChromeDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.By&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.Keys&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">Keyboard&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="kd">throws&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">InterruptedException&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ChromeDriver&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;https://www.baidu.com&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebElement&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">input&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;kw&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//输入框输入内容&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">input&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;seleniumm&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2000&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//删除多输入的一个 m&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">input&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Keys&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">BACK_SPACE&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2000&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//输入空格键+“教程”&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">input&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Keys&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">SPACE&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">input&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;教程&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2000&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//ctrl+a 全选输入框内容&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">input&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Keys&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">CONTROL&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="s">&amp;#34;a&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2000&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//ctrl+x 剪切输入框内容&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">input&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Keys&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">CONTROL&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="s">&amp;#34;x&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2000&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//ctrl+v 粘贴内容到输入框&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">input&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Keys&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">CONTROL&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="s">&amp;#34;v&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2000&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//通过回车键盘来代替点击操作&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">input&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Keys&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">ENTER&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2000&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">quit&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>需要说明的是，上面的脚本没有什么实际意义，但向我们展示了模拟键盘各种按键与组合键的用法。&lt;/p></description></item><item><title>（九）设置元素等待</title><link>https://itest2025.pages.dev/tutorials/24-009-%E4%B9%9D%E8%AE%BE%E7%BD%AE%E5%85%83%E7%B4%A0%E7%AD%89%E5%BE%85/</link><pubDate>Thu, 22 Jun 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/24-009-%E4%B9%9D%E8%AE%BE%E7%BD%AE%E5%85%83%E7%B4%A0%E7%AD%89%E5%BE%85/</guid><description>&lt;br>
WebDriver提供了两种类型的等待：__显式等待__和__隐式等待__。
&lt;h3 id="显式等待">显式等待&lt;/h3>
&lt;p>显式等待使WebdDriver等待某个条件成立时继续执行，否则在达到最大时长时抛出超时异常（TimeoutException）。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">webdriver&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium.webdriver.common.by&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">By&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium.webdriver.support.ui&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">WebDriverWait&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium.webdriver.support&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">expected_conditions&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">EC&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">webdriver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Firefox&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;http://www.baidu.com&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">element&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">WebDriverWait&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">0.5&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">until&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">EC&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">presence_of_element_located&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ID&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;kw&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">element&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">send_keys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;selenium&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">quit&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>WebDriverWait类是由WebDirver 提供的等待方法。在设置时间内，默认每隔一段时间检测一次当前页面元素是否存在，如果超过设置时间检测不到则抛出异常。具体格式如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">WebDriverWait&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">timeout&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">poll_frequency&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">0.5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ignored_exceptions&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">None&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>driver ：浏览器驱动。&lt;/li>
&lt;li>timeout ：最长超时时间，默认以秒为单位。&lt;/li>
&lt;li>poll_frequency ：检测的间隔（步长）时间，默认为0.5S。&lt;/li>
&lt;li>ignored_exceptions ：超时后的异常信息，默认情况下抛NoSuchElementException异常。&lt;/li>
&lt;/ul>
&lt;p>WebDriverWait()一般由until()或until_not()方法配合使用，下面是until()和until_not()方法的说明。&lt;/p>
&lt;ul>
&lt;li>until(method, message=‘’)
调用该方法提供的驱动程序作为一个参数，直到返回值为True。&lt;/li>
&lt;li>until_not(method, message=‘’)
调用该方法提供的驱动程序作为一个参数，直到返回值为False。&lt;/li>
&lt;/ul>
&lt;p>在本例中，通过as关键字将expected_conditions 重命名为EC，并调用presence_of_element_located()方法判断元素是否存在。&lt;/p>
&lt;h3 id="隐式等待">隐式等待&lt;/h3>
&lt;p>WebDriver提供了implicitly_wait()方法来实现隐式等待，默认设置为0。它的用法相对来说要简单得多。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">webdriver&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium.common.exceptions&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">NoSuchElementException&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">time&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">ctime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">webdriver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Firefox&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 设置隐式等待为10秒&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">implicitly_wait&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;http://www.baidu.com&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ctime&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_element_by_id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;kw22&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">send_keys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;selenium&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">except&lt;/span> &lt;span class="n">NoSuchElementException&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">finally&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ctime&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">quit&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>implicitly_wait()默认参数的单位为秒，本例中设置等待时长为10秒。首先这10秒并非一个固定的等待时间，它并不影响脚本的执行速度。其次，它并不针对页面上的某一元素进行等待。当脚本执行到某个元素定位时，如果元素可以定位，则继续执行；如果元素定位不到，则它将以轮询的方式不断地判断元素是否被定位到。假设在第6秒定位到了元素则继续执行，若直到超出设置时长（10秒）还没有定位到元素，则抛出异常。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1459695452562-46cc57bef5f6?w=300"
 data-srcset="https://images.unsplash.com/photo-1459695452562-46cc57bef5f6?w=300, https://images.unsplash.com/photo-1459695452562-46cc57bef5f6?w=300 1.5x, https://images.unsplash.com/photo-1459695452562-46cc57bef5f6?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1459695452562-46cc57bef5f6?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（十）Docker Compose安装与创建Flask web应用</title><link>https://itest2025.pages.dev/tutorials/30-010-%E5%8D%81docker-compose%E5%AE%89%E8%A3%85%E4%B8%8E%E5%88%9B%E5%BB%BAflask-web%E5%BA%94%E7%94%A8/</link><pubDate>Mon, 22 Jan 2018 14:25:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/30-010-%E5%8D%81docker-compose%E5%AE%89%E8%A3%85%E4%B8%8E%E5%88%9B%E5%BB%BAflask-web%E5%BA%94%E7%94%A8/</guid><description>&lt;p>Docker Compose 是 Docker 官方编排（Orchestration）项目之一， 负责快速在集群中部署分布式应用。&lt;/p>
&lt;p>Dockerfile 可以让用户管理一个单独的应用容器；而	Compose	则允许用户在一个模板（YAML	格式）中定义一组相关联的应用容器（被称为一个 project，即项目），例如一个Web服务容器再加上后端的数据库服务容器等。&lt;/p>
&lt;h4 id="安装">安装&lt;/h4>
&lt;hr>
&lt;p>该项目由 Python 编写，实际上调用了 Docker 提供的	API	来实现。 通过&lt;code>pip&lt;/code>安装。&lt;/p>
&lt;pre tabindex="0">&lt;code>$ python3 -m pip install docker-compose
&lt;/code>&lt;/pre>&lt;p>安装成功后，可以查看&lt;code>docker-compose&lt;/code>命令的用法。&lt;/p>
&lt;pre tabindex="0">&lt;code>$ docker-compose
Define and run multi-container applications with Docker.

Usage:
 docker-compose [-f &amp;lt;arg&amp;gt;...] [options] [COMMAND] [ARGS...]
 docker-compose -h|--help

Options:
 -f, --file FILE Specify an alternate compose file (default: docker-compose.yml)
 -p, --project-name NAME Specify an alternate project name (default: directory name)
 --verbose Show more output
 --no-ansi Do not print ANSI control characters
 -v, --version Print version and exit
 -H, --host HOST Daemon socket to connect to

 ……
&lt;/code>&lt;/pre>&lt;h4 id="创建-flask-应用">创建 Flask 应用&lt;/h4>
&lt;hr>
&lt;p>创建使用Flask web应用，并将数值记入Redis。&lt;/p></description></item><item><title>（十） TestNG 多线程运行用例</title><link>https://itest2025.pages.dev/tutorials/36-010-%E5%8D%81-testng-%E5%A4%9A%E7%BA%BF%E7%A8%8B%E8%BF%90%E8%A1%8C%E7%94%A8%E4%BE%8B/</link><pubDate>Sat, 25 Nov 2017 12:15:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/36-010-%E5%8D%81-testng-%E5%A4%9A%E7%BA%BF%E7%A8%8B%E8%BF%90%E8%A1%8C%E7%94%A8%E4%BE%8B/</guid><description>&lt;p>TestNG 是我接触过的唯一自身支持多程技术的单元测试框架。虽然代码级别的单元测试运行得很快，多线程的意义并不大。但如果是UI自动化测试的话运行速度就会非常慢，这个时候多线程技术就会变得很重要。&lt;/p>
&lt;h4 id="多线程配置">多线程配置&lt;/h4>
&lt;hr>
&lt;p>这里只介绍 &lt;strong>testng.xml&lt;/strong> 文件，其中的使用到的测试用例，请参考前面的章节创建。&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;lt;!DOCTYPE suite SYSTEM &amp;#34;http://testng.org/testng-1.0.dtd&amp;#34; &amp;gt;
&amp;lt;suite name=&amp;#34;测试套件&amp;#34; parallel=&amp;#34;classes&amp;#34; thread-count=&amp;#34;2&amp;#34; &amp;gt;
 &amp;lt;test name=&amp;#34;简单测试&amp;#34;&amp;gt;
 &amp;lt;classes&amp;gt;
 &amp;lt;class name=&amp;#34;test.sample.FirstTest&amp;#34; /&amp;gt;
 &amp;lt;class name=&amp;#34;test.sample.SecondTest&amp;#34; /&amp;gt;
 &amp;lt;/classes&amp;gt;
 &amp;lt;/test&amp;gt;
&amp;lt;/suite&amp;gt;
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>
&lt;p>parallel 设置多线程的级别划分。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>parallel=&amp;ldquo;methods&amp;rdquo;: TestNG将在不同的线程中运行所有的测试方法。依赖方法也将在单独的线程中运行，但它们将尊重你指定的顺序。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>parallel=&amp;ldquo;tests&amp;rdquo;: TestNG 将在同一个线程中运行相同的&lt;test>标记的所有方法，但是每个&lt;test>标记将在一个单独的线程中。这允许你将所有非线程安全的类分组在同一个&lt;test>中，并保证它们将在同一个线程中运行，同时利用尽可能多的线程来运行测试。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>parallel=&amp;ldquo;classes&amp;rdquo;: TestNG将在同一个线程中运行同一个类中的所有方法，但是每个类都将在一个单独的线程中运行。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>parallel=&amp;ldquo;instances&amp;rdquo;: TestNG将在同一个线程中运行相同实例中的所有方法，但是在两个不同实例上的两个方法将在不同的线程中运行。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>thread-count 用于指定线程的个数。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1517048676732-d65bc937f952?w=300"
 data-srcset="https://images.unsplash.com/photo-1517048676732-d65bc937f952?w=300, https://images.unsplash.com/photo-1517048676732-d65bc937f952?w=300 1.5x, https://images.unsplash.com/photo-1517048676732-d65bc937f952?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1517048676732-d65bc937f952?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>requests中如何查看响应的headers?</title><link>https://itest2025.pages.dev/tutorials/42-010-requests%E4%B8%AD%E5%A6%82%E4%BD%95%E6%9F%A5%E7%9C%8B%E5%93%8D%E5%BA%94%E7%9A%84headers/</link><pubDate>Wed, 22 Nov 2017 03:23:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/42-010-requests%E4%B8%AD%E5%A6%82%E4%BD%95%E6%9F%A5%E7%9C%8B%E5%93%8D%E5%BA%94%E7%9A%84headers/</guid><description>&lt;p>&lt;code>r.headers&lt;/code> 可以拿到Python 字典形式展示的服务器响应头：&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; r.headers
{
 &amp;#39;content-encoding&amp;#39;: &amp;#39;gzip&amp;#39;,
 &amp;#39;transfer-encoding&amp;#39;: &amp;#39;chunked&amp;#39;,
 &amp;#39;connection&amp;#39;: &amp;#39;close&amp;#39;,
 &amp;#39;server&amp;#39;: &amp;#39;nginx/1.0.4&amp;#39;,
 &amp;#39;x-runtime&amp;#39;: &amp;#39;148ms&amp;#39;,
 &amp;#39;etag&amp;#39;: &amp;#39;&amp;#34;e1ca502697e5c9317743dc078f67693f&amp;#34;&amp;#39;,
 &amp;#39;content-type&amp;#39;: &amp;#39;application/json&amp;#39;
}
&lt;/code>&lt;/pre>&lt;p>但是这个字典比较特殊：它是仅为 HTTP 头部而生的。根据&lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html" target="_blank" rel="noopener noreffer ">RFC 2616&lt;/a>， HTTP 头部是大小写不敏感的。&lt;/p>
&lt;p>因此，我们可以使用任意大写形式来访问这些响应头字段：&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; r.headers[&amp;#39;Content-Type&amp;#39;]
&amp;#39;application/json&amp;#39;

&amp;gt;&amp;gt;&amp;gt; r.headers.get(&amp;#39;content-type&amp;#39;)
&amp;#39;application/json&amp;#39;
&lt;/code>&lt;/pre>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1501959181532-7d2a3c064642?w=300"
 data-srcset="https://images.unsplash.com/photo-1501959181532-7d2a3c064642?w=300, https://images.unsplash.com/photo-1501959181532-7d2a3c064642?w=300 1.5x, https://images.unsplash.com/photo-1501959181532-7d2a3c064642?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1501959181532-7d2a3c064642?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（十）JUnit5 创建测试</title><link>https://itest2025.pages.dev/tutorials/31-010-%E5%8D%81junit5-%E5%88%9B%E5%BB%BA%E6%B5%8B%E8%AF%95/</link><pubDate>Mon, 13 Nov 2017 12:25:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/31-010-%E5%8D%81junit5-%E5%88%9B%E5%BB%BA%E6%B5%8B%E8%AF%95/</guid><description>&lt;h4 id="创建测试用例">创建测试用例&lt;/h4>
&lt;hr>
&lt;p>我在 IntelliJ IDEA 中创建的 Maven 项目，目录结构如下：&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/junit_5_maven_project.png"
 data-srcset="http://img.testclass.net/junit_5_maven_project.png, http://img.testclass.net/junit_5_maven_project.png 1.5x, http://img.testclass.net/junit_5_maven_project.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/junit_5_maven_project.png"
 title="http://img.testclass.net/junit_5_maven_project.png" />&lt;/p>
&lt;p>在 test.java 目录下创建一个 FistJUnit5Tests 类。代码如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.jupiter.api.Assertions.assertEquals&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.jupiter.api.Test&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">FirstJUnit5Tests&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">myFirstTest&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>明显看出和 Junit4 还是有些不同的。&lt;/p>
&lt;p>首先，导入测试测试注解（@Test）和断言方法（assertEquals）的路径不同。&lt;/p>
&lt;p>其次，不需要手动把测试和测试方法声明为 public 了。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1461749280684-dccba630e2f6?w=300"
 data-srcset="https://images.unsplash.com/photo-1461749280684-dccba630e2f6?w=300, https://images.unsplash.com/photo-1461749280684-dccba630e2f6?w=300 1.5x, https://images.unsplash.com/photo-1461749280684-dccba630e2f6?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1461749280684-dccba630e2f6?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>10.使用fixture参数化测试预期结果</title><link>https://itest2025.pages.dev/tutorials/25-010-10%E4%BD%BF%E7%94%A8fixture%E5%8F%82%E6%95%B0%E5%8C%96%E6%B5%8B%E8%AF%95%E9%A2%84%E6%9C%9F%E7%BB%93%E6%9E%9C/</link><pubDate>Wed, 25 Oct 2017 07:22:42 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/25-010-10%E4%BD%BF%E7%94%A8fixture%E5%8F%82%E6%95%B0%E5%8C%96%E6%B5%8B%E8%AF%95%E9%A2%84%E6%9C%9F%E7%BB%93%E6%9E%9C/</guid><description>&lt;h3 id="背景">背景&lt;/h3>
&lt;p>接上一节&lt;a href="http://www.v2ex.com" target="_blank" rel="noopener noreffer ">v2ex&lt;/a>网站的查看论坛节点信息的api。&lt;/p>
&lt;p>我们在上一节的测试用例里只断言了返回值的name字段必须与我们传入的入参相同，但是返回值的id却没有进行判定。这一节里我们加强一下测试脚本，实现判断id的功能。&lt;/p>
&lt;h3 id="测试数据">测试数据&lt;/h3>
&lt;pre tabindex="0">&lt;code>python, id=90
java, id=63
nodejs, id=436
go, id=375
&lt;/code>&lt;/pre>&lt;h3 id="代码实现">代码实现&lt;/h3>
&lt;p>在&lt;code>v2ex_api_test.py&lt;/code>的文件中加入如下内容:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">TestV2exApiWithExpectation&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">object&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">domain&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;https://www.v2ex.com/&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@pytest.mark.parametrize&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;name,node_id&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">[(&lt;/span>&lt;span class="s1">&amp;#39;python&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">90&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;java&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">63&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;go&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">375&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;nodejs&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">436&lt;/span>&lt;span class="p">)])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">test_node&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">node_id&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;api/nodes/show.json?name=&lt;/span>&lt;span class="si">%s&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span> &lt;span class="o">%&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">url&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">domain&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">path&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">requests&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">json&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="n">res&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;name&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">name&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="n">res&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;id&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">node_id&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行及结果">运行及结果&lt;/h3>
&lt;pre tabindex="0">&lt;code>$ pytest v2ex_api_test.py
======================================================================== test session starts ========================================================================
platform darwin -- Python 2.7.12, pytest-3.2.3, py-1.4.34, pluggy-0.4.0
rootdir: /Users/easonhan/code/testclass.net/src/pytest, inifile:
collected 9 items

v2ex_api_test.py .FFFFFFFF

============================================================================= FAILURES ==============================================================================
______________________________________________________________ TestV2exApiWithParams.test_node[python] ______________________________________________________________

self = &amp;lt;v2ex_api_test.TestV2exApiWithParams object at 0x10618eb10&amp;gt;, lang = &amp;#39;python&amp;#39;

 def test_node(self, lang):
 path = &amp;#39;api/nodes/show.json?name=%s&amp;#39; %(lang)
 url = self.domain + path
 res = requests.get(url).json()
 assert res[&amp;#39;name&amp;#39;] == lang
&amp;gt; assert 0
E assert 0

v2ex_api_test.py:27: AssertionError
_______________________________________________________________ TestV2exApiWithParams.test_node[java] _______________________________________________________________

self = &amp;lt;v2ex_api_test.TestV2exApiWithParams object at 0x106691790&amp;gt;, lang = &amp;#39;java&amp;#39;

 def test_node(self, lang):
 path = &amp;#39;api/nodes/show.json?name=%s&amp;#39; %(lang)
 url = self.domain + path
 res = requests.get(url).json()
 assert res[&amp;#39;name&amp;#39;] == lang
&amp;gt; assert 0
E assert 0

v2ex_api_test.py:27: AssertionError
________________________________________________________________ TestV2exApiWithParams.test_node[go] ________________________________________________________________

self = &amp;lt;v2ex_api_test.TestV2exApiWithParams object at 0x10666dc50&amp;gt;, lang = &amp;#39;go&amp;#39;

 def test_node(self, lang):
 path = &amp;#39;api/nodes/show.json?name=%s&amp;#39; %(lang)
 url = self.domain + path
 res = requests.get(url).json()
 assert res[&amp;#39;name&amp;#39;] == lang
&amp;gt; assert 0
E assert 0

v2ex_api_test.py:27: AssertionError
______________________________________________________________ TestV2exApiWithParams.test_node[nodejs] ______________________________________________________________

self = &amp;lt;v2ex_api_test.TestV2exApiWithParams object at 0x106691890&amp;gt;, lang = &amp;#39;nodejs&amp;#39;

 def test_node(self, lang):
 path = &amp;#39;api/nodes/show.json?name=%s&amp;#39; %(lang)
 url = self.domain + path
 res = requests.get(url).json()
 assert res[&amp;#39;name&amp;#39;] == lang
&amp;gt; assert 0
E assert 0

v2ex_api_test.py:27: AssertionError
__________________________________________________________ TestV2exApiWithExpectation.test_node[python-90] __________________________________________________________

self = &amp;lt;v2ex_api_test.TestV2exApiWithExpectation object at 0x1066d20d0&amp;gt;, name = &amp;#39;python&amp;#39;, node_id = 90

 @pytest.mark.parametrize(&amp;#39;name,node_id&amp;#39;, [(&amp;#39;python&amp;#39;, 90), (&amp;#39;java&amp;#39;, 63), (&amp;#39;go&amp;#39;, 375), (&amp;#39;nodejs&amp;#39;, 436)])

 def test_node(self, name, node_id):
 path = &amp;#39;api/nodes/show.json?name=%s&amp;#39; %(name)
 url = self.domain + path
 res = requests.get(url).json()
 assert res[&amp;#39;name&amp;#39;] == name
 assert res[&amp;#39;id&amp;#39;] == node_id
&amp;gt; assert 0
E assert 0

v2ex_api_test.py:40: AssertionError
___________________________________________________________ TestV2exApiWithExpectation.test_node[java-63] ___________________________________________________________

self = &amp;lt;v2ex_api_test.TestV2exApiWithExpectation object at 0x1066e9690&amp;gt;, name = &amp;#39;java&amp;#39;, node_id = 63

 @pytest.mark.parametrize(&amp;#39;name,node_id&amp;#39;, [(&amp;#39;python&amp;#39;, 90), (&amp;#39;java&amp;#39;, 63), (&amp;#39;go&amp;#39;, 375), (&amp;#39;nodejs&amp;#39;, 436)])

 def test_node(self, name, node_id):
 path = &amp;#39;api/nodes/show.json?name=%s&amp;#39; %(name)
 url = self.domain + path
 res = requests.get(url).json()
 assert res[&amp;#39;name&amp;#39;] == name
 assert res[&amp;#39;id&amp;#39;] == node_id
&amp;gt; assert 0
E assert 0

v2ex_api_test.py:40: AssertionError
___________________________________________________________ TestV2exApiWithExpectation.test_node[go-375] ____________________________________________________________

self = &amp;lt;v2ex_api_test.TestV2exApiWithExpectation object at 0x10666d790&amp;gt;, name = &amp;#39;go&amp;#39;, node_id = 375

 @pytest.mark.parametrize(&amp;#39;name,node_id&amp;#39;, [(&amp;#39;python&amp;#39;, 90), (&amp;#39;java&amp;#39;, 63), (&amp;#39;go&amp;#39;, 375), (&amp;#39;nodejs&amp;#39;, 436)])

 def test_node(self, name, node_id):
 path = &amp;#39;api/nodes/show.json?name=%s&amp;#39; %(name)
 url = self.domain + path
 res = requests.get(url).json()
 assert res[&amp;#39;name&amp;#39;] == name
 assert res[&amp;#39;id&amp;#39;] == node_id
&amp;gt; assert 0
E assert 0

v2ex_api_test.py:40: AssertionError
_________________________________________________________ TestV2exApiWithExpectation.test_node[nodejs-436] __________________________________________________________

self = &amp;lt;v2ex_api_test.TestV2exApiWithExpectation object at 0x1066d2710&amp;gt;, name = &amp;#39;nodejs&amp;#39;, node_id = 436

 @pytest.mark.parametrize(&amp;#39;name,node_id&amp;#39;, [(&amp;#39;python&amp;#39;, 90), (&amp;#39;java&amp;#39;, 63), (&amp;#39;go&amp;#39;, 375), (&amp;#39;nodejs&amp;#39;, 436)])

 def test_node(self, name, node_id):
 path = &amp;#39;api/nodes/show.json?name=%s&amp;#39; %(name)
 url = self.domain + path
 res = requests.get(url).json()
 assert res[&amp;#39;name&amp;#39;] == name
 assert res[&amp;#39;id&amp;#39;] == node_id
&amp;gt; assert 0
E assert 0

v2ex_api_test.py:40: AssertionError
================================================================ 8 failed, 1 passed in 1.81 seconds =================================================================
&lt;/code>&lt;/pre>&lt;p>原始封面&lt;/p></description></item><item><title>10. UI 主题、字体、编辑区主题、文件编码修改、乱码问题（新用户必看）</title><link>https://itest2025.pages.dev/tutorials/37-010-10-ui-%E4%B8%BB%E9%A2%98%E5%AD%97%E4%BD%93%E7%BC%96%E8%BE%91%E5%8C%BA%E4%B8%BB%E9%A2%98%E6%96%87%E4%BB%B6%E7%BC%96%E7%A0%81%E4%BF%AE%E6%94%B9%E4%B9%B1%E7%A0%81%E9%97%AE%E9%A2%98%E6%96%B0%E7%94%A8%E6%88%B7%E5%BF%85%E7%9C%8B/</link><pubDate>Mon, 16 Oct 2017 03:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/37-010-10-ui-%E4%B8%BB%E9%A2%98%E5%AD%97%E4%BD%93%E7%BC%96%E8%BE%91%E5%8C%BA%E4%B8%BB%E9%A2%98%E6%96%87%E4%BB%B6%E7%BC%96%E7%A0%81%E4%BF%AE%E6%94%B9%E4%B9%B1%E7%A0%81%E9%97%AE%E9%A2%98%E6%96%B0%E7%94%A8%E6%88%B7%E5%BF%85%E7%9C%8B/</guid><description>&lt;h1 id="intellij-idea-主题字体编辑区主题文件编码修改乱码问题">IntelliJ IDEA 主题、字体、编辑区主题、文件编码修改、乱码问题&lt;/h1>
&lt;h2 id="主题修改">主题修改&lt;/h2>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/x-a-theme-setting-1.jpg"
 data-srcset="http://img.testclass.net/x-a-theme-setting-1.jpg, http://img.testclass.net/x-a-theme-setting-1.jpg 1.5x, http://img.testclass.net/x-a-theme-setting-1.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/x-a-theme-setting-1.jpg"
 title="主题修改" />&lt;/p>
&lt;blockquote>
&lt;ul>
&lt;li>上图标注 1 所示为 IntelliJ IDEA 修改主题的地方，在 Windows 系统上 IntelliJ IDEA 默认提供的主题有四套：&lt;code>Darcula&lt;/code>、&lt;code>IntelliJ&lt;/code>、&lt;code>Windows&lt;/code>、&lt;code>Alloy. IDEA Theme&lt;/code>。除了 &lt;code>Darcula&lt;/code> 是黑色主题，其他三套都是以白色为背景的。&lt;/li>
&lt;li>其他操作系统上不一定会也有四套主题的，主题的选择上大家根据自己喜好即可。改变主题需要重启 IntelliJ IDEA 方可看到效果。&lt;/li>
&lt;/ul>&lt;/blockquote>
&lt;h2 id="字体修改">字体修改&lt;/h2>
&lt;h3 id="主题字体修改">主题字体修改&lt;/h3>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/x-b-font-setting-1.jpg"
 data-srcset="http://img.testclass.net/x-b-font-setting-1.jpg, http://img.testclass.net/x-b-font-setting-1.jpg 1.5x, http://img.testclass.net/x-b-font-setting-1.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/x-b-font-setting-1.jpg"
 title="主题字体修改" />&lt;/p>
&lt;blockquote>
&lt;ul>
&lt;li>如上图标注 1 所示，IntelliJ IDEA 主题字体的修改要先勾选 &lt;code>Override default fonts by&lt;/code> 。默认 IntelliJ IDEA 是不推荐修改的，但是由于字体是有分包含中文和不包含中文之分的，一般使用英文的国家是不需要额外担心乱码问题的，而我们需要。&lt;/li>
&lt;li>字体的审美上每个人不一样，但是如上一段说的，这里的字体修改是需要知道一个前提的，那就是你选择的那个字体必须含有中文，比如微软雅黑和宋体这类是包含中文的，而 &lt;code>Courier New&lt;/code> 和 &lt;code>Monaco&lt;/code> 这类只是单纯的英文字体。&lt;/li>
&lt;li>如果你选择的字体不包含中文，那可能会在很多位置上出现类似 &lt;code>口口口口口&lt;/code> 这样的乱码问题，比如文件名含有中文、字体是中文名字的都会变成 &lt;code>口口口口口&lt;/code>。&lt;/li>
&lt;li>在修改 IntelliJ IDEA 的主题字体的时候，不建议把字体调成很大，因为很多人遇到这样一种情况：显示器分辨率低，主题字体又大，在 IntelliJ IDEA 的某些操作的工具菜单、右键菜单选项中部分选项超出了分辨率显示范围，没办法被选中。当然了，如果你一定要把字体改大，又不用大分辨率显示器，那可以通过 IntelliJ IDEA 的 &lt;code>Menus and Toolbars&lt;/code> 删除部分你认为用不到的菜单，但是一般不建议这样做。&lt;/li>
&lt;li>还需要特别注意的时候，如果你是开着 IntelliJ IDEA 的时候，新装了一个字体的话，那必须重启IntelliJ IDEA 之后才能在下拉列表找到新装的字体。&lt;/li>
&lt;/ul>&lt;/blockquote>
&lt;h3 id="代码编辑字体修改">代码编辑字体修改&lt;/h3>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/x-b-font-setting-2.jpg"
 data-srcset="http://img.testclass.net/x-b-font-setting-2.jpg, http://img.testclass.net/x-b-font-setting-2.jpg 1.5x, http://img.testclass.net/x-b-font-setting-2.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/x-b-font-setting-2.jpg"
 title="代码编辑字体修改" />&lt;/p></description></item><item><title>appium新手入门（10）—— appium API 之上下文操作</title><link>https://itest2025.pages.dev/tutorials/21-010-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A810-appium-api-%E4%B9%8B%E4%B8%8A%E4%B8%8B%E6%96%87%E6%93%8D%E4%BD%9C/</link><pubDate>Thu, 07 Sep 2017 10:22:12 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/21-010-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A810-appium-api-%E4%B9%8B%E4%B8%8A%E4%B8%8B%E6%96%87%E6%93%8D%E4%BD%9C/</guid><description>&lt;p>其实上下文的操作主要针对于混合应用。啥是混合应用，简单来说就是APP用里面嵌入网页。Android上的浏览器就属于混合应用。&lt;/p>
&lt;h4 id="1获取当前上下文">1、获取当前上下文&lt;/h4>
&lt;hr>
&lt;p>方法：&lt;/p>
&lt;ul>
&lt;li>getContext()&lt;/li>
&lt;/ul>
&lt;p>获取当前所有的可用的上下文。该方法不需要入参。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ct&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">getContext&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ct&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="o">-----------&lt;/span>&lt;span class="n">计算器应用的打印结果&lt;/span>&lt;span class="o">-----------------------&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">NATIVE_APP&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="2当前所有上下文句柄">2、当前所有上下文句柄&lt;/h4>
&lt;hr>
&lt;p>方法：&lt;/p>
&lt;ul>
&lt;li>getContextHandles()&lt;/li>
&lt;/ul>
&lt;p>获取当前所有可用的上下文。该方法不需要入参。&lt;/p>
&lt;h4 id="3切换上下文">3、切换上下文&lt;/h4>
&lt;hr>
&lt;ul>
&lt;li>context()&lt;/li>
&lt;/ul>
&lt;p>切换到特定的上下文中。需要指定上下文的名称。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">context&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">NATIVE_APP&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">context&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">WEBVIEW_1&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1505312926838-645f295a20e1?w=300"
 data-srcset="https://images.unsplash.com/photo-1505312926838-645f295a20e1?w=300, https://images.unsplash.com/photo-1505312926838-645f295a20e1?w=300 1.5x, https://images.unsplash.com/photo-1505312926838-645f295a20e1?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1505312926838-645f295a20e1?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>JMeter官方文档：10. 创建一个点对点的 JMS 测试计划</title><link>https://itest2025.pages.dev/tutorials/22-010-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A310-%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E7%82%B9%E5%AF%B9%E7%82%B9%E7%9A%84-jms-%E6%B5%8B%E8%AF%95%E8%AE%A1%E5%88%92/</link><pubDate>Thu, 24 Aug 2017 08:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/22-010-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A310-%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E7%82%B9%E5%AF%B9%E7%82%B9%E7%9A%84-jms-%E6%B5%8B%E8%AF%95%E8%AE%A1%E5%88%92/</guid><description>&lt;p>&lt;a href="https://itest2025.pages.dev/2017/08/24/jmeter-translation-plans/" rel="">《JMeter官方文档&amp;ndash;翻译计划》&lt;/a> &lt;a href="http://jmeter.apache.org/usermanual/build-jms-point-to-point-test-plan.html" target="_blank" rel="noopener noreffer ">原文地址&lt;/a>&lt;/p>
&lt;h2 id="10创建一个点对点的-jms-测试计划">10.创建一个点对点的 JMS 测试计划&lt;/h2>
&lt;hr>
&lt;blockquote>
&lt;p>确保所需的jar文件位于JMeter lib目录中。 如果没有，关闭JMeter，复制jar文件并重新启动JMeter。 &lt;a href="http://jmeter.apache.org/usermanual/get-started.html#libraries_activemq" target="_blank" rel="noopener noreffer ">参见详细教程&lt;/a>&lt;/p>&lt;/blockquote>
&lt;p>在本节中，将学习如何创建&lt;a href="http://jmeter.apache.org/usermanual/build-test-plan.html" target="_blank" rel="noopener noreffer ">测试计划&lt;/a>来测试JMS点对点消息传递。 先设置1个线程组5个线程发送4个请求，通过队列的形式发送。 固定的回复队列将用于监听回复消息。 要构建测试计划，您将使用以下元素：&lt;a href="http://jmeter.apache.org/usermanual/test_plan.html#thread_group" target="_blank" rel="noopener noreffer ">线程组&lt;/a>，&lt;a href="http://jmeter.apache.org/usermanual/component_reference.html#JMS_Point-to-Point" target="_blank" rel="noopener noreffer ">JMS点对点&lt;/a>和&lt;a href="http://jmeter.apache.org/usermanual/component_reference.html#Graph_Results" target="_blank" rel="noopener noreffer ">图形结果&lt;/a>。&lt;/p>
&lt;p>关于 JMS 的一般注意事项：目前有两个JMS采样器。 一个是使用 JMS Topic，另一个时使用 Queue。 Topic 通常被称为pub/sub消息。 Topic 消息通常用于生产者发布消息并由多个订阅者接收的情况。 JMS 采样器需要 JMS 实现 jar 文件，比如 Apache ActiveMQ 包。 &lt;a href="http://jmeter.apache.org/usermanual/get-started.html#libraries_activemq" target="_blank" rel="noopener noreffer ">参见这里&lt;/a>的 ActiveMQ 提供的 jar 的列表。&lt;/p>
&lt;h3 id="101-增加一个线程组">10.1 增加一个线程组&lt;/h3>
&lt;hr>
&lt;p>首先，对每个要执行的 JMeter 测试计划添加一个线程组。 线程组会告诉 JMeter 需要模拟的用户数量，发送请求的频率以及发送请求的数量。&lt;/p>
&lt;p>然后，添加 ThreadGroup 元素，首先选择测试计划，单击鼠标右键获取添加菜单，然后选择添加→线程组。&lt;/p>
&lt;p>接下来，需要修改默认属性。 现在可以在 JMeter 窗口的右侧部分看到线程组控制面板（参见下面的图10.1）&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/thread_group.png"
 data-srcset="http://img.testclass.net/thread_group.png, http://img.testclass.net/thread_group.png 1.5x, http://img.testclass.net/thread_group.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/thread_group.png"
 title="image" />&lt;/p></description></item><item><title>10.使用flask实现mock server</title><link>https://itest2025.pages.dev/tutorials/40-010-10%E4%BD%BF%E7%94%A8flask%E5%AE%9E%E7%8E%B0mock-server/</link><pubDate>Mon, 21 Aug 2017 04:41:43 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/40-010-10%E4%BD%BF%E7%94%A8flask%E5%AE%9E%E7%8E%B0mock-server/</guid><description>&lt;h3 id="flask">flask&lt;/h3>
&lt;p>flask是python实现的简单的web框架，与django互补。&lt;/p>
&lt;h3 id="flask教程">flask教程&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="http://flask.pocoo.org/" target="_blank" rel="noopener noreffer ">官方文档&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://www.pythondoc.com/flask-mega-tutorial/index.html" target="_blank" rel="noopener noreffer ">flask大型项目教程&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="如何理解flask">如何理解flask&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>路由 -&amp;gt; /request/uri&lt;/p>
&lt;/li>
&lt;li>
&lt;p>handler -&amp;gt; 路由进来之后处理request并返回response的逻辑&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="最简单的例子">最简单的例子&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">flask&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Flask&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">app&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Flask&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="vm">__name__&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@app.route&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;/&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 路由&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">hello&lt;/span>&lt;span class="p">():&lt;/span> &lt;span class="c1"># handler&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s2">&amp;#34;Hello World!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="实现mocked-smile-task-api">实现mocked smile task api&lt;/h3>
&lt;p>获取所有的任务&lt;/p>
&lt;pre tabindex="0">&lt;code>GET /api/tasks # get all tasks
&lt;/code>&lt;/pre>&lt;p>查看一个任务的详情&lt;/p>
&lt;pre tabindex="0">&lt;code>GET /api/tastks/:task_id # get a task with task_id
&lt;/code>&lt;/pre>&lt;p>完成一个任务&lt;/p>
&lt;pre tabindex="0">&lt;code>PUT /api/tastks/:task_id # complete a task
&lt;/code>&lt;/pre>&lt;h3 id="代码">代码&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">flask&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Flask&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">jsonify&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">g&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">copy&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">app&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Flask&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="vm">__name__&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@app.before_request&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">set_up_data&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;id&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;title&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;task 1&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;desc&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;this is task 1&amp;#39;&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;id&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;title&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;task 2&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;desc&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;this is task 2&amp;#39;&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;id&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;title&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;task 3&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;desc&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;this is task 3&amp;#39;&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;id&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;title&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;task 4&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;desc&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;this is task 4&amp;#39;&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;id&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;title&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;task 5&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;desc&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;this is task 5&amp;#39;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">task_does_not_exist&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;msg&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;task does not exist&amp;#34;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@app.route&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;/api/tasks&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">get_all_tasks&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">jsonify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">g&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@app.route&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;/api/tasks/&amp;lt;int:task_id&amp;gt;&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">get_task&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">task_id&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">task_id&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="n">task_id&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">g&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">jsonify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">g&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">task_id&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">jsonify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">g&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">task_does_not_exist&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@app.route&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;/api/tasks/&amp;lt;int:task_id&amp;gt;&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">methods&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;PUT&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">complete_task&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">task_id&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">task_id&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="n">task_id&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">g&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tmp&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">copy&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">deepcopy&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">g&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">task_id&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tmp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;done&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">jsonify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">tmp&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">jsonify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">g&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">task_does_not_exist&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行">运行&lt;/h3>
&lt;pre tabindex="0">&lt;code>set FLASK_APP=smile_task_mock_server.py

flask run
* Serving Flask app &amp;#34;smile_task_mock_server&amp;#34;
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
&lt;/code>&lt;/pre>&lt;p>浏览器打开localhost:5000就好了&lt;/p></description></item><item><title>appium简明教程（10）——控件定位基础</title><link>https://itest2025.pages.dev/tutorials/21-010-appium%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B10%E6%8E%A7%E4%BB%B6%E5%AE%9A%E4%BD%8D%E5%9F%BA%E7%A1%80/</link><pubDate>Fri, 11 Aug 2017 08:40:32 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/21-010-appium%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B10%E6%8E%A7%E4%BB%B6%E5%AE%9A%E4%BD%8D%E5%9F%BA%E7%A1%80/</guid><description>&lt;p>狭义上讲，UI级的自动化测试就是让机器代替人去点来点去的过程。&lt;/p>
&lt;p>但机器去点什么（点上面还是点左边），怎么点（是长按还是轻触），这些东西是必须由代码的编写者所指示清楚的。&lt;/p>
&lt;p>控件定位就是解决机器点什么的问题的。&lt;/p>
&lt;p>一般说来，我们可以这样告诉机器：去点登陆按钮。&lt;/p>
&lt;p>机器很笨，它并不知道什么是登陆按钮。因为登陆按钮是自然语言的描述。&lt;/p>
&lt;p>如果你让一个人去点登陆按钮，那么他其实也是要经过一系列的脑补以后才可以做这件事的。&lt;/p>
&lt;p>这个脑补的过程还原如下：&lt;/p>
&lt;pre tabindex="0">&lt;code>这个一定是个按钮

这个按钮一定在被测的应用上

这个按钮大概上面有登陆这个文字信息

嗯，还真有一个，那么点吧。
&lt;/code>&lt;/pre>&lt;p>这就是人探索性测试的一个简单过程。一般来说，如果你给出的信息不太充分，人类还是可以通过一系列的探索性思维去理解你的描述的。这个属于心理学的问题，不展开解释。&lt;/p>
&lt;p>但是机器并不是人，如果你给出的描述不精确的话，机器是不会自发性的进行探索和脑补的。&lt;/p>
&lt;p>因此控件定位就是精确的描述控件特征并告诉机器的过程。&lt;/p>
&lt;p>本文版权归乙醇所有，欢迎转载，但请注明作者与出处，严禁用于任何商业用途&lt;/p>
&lt;p>控件的特征就是控件的属性，我们可以通过上一讲中的uiautomatorviewer去获取。&lt;/p>
&lt;p>在appium的定位世界里，下面这些方法是可以为我们使用的。也就是说，我们通过下面几个约定好的方式，按照webdriver和appium的DSL（自行搜索并理解）进行控件特征的描述和定位。&lt;/p>
&lt;p>继承自webdriver的方法，也就是通过这3个特征可以定位控件&lt;/p>
&lt;ul>
&lt;li>find by &amp;ldquo;class&amp;rdquo; (i.e., ui component type，andorid上可以是android.widget.TextView)&lt;/li>
&lt;li>find by &amp;ldquo;xpath&amp;rdquo; (i.e., an abstract representation of a path to an element, with certain constraints，由于appium的xpath库不完备的原因，这个不太推荐)&lt;/li>
&lt;li>find by &amp;ldquo;id&amp;rdquo;(android上是控件的resource id)&lt;/li>
&lt;/ul>
&lt;p>由&lt;a href="https://code.google.com/p/selenium/source/browse/spec-draft.md?repo=mobile" target="_blank" rel="noopener noreffer ">Mobile JSON Wire Protocol&lt;/a> 协议中定义的方法，更适合移动设备上的控件定位&lt;/p>
&lt;ul>
&lt;li>-ios uiautomation: a string corresponding to a recursive element search using the UIAutomation library (iOS-only)&lt;/li>
&lt;li>-android uiautomator: a string corresponding to a recursive element search using the UiAutomator Api (Android-only)&lt;/li>
&lt;li>accessibility id: a string corresponding to a recursive element search using the Id/Name that the native Accessibility options utilize.&lt;/li>
&lt;/ul>
&lt;p>在appium 的client对&lt;a href="https://code.google.com/p/selenium/source/browse/spec-draft.md?repo=mobile" target="_blank" rel="noopener noreffer ">Mobile JSON Wire Protocol&lt;/a>中定义的方法进行了封装，使其调用起来更加方便&lt;/p></description></item><item><title>性能测试流程（五）——测试计划</title><link>https://itest2025.pages.dev/tutorials/14-010-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E6%B5%81%E7%A8%8B%E4%BA%94%E6%B5%8B%E8%AF%95%E8%AE%A1%E5%88%92/</link><pubDate>Fri, 11 Aug 2017 04:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/14-010-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E6%B5%81%E7%A8%8B%E4%BA%94%E6%B5%8B%E8%AF%95%E8%AE%A1%E5%88%92/</guid><description>&lt;h4 id="一简介">一．简介&lt;/h4>
&lt;p> 
简介部分就不用过多描述了，无非项目的背景，进行此次性能测试的原因，以及性能测试覆盖的范围等等，几乎所有项目文档都在开端对项目进行简单的阐述。
 &lt;/p>
&lt;h4 id="二性能测试需求">二．性能测试需求&lt;/h4>
&lt;p> 
寻找的被测试对象和压力点&lt;/p>
&lt;p>要测试的对象不是凭空想象出来，而是经过分析与系统数据收集得到。以下取几个典型的压力点。&lt;/p>
&lt;p>登录：对于一般的系统来说，登录是用户操作系统的前提，如果用户根本就登录不了，那么其它功能将毫无用处。例如网游戏，开新服的时候，玩家挤破了脑袋只为登录。&lt;/p>
&lt;p>查询：查询一般比较消耗系统和数据库资源。搜索引擎的查询功能就是典型，如果你在输入框内输入内容，很久就得不到结果。我想被称为“互联网入口”的搜索引擎就不会存在。&lt;/p>
&lt;p>交易：对于一些电子商务系统来说，交易过程的性能要求是很高的，如果交易过程消耗用户很长时间的话，用户可能会转投其它平台。当然，除了交易速度外，对交易的成功率要求也是非常高的。不然，造成的损失也是不可估量的。&lt;/p>
&lt;p>被测的系统应该是最重要的最基本的功能，也是用户使用最频繁的功能。
 
 &lt;/p>
&lt;h4 id="三测试环境">三．测试环境&lt;/h4>
&lt;p> 
这里的测试环境主要指的软件硬件环境和网络环境。&lt;/p>
&lt;p>笔者认为性能测试最好在一个独立的环境内进行，这样不会受到外界的干扰，能够保证测试的数据是独立有效的。如果现你对某个已经上线的网站进行压力测试，那么你得到的数据不是独立的，因为你在做压力测试的时候，其它散户也在访问系统。&lt;/p>
&lt;ul>
&lt;li>软件环境：&lt;/li>
&lt;/ul>
&lt;p>这里的软件环境主要指项目运行的环境，比如采用什么样的操作系统、中间件、和数据库。&lt;/p>
&lt;ul>
&lt;li>硬件环境：&lt;/li>
&lt;/ul>
&lt;p>这里的硬件环境除了主要包括主机内部部件，cpu、内存、磁盘以及主板、网卡等，传输介质和路由器也应该考虑在内，&lt;/p>
&lt;ul>
&lt;li>网络环境：&lt;/li>
&lt;/ul>
&lt;p>网络环境除了考虑测试机与被系统服务器在一个局域网中进行，还应该保证这个网络的独立性。如果在在性能测试的过程中，其它机子也在消耗着路由器资源。那么路由器也会影响到数据库的传输速度。
 
 &lt;/p>
&lt;h4 id="四数据准备">四．数据准备&lt;/h4>
&lt;p> 
在很多时候，我们是要准备测试数据的，例如系统不允许相同用户的重复登录，那么必须要生成合法的用户数据。有时要对系统进行查询测试，只有在系统有一定数据量进才能验证出系统的真实性能。一个数据库中有两条数据和有两千万条数据，同相一条查询操作，对系统造成的压力是完全不一样的。&lt;/p>
&lt;p>系统所需数据的分析可以参考以下方式：&lt;/p>
&lt;p>历史数据分析有助于数据量级的确定。从历史数据入手，找出高峰期数据量。&lt;/p>
&lt;p>从其他相似或者相同系统入手，进行数据分析，找出高峰期数据量。&lt;/p>
&lt;p>无历史或者相关系统可以参考的时候，就要对系统的性能数据进行估算，包含系统容量，并发数等数据，估算以后给相关人员进行评审或者修订以后，按照大家同意的性能指标进行测试。&lt;/p>
&lt;p>…………&lt;/p>
&lt;p>测试数据最好和真实数据相同，如果能够获得真实系统运行3个月的数据，我们就可以在此基础上进行性能测试。&lt;/p>
&lt;p>关于数据的生成，我们可以通过工具完成，如数据库数据生成工具，大小文件生成工具等。
 &lt;/p>
&lt;h4 id="五测试工具">五．测试工具&lt;/h4>
&lt;p> 
前面已经介绍如何分析需求，需求确定下来之后，我们可以考虑引入什么样的工具适合性能需求。&lt;/p>
&lt;p>当然，在引入工具的时候除了考虑可以是否满足需求，还应该考虑工具的成本，这不单指工具的购买成本，还有测试人员对工具的学习成本。&lt;/p>
&lt;p>关于测试工具的选择，后面会单独有一章节介绍，这里就不细说了。&lt;/p>
&lt;p>如果你选择的性能测试工具不是足够的强大的话，你可能还需要其它的辅助的工具。如果Jmeter利用BadBoy来录制脚本，更能提高脚本开发效率。在压力测试的过程中也可能需要性能计数器来记录软硬件的性能。如监控服务器CPU、内存的计数器，记录中间件日志的监控中工具，监控数据库性能的监控工具等。
 &lt;/p>
&lt;h4 id="六测试策略">六．测试策略&lt;/h4>
&lt;p> 
对于一个特定的业务系统，用户一般会分散在一天的各个时间段进行访问。在不同的时间段中，用户使用业务系统的频率不同，而系统的繁忙程度不同。在一些特定的条件下，可能出现短时间内用户集中访问某个业务系统的情况。例如对于公文处理子系统而言，可能就存在短时间内大量用户查看并办理某条公文的情况。 在进行性能测试时，应当使用“考虑最坏情况的原则”。也就是应当在用户使用业务系统最频繁、对系统造成最大压力的情况下对系统的功能进行测试，判断各功能和页面是否能够满足性能的要求，系统的响应时间是否过长。&lt;/p>
&lt;p>另一方面，系统性能的验证必须做到“覆盖全面”。虽然系统中各个功能的使用频率并不相同，一些功能的使用频率相对于其他功能来说比较低，但是在进行性能测试和优化时，不能忽略这些功能，编制测试用例时也不能仅仅选择最常用功能。例如可能所有的用户都会访问我的通知列表，但是一般只有5%的用户会使用通过系统设置模块查找某个用户的信息；但是在测试时，我们并不能因为查看用户信息功能的使用频率相对较少，而忽略掉这项功能的测试。所以，这里进行系统性能测试时，对于不同业务，用户的访问比例应该做一个合理分配。&lt;/p>
&lt;p>在测试策略上，我们还应该考虑，同一个系统在不同硬件环境下的性能表现。从而让系统满足需求的情况下，硬件配置也能达到一个最佳的状态。过份的增加硬件来满足需求也是一种浪费。再说增加硬件设备不是能解决所有性能问题的。&lt;/p>
&lt;h4 id="七人力与时间安排">七．人力与时间安排&lt;/h4>
&lt;p> 
最后一条，就是要根据项目的进度要求以及规模，来进行人力与时间的安排。对于大型的性能测试，项目前期的需求调研，环境的部署，工具的选购或开发，人员对测试工具的学习与使用，性能测试的后进行，后期数据的分析与调优。都需要人员安排的。有可以需要专业的，系统工程师、数据库工程师、软件开发工程师、网络工程师以及性能测试工程师的共同参与配合完成。不是一个性能测试人员就可以全部搞定的。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1522069365959-25716fb5001a?w=300"
 data-srcset="https://images.unsplash.com/photo-1522069365959-25716fb5001a?w=300, https://images.unsplash.com/photo-1522069365959-25716fb5001a?w=300 1.5x, https://images.unsplash.com/photo-1522069365959-25716fb5001a?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1522069365959-25716fb5001a?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（十）模拟键盘按键</title><link>https://itest2025.pages.dev/tutorials/20-010-%E5%8D%81%E6%A8%A1%E6%8B%9F%E9%94%AE%E7%9B%98%E6%8C%89%E9%94%AE/</link><pubDate>Fri, 04 Aug 2017 02:49:18 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/20-010-%E5%8D%81%E6%A8%A1%E6%8B%9F%E9%94%AE%E7%9B%98%E6%8C%89%E9%94%AE/</guid><description>&lt;h3 id="sendkeys">sendKeys&lt;/h3>
&lt;p>sendKeys()方法可以用来模拟用户按下键盘，组合键比如&lt;code>ctrl+c&lt;/code>等也可以模拟。&lt;/p>
&lt;h3 id="目的">目的&lt;/h3>
&lt;ul>
&lt;li>学会使用sendKeys方法&lt;/li>
&lt;li>学会使用模拟&lt;a href="http://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_Key.html" target="_blank" rel="noopener noreffer ">特殊按钮&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="场景">场景&lt;/h3>
&lt;p>测试中我们经常会打开一个页面，然后一下往下拉，直到滚动条拉到最底部，这怎么用selenium来实现呢？&lt;/p>
&lt;p>其实我们可以用模拟按空格键的方式实现。大家都知道，在页面上一直按空格键，页面就会到达最底部，当然这并不精确，但大多数时候都是管用的。&lt;/p>
&lt;p>下面我们就用代码实现打开&lt;a href="http://www.qq.com/" target="_blank" rel="noopener noreffer ">qq首页&lt;/a>，然后模拟按10下空格键，使页面滚动到最最底部。&lt;/p>
&lt;h3 id="代码">代码&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">webdriver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;selenium-webdriver&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">By&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">Key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Key&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">dr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Builder&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">forBrowser&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;chrome&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">build&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;http://www.qq.com&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 把页面的body找到，在body上模拟按钮，这是整页面模拟按键事件的小技巧
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kd">var&lt;/span> &lt;span class="nx">body&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">css&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;body&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 每隔1.5s按一次空格键
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// setTimeout在js binding中相当于其他binding中的sleep功能
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kd">var&lt;/span> &lt;span class="nx">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="nx">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="nx">i&lt;/span>&lt;span class="o">++&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">setTimeout&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">body&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">Key&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">SPACE&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span> &lt;span class="nx">i&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">1500&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行结果">运行结果&lt;/h3>
&lt;p>页面会缓慢的滚到最底部，如果你的页面滚到中间就停住了，增加滚动次数即可。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1475299137256-e36862458196?w=300"
 data-srcset="https://images.unsplash.com/photo-1475299137256-e36862458196?w=300, https://images.unsplash.com/photo-1475299137256-e36862458196?w=300 1.5x, https://images.unsplash.com/photo-1475299137256-e36862458196?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1475299137256-e36862458196?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>10. 写文件</title><link>https://itest2025.pages.dev/tutorials/28-010-10-%E5%86%99%E6%96%87%E4%BB%B6/</link><pubDate>Sat, 01 Jul 2017 08:17:22 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/28-010-10-%E5%86%99%E6%96%87%E4%BB%B6/</guid><description>&lt;h3 id="背景">背景&lt;/h3>
&lt;p>这一节里我们来学习如何使用python向文本文件中写入的内容。&lt;/p>
&lt;p>我们将实现一个简单的创建测试用例文件的脚本，脚本运行时候接收3个参数，分别是&lt;/p>
&lt;ul>
&lt;li>用例编号&lt;/li>
&lt;li>用例名称&lt;/li>
&lt;li>断言&lt;/li>
&lt;/ul>
&lt;p>这里我们忽略写入测试步骤，这&lt;strong>并不表示编写用例时可以忽略测试步骤&lt;/strong>&lt;/p>
&lt;h3 id="代码实现">代码实现&lt;/h3>
&lt;p>新建名为&lt;code>write_case.py&lt;/code>，内容如下&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">sys&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">argv&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">script&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">case_number&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">case_name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">assertion&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">argv&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">file_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;case002.txt&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;用例编号: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">case_number&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;用例名称: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">case_name&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;断言: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">assertion&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">target&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file_name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;w&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Truncating the file. Goodbye!&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;write file: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">file_name&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">target&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;用例编号: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">case_number&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">target&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">target&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;用例名称: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">case_name&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">target&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">target&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;断言: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">assertion&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">target&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">target&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">close&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行">运行&lt;/h3>
&lt;p>在命令行中使用下面的命令去执行代码&lt;/p>
&lt;pre tabindex="0">&lt;code>$ python write_case.py 002 Get接口测试 接口返回的状态码必须是200
&lt;/code>&lt;/pre>&lt;h3 id="你应该可以看到">你应该可以看到&lt;/h3>
&lt;p>按照下面展示的情况进行输入，如果没有出错的话，你应该可以看到命令行窗口显示如下的内容&lt;/p>
&lt;pre tabindex="0">&lt;code>用例编号: 002
用例名称: Get接口测试
断言: 接口返回的状态码必须是200
Truncating the file. Goodbye!
write file: case002.txt
&lt;/code>&lt;/pre>&lt;p>这时候当前文件夹会出现case002.txt文件，内容应该如下所示&lt;/p>
&lt;pre tabindex="0">&lt;code>用例编号: 002
用例名称: Get接口测试
断言: 接口返回的状态码必须是200
&lt;/code>&lt;/pre>&lt;h3 id="关于文件操作">关于文件操作&lt;/h3>
&lt;p>关于文件的操作，请试着自己写代码去调用下面的方法，实践出真知。&lt;/p></description></item><item><title>（十）获取断言信息</title><link>https://itest2025.pages.dev/tutorials/19-010-%E5%8D%81%E8%8E%B7%E5%8F%96%E6%96%AD%E8%A8%80%E4%BF%A1%E6%81%AF/</link><pubDate>Fri, 30 Jun 2017 07:37:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/19-010-%E5%8D%81%E8%8E%B7%E5%8F%96%E6%96%AD%E8%A8%80%E4%BF%A1%E6%81%AF/</guid><description>&lt;br>
不管是在做功能测试还是自动化测试，最后一步需要拿实际结果与预期进行比较。这个比较的称之为__断言__。
&lt;p>我们通常可以通过获取title 、URL和text等信息进行断言。text方法在前面已经讲过，它用于获取标签对之间的文本信息。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>getTitle()： 用于获得当前页面的title。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>getCurrentUrl() ： 用户获得当前页面的URL。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>getText() 获取页面文本信息。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>下面同样以百度为例，介绍如何获取这些信息。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.By&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.Keys&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.WebDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.WebElement&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.chrome.ChromeDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">AssertDemo&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">throws&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">InterruptedException&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ChromeDriver&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;https://www.baidu.com&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Search before================&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//获取当前的 title 和 url&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">printf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;title of current page is %s\n&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">getTitle&lt;/span>&lt;span class="p">());&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">printf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;url of current page is %s\n&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">getCurrentUrl&lt;/span>&lt;span class="p">());&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//百度搜索&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebElement&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">search&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;kw&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">search&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Selenium&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">search&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Keys&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">ENTER&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2000&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Search after================&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//获取当前的 title 和 url&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">printf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;title of current page is %s\n&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">getTitle&lt;/span>&lt;span class="p">());&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">printf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;url of current page is %s\n&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">getCurrentUrl&lt;/span>&lt;span class="p">());&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//获取第一条搜索结果的标题&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebElement&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">xpath&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;//div[@id=&amp;#39;content_left&amp;#39;]/div/h3/a&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">getText&lt;/span>&lt;span class="p">());&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">quit&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>打印结果：&lt;/p></description></item><item><title>（十）定位一组元素</title><link>https://itest2025.pages.dev/tutorials/24-010-%E5%8D%81%E5%AE%9A%E4%BD%8D%E4%B8%80%E7%BB%84%E5%85%83%E7%B4%A0/</link><pubDate>Wed, 21 Jun 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/24-010-%E5%8D%81%E5%AE%9A%E4%BD%8D%E4%B8%80%E7%BB%84%E5%85%83%E7%B4%A0/</guid><description>&lt;br>
WebDriver还提供了8种用于定位一组元素的方法。
```python
find_elements_by_id()
find_elements_by_name()
find_elements_by_class_name()
find_elements_by_tag_name()
find_elements_by_link_text()
find_elements_by_partial_link_text()
find_elements_by_xpath()
find_elements_by_css_selector()
```
定位一组元素的方法与定位单个元素的方法类似，唯一的区别是在单词element后面多了一个s表示复数。
&lt;p>接下来通过例子演示定位一组元素的使用：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">webdriver&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">time&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">sleep&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">webdriver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Chrome&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;https://www.baidu.com&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_element_by_id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;kw&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">send_keys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;selenium&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_element_by_id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;su&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">click&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 定位一组元素&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">texts&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_elements_by_xpath&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;//div/h3/a&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 循环遍历出每一条搜索结果的标题&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">t&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">texts&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">t&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">quit&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>程序运行结果：&lt;/p>
&lt;pre tabindex="0">&lt;code>Selenium - Web Browser Automation
官网
功能自动化测试工具——Selenium篇
selenium + python自动化测试环境搭建 - 虫师 - 博客园
selenium是什么?_百度知道
怎样开始用selenium进行自动化测试(个人总结)_百度经验
Selenium_百度百科
selenium_百度翻译
Selenium官网教程_selenium自动化测试实践_Selenium_领测软件测试网
Selenium(浏览器自动化测试框架)_百度百科
自动化基础普及之selenium是啥? - 虫师 - 博客园
python十大主流开源框架 「菜鸟必看」
&lt;/code>&lt;/pre>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1523712999610-f77fbcfc3843?w=300"
 data-srcset="https://images.unsplash.com/photo-1523712999610-f77fbcfc3843?w=300, https://images.unsplash.com/photo-1523712999610-f77fbcfc3843?w=300 1.5x, https://images.unsplash.com/photo-1523712999610-f77fbcfc3843?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1523712999610-f77fbcfc3843?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（十一）Docker Compose创建Wordpress应用</title><link>https://itest2025.pages.dev/tutorials/30-011-%E5%8D%81%E4%B8%80docker-compose%E5%88%9B%E5%BB%BAwordpress%E5%BA%94%E7%94%A8/</link><pubDate>Mon, 22 Jan 2018 14:22:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/30-011-%E5%8D%81%E4%B8%80docker-compose%E5%88%9B%E5%BB%BAwordpress%E5%BA%94%E7%94%A8/</guid><description>&lt;p>wordpress是最常见博客系统，一般部署需要LAMP/WAMP环境，这介绍通过Docker compose对它进行编排和部署。&lt;/p>
&lt;p>Docker Hub地址: &lt;a href="https://hub.docker.com/_/wordpress/" target="_blank" rel="noopener noreffer ">https://hub.docker.com/_/wordpress/&lt;/a>&lt;/p>
&lt;h4 id="wordpress-应用部署">wordpress 应用部署&lt;/h4>
&lt;hr>
&lt;h5 id="1-建立一个应用的目录">1、 建立一个应用的目录&lt;/h5>
&lt;pre tabindex="0">&lt;code>$ mkdir wordpress
$ cd wordpress
&lt;/code>&lt;/pre>&lt;h5 id="2创建-docker-composeyml">2、创建 docker-compose.yml&lt;/h5>
&lt;pre tabindex="0">&lt;code>version: &amp;#39;3.1&amp;#39;

services:

 wordpress:
 image: wordpress
 restart: always
 ports:
 - 8081:80
 environment:
 WORDPRESS_DB_PASSWORD: pw123

 mysql:
 image: mysql:5.7
 restart: always
 environment:
 MYSQL_ROOT_PASSWORD: pw123
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>images 镜像名&lt;/li>
&lt;li>restart 指定版本&lt;/li>
&lt;li>ports &lt;code>80&lt;/code>为镜像端口， 映射的&lt;code>8081&lt;/code>为主机端口。&lt;/li>
&lt;li>environment 环境配置，例，&lt;code>WORDPRESS_DB_PASSWORD&lt;/code> 为wordpress数据库密码。&lt;/li>
&lt;/ul>
&lt;h5 id="3启动应用">3、启动应用&lt;/h5>
&lt;p>&lt;code>docker-compose&lt;/code>执行编排脚本，分别制作和抓取web，redis镜像，启动容器。&lt;/p>
&lt;pre tabindex="0">&lt;code>$ sudo docker-compose up

……

Creating wordpress_mysql_1 ... done
Creating wordpress_wordpress_1 ... done
&lt;/code>&lt;/pre>&lt;p>整个过程会比较漫长。。。&lt;/p>
&lt;h5 id="5访问应用">5、访问应用&lt;/h5>
&lt;p>打开浏览器方位: http://0.0.0.0:5081/&lt;/p>
&lt;p>进入wordpress安装配置界面：&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/docker_wordpress.png"
 data-srcset="http://img.testclass.net/docker_wordpress.png, http://img.testclass.net/docker_wordpress.png 1.5x, http://img.testclass.net/docker_wordpress.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/docker_wordpress.png"
 title="http://img.testclass.net/docker_wordpress.png" />&lt;/p></description></item><item><title>（十一）TestNG 其他使用技巧</title><link>https://itest2025.pages.dev/tutorials/36-011-%E5%8D%81%E4%B8%80testng-%E5%85%B6%E4%BB%96%E4%BD%BF%E7%94%A8%E6%8A%80%E5%B7%A7/</link><pubDate>Sat, 25 Nov 2017 12:10:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/36-011-%E5%8D%81%E4%B8%80testng-%E5%85%B6%E4%BB%96%E4%BD%BF%E7%94%A8%E6%8A%80%E5%B7%A7/</guid><description>&lt;p>除了前面介绍的功能外，TestNG 还有一些使用技巧，相对比较简单，这里通过一个例子来演示。&lt;/p>
&lt;h4 id="其它使用技巧">其它使用技巧&lt;/h4>
&lt;hr>
&lt;pre tabindex="0">&lt;code>import org.testng.annotations.Test;
import static org.testng.AssertJUnit.assertEquals;


public class OtherTest {

 // 该条用例跳过执行
 @Test(enabled = false)
 public void testCase1(){
 assertEquals(2+2, 4);
 }

 // 设定用例超时时间
 @Test(timeOut = 3000)
 public void testCase2() throws InterruptedException {
 Thread.sleep(3001);
 }

 // 预设用例抛出的异常类型
 @Test(expectedExceptions = RuntimeException.class)
 public void testCase3(){
 assertEquals(2/0,1);
 }

}
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>
&lt;p>enabled 设置用例是否跳过执行，默认为：&lt;strong>true&lt;/strong> ，表示不跳过。&lt;strong>false&lt;/strong> 表示跳过执行。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>timeOut 设置用例运行的超时间，3000 单位为毫秒，当用例运行时间超过 3000 毫秒则判定为失败。不管用例本身是否运行失败。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>expectedExceptions 用来预设用例运行会出现的异常。例如 2/0 将会抛出 RuntimeException 类型的异常，如果出现异常则表示用例执行成功。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1515965885361-f1e0095517ea?w=300"
 data-srcset="https://images.unsplash.com/photo-1515965885361-f1e0095517ea?w=300, https://images.unsplash.com/photo-1515965885361-f1e0095517ea?w=300 1.5x, https://images.unsplash.com/photo-1515965885361-f1e0095517ea?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1515965885361-f1e0095517ea?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>requests如何解析json响应?</title><link>https://itest2025.pages.dev/tutorials/42-011-requests%E5%A6%82%E4%BD%95%E8%A7%A3%E6%9E%90json%E5%93%8D%E5%BA%94/</link><pubDate>Wed, 22 Nov 2017 03:23:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/42-011-requests%E5%A6%82%E4%BD%95%E8%A7%A3%E6%9E%90json%E5%93%8D%E5%BA%94/</guid><description>&lt;p>&lt;a href="http://docs.python-requests.org/en/master/user/quickstart/#json-response-content" target="_blank" rel="noopener noreffer ">官方文档&lt;/a>&lt;/p>
&lt;p>如果服务器返回json格式的数据，那么我们一般希望可以把json字符串转成python的dict数据类型。&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; import requests

&amp;gt;&amp;gt;&amp;gt; r = requests.get(&amp;#39;https://api.github.com/events&amp;#39;)
&amp;gt;&amp;gt;&amp;gt; r.json()
[{u&amp;#39;repository&amp;#39;: {u&amp;#39;open_issues&amp;#39;: 0, u&amp;#39;url&amp;#39;: &amp;#39;https://github.com/...
&lt;/code>&lt;/pre>&lt;p>如果JSON解析失败，r.json()会抛异常。比如假设响应的返回状态码是204(No Content)，又或者响应的返回json字符串格式有错误，那么r.json()回抛出&lt;code>ValueError: No JSON object could be decoded.&lt;/code>异常。&lt;/p>
&lt;p>需要引起注意的是r.json()解析成功了并不代表请求是成功的。很多服务器在响应失败的时候也会返回json字符串，如果要判断响应的状态的话，建议使用&lt;code>r.raise_for_status()&lt;/code> 或者使用&lt;code>check r.status_code&lt;/code>来判断返回值是否符合预期。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1497215641119-bbe6d71ebaae?w=300"
 data-srcset="https://images.unsplash.com/photo-1497215641119-bbe6d71ebaae?w=300, https://images.unsplash.com/photo-1497215641119-bbe6d71ebaae?w=300 1.5x, https://images.unsplash.com/photo-1497215641119-bbe6d71ebaae?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1497215641119-bbe6d71ebaae?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（十一）JUnit5 新的用法</title><link>https://itest2025.pages.dev/tutorials/31-011-%E5%8D%81%E4%B8%80junit5-%E6%96%B0%E7%9A%84%E7%94%A8%E6%B3%95/</link><pubDate>Mon, 13 Nov 2017 12:20:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/31-011-%E5%8D%81%E4%B8%80junit5-%E6%96%B0%E7%9A%84%E7%94%A8%E6%B3%95/</guid><description>&lt;h4 id="junit5-新的用法">Junit5 新的用法&lt;/h4>
&lt;hr>
&lt;p>创建 JUnit5NewTests 测试类。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.jupiter.api.Assertions.assertEquals&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.jupiter.api.Assertions.assertTrue&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.jupiter.api.Assertions.assertAll&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.jupiter.api.*&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">JUnit5NewTests&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@BeforeEach&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@DisplayName&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;每条用例开始时执行&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">start&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@AfterEach&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@DisplayName&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;每条用例结束时执行&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">end&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">myFirstTest&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@DisplayName&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;描述测试用例╯°□°）╯&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">testWithDisplayName&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Disabled&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;这条用例暂时跑不过，忽略!&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">myFailTest&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@DisplayName&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;运行一组断言&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">assertAllCase&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">assertAll&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;groupAssert&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">assertTrue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">0&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@DisplayName&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;依赖注入1&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">testInfo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">final&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">TestInfo&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">testInfo&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">testInfo&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">getDisplayName&lt;/span>&lt;span class="p">());&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@DisplayName&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;依赖注入2&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">testReporter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">final&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">TestReporter&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">testReporter&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">testReporter&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">publishEntry&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;Alex&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>用法都已经通过测试用例的 &lt;strong>@DisplayName&lt;/strong> 进行了说明，这里不再解释。&lt;/p></description></item><item><title>11.生成xml格式的测试报告</title><link>https://itest2025.pages.dev/tutorials/25-011-11%E7%94%9F%E6%88%90xml%E6%A0%BC%E5%BC%8F%E7%9A%84%E6%B5%8B%E8%AF%95%E6%8A%A5%E5%91%8A/</link><pubDate>Wed, 25 Oct 2017 07:22:42 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/25-011-11%E7%94%9F%E6%88%90xml%E6%A0%BC%E5%BC%8F%E7%9A%84%E6%B5%8B%E8%AF%95%E6%8A%A5%E5%91%8A/</guid><description>&lt;p>pytest有非常友好的命令行报告输出，在做用例开发的时候，这是极好的。然而我们在运行用例后经常会需要将测试结果广而告之，发送给相关责任人浏览，所以生成简洁美观的测试报告是很有必要的。&lt;/p>
&lt;h3 id="生成junit格式的xml报告">生成junit格式的xml报告&lt;/h3>
&lt;p>pytest可以生成junit格式的xml报告，在命令行中加入&lt;code>--junit-xml=path&lt;/code> 参数就可以了。&lt;/p>
&lt;pre tabindex="0">&lt;code>pytest test_quick_start.py --junit-xml=report.xml
&lt;/code>&lt;/pre>&lt;p>上面的命令在当前文件夹中生成了名为report.xml的测试报告&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;utf-8&amp;#34;?&amp;gt;&amp;lt;testsuite errors=&amp;#34;0&amp;#34; failures=&amp;#34;0&amp;#34; name=&amp;#34;pytest&amp;#34; skips=&amp;#34;0&amp;#34; tests=&amp;#34;1&amp;#34; time=&amp;#34;0.009&amp;#34;&amp;gt;&amp;lt;testcase classname=&amp;#34;test_quick_start&amp;#34; file=&amp;#34;test_quick_start.py&amp;#34; line=&amp;#34;3&amp;#34; name=&amp;#34;test_reverse&amp;#34; time=&amp;#34;0.000499725341797&amp;#34;&amp;gt;&amp;lt;/testcase&amp;gt;&amp;lt;/testsuite&amp;gt;%
&lt;/code>&lt;/pre>&lt;h3 id="ci集成">ci集成&lt;/h3>
&lt;p>jenkins在build后可以通过插件展示junit格式的测试报告，具体步骤就不描述了。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1426604966848-d7adac402bff?w=300"
 data-srcset="https://images.unsplash.com/photo-1426604966848-d7adac402bff?w=300, https://images.unsplash.com/photo-1426604966848-d7adac402bff?w=300 1.5x, https://images.unsplash.com/photo-1426604966848-d7adac402bff?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1426604966848-d7adac402bff?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>11. 常见各类文件类型图标（新用户必看）</title><link>https://itest2025.pages.dev/tutorials/37-011-11-%E5%B8%B8%E8%A7%81%E5%90%84%E7%B1%BB%E6%96%87%E4%BB%B6%E7%B1%BB%E5%9E%8B%E5%9B%BE%E6%A0%87%E6%96%B0%E7%94%A8%E6%88%B7%E5%BF%85%E7%9C%8B/</link><pubDate>Mon, 16 Oct 2017 02:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/37-011-11-%E5%B8%B8%E8%A7%81%E5%90%84%E7%B1%BB%E6%96%87%E4%BB%B6%E7%B1%BB%E5%9E%8B%E5%9B%BE%E6%A0%87%E6%96%B0%E7%94%A8%E6%88%B7%E5%BF%85%E7%9C%8B/</guid><description>&lt;h1 id="常见文件类型的图标介绍">常见文件类型的图标介绍&lt;/h1>
&lt;h2 id="java-类相关图标介绍">Java 类相关图标介绍&lt;/h2>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/xi-a-file-symbols-1.jpg"
 data-srcset="http://img.testclass.net/xi-a-file-symbols-1.jpg, http://img.testclass.net/xi-a-file-symbols-1.jpg 1.5x, http://img.testclass.net/xi-a-file-symbols-1.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/xi-a-file-symbols-1.jpg"
 title="Java 类相关图标介绍" />&lt;/p>
&lt;blockquote>
&lt;ul>
&lt;li>官网地址：&lt;a href="http://www.jetbrains.com/idea/webhelp/symbols.html" target="_blank" rel="noopener noreffer ">http://www.jetbrains.com/idea/webhelp/symbols.html&lt;/a>&lt;/li>
&lt;li>对于各个图标，上图的 &lt;code>Description&lt;/code> 写得非常详细，但是有几个还是需要进行特别的说明下。&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;ul>
&lt;li>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/xi-a-file-symbols-2.gif"
 data-srcset="http://img.testclass.net/xi-a-file-symbols-2.gif, http://img.testclass.net/xi-a-file-symbols-2.gif 1.5x, http://img.testclass.net/xi-a-file-symbols-2.gif 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/xi-a-file-symbols-2.gif"
 title="http://img.testclass.net/xi-a-file-symbols-2.gif" /> &lt;code>Source root&lt;/code>，你可以理解为源目录，源码的作用就是用来专门放 Java 类文件，相对于编译出来的 class 文件而言，它就是源。我们一般默认名字叫 &lt;code>src&lt;/code> 的目录就是源目录，但是其实并不是这样的，在 IntelliJ IDEA 中，即使叫 &lt;code>srcs&lt;/code> 也是可以设置为 &lt;code>Source root&lt;/code>，所以源目录跟目录命名是没有关系的，而是在于 IntelliJ IDEA 支持对任意目录进行设置为 &lt;code>Source root&lt;/code>，具体设置在会后面章节进行详解。 &lt;code>Source root&lt;/code> 的作用是标记该目录下的文件是可编译的。&lt;/li>
&lt;li>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/xi-a-file-symbols-3.png"
 data-srcset="http://img.testclass.net/xi-a-file-symbols-3.png, http://img.testclass.net/xi-a-file-symbols-3.png 1.5x, http://img.testclass.net/xi-a-file-symbols-3.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/xi-a-file-symbols-3.png"
 title="http://img.testclass.net/xi-a-file-symbols-3.png" /> &lt;code>Java class located out of the source root&lt;/code>，由于上一条我们知道 &lt;code>Source root&lt;/code> 目录是用来告诉 IntelliJ IDEA 这是编译目录，而假如你 Java 类文件没有放在该目录或是该目录的子包下，那该 Java 类则无法编译，就会被表示成这个图标。&lt;/li>
&lt;/ul>&lt;/blockquote>&lt;/blockquote>
&lt;h2 id="各类文件类型图标介绍">各类文件类型图标介绍&lt;/h2>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/xi-b-file-symbols-1.jpg"
 data-srcset="http://img.testclass.net/xi-b-file-symbols-1.jpg, http://img.testclass.net/xi-b-file-symbols-1.jpg 1.5x, http://img.testclass.net/xi-b-file-symbols-1.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/xi-b-file-symbols-1.jpg"
 title="各类文件类型图标介绍" />&lt;/p></description></item><item><title>appium新手入门（11）—— appium API 之键盘操作</title><link>https://itest2025.pages.dev/tutorials/21-011-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A811-appium-api-%E4%B9%8B%E9%94%AE%E7%9B%98%E6%93%8D%E4%BD%9C/</link><pubDate>Thu, 07 Sep 2017 10:20:12 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/21-011-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A811-appium-api-%E4%B9%8B%E9%94%AE%E7%9B%98%E6%93%8D%E4%BD%9C/</guid><description>&lt;p>模拟键盘输入也是非常重要的操作。这一小节来介绍那些关于键盘的操作。&lt;/p>
&lt;h4 id="1sendkeys方法">1、sendKeys()方法&lt;/h4>
&lt;hr>
&lt;p>方法：&lt;/p>
&lt;ul>
&lt;li>sendKeys()&lt;/li>
&lt;/ul>
&lt;p>用法：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElements&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Name&amp;#34;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;jack&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="2presskeycode方法">2、pressKeyCode()方法&lt;/h3>
&lt;hr>
&lt;p>除此之外，appium扩展提供了pressKeyCode()方法。该方法Android特有。&lt;/p>
&lt;p>方法：&lt;/p>
&lt;ul>
&lt;li>pressKeyCode()&lt;/li>
&lt;/ul>
&lt;p>发送一个键码的操作。需要一个入参。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">pressKeyCode&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">29&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// 字母“a”&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果想点击Android的HOME键应该怎么实现的呢？如下&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">pressKeyCode&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">AndroidKeyCode&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">HOME&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;font color="blue">&lt;strong>下面提供Android keycode参考表：&lt;/strong>&lt;/font>&lt;/p>
&lt;p>&lt;strong>电话键&lt;/strong>&lt;/p>
&lt;p>KEYCODE_CALL 拨号键 5&lt;/p>
&lt;p>KEYCODE_ENDCALL 挂机键 6&lt;/p>
&lt;p>KEYCODE_HOME 按键Home 3&lt;/p>
&lt;p>KEYCODE_MENU 菜单键 82&lt;/p>
&lt;p>KEYCODE_BACK 返回键 4&lt;/p>
&lt;p>KEYCODE_SEARCH 搜索键 84&lt;/p>
&lt;p>KEYCODE_CAMERA 拍照键 27&lt;/p>
&lt;p>KEYCODE_FOCUS 拍照对焦键 80&lt;/p>
&lt;p>KEYCODE_POWER 电源键 26&lt;/p>
&lt;p>KEYCODE_NOTIFICATION 通知键 83&lt;/p>
&lt;p>KEYCODE_MUTE 话筒静音键 91&lt;/p>
&lt;p>KEYCODE_VOLUME_MUTE 扬声器静音键 164&lt;/p>
&lt;p>KEYCODE_VOLUME_UP 音量增加键 24&lt;/p>
&lt;p>KEYCODE_VOLUME_DOWN 音量减小键 25&lt;/p>
&lt;p>&lt;strong>控制键&lt;/strong>&lt;/p>
&lt;p>KEYCODE_ENTER 回车键 66&lt;/p>
&lt;p>KEYCODE_ESCAPE ESC键 111&lt;/p>
&lt;p>KEYCODE_DPAD_CENTER 导航键 确定键 23&lt;/p>
&lt;p>KEYCODE_DPAD_UP 导航键 向上 19&lt;/p></description></item><item><title>JMeter官方文档：11. 新建一个 JMS 主题的测试计划</title><link>https://itest2025.pages.dev/tutorials/22-011-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A311-%E6%96%B0%E5%BB%BA%E4%B8%80%E4%B8%AA-jms-%E4%B8%BB%E9%A2%98%E7%9A%84%E6%B5%8B%E8%AF%95%E8%AE%A1%E5%88%92/</link><pubDate>Thu, 24 Aug 2017 08:55:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/22-011-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A311-%E6%96%B0%E5%BB%BA%E4%B8%80%E4%B8%AA-jms-%E4%B8%BB%E9%A2%98%E7%9A%84%E6%B5%8B%E8%AF%95%E8%AE%A1%E5%88%92/</guid><description>&lt;p>&lt;a href="https://itest2025.pages.dev/2017/08/24/jmeter-translation-plans/" rel="">《JMeter官方文档&amp;ndash;翻译计划》&lt;/a> &lt;a href="http://jmeter.apache.org/usermanual/build-jms-topic-test-plan.html" target="_blank" rel="noopener noreffer ">原文地址&lt;/a>&lt;/p>
&lt;h2 id="11新建一个-jms-主题的测试计划">11.新建一个 JMS 主题的测试计划&lt;/h2>
&lt;hr>
&lt;blockquote>
&lt;p>JMS 需要下载一些可选的jar 文件。详细信息请参阅 第一章：新手入门。&lt;/p>&lt;/blockquote>
&lt;p>在本章节，将学习如何创建&lt;a href="http://jmeter.apache.org/usermanual/build-test-plan.html" target="_blank" rel="noopener noreffer ">测试计划&lt;/a>来测试JMS提供程序。创建5个订阅者和1个发布者。创建2个线程组并且设置每个线程组迭代10次。消息总数是（6个线程）x （1 个消息）x（重复10次）= 60 个消息。为了构建测试计划将使用以下元素：&lt;a href="http://jmeter.apache.org/usermanual/test_plan.html#thread_group" target="_blank" rel="noopener noreffer ">线程组&lt;/a> , &lt;a href="http://jmeter.apache.org/usermanual/component_reference.html#JMS_Publisher" target="_blank" rel="noopener noreffer ">JMS 发布者&lt;/a>， &lt;a href="http://jmeter.apache.org/usermanual/component_reference.html#JMS_Publisher" target="_blank" rel="noopener noreffer ">JMS 订阅者&lt;/a>， 和 &lt;a href="http://jmeter.apache.org/usermanual/component_reference.html#Graph_Results" target="_blank" rel="noopener noreffer ">图结果&lt;/a>。&lt;/p>
&lt;p>关于JMS的一般注意事项：目前有两种 JMS 采样器(samplers)。一种使用 JMS 主题(topics)，另一种使用队列(queues)。主题消息通常被称为发布/订阅消息。主题消息传递通常用于消息由生产者发布并由多个订阅者消费的情况。队列消息传递通常用于发件人期望响应的事务。消息系统与普通的HTTP请求完全不同。在HTTP中，一个用户发送一个请求并得到一个响应。消息系统可以通过同步和异步模式工作。JMS采样器需要JMS实现的jar文件（由于JMeter不提供JMS实现的jar，需要下载后放置lib库）; 例如，来自Apache ActiveMQ。请参阅&lt;a href="http://jmeter.apache.org/usermanual/get-started.html#libraries_activemq" target="_blank" rel="noopener noreffer ">这里&lt;/a> 查看 ActiveMQ 提供的 jar 列表。&lt;/p>
&lt;h3 id="111添加用户">11.1添加用户&lt;/h3>
&lt;hr>
&lt;p>第一步是添加一个&lt;a href="http://jmeter.apache.org/usermanual/test_plan.html#thread_group" target="_blank" rel="noopener noreffer ">线程组&lt;/a>元素。线程组告诉JMeter想要模拟的用户数量，发送请求的频率以及发送请求的数量。&lt;/p>
&lt;p>添加线程组元素，首先选择测试计划，单击鼠标右键获取添加菜单，然后选择 &lt;strong>添加 → 线程组&lt;/strong>。此时可以在测试计划下面看到线程组元素，如果不能，可以通过在测试计划元素上单击“展开”测试计划树。&lt;/p>
&lt;p>接下来，你需要修改默认属性。如果尚未选择树中的线程组元素，请先选择。此时可以看到JMeter窗口右侧的线程组控制面板（请参见下面的图11.1）&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/thread_group.png"
 data-srcset="http://img.testclass.net/thread_group.png, http://img.testclass.net/thread_group.png 1.5x, http://img.testclass.net/thread_group.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/thread_group.png"
 title="http://img.testclass.net/thread_group.png" />
图11.1. 线程组默认设置&lt;/p>
&lt;p>首先为我们的线程组提供一个更具描述性的名称。在名称字段输入: &lt;strong>Subscribers&lt;/strong> 。&lt;/p>
&lt;p>接下来，将用户（称为线程）的数量增加到 &lt;strong>5&lt;/strong>。&lt;/p>
&lt;p>在下一个字段 Ramp-Up Period 中，将该值设置为 &lt;strong>0&lt;/strong> 秒。这个属性告诉JMeter启动每个用户之间要延迟多久。例如，如果输入一个5秒的渐变周期，JMeter将在5秒钟内完成所有用户的启动。所以，如果我们有5个用户和一个5秒钟的Ramp-Up Period值，那么用户启动之间的延迟将是1秒（5个用户/ 5秒= 1个用户每秒）。如果将该值设置为0，则JMeter将立即启动所有用户。&lt;/p></description></item><item><title>性能测试流程（六）——测试环境搭建</title><link>https://itest2025.pages.dev/tutorials/14-011-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E6%B5%81%E7%A8%8B%E5%85%AD%E6%B5%8B%E8%AF%95%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/</link><pubDate>Fri, 11 Aug 2017 03:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/14-011-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E6%B5%81%E7%A8%8B%E5%85%AD%E6%B5%8B%E8%AF%95%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/</guid><description>&lt;br>
#### 性能测试环境与功能测试环境的区别
那么性能测试环境与功能测试环境有所不同，对于一些企业为了节约资源，进行功能测试的测试环境，一台服务器可以运行多个系统，通过技术手段可以使系统之间是不会相互影响的（以前公司就是一台服务器上跑多个tomcat）。
性能测试是要对整个系统运行的软件硬件环境进行测试的，如果某环境下运行多个系统，就很难判断其中的某个环境对资源的占用情况。
&lt;br>
#### 保证测试环境与生产环境的一致性 
&lt;p>&lt;strong>1、硬件环境，包括服务器环境、与网络环境&lt;/strong>&lt;/p>
&lt;p>如服务器的型号以及是否和其它应用程序共享此服务器，是否在集群环境下，是否通过BIGIP进行负载均衡，客户使用的硬件配置情况，使用的交换机型号，网络传输速率。&lt;/p>
&lt;p>&lt;strong>2、软件环境&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>版本一致性&lt;/li>
&lt;/ul>
&lt;p>包括包括操作系统、数据库、中间件的版本，被测系统的版本。&lt;/p>
&lt;ul>
&lt;li>配置一致性&lt;/li>
&lt;/ul>
&lt;p>系统（操作系统/数据库/中间件/被测试系统）参数的配置一致，这些系统参数的配置有可能对系统造成巨大的影响。所以，除了保证测试环境与真实环境所使用的软件版本一致，也要关注其参数的配置是否一致。&lt;/p>
&lt;p>&lt;strong>3、使用场景的一致性&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>基础数据的一致性&lt;/li>
&lt;/ul>
&lt;p>包括预测的业务数据量，以及数据类型的分配。很简单的一个列子，一个系统的数据库只有10条数据和一条数据库里几千万条数据，我们在对其进行性能测试时，得到的性能指标可能会有非常大的差别。&lt;/p>
&lt;p>为了保证每次测试环境的更加一致性，磁盘的使用情况以及磁盘的碎片情况也会或多或少的影响的性能。&lt;/p>
&lt;ul>
&lt;li>使用模式的一致性&lt;/li>
&lt;/ul>
&lt;p>尽量模拟真实场景下用户的使用情况，其实，我们在做性能测试前期的需求分析，其主要目的也就是为了更真实的模拟用户的使用情况。&lt;/p>
&lt;br>
#### 实施策略
&lt;p>上面讲测试环境与生产环境保持一致所需要注意的内容。在实际的测试中，处于成本考虑，在很多情况下，我们很难申请到足够的且一致的资源，所以，很难搭建出与生产环境完全一致的一个测试环境。&lt;/p>
&lt;p>我们一般通过两种策略来搭建性能测试环境（预估方式均有误差）&lt;/p>
&lt;p>&lt;strong>1、通过建模的方式实现低端硬件对高端硬件的模拟&lt;/strong>&lt;/p>
&lt;p>通过配置测试来计算不同配置下的硬件性能和系统处理能力的关系，从而推导出满足系统性能的真实配置情况，这种模拟需要精确的建模，模型的采样点越多，那么得到的结果越精确，从而将在低端配置下的性能指标通过该模型转化为高端配置下的最终预计性能指标。&lt;/p>
&lt;p>例如：搭建一个低端环境，首先需要对这个环境的CPU和内存进行单独的性能基准测试，同过在不同的配置的性能测试，得到一个基准信息列表，当然，在进行这个性能测试的过程中，我们要确定硬件是系统的瓶颈。如果只用一个CUP，在性能测试过程中，其使用率很低，但得到的性能数据都非常底，这起码说明CUP不是系统的瓶颈，这种情况下就无法得到想要的基准值。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/cpu_expand.png"
 data-srcset="http://img.testclass.net/cpu_expand.png, http://img.testclass.net/cpu_expand.png 1.5x, http://img.testclass.net/cpu_expand.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/cpu_expand.png"
 title="http://img.testclass.net/cpu_expand.png" />&lt;/p>
&lt;p>如上图，在一颗CPU情况下，运行100个用户且CUP使用率接近饱和（100%）。在增加至两颗CUP的情况下，可以运行190个用户且UPU使用率接近饱和（100%），以此做记录，那么我们就可以推算出运行800个用户需要多少颗CUP。
如果你在实际应用中使用的CUP型号及其频率并非完全一样，这个时候可以使用EVEREST工具计算每种CUP的得分，对其性能进行评估。
内存也可以使用此方法进行测试推导，这里需要我们多进行试验，对硬件的性能以及对整个项目的结构都要做深入的了解，以便尽量减少误差。&lt;/p>
&lt;p>&lt;strong>2、通过集群的方式计算&lt;/strong>&lt;/p>
&lt;p>对于较大的系统来说，单台服务器的处理能力是有限的，通常都会采用集群的方式来进行负载均衡，完成对海量请求的处理。虽然无法获得整体集群的测试环境，但是可以对集群上的一个节点进行性能测试，得出该节点的处理能力，再计算每增加一个节点的性能损失，同样也可以能过建模的方式得到大型负载均衡情况下的预计性能指标。&lt;/p>
&lt;p>例如:首先在单台服务器上获得具体的性能指标，每台服务器能够承受500用户并发，平均TPS为60，响应时间为2秒，接着，添加负载均衡策略，再次测试负载策略下的数据损耗。得出数据后添加1台负载均衡服务器，测试在两台服务器下每台服务器的性能指标，以此类推，可以得到下表：&lt;/p>
&lt;p>表：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>负载服务器个数&lt;/th>
 &lt;th style="text-align: center">并发用户数&lt;/th>
 &lt;th style="text-align: center">平均TPS&lt;/th>
 &lt;th style="text-align: center">响应时间&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>1&lt;/td>
 &lt;td style="text-align: center">500&lt;/td>
 &lt;td style="text-align: center">60&lt;/td>
 &lt;td style="text-align: center">2&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>1&lt;/td>
 &lt;td style="text-align: center">490&lt;/td>
 &lt;td style="text-align: center">58&lt;/td>
 &lt;td style="text-align: center">2&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>2&lt;/td>
 &lt;td style="text-align: center">490&lt;/td>
 &lt;td style="text-align: center">58&lt;/td>
 &lt;td style="text-align: center">2&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>3&lt;/td>
 &lt;td style="text-align: center">480&lt;/td>
 &lt;td style="text-align: center">57&lt;/td>
 &lt;td style="text-align: center">2&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>随着负载均衡服务器的添加，平均每台服务器的处理能力会逐渐稳定，从而了解在什么情况下需要多少台负载均衡服务器。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1433357977371-7960aa14e614?w=300"
 data-srcset="https://images.unsplash.com/photo-1433357977371-7960aa14e614?w=300, https://images.unsplash.com/photo-1433357977371-7960aa14e614?w=300 1.5x, https://images.unsplash.com/photo-1433357977371-7960aa14e614?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1433357977371-7960aa14e614?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（十一）ActionSequence</title><link>https://itest2025.pages.dev/tutorials/20-011-%E5%8D%81%E4%B8%80actionsequence/</link><pubDate>Thu, 03 Aug 2017 02:49:18 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/20-011-%E5%8D%81%E4%B8%80actionsequence/</guid><description>&lt;h3 id="组合事件">组合事件&lt;/h3>
&lt;p>当页面的交互比较复杂的时候，我们可能会使用到组合事件。比如先把鼠标移动到某个元素上，然后按住鼠标，将该元素拖到另一个地方。为了完成这种操作，我们就需要使用组合事件&lt;a href="http://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_ActionSequence.html" target="_blank" rel="noopener noreffer ">ActionSequence&lt;/a>&lt;/p>
&lt;p>组合事件中，我们可以组合鼠标和键盘的操作，这些操作将根据我们组合的顺序依次执行。&lt;/p>
&lt;h3 id="基本用法">基本用法&lt;/h3>
&lt;ul>
&lt;li>直接使用&lt;code>WebDriver.actions()&lt;/code>进行调用，不需要额外的初始化工作;&lt;/li>
&lt;li>只有显示调用了&lt;code>perform()&lt;/code>方法才让所有动作真正得到执行；简而言之，一定要调用&lt;code>perform()&lt;/code>;&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="nx">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">actions&lt;/span>&lt;span class="p">().&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">keyDown&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">Key&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">SHIFT&lt;/span>&lt;span class="p">).&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">click&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">element1&lt;/span>&lt;span class="p">).&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">click&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">element2&lt;/span>&lt;span class="p">).&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">dragAndDrop&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">element3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">element4&lt;/span>&lt;span class="p">).&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">keyUp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">Key&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">SHIFT&lt;/span>&lt;span class="p">).&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">perform&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="实例方法">实例方法&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>click( opt_elementOrButton, opt_button ): 单击，相当于把鼠标移动到元素的中心，然后点击左键&lt;/p>
&lt;/li>
&lt;li>
&lt;p>doubleClick( opt_elementOrButton, opt_button ): 双击, 相当于把鼠标移动到元素的中心，然后双击左键&lt;/p>
&lt;/li>
&lt;li>
&lt;p>this.dragAndDrop( element, location ): 拖拽，第1个参数是拖谁(WebElement)，第2个参数是拽到哪里，可以是WebElement，也可以是坐标&lt;code>{x: number, y: number}&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>this.keyDown( key ): 按下一个键，必须是{ALT, CONTROL, SHIFT, COMMAND, META}中的一个， 会一直按着，除非调用keyUp()进行松开&lt;/p>
&lt;/li>
&lt;li>
&lt;p>this.keyUp( key ): 松开一个键，必须是{ALT, CONTROL, SHIFT, COMMAND, META}中的一个&lt;/p>
&lt;/li>
&lt;li>
&lt;p>this.mouseDown( opt_elementOrButton, opt_button ): 按下鼠标，除非mouseUp，否则不松开&lt;/p>
&lt;/li>
&lt;li>
&lt;p>this.mouseMove( location, opt_offset ): 把鼠标移动到元素的中心或者具体位置，当然，第2个参数可以也可以增加1个偏移量, &lt;code>{x: number, y: number}&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>this.mouseUp( opt_elementOrButton, opt_button ): 松开鼠标&lt;/p></description></item><item><title>11. 函数</title><link>https://itest2025.pages.dev/tutorials/28-011-11-%E5%87%BD%E6%95%B0/</link><pubDate>Thu, 29 Jun 2017 08:17:22 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/28-011-11-%E5%87%BD%E6%95%B0/</guid><description>&lt;h3 id="背景">背景&lt;/h3>
&lt;p>这一节里我们来了解一下什么是函数。&lt;/p>
&lt;p>简单来说函数就是一段代码，只不过这段代码有名字，可能有输入和输出，我们可以使用函数的名字反复去调用这段代码。&lt;/p>
&lt;p>函数主要做了下面3件事情&lt;/p>
&lt;ul>
&lt;li>给一段代码命名，就像是我们之前给字符串和数字取个变量名一样&lt;/li>
&lt;li>可以像之前我们在调用脚本时使用&lt;code>argv&lt;/code>一样的使用传入参数&lt;/li>
&lt;li>把上面2步结合起来，我们可以创建一些重复使用的脚本❤️&lt;/li>
&lt;/ul>
&lt;p>下面我们演示一下如何定义函数和调用函数&lt;/p>
&lt;h3 id="代码实现">代码实现&lt;/h3>
&lt;p>新建名为&lt;code>print_case.py&lt;/code>，内容如下&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># *args跟之前argv差不多&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">print_case&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">case_number&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">case_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">args&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;用例编号: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">case_number&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;用例名称: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">case_name&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2个参数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">print_case_again&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">case_number&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">case_name&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;用例编号: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">case_number&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;用例名称: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">case_name&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1个参数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">print_delimiter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">delimiter&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">delimiter&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">20&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 没有参数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">print_end&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;打印结束&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">print_case&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;001&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;验证GET请求的返回状态码&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">print_delimiter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;*&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">print_case_again&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;002&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;验证GET请求的返回值&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">print_delimiter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;*&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">print_end&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>详细的看一下&lt;code>print_case()&lt;/code>函数。&lt;/p>
&lt;ul>
&lt;li>首先我们告诉python，我们需要定义一个函数，约定好的关键字是&lt;code>def&lt;/code>，也就是define的意思&lt;/li>
&lt;li>然后我们为这个函数取个名字print_case，当然了，如果你觉得这个名字不好，你也可以换一个，不过我们一般在给函数取名的时候都是言简意赅的去表明这个函数到底是要做什么&lt;/li>
&lt;li>然后我们告诉python，我们需要传入*args，就像是使用&lt;code>argv&lt;/code>一样。*args就是函数的参数，需要放在一对小括号里&lt;code>()&lt;/code>&lt;/li>
&lt;li>在这一行的结束位置，不要忘了加个&lt;code>:&lt;/code>冒号，表示引出下面的函数正文&lt;/li>
&lt;li>另起一行，不要忘了缩进，就像使用&lt;code>argv&lt;/code>一样，取出用例编号和名称&lt;/li>
&lt;li>最后打印出用例名称和编号&lt;/li>
&lt;/ul>
&lt;h3 id="运行">运行&lt;/h3>
&lt;p>在命令行中使用下面的命令去执行代码&lt;/p>
&lt;pre tabindex="0">&lt;code>$ python print_case.py
&lt;/code>&lt;/pre>&lt;h3 id="你应该可以看到">你应该可以看到&lt;/h3>
&lt;p>按照下面展示的情况进行输入，如果没有出错的话，你应该可以看到命令行窗口显示如下的内容&lt;/p>
&lt;pre tabindex="0">&lt;code>用例编号: 001
用例名称: 验证GET请求的返回状态码
********************
用例编号: 002
用例名称: 验证GET请求的返回值
********************
打印结束
&lt;/code>&lt;/pre>&lt;h3 id="动手时间">动手时间&lt;/h3>
&lt;ul>
&lt;li>给代码增加注释，解释一下这段代码做了些什么&lt;/li>
&lt;li>函数的调用是什么意思？你能解释一下么？&lt;/li>
&lt;li>函数的参数是什么意思？你能解释一下么？&lt;/li>
&lt;li>缩进是什么？python中的强制缩进又是什么意思？&lt;/li>
&lt;/ul>
&lt;h3 id="常见问题">常见问题&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>给函数命名的时候，是不是任意的名字都可以？ 一般来说是这样的，跟变量名类似，函数名不能以数字开头，并且一般只能包含字母数字和下划线。&lt;/p></description></item><item><title>（十一）设置元素等待</title><link>https://itest2025.pages.dev/tutorials/19-011-%E5%8D%81%E4%B8%80%E8%AE%BE%E7%BD%AE%E5%85%83%E7%B4%A0%E7%AD%89%E5%BE%85/</link><pubDate>Thu, 29 Jun 2017 07:37:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/19-011-%E5%8D%81%E4%B8%80%E8%AE%BE%E7%BD%AE%E5%85%83%E7%B4%A0%E7%AD%89%E5%BE%85/</guid><description>&lt;br>
WebDriver提供了两种类型的等待：__显式等待__和__隐式等待__。
&lt;h3 id="显式等待">显式等待&lt;/h3>
&lt;p>WebDriver提供了显式等待方法，专门针对某个元素进行等待判断。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.By&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.WebDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.WebElement&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.chrome.ChromeDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.support.ui.WebDriverWait&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.support.ui.ExpectedCondition&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">TimeOut01&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[]&lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">throws&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">InterruptedException&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ChromeDriver&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;https://www.baidu.com&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//显式等待， 针对某个元素等待&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebDriverWait&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">wait&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">WebDriverWait&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">10&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">wait&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">until&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ExpectedCondition&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">WebElement&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Override&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">WebElement&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">apply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">WebDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">return&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;kw&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}).&lt;/span>&lt;span class="na">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;selenium&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;su&amp;#34;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">click&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2000&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">quit&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>WebDriverWait类是由WebDirver提供的等待方法。在设置时间内，默认每隔一段时间检测一次当前页面元素是否存在，如果超过设置时间检测不到则抛出异常。具体格式如下：&lt;/p></description></item><item><title>（十一）多表单切换</title><link>https://itest2025.pages.dev/tutorials/24-011-%E5%8D%81%E4%B8%80%E5%A4%9A%E8%A1%A8%E5%8D%95%E5%88%87%E6%8D%A2/</link><pubDate>Tue, 20 Jun 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/24-011-%E5%8D%81%E4%B8%80%E5%A4%9A%E8%A1%A8%E5%8D%95%E5%88%87%E6%8D%A2/</guid><description>&lt;br>
在Web应用中经常会遇到frame/iframe表单嵌套页面的应用，WebDriver只能在一个页面上对元素识别与定位，对于frame/iframe表单内嵌页面上的元素无法直接定位。这时就需要通过switch_to.frame()方法将当前定位的主体切换为frame/iframe表单的内嵌页面中。
```html
&lt;html>
 &lt;body>
 ...
 &lt;iframe id="x-URS-iframe" ...>
 &lt;html>
 &lt;body>
 ...
 &lt;input name="email" >
```
126邮箱登录框的结构大概是这样子的，想要操作登录框必须要先切换到iframe表单。
```python
from selenium import webdriver
&lt;p>driver = webdriver.Chrome()
driver.get(&amp;ldquo;&lt;a href="http://www.126.com" target="_blank" rel="noopener noreffer ">http://www.126.com&lt;/a>&amp;rdquo;)&lt;/p>
&lt;p>driver.switch_to.frame(&amp;lsquo;x-URS-iframe&amp;rsquo;)
driver.find_element_by_name(&amp;ldquo;email&amp;rdquo;).clear()
driver.find_element_by_name(&amp;ldquo;email&amp;rdquo;).send_keys(&amp;ldquo;username&amp;rdquo;)
driver.find_element_by_name(&amp;ldquo;password&amp;rdquo;).clear()
driver.find_element_by_name(&amp;ldquo;password&amp;rdquo;).send_keys(&amp;ldquo;password&amp;rdquo;)
driver.find_element_by_id(&amp;ldquo;dologin&amp;rdquo;).click()
driver.switch_to.default_content()&lt;/p>
&lt;p>driver.quit()&lt;/p>
&lt;pre tabindex="0">&lt;code>switch_to.frame() 默认可以直接取表单的id 或name属性。如果iframe没有可用的id和name属性，则可以通过下面的方式进行定位。
```python
……
#先通过xpth定位到iframe
xf = driver.find_element_by_xpath(&amp;#39;//*[@id=&amp;#34;x-URS-iframe&amp;#34;]&amp;#39;)

#再将定位对象传给switch_to.frame()方法
driver.switch_to.frame(xf)
……
driver.switch_to.parent_frame()
&lt;/code>&lt;/pre>&lt;p>除此之外，在进入多级表单的情况下，还可以通过switch_to.default_content()跳回最外层的页面。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1496297485239-4265d2ba2105?w=300"
 data-srcset="https://images.unsplash.com/photo-1496297485239-4265d2ba2105?w=300, https://images.unsplash.com/photo-1496297485239-4265d2ba2105?w=300 1.5x, https://images.unsplash.com/photo-1496297485239-4265d2ba2105?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1496297485239-4265d2ba2105?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（十二）Docker Machine介绍</title><link>https://itest2025.pages.dev/tutorials/30-012-%E5%8D%81%E4%BA%8Cdocker-machine%E4%BB%8B%E7%BB%8D/</link><pubDate>Mon, 22 Jan 2018 14:20:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/30-012-%E5%8D%81%E4%BA%8Cdocker-machine%E4%BB%8B%E7%BB%8D/</guid><description>&lt;p>官方文档：https://docs.docker.com/machine/overview/&lt;/p>
&lt;p>&lt;strong>可以使用Docker Machine做什么？&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>在Mac或Windows上安装并运行Docker&lt;/li>
&lt;li>配置和管理多个远程Docker主机&lt;/li>
&lt;li>提供Swarm集群&lt;/li>
&lt;/ul>
&lt;h4 id="什么是docker-machine">什么是Docker Machine?&lt;/h4>
&lt;hr>
&lt;p>Docker Machine是一个工具，可以让你在虚拟主机上安装Docker Engine，并用docker-machine命令管理主机。你可以使用计算机在本地Mac或Windows计算机上，公司网络，数据中心或云提供商（如Azure，AWS或Digital Ocean）上创建Docker主机。&lt;/p>
&lt;p>使用docker-machine命令，你可以启动，检查，停止和重新启动托管主机，升级Docker客户端和守护进程，并配置Docker客户端与主机通信。&lt;/p>
&lt;p>将机器CLI指向正在运行的托管主机，并且可以直接在该主机上运行&lt;code>docker&lt;/code>命令。例如，运行&lt;code>docker-machine env default&lt;/code>指向一个名为&lt;code>default&lt;/code>的主机，按照屏幕上的说明完成env设置，然后运行&lt;code>docker ps&lt;/code>，&lt;code>docker run hello-world&lt;/code>等等。&lt;/p>
&lt;p>Machine是在Docker v1.12之前在Mac或Windows上运行Docker的唯一方法。从测试版和Docker v1.12开始，Docker for Mac和Docker for Windows作为本地应用程序提供，并且是更新桌面和笔记本电脑上更好的选择。我们鼓励你尝试这些新的应用程序。 Docker for Mac和Docker for Windows的安装程序包括Docker Machine和Docker Compose。&lt;/p>
&lt;p>如果你不确定从哪里开始，请参阅Docker入门，它将指导您完成Docker的简要端到端教程。&lt;/p>
&lt;h5 id="为什么要使用docker-machine">为什么要使用Docker Machine?&lt;/h5>
&lt;hr>
&lt;p>Docker Machine使你能够在各种类型的Linux上配置多个远程Docker主机。&lt;/p>
&lt;p>此外，Machine允许你在旧版Mac或Windows系统上运行Docker，如上一主题中所述。&lt;/p>
&lt;p>Docker Machine有这两个广泛的用例。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>你有一个较旧的桌面系统，并希望在Mac或Windows上运行Docker&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/docker_machine-mac-win.png"
 data-srcset="http://img.testclass.net/docker_machine-mac-win.png, http://img.testclass.net/docker_machine-mac-win.png 1.5x, http://img.testclass.net/docker_machine-mac-win.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/docker_machine-mac-win.png"
 title="http://img.testclass.net/docker_machine-mac-win.png" />&lt;/p>
&lt;p>如果你主要工作不符合新版Docker for Mac和Docker for Windows应用程序要求的较旧的Mac或Windows笔记本电脑或台式机上，那么需要在本地运行Docker机器运行Docker Engine。使用Docker Toolbox安装程序在Mac或Windows上安装Docker Machine可以为本地虚拟机配置Docker Engine，使您能够连接它并运行&lt;code>docker&lt;/code>命令。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>我想在远程系统上配置Docker主机&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/docker_provision-use-case.png"
 data-srcset="http://img.testclass.net/docker_provision-use-case.png, http://img.testclass.net/docker_provision-use-case.png 1.5x, http://img.testclass.net/docker_provision-use-case.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/docker_provision-use-case.png"
 title="http://img.testclass.net/docker_provision-use-case.png" />&lt;/p></description></item><item><title>（十二）TestNG 生成测试报告</title><link>https://itest2025.pages.dev/tutorials/36-012-%E5%8D%81%E4%BA%8Ctestng-%E7%94%9F%E6%88%90%E6%B5%8B%E8%AF%95%E6%8A%A5%E5%91%8A/</link><pubDate>Sat, 25 Nov 2017 12:10:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/36-012-%E5%8D%81%E4%BA%8Ctestng-%E7%94%9F%E6%88%90%E6%B5%8B%E8%AF%95%E6%8A%A5%E5%91%8A/</guid><description>&lt;p>TestNG 默认自带的有HTML格式的测试报告。这也充分说明拿它来做 UI 自动化测试的优势。&lt;/p>
&lt;h4 id="通过-maven-生成报告">通过 Maven 生成报告&lt;/h4>
&lt;hr>
&lt;p>切换到 &lt;strong>TestngTest&lt;/strong> 项目的跟目录下，通过 &lt;code>mvn test&lt;/code> 命令运行测试。&lt;/p>
&lt;pre tabindex="0">&lt;code>TestngTest&amp;gt; mvn test

[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building TestngTest 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ TestngTest
 --- [WARNING] Using platform encoding (GBK actually) to copy filtered resources,
 i.e. build is platform dependent!
[INFO] Copying 0 resource

...

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running TestSuite
Configuring TestNG with: org.apache.maven.surefire.testng.conf.TestNG652Configurator@104e3b2
Tests run: 19, Failures: 5, Errors: 0, Skipped: 2, Time elapsed: 3.862 sec &amp;lt;&amp;lt;&amp;lt; FAILURE!
&lt;/code>&lt;/pre>&lt;p>在该系列教程开始前，我已经说明了整个项目基于 &lt;a href="https://itest2025.pages.dev/maven/" rel="">Maven&lt;/a> 创建。&lt;/p></description></item><item><title>requests如何查看cookies和发送cookies?</title><link>https://itest2025.pages.dev/tutorials/42-012-requests%E5%A6%82%E4%BD%95%E6%9F%A5%E7%9C%8Bcookies%E5%92%8C%E5%8F%91%E9%80%81cookies/</link><pubDate>Wed, 22 Nov 2017 03:23:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/42-012-requests%E5%A6%82%E4%BD%95%E6%9F%A5%E7%9C%8Bcookies%E5%92%8C%E5%8F%91%E9%80%81cookies/</guid><description>&lt;p>如果某个响应中包含一些 cookie，你可以快速访问它们：&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; url = &amp;#39;http://example.com/some/cookie/setting/url&amp;#39;
&amp;gt;&amp;gt;&amp;gt; r = requests.get(url)

&amp;gt;&amp;gt;&amp;gt; r.cookies[&amp;#39;example_cookie_name&amp;#39;]
&amp;#39;example_cookie_value&amp;#39;
&lt;/code>&lt;/pre>&lt;p>要想发送你的cookies到服务器，可以使用 cookies 参数：&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; url = &amp;#39;http://httpbin.org/cookies&amp;#39;
&amp;gt;&amp;gt;&amp;gt; cookies = dict(cookies_are=&amp;#39;working&amp;#39;)

&amp;gt;&amp;gt;&amp;gt; r = requests.get(url, cookies=cookies)
&amp;gt;&amp;gt;&amp;gt; r.text
&amp;#39;{&amp;#34;cookies&amp;#34;: {&amp;#34;cookies_are&amp;#34;: &amp;#34;working&amp;#34;}}&amp;#39;
&lt;/code>&lt;/pre>&lt;p>Cookie 的返回对象为 &lt;a href="http://docs.python-requests.org/zh_CN/latest/api.html#requests.cookies.RequestsCookieJar" target="_blank" rel="noopener noreffer ">RequestsCookieJar&lt;/a>，它的行为和字典类似，但界面更为完整，适合跨域名跨路径使用。你还可以把 Cookie Jar 传到 Requests 中：&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; jar = requests.cookies.RequestsCookieJar()
&amp;gt;&amp;gt;&amp;gt; jar.set(&amp;#39;tasty_cookie&amp;#39;, &amp;#39;yum&amp;#39;, domain=&amp;#39;httpbin.org&amp;#39;, path=&amp;#39;/cookies&amp;#39;)
&amp;gt;&amp;gt;&amp;gt; jar.set(&amp;#39;gross_cookie&amp;#39;, &amp;#39;blech&amp;#39;, domain=&amp;#39;httpbin.org&amp;#39;, path=&amp;#39;/elsewhere&amp;#39;)
&amp;gt;&amp;gt;&amp;gt; url = &amp;#39;http://httpbin.org/cookies&amp;#39;
&amp;gt;&amp;gt;&amp;gt; r = requests.get(url, cookies=jar)
&amp;gt;&amp;gt;&amp;gt; r.text
&amp;#39;{&amp;#34;cookies&amp;#34;: {&amp;#34;tasty_cookie&amp;#34;: &amp;#34;yum&amp;#34;}}&amp;#39;
&lt;/code>&lt;/pre>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1501891037204-8754d498396b?w=300"
 data-srcset="https://images.unsplash.com/photo-1501891037204-8754d498396b?w=300, https://images.unsplash.com/photo-1501891037204-8754d498396b?w=300 1.5x, https://images.unsplash.com/photo-1501891037204-8754d498396b?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1501891037204-8754d498396b?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（十二）补充：JUnit 注解之Rule</title><link>https://itest2025.pages.dev/tutorials/31-012-%E5%8D%81%E4%BA%8C%E8%A1%A5%E5%85%85junit-%E6%B3%A8%E8%A7%A3%E4%B9%8Brule/</link><pubDate>Mon, 13 Nov 2017 12:15:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/31-012-%E5%8D%81%E4%BA%8C%E8%A1%A5%E5%85%85junit-%E6%B3%A8%E8%A7%A3%E4%B9%8Brule/</guid><description>&lt;p>一个JUnit Rule就是一个实现了TestRule的类，这些类的作用类似于 &lt;code>@Before&lt;/code>、&lt;code>@After&lt;/code>，是用来在每个测试方法的执行前后执行一些代码的一个方法。
那为什么不直接用这些 &lt;code>@Before&lt;/code>、&lt;code>@After&lt;/code>呢？这是因为它们都只能作用于一个类，如果同一个setup需要在两个类里面同时使用，那么你就要在两个测试类里面定义相同的@Before方法，然后里面写相同的代码，这就造成了代码重复。&lt;/p>
&lt;p>此外，JUnit Rule还能做一些 &lt;code>@Before&lt;/code>、&lt;code>@After&lt;/code>这些注解做不到的事情，那就是他们可以动态的获取将要运行的测试类、测试方法的信息。&lt;/p>
&lt;h4 id="使用框架自带的rule">使用框架自带的Rule&lt;/h4>
&lt;hr>
&lt;p>除了增加Rule特性，新版JUnit还添加了很多核心Rule&lt;/p>
&lt;ul>
&lt;li>TemporaryFolder：测试可以创建文件与目录并且会在测试运行结束后将其删除。这对于那些与文件系统打交道且独立运行的测试来说很有用。&lt;/li>
&lt;li>ExternalResource：这是一种资源使用模式，它会提前建立好资源并且会在测试结束后将其销毁。这对于那些使用socket、嵌入式服务器等资源的测试来说很有用。&lt;/li>
&lt;li>ErrorCollector：可以让测试在失败后继续运行并在测试结束时报告所有错误。这对于那些需要验证大量独立条件的测试来说很有用（尽管这本身可能是个“test smell”）。&lt;/li>
&lt;li>ExpectedException：可以在测试中指定期望的异常类型与消息。&lt;/li>
&lt;li>Timeout：为类中的所有测试应用相同的超时时间。&lt;/li>
&lt;/ul>
&lt;p>例如，TimeOut这个Rule的使用。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.Rule&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.Test&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.junit.rules.Timeout&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">RuleTestDemo&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//使用Timeout这个Rule&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Rule&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Timeout&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">timeout&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Timeout&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1000&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">testMethod1&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">throws&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Exception&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1001&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nd">@Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">testMethod2&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">throws&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Exception&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">999&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>使用JUnit所提供的Timeout类，该类用于控制测试用例的执行超时时间。这里设置为1秒，当用例执行超过1秒则失败。接下来分别在 testMethod1和testMethod2两个用例中使用sleep()方法来控制用例的执行时间，显然testMethod1超过1秒，则运行失败。&lt;/p></description></item><item><title>12. IntelliJ IDEA 搜索快的原因：索引（新用户必看）</title><link>https://itest2025.pages.dev/tutorials/37-012-12-intellij-idea-%E6%90%9C%E7%B4%A2%E5%BF%AB%E7%9A%84%E5%8E%9F%E5%9B%A0%E7%B4%A2%E5%BC%95%E6%96%B0%E7%94%A8%E6%88%B7%E5%BF%85%E7%9C%8B/</link><pubDate>Mon, 16 Oct 2017 01:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/37-012-12-intellij-idea-%E6%90%9C%E7%B4%A2%E5%BF%AB%E7%9A%84%E5%8E%9F%E5%9B%A0%E7%B4%A2%E5%BC%95%E6%96%B0%E7%94%A8%E6%88%B7%E5%BF%85%E7%9C%8B/</guid><description>&lt;h1 id="intellij-idea-缓存和索引介绍和清理方法">IntelliJ IDEA 缓存和索引介绍和清理方法&lt;/h1>
&lt;h2 id="缓存和索引介绍">缓存和索引介绍&lt;/h2>
&lt;p>在&lt;a href="interface-introduce.md" rel="">《IntelliJ IDEA 界面介绍》&lt;/a>章节里已经点到了 IntelliJ IDEA 首次加载项目的时候，都会创建索引，而创建索引的时间跟项目的文件多少成正比，我也简单强调了 IntelliJ IDEA 索引的重要性。这里我们再对此进行详细说明索引、缓存对 IntelliJ IDEA 的重要性。&lt;/p>
&lt;p>通过《常见文件类型的图标介绍》章节，你已经认识到 IntelliJ IDEA 下各个文件类型的图标是什么样子的。其中有一个图标我是专门进行了讲解：&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/xi-a-file-symbols-3.png"
 data-srcset="http://img.testclass.net/xi-a-file-symbols-3.png, http://img.testclass.net/xi-a-file-symbols-3.png 1.5x, http://img.testclass.net/xi-a-file-symbols-3.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/xi-a-file-symbols-3.png"
 title="http://img.testclass.net/xi-a-file-symbols-3.png" /> &lt;code>Java class located out of the source root&lt;/code>。我们也都知道该图标是表示 Java 类文件没有在 &lt;code>Source root&lt;/code> 目录下的文件夹下会显示此图标，但是其实还有一种情况也是会显示此图标的。那就是：在 IntelliJ IDEA 创建索引过程中，所有的 Java类 都是这个图标，如果你项目大的话很容易观察到的，几个文件的小项目倒是不一定会看到。所以在 IntelliJ IDEA 创建索引过程即使你编辑了代码也是编译不了、运行不起来的，所以还是安安静静等 IntelliJ IDEA 创建索引完成。&lt;/p>
&lt;p>IntelliJ IDEA 的缓存和索引主要是用来加快文件查询，从而加快各种查找、代码提示等操作的速度，所以 IntelliJ IDEA 的索引的重要性我再唠叨一万遍都不为过。但是，IntelliJ IDEA 的索引和缓存并不是一直会良好地支持 IntelliJ IDEA 的，这某些特殊条件下，IntelliJ IDEA 的缓存和索引文件也是会损坏的，比如断电、蓝屏引起的强制关机，当你重新打开 IntelliJ IDEA，基本上百分八十的可能 IntelliJ IDEA 都会报各种莫名其妙错误，甚至项目打不开，IntelliJ IDEA 主题还原成默认状态。也有一些即使没有断电、蓝屏，也会有莫名奇怪的问题的时候，也很有可能是 IntelliJ IDEA 缓存和索引出问题，这种情况还不少。遇到此类问题也不用过多担心，下面就来讲解如何解决。&lt;/p></description></item><item><title>appium新手入门（12）—— appium API 之 TouchAction 操作</title><link>https://itest2025.pages.dev/tutorials/21-012-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A812-appium-api-%E4%B9%8B-touchaction-%E6%93%8D%E4%BD%9C/</link><pubDate>Thu, 07 Sep 2017 10:10:12 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/21-012-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A812-appium-api-%E4%B9%8B-touchaction-%E6%93%8D%E4%BD%9C/</guid><description>&lt;p>Appium的辅助类，主要针对手势操作，比如滑动、长按、拖动等。&lt;/p>
&lt;h4 id="1按压控件">1、按压控件&lt;/h4>
&lt;hr>
&lt;p>方法：&lt;/p>
&lt;ul>
&lt;li>press()&lt;/li>
&lt;/ul>
&lt;p>开始按压一个元素或坐标点（x,y）。通过手指按压手机屏幕的某个位置。&lt;/p>
&lt;p>&lt;strong>press(WebElement el, int x, int y)&lt;/strong>&lt;/p>
&lt;p>press也可以接收屏幕的坐标（x,y）。&lt;/p>
&lt;p>例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">TouchAction&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="na">press&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">0&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">308&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="na">release&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="na">perform&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>除了press()方法之外，本例中还用到了别外两个新方法。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>release()
结束的行动取消屏幕上的指针。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Perform()
执行的操作发送到服务器的命令操作。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h4 id="2长按控件">2、长按控件&lt;/h4>
&lt;hr>
&lt;p>方法：&lt;/p>
&lt;ul>
&lt;li>longPress()&lt;/li>
&lt;/ul>
&lt;p>开始按压一个元素或坐标点（x,y）。
相比press()方法，longPress()多了一个入参，既然长按，得有按的时间吧。duration以毫秒为单位。1000表示按一秒钟。其用法与press()方法相同。&lt;/p>
&lt;p>&lt;strong>longPress(WebElement el, int x, int y, Duration duration)&lt;/strong>&lt;/p>
&lt;p>例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">TouchAction&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">action&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">TouchAction&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">action&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">longPress&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">names&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="n">1000&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="na">perform&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="na">release&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">action&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">longPress&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">302&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">1000&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="na">perform&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="na">release&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="3点击控件">3、点击控件&lt;/h4>
&lt;hr>
&lt;p>方法：&lt;/p>
&lt;ul>
&lt;li>tap()&lt;/li>
&lt;/ul>
&lt;p>对一个元素或控件执行点击操作。用法参考press()。&lt;/p>
&lt;p>&lt;strong>tap(WebElement el, int x, int y)&lt;/strong>&lt;/p>
&lt;p>例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">TouchAction&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">action&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">TouchAction&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">action&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">tap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">names&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">perform&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="na">release&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">action&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">tap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">302&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="na">perform&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="na">release&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="4移动">4、移动&lt;/h4>
&lt;hr>
&lt;p>方法：&lt;/p>
&lt;ul>
&lt;li>moveTo()&lt;/li>
&lt;/ul>
&lt;p>将指针（光标）从过去指向指定的元素或点。&lt;/p>
&lt;p>&lt;strong>movTo(WebElement el, int x, int y)&lt;/strong>&lt;/p></description></item><item><title>性能测试流程（七）——测试执行</title><link>https://itest2025.pages.dev/tutorials/14-012-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E6%B5%81%E7%A8%8B%E4%B8%83%E6%B5%8B%E8%AF%95%E6%89%A7%E8%A1%8C/</link><pubDate>Fri, 11 Aug 2017 02:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/14-012-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E6%B5%81%E7%A8%8B%E4%B8%83%E6%B5%8B%E8%AF%95%E6%89%A7%E8%A1%8C/</guid><description>&lt;p>参考&lt;a href="https://itest2025.pages.dev/performance/test-plan/" rel="">测试计划&lt;/a>，大概执行过程如下：&lt;/p>
&lt;h4 id="1准备测试数据">1、准备测试数据&lt;/h4>
&lt;h4 id="2使用测试工具模拟测试点回放ok">2、使用测试工具模拟测试点，回放OK&lt;/h4>
&lt;h4 id="3根据测试策略使用不同的虚拟用户和测试组合-运行测试">3、根据测试策略，使用不同的虚拟用户和测试组合 运行测试。&lt;/h4>
&lt;h4 id="4监控系统cpu内存中间件数据库的性能收集数据">4、监控系统CPU、内存、中间件，数据库的性能，收集数据。&lt;/h4>
&lt;h4 id="5重复34">5、重复3、4。&lt;/h4>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1471623320832-752e8bbf8413?w=300"
 data-srcset="https://images.unsplash.com/photo-1471623320832-752e8bbf8413?w=300, https://images.unsplash.com/photo-1471623320832-752e8bbf8413?w=300 1.5x, https://images.unsplash.com/photo-1471623320832-752e8bbf8413?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1471623320832-752e8bbf8413?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（十二）定位一组元素</title><link>https://itest2025.pages.dev/tutorials/20-012-%E5%8D%81%E4%BA%8C%E5%AE%9A%E4%BD%8D%E4%B8%80%E7%BB%84%E5%85%83%E7%B4%A0/</link><pubDate>Wed, 02 Aug 2017 07:27:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/20-012-%E5%8D%81%E4%BA%8C%E5%AE%9A%E4%BD%8D%E4%B8%80%E7%BB%84%E5%85%83%E7%B4%A0/</guid><description>&lt;h3 id="定位一组元素">定位一组元素&lt;/h3>
&lt;p>定位一组元素一般有如下的作用&lt;/p>
&lt;ul>
&lt;li>找到一组属性部分相同的元素，遍历元素，做一些批量操作&lt;/li>
&lt;li>找到一组属性部分相同的元素，遍历元素，返回&lt;strong>1个或几个&lt;/strong>特定的元素，做更精确的定位&lt;/li>
&lt;/ul>
&lt;p>findElements方法可以定位一组元素。该方法的参数跟findElement方法一致。&lt;/p>
&lt;h3 id="目的">目的&lt;/h3>
&lt;ul>
&lt;li>学会使用findElements方法&lt;/li>
&lt;li>学会使用getAttribute方法&lt;/li>
&lt;/ul>
&lt;h3 id="场景">场景&lt;/h3>
&lt;p>打印&lt;a href="http://www.testclass.net/" target="_blank" rel="noopener noreffer ">测试教程网&lt;/a>中所有的&lt;a href="http://www.testclass.net/selenium_javascript/" target="_blank" rel="noopener noreffer ">selenium javascript&lt;/a>教程的链接&lt;/p>
&lt;h3 id="代码">代码&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">webdriver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;selenium-webdriver&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">By&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">dr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Builder&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">forBrowser&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;chrome&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">build&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;http://www.testclass.net/selenium_javascript/&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElements&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">css&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;.post-stub a&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">then&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">links&lt;/span>&lt;span class="p">){&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kd">var&lt;/span> &lt;span class="nx">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="nx">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="nx">links&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">length&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="nx">i&lt;/span>&lt;span class="o">++&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">links&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nx">i&lt;/span>&lt;span class="p">].&lt;/span>&lt;span class="nx">getAttribute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;href&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">then&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">href&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">href&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">quit&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行结果">运行结果&lt;/h3>
&lt;p>如下所示&lt;/p>
&lt;pre tabindex="0">&lt;code>http://www.testclass.net/selenium_javascript/init/
http://www.testclass.net/selenium_javascript/simple_automation_scripts/
http://www.testclass.net/selenium_javascript/view_document/
http://www.testclass.net/selenium_javascript/by_id/
http://www.testclass.net/selenium_javascript/by_name/
http://www.testclass.net/selenium_javascript/by_classname/
http://www.testclass.net/selenium_javascript/by_link_text/
http://www.testclass.net/selenium_javascript/by_css/
http://www.testclass.net/selenium_javascript/by_xpath/
http://www.testclass.net/selenium_javascript/keyboard/
http://www.testclass.net/selenium_javascript/action_sequence/
......
......
......
......
&lt;/code>&lt;/pre>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1477005264461-b0e201668d92?w=300"
 data-srcset="https://images.unsplash.com/photo-1477005264461-b0e201668d92?w=300, https://images.unsplash.com/photo-1477005264461-b0e201668d92?w=300 1.5x, https://images.unsplash.com/photo-1477005264461-b0e201668d92?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1477005264461-b0e201668d92?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>12. 函数与变量</title><link>https://itest2025.pages.dev/tutorials/28-012-12-%E5%87%BD%E6%95%B0%E4%B8%8E%E5%8F%98%E9%87%8F/</link><pubDate>Wed, 28 Jun 2017 08:17:22 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/28-012-12-%E5%87%BD%E6%95%B0%E4%B8%8E%E5%8F%98%E9%87%8F/</guid><description>&lt;h3 id="背景">背景&lt;/h3>
&lt;p>对于初学者来说函数的概念比较的烧脑，刚开始理解起来会各种困难，不过没关系，继续多多练习，习惯之后就不会有太多问题了。&lt;/p>
&lt;p>这一节里我们解决一个小问题，就是函数里的变量名和函数外的变量名是不是会冲突的问题。&lt;/p>
&lt;p>结论是不冲突，下面我们演示一下具体情况。&lt;/p>
&lt;h3 id="代码实现">代码实现&lt;/h3>
&lt;p>新建名为&lt;code>print_case01.py&lt;/code>，内容如下&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">print_case_count&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">success&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">failed&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">total_count&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">success&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">failed&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;一共&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">total_count&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">个用例, 成功&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">success&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">个, 失败&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">failed&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">个&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">print_end&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;打印结束&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;第一次运行&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">print_case_count&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">95&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;第二次运行&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">success&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">101&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">failed&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">print_case_count&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">success&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">failed&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;第三次运行&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">total&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">100&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">failed&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">7&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">print_case_count&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">total&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">failed&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">failed&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">print_end&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上面的代码说明了一些问题&lt;/p>
&lt;ul>
&lt;li>函数调用有很多的方式，传参的时候我们可以直接传值，传变量，甚至是合法的表达式(&lt;code>total - failed&lt;/code>)&lt;/li>
&lt;li>函数外的变量名不会影响函数内的，另一种说法是我们可以在函数内用函数外相同的变量名&lt;/li>
&lt;/ul>
&lt;h3 id="运行">运行&lt;/h3>
&lt;p>在命令行中使用下面的命令去执行代码&lt;/p>
&lt;pre tabindex="0">&lt;code>$ python print_case01.py
&lt;/code>&lt;/pre>&lt;h3 id="你应该可以看到">你应该可以看到&lt;/h3>
&lt;p>按照下面展示的情况进行输入，如果没有出错的话，你应该可以看到命令行窗口显示如下的内容&lt;/p>
&lt;pre tabindex="0">&lt;code>第一次运行 
一共100个用例, 成功95个, 失败5个 
第二次运行 
一共101个用例, 成功101个, 失败0个 
第三次运行 
一共100个用例, 成功93个, 失败7个 
打印结束 
&lt;/code>&lt;/pre>&lt;h3 id="动手时间">动手时间&lt;/h3>
&lt;ul>
&lt;li>修改&lt;code>print_case_count()&lt;/code>函数，使其可以输出用例的通过率&lt;/li>
&lt;li>自行去了解一下python中变量的作用域，推荐搜索关键字&lt;strong>python variable scope&lt;/strong>&lt;/li>
&lt;li>自行去了解什么是全局变量，什么是局部变量&lt;/li>
&lt;/ul>
&lt;h3 id="常见问题">常见问题&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>为什么搜索的时候推荐英文关键字？ 英文关键字可以使我们找到第一手官方的解释，准确性更高。另外阅读一些英文文档也不是啥坏事。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>怎么去计算用例的通过率？ 公式大概是&lt;code>success_count / total_count&lt;/code>，注意算出来的结果应该是浮点型&lt;/p>
&lt;/li>
&lt;li>
&lt;p>什么是浮点型？ 简单理解为带有小数位的数，如果你对这个答案不满意，你可以看一下&lt;a href="https://en.wikipedia.org/wiki/Floating-point_arithmetic" target="_blank" rel="noopener noreffer ">这里&lt;/a>&lt;/p></description></item><item><title>（十二）定位一组元素</title><link>https://itest2025.pages.dev/tutorials/19-012-%E5%8D%81%E4%BA%8C%E5%AE%9A%E4%BD%8D%E4%B8%80%E7%BB%84%E5%85%83%E7%B4%A0/</link><pubDate>Wed, 28 Jun 2017 07:37:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/19-012-%E5%8D%81%E4%BA%8C%E5%AE%9A%E4%BD%8D%E4%B8%80%E7%BB%84%E5%85%83%E7%B4%A0/</guid><description>&lt;br>
在第（五）节我们已经学习了8种定位方法， 那8种定位方法是针对单个元素定位的， WebDriver还提供了另外8种用于定位一组元素的方法。
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.By&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">......&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">findElements&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">id&lt;/span>&lt;span class="p">())&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">findElements&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">name&lt;/span>&lt;span class="p">())&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">findElements&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">className&lt;/span>&lt;span class="p">())&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">findElements&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">tagName&lt;/span>&lt;span class="p">())&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">findElements&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">linkText&lt;/span>&lt;span class="p">())&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">findElements&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">partialLinkText&lt;/span>&lt;span class="p">())&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">findElements&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">xpath&lt;/span>&lt;span class="p">())&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">findElements&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">cssSelector&lt;/span>&lt;span class="p">())&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>定位一组元素的方法与定位单个元素的方法类似，唯一的区别是在单词 findElement 后面多了一个 &lt;strong>s&lt;/strong> 表示复数。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.By&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.WebDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.WebElement&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.chrome.ChromeDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">java.util.List&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">ElementsDemo&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">throws&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">InterruptedException&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ChromeDriver&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;https://www.baidu.com/&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebElement&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">search_text&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;kw&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">search_text&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;selenium&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">search_text&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">submit&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2000&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//匹配第一页搜索结果的标题， 循环打印&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">List&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">WebElement&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">search_result&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElements&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">xpath&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;//div/div/h3&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//打印元素的个数&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">search_result&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">size&lt;/span>&lt;span class="p">());&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// 循环打印搜索结果的标题&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">WebElement&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">search_result&lt;/span>&lt;span class="p">){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">getText&lt;/span>&lt;span class="p">());&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;-------我是分割线---------&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//打印第n结果的标题&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebElement&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">search_result&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">search_result&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">size&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">10&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">getText&lt;/span>&lt;span class="p">());&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">quit&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>打印结果：&lt;/p></description></item><item><title>（十二）多窗口切换</title><link>https://itest2025.pages.dev/tutorials/24-012-%E5%8D%81%E4%BA%8C%E5%A4%9A%E7%AA%97%E5%8F%A3%E5%88%87%E6%8D%A2/</link><pubDate>Mon, 19 Jun 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/24-012-%E5%8D%81%E4%BA%8C%E5%A4%9A%E7%AA%97%E5%8F%A3%E5%88%87%E6%8D%A2/</guid><description>&lt;br>
在页面操作过程中有时候点击某个链接会弹出新的窗口，这时就需要主机切换到新打开的窗口上进行操作。WebDriver提供了switch_to.window()方法，可以实现在不同的窗口之间切换。
以百度首页和百度注册页为例，在两个窗口之间的切换如下图。
![](http://orru5lls3.bkt.clouddn.com/more_windows_n.png)
```python
from selenium import webdriver
import time
&lt;p>driver = webdriver.Firefox()
driver.implicitly_wait(10)
driver.get(&amp;ldquo;&lt;a href="http://www.baidu.com" target="_blank" rel="noopener noreffer ">http://www.baidu.com&lt;/a>&amp;rdquo;)&lt;/p>
&lt;h1 id="获得百度搜索窗口句柄">获得百度搜索窗口句柄&lt;/h1>
&lt;p>sreach_windows = driver.current_window_handle&lt;/p>
&lt;p>driver.find_element_by_link_text(&amp;lsquo;登录&amp;rsquo;).click()
driver.find_element_by_link_text(&amp;ldquo;立即注册&amp;rdquo;).click()&lt;/p>
&lt;h1 id="获得当前所有打开的窗口的句柄">获得当前所有打开的窗口的句柄&lt;/h1>
&lt;p>all_handles = driver.window_handles&lt;/p>
&lt;h1 id="进入注册窗口">进入注册窗口&lt;/h1>
&lt;p>for handle in all_handles:
if handle != sreach_windows:
driver.switch_to.window(handle)
print(&amp;rsquo;now register window!&amp;rsquo;)
driver.find_element_by_name(&amp;ldquo;account&amp;rdquo;).send_keys(&amp;lsquo;username&amp;rsquo;)
driver.find_element_by_name(&amp;lsquo;password&amp;rsquo;).send_keys(&amp;lsquo;password&amp;rsquo;)
time.sleep(2)
# ……&lt;/p>
&lt;p>driver.quit()&lt;/p>
&lt;pre tabindex="0">&lt;code>在本例中所涉及的新方法如下：

* current_window_handle：获得当前窗口句柄。
* window_handles：返回所有窗口的句柄到当前会话。
* switch_to.window()：用于切换到相应的窗口，与上一节的switch_to.frame()类似，前者用于不同窗口的切换，后者用于不同表单之间的切换。




原始封面

![课程图片](https://images.unsplash.com/photo-1434873740857-1bc5653afda8?w=300)
&lt;/code>&lt;/pre></description></item><item><title>（十三）Docker Machine安装</title><link>https://itest2025.pages.dev/tutorials/30-013-%E5%8D%81%E4%B8%89docker-machine%E5%AE%89%E8%A3%85/</link><pubDate>Mon, 22 Jan 2018 14:18:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/30-013-%E5%8D%81%E4%B8%89docker-machine%E5%AE%89%E8%A3%85/</guid><description>&lt;p>在macOS和Windows上，当你安装Docker for Mac，Docker for Windows或Docker Toolbox时，Machine将与其他Docker产品一起安装。&lt;/p>
&lt;p>如果你只需要Docker Machine，则可以按照下一节中的说明直接安装Machine二进制文件。 你可以在GitHub上的&lt;a href="https://github.com/docker/machine/releases/" target="_blank" rel="noopener noreffer ">docker/machine release&lt;/a> 页面上找到最新版本的二进制文件。&lt;/p>
&lt;h4 id="直接安装">直接安装&lt;/h4>
&lt;h5 id="1安装-docker">1、安装 Docker。&lt;/h5>
&lt;h5 id="2下载docker-machine二进制文件并将其解压到path">2、下载Docker Machine二进制文件并将其解压到PATH。&lt;/h5>
&lt;p>如果你是 &lt;strong>macOS&lt;/strong> 系统，运行:&lt;/p>
&lt;pre tabindex="0">&lt;code>$ curl -L https://github.com/docker/machine/releases/download/v0.13.0/docker-machine-`uname -s`-`uname -m` &amp;gt;/usr/local/bin/docker-machine &amp;amp;&amp;amp; \
 chmod +x /usr/local/bin/docker-machine
&lt;/code>&lt;/pre>&lt;p>如果你是 &lt;strong>Linux&lt;/strong> 系统，运行:&lt;/p>
&lt;pre tabindex="0">&lt;code>$ curl -L https://github.com/docker/machine/releases/download/v0.13.0/docker-machine-`uname -s`-`uname -m` &amp;gt;/tmp/docker-machine &amp;amp;&amp;amp; \
sudo install /tmp/docker-machine /usr/local/bin/docker-machine
&lt;/code>&lt;/pre>&lt;p>如果你是 &lt;strong>Windows&lt;/strong> 系统，通过&lt;a href="https://gitforwindows.org/" target="_blank" rel="noopener noreffer ">Git BASH&lt;/a> 运行:&lt;/p>
&lt;pre tabindex="0">&lt;code>$ if [[ ! -d &amp;#34;$HOME/bin&amp;#34; ]]; then mkdir -p &amp;#34;$HOME/bin&amp;#34;; fi &amp;amp;&amp;amp; \
curl -L https://github.com/docker/machine/releases/download/v0.13.0/docker-machine-Windows-x86_64.exe &amp;gt; &amp;#34;$HOME/bin/docker-machine.exe&amp;#34; &amp;amp;&amp;amp; \
chmod +x &amp;#34;$HOME/bin/docker-machine.exe&amp;#34;
&lt;/code>&lt;/pre>&lt;blockquote>
&lt;p>注意：只有当你使用像Git BASH这样的支持Linux命令（如chmod）的终端模拟器时，上面的命令才能在Windows上运行。&lt;/p></description></item><item><title>requests如何处理url的重定向?</title><link>https://itest2025.pages.dev/tutorials/42-013-requests%E5%A6%82%E4%BD%95%E5%A4%84%E7%90%86url%E7%9A%84%E9%87%8D%E5%AE%9A%E5%90%91/</link><pubDate>Wed, 22 Nov 2017 03:23:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/42-013-requests%E5%A6%82%E4%BD%95%E5%A4%84%E7%90%86url%E7%9A%84%E9%87%8D%E5%AE%9A%E5%90%91/</guid><description>&lt;p>默认情况下，除了HEAD请求, Requests 会自动处理所有重定向。&lt;/p>
&lt;p>如果你使用的是GET、OPTIONS、POST、PUT、PATCH 或者 DELETE，那么你可以通过 allow_redirects 参数禁用重定向处理：&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; r = requests.get(&amp;#39;http://github.com&amp;#39;, allow_redirects=False)
&amp;gt;&amp;gt;&amp;gt; r.status_code
301
&amp;gt;&amp;gt;&amp;gt; r.history
[]
&lt;/code>&lt;/pre>&lt;p>可以使用&lt;code>history&lt;/code>方法来追踪重定向&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; r = requests.get(&amp;#39;http://github.com&amp;#39;)

&amp;gt;&amp;gt;&amp;gt; r.url
&amp;#39;https://github.com/&amp;#39;

&amp;gt;&amp;gt;&amp;gt; r.status_code
200

&amp;gt;&amp;gt;&amp;gt; r.history
[&amp;lt;Response [301]&amp;gt;]
&lt;/code>&lt;/pre>&lt;p>如果你使用了 HEAD 方法，你也可以启用重定向：&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; r = requests.head(&amp;#39;http://github.com&amp;#39;, allow_redirects=True)
&amp;gt;&amp;gt;&amp;gt; r.url
&amp;#39;https://github.com/&amp;#39;
&amp;gt;&amp;gt;&amp;gt; r.history
[&amp;lt;Response [301]&amp;gt;]
&lt;/code>&lt;/pre>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1542744095-fcf48d80b0fd?w=300"
 data-srcset="https://images.unsplash.com/photo-1542744095-fcf48d80b0fd?w=300, https://images.unsplash.com/photo-1542744095-fcf48d80b0fd?w=300 1.5x, https://images.unsplash.com/photo-1542744095-fcf48d80b0fd?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1542744095-fcf48d80b0fd?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>13. Java 文件编译方式（新用户必看）</title><link>https://itest2025.pages.dev/tutorials/37-013-13-java-%E6%96%87%E4%BB%B6%E7%BC%96%E8%AF%91%E6%96%B9%E5%BC%8F%E6%96%B0%E7%94%A8%E6%88%B7%E5%BF%85%E7%9C%8B/</link><pubDate>Mon, 16 Oct 2017 00:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/37-013-13-java-%E6%96%87%E4%BB%B6%E7%BC%96%E8%AF%91%E6%96%B9%E5%BC%8F%E6%96%B0%E7%94%A8%E6%88%B7%E5%BF%85%E7%9C%8B/</guid><description>&lt;h1 id="intellij-idea-编译方式介绍">IntelliJ IDEA 编译方式介绍&lt;/h1>
&lt;h2 id="编译方式介绍">编译方式介绍&lt;/h2>
&lt;p>相比较于 Eclipse 的实时自动编译，IntelliJ IDEA 的编译更加手动化，虽然 IntelliJ IDEA 也支持通过设置开启实时编译，但是不建议，因为太占资源了。IntelliJ IDEA 编译方式除了手工点击编译按钮进行编译之外，还有就是在容器运行之前配置上一个编译事件，先编译后运行。默认下 IntelliJ IDEA 也都是这样的设置，所以实际开发中你也不用太注意编译这件事。虽然 IntelliJ IDEA 没有实时编译，但是对于代码检查完全是没有影响。但是多个类之间的关联关系还是要等 Make 或 Rebuild 触发的时候才会做相关检查的。&lt;/p>
&lt;p>在 IntelliJ IDEA 里，编译方式一共有三种：&lt;/p>
&lt;blockquote>
&lt;ul>
&lt;li>Compile：对选定的目标（Java 类文件），进行强制性编译，不管目标是否是被修改过。&lt;/li>
&lt;li>Rebuild：对选定的目标（Project），进行强制性编译，不管目标是否是被修改过，由于 Rebuild 的目标只有 Project，所以 Rebuild 每次花的时间会比较长。&lt;/li>
&lt;li>Make：使用最多的编译操作。对选定的目标（Project 或 Module）进行编译，但只编译有修改过的文件，没有修改过的文件不会编译，这样平时开发大型项目才不会浪费时间在编译过程中。&lt;/li>
&lt;/ul>&lt;/blockquote>
&lt;h2 id="编译触发按钮">编译触发按钮&lt;/h2>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/xiii-a-make-introduce-1.jpg"
 data-srcset="http://img.testclass.net/xiii-a-make-introduce-1.jpg, http://img.testclass.net/xiii-a-make-introduce-1.jpg 1.5x, http://img.testclass.net/xiii-a-make-introduce-1.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/xiii-a-make-introduce-1.jpg"
 title="IntelliJ IDEA 编译触发按钮" />&lt;/p>
&lt;blockquote>
&lt;ul>
&lt;li>如上图标注 1 所示，Compile 的操作有：&lt;code>Compile&lt;/code> 指定类&lt;/li>
&lt;li>如上图标注 1 所示，Rebuild 的操作有：&lt;code>Rebuild Project&lt;/code>&lt;/li>
&lt;li>如上图标注 1 所示，Make 的操作有：&lt;code>Make Project&lt;/code>、&lt;code>Make Module&lt;/code>&lt;/li>
&lt;/ul>&lt;/blockquote>
&lt;h2 id="运行之前的编译">运行之前的编译&lt;/h2>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/xiii-b-befour-launch-1.jpg"
 data-srcset="http://img.testclass.net/xiii-b-befour-launch-1.jpg, http://img.testclass.net/xiii-b-befour-launch-1.jpg 1.5x, http://img.testclass.net/xiii-b-befour-launch-1.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/xiii-b-befour-launch-1.jpg"
 title="IntelliJ IDEA 运行之前的编译" />&lt;/p></description></item><item><title>appium新手入门（13）—— appium API 之其他操作</title><link>https://itest2025.pages.dev/tutorials/21-013-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A813-appium-api-%E4%B9%8B%E5%85%B6%E4%BB%96%E6%93%8D%E4%BD%9C/</link><pubDate>Thu, 07 Sep 2017 10:01:12 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/21-013-appium%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A813-appium-api-%E4%B9%8B%E5%85%B6%E4%BB%96%E6%93%8D%E4%BD%9C/</guid><description>&lt;p>其它操作针对移动设备上特有的一些操作。&lt;/p>
&lt;h4 id="1熄屏">1、熄屏&lt;/h4>
&lt;hr>
&lt;p>方法：&lt;/p>
&lt;ul>
&lt;li>lockDevice()&lt;/li>
&lt;/ul>
&lt;p>点击电源键熄灭屏幕。&lt;/p>
&lt;p>在iOS设备可以设置熄屏一段时间。Android上面不带参数，所以熄屏之后就不会再点亮屏幕了。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">lockDevice&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">1000&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// iOS&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">lockDriice&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//Android &lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="2当前activityandroid-only">2、当前Activity（Android only）&lt;/h4>
&lt;hr>
&lt;p>方法：&lt;/p>
&lt;ul>
&lt;li>currentActivity()&lt;/li>
&lt;/ul>
&lt;p>得到当前应用的activity。只适用于Android。
例（通讯录）：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ca&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">currentActivity&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ca&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="o">-------------&lt;/span>&lt;span class="n">输出结果为&lt;/span>&lt;span class="o">-------------&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">activities&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">PeopleActivity&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="3收起键盘">3、收起键盘&lt;/h3>
&lt;hr>
&lt;p>方法：&lt;/p>
&lt;ul>
&lt;li>hideKeyboard()&lt;/li>
&lt;/ul>
&lt;p>收起键盘，这个方法很有用，当我们对一个输入框输入完成后，需要将键盘收起，再切换到一下输入框进行输入。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">hideKeyboard&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">//收起键盘&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="4滑动">4、滑动&lt;/h4>
&lt;hr>
&lt;p>方法：&lt;/p>
&lt;ul>
&lt;li>swipe()&lt;/li>
&lt;/ul>
&lt;p>模拟用户滑动。将控件或元素从一个位置（x,y）拖动到另一个位置（x,y）。&lt;/p>
&lt;p>&lt;strong>swipe(int startx, int starty, int endx, int endy, int duration)&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>start_x：开始滑动的x坐标。&lt;/li>
&lt;li>start_y：开始滑动的y坐标。&lt;/li>
&lt;li>end_x：结束滑动的x坐标。&lt;/li>
&lt;li>end_y：结束滑动的y坐标。&lt;/li>
&lt;li>duration：持续时间。&lt;/li>
&lt;/ul>
&lt;p>例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">swipe&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">75&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">500&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">75&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">0&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">800&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="5拉出文件">5、拉出文件&lt;/h4>
&lt;hr>
&lt;p>方法：&lt;/p>
&lt;ul>
&lt;li>pullFile()&lt;/li>
&lt;/ul>
&lt;p>从设备中拉出文件。&lt;/p>
&lt;p>例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">pullFile&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Library&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">AddressBook&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">AddressBook&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sqlitedb&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="6推送文件">6、推送文件&lt;/h4>
&lt;hr>
&lt;p>方法：&lt;/p>
&lt;ul>
&lt;li>pushFile()&lt;/li>
&lt;/ul>
&lt;p>推送文件到设备中去。&lt;/p>
&lt;p>&lt;strong>pushFile(String remotePath, byte[] base64Data)&lt;/strong>&lt;/p></description></item><item><title>性能测试流程（八）——性能调优</title><link>https://itest2025.pages.dev/tutorials/14-013-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E6%B5%81%E7%A8%8B%E5%85%AB%E6%80%A7%E8%83%BD%E8%B0%83%E4%BC%98/</link><pubDate>Fri, 11 Aug 2017 01:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/14-013-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E6%B5%81%E7%A8%8B%E5%85%AB%E6%80%A7%E8%83%BD%E8%B0%83%E4%BC%98/</guid><description>&lt;br>
![](http://img.testclass.net/tuning.jpg)
&lt;h4 id="一般系统的瓶颈">一般系统的瓶颈&lt;/h4>
&lt;hr>
&lt;p>性能测试调优需要先发现瓶颈，那么系统一般会存在哪些瓶颈：&lt;/p>
&lt;p>&lt;strong>硬件上的性能瓶颈：&lt;/strong>&lt;/p>
&lt;p>一般指的是CPU、内存、磁盘I/O 方面的问题，分为服务器硬件瓶颈、网络瓶颈（对局域网可以不考虑）、服务器操作系统瓶颈（参数配置）、中间件瓶颈（参数配置、数据库、web服务器等）、应用瓶颈（SQL 语句、数据库设计、业务逻辑、算法等）。&lt;/p>
&lt;p>&lt;strong>应用软件上的性能瓶颈：&lt;/strong>&lt;/p>
&lt;p>一般指的是应用服务器、web 服务器等应用软件，还包括数据库系统。&lt;/p>
&lt;p>例如：中间件weblogic 平台上配置的JDBC连接池的参数设置不合理，造成的瓶颈。&lt;/p>
&lt;p>&lt;strong>应用程序上的性能瓶颈：&lt;/strong>&lt;/p>
&lt;p>一般指的是开发人员新开发出来的应用程序。&lt;/p>
&lt;p>例如，程序架构规划不合理，程序本身设计有问题（串行处理、请求的处理线程不够），造成系统在大量用户访问时性能低下而造成的瓶颈。&lt;/p>
&lt;p>&lt;strong>操作系统上的性能瓶颈：&lt;/strong>&lt;/p>
&lt;p>一般指的是windows、UNIX、Linux等操作系统。&lt;/p>
&lt;p>例如，在进行性能测试，出现物理内存不足时，虚拟内存设置也不合理，虚拟内存的交换效率就会大大降低，从而导致行为的响应时间大大增加，这时认为操作系统上出现性能瓶颈。&lt;/p>
&lt;p>&lt;strong>网络设备上的性能瓶颈：&lt;/strong>&lt;/p>
&lt;p>一般指的是防火墙、动态负载均衡器、交换机等设备。&lt;/p>
&lt;p>例如，在动态负载均衡器上设置了动态分发负载的机制，当发现某个应用服务器上的硬件资源已经到达极限时，动态负载均衡器将后续的交易请求发送到其他负载较轻的应用服务器上。在测试时发现，动态负载均衡器没有起到相应的作用，这时可以认为网络瓶颈。
 
性能测试出现的原因及其定位十分复杂，这里只是简单介绍常见的几种瓶颈类型和特征，而性能测试所需要做的就是根据各种情况因素综合考虑，然后协助开发人员\DBA\运维人员一起定位性能瓶颈。&lt;/p>
&lt;br>
#### 一般性能调优步骤                                                                                      
---
&lt;p>&lt;strong>步骤一：确定问题&lt;/strong>&lt;/p>
&lt;p>应用程序代码：在通常情况下，很多程序的性能问题都是写出来的，因此对于发现瓶颈的模块，应该首先检查一下代码。&lt;/p>
&lt;p>数据库配置：经常引起整个系统运行缓慢，一些诸如oracle 的大型数据库都是需要DBA进行正确的参数调整才能投产的。&lt;/p>
&lt;p>操作系统配置：不合理就可能引起系统瓶颈。&lt;/p>
&lt;p>硬件设置：硬盘速度、内存大小等都是容易引起瓶颈的原因，因此这些都是分析的重点。&lt;/p>
&lt;p>网络：网络负载过重导致网络冲突和网络延迟。&lt;/p>
&lt;p>&lt;strong>步骤二：分析问题&lt;/strong>&lt;/p>
&lt;p>当确定了问题之后，我们要明确这个问题影响的是响应时间吞吐量，还是其他问题？是多数用户还是少数用户遇到了问题？如果是少数用户，这几个用户与其它用户的操作有什么不用？系统资源监控的结果是否正常？CPU的使用是否到达极限？I/O 情况如何？问题是否集中在某一类模块中？ 是客户端还是服务器出现问题？ 系统硬件配置是否够用？实际负载是否超过了系统的负载能力？ 是否未对系统进行优化？&lt;/p>
&lt;p>通过这些分析及一些与系统相关的问题，可以对系统瓶颈有更深入的了解，进而分析出真正的原因。&lt;/p>
&lt;p>&lt;strong>步骤三： 确定调整目标和解决方案&lt;/strong>&lt;/p>
&lt;p>得高系统吞吐量，缩短响应时间，更好地支持并发。&lt;/p>
&lt;p>&lt;strong>步骤四：测试解决方案&lt;/strong>&lt;/p>
&lt;p>对通过解决方案调优后的系统进行基准测试。（基准测试是指通过设计科学的测试方法、测试工具和测试系统，实现对一类测试对象的某项性能指标进行定量的和可对比的测试）&lt;/p>
&lt;p>&lt;strong>步骤五：分析调优结果&lt;/strong>&lt;/p>
&lt;p>系统调优是否达到或者超出了预定目标？系统是整体性能得到了改善，还是以系统某部分性能来解决其他问题。调优是否可以结束了。&lt;/p>
&lt;p>最后，如果达到了预期目标，调优工作就基本可以结束了。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1454793147212-9e7e57e89a4f?w=300"
 data-srcset="https://images.unsplash.com/photo-1454793147212-9e7e57e89a4f?w=300, https://images.unsplash.com/photo-1454793147212-9e7e57e89a4f?w=300 1.5x, https://images.unsplash.com/photo-1454793147212-9e7e57e89a4f?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1454793147212-9e7e57e89a4f?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（十三）切换frame</title><link>https://itest2025.pages.dev/tutorials/20-013-%E5%8D%81%E4%B8%89%E5%88%87%E6%8D%A2frame/</link><pubDate>Tue, 01 Aug 2017 07:27:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/20-013-%E5%8D%81%E4%B8%89%E5%88%87%E6%8D%A2frame/</guid><description>&lt;h3 id="为什么要切换">为什么要切换&lt;/h3>
&lt;p>当我们要定位的元素位于页面中的iframe或frame标签中时，我们必须将定位的上下文切换到对应的frame中去，否则我们将没有办法定位到frame中的元素，这是套路，可以先无脑记住。&lt;/p>
&lt;h3 id="目的">目的&lt;/h3>
&lt;p>学会使用switchTo().frame(id)方法&lt;/p>
&lt;h3 id="switchtoframeid方法详解">switchTo().frame(id)方法详解&lt;/h3>
&lt;ul>
&lt;li>id可以是1个数字，从0开始。switchTo().frame(0)表示切换到页面上的第1个frame，依此类推;&lt;/li>
&lt;li>id也可以是1个WebElement对象，也就是需要切换到的frame;&lt;/li>
&lt;li>id可以是null，等于是调用了switchTo().defaultContent()方法;&lt;/li>
&lt;/ul>
&lt;h3 id="switchtodefaultcontent方法">switchTo().defaultContent()方法&lt;/h3>
&lt;p>切换回到主页面，调用这个方法会将定位的上下文切回主页面，此后就可以继续定位主页面上的元素了。&lt;/p>
&lt;h3 id="示例代码">示例代码&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">webdriver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;selenium-webdriver&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">By&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">dr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Builder&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">forBrowser&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;chrome&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">build&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;some url&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 切换到第2个frame进行元素定位
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">switchTo&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">frame&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">then&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;this-element-is-in-frame&amp;#39;&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 切换到第id==example-frame的frame中进行元素定位
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;example-frame&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">then&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">iframe&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">switchTo&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">frame&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">iframe&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">then&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;this-element-is-in-frame&amp;#39;&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 切换回主页面
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">switchTo&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">defaultContent&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1502481851512-e9e2529bfbf9?w=300"
 data-srcset="https://images.unsplash.com/photo-1502481851512-e9e2529bfbf9?w=300, https://images.unsplash.com/photo-1502481851512-e9e2529bfbf9?w=300 1.5x, https://images.unsplash.com/photo-1502481851512-e9e2529bfbf9?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1502481851512-e9e2529bfbf9?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>13. 函数与文件</title><link>https://itest2025.pages.dev/tutorials/28-013-13-%E5%87%BD%E6%95%B0%E4%B8%8E%E6%96%87%E4%BB%B6/</link><pubDate>Tue, 27 Jun 2017 08:17:22 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/28-013-13-%E5%87%BD%E6%95%B0%E4%B8%8E%E6%96%87%E4%BB%B6/</guid><description>&lt;h3 id="背景">背景&lt;/h3>
&lt;p>继续通过练习来熟悉函数。&lt;/p>
&lt;p>这一节里我们将使用函数和文件的知识来重构第9节中的内容。&lt;/p>
&lt;h3 id="什么是重构">什么是重构&lt;/h3>
&lt;p>重构简单来说就是在不改变原有代码功能的情况下修改先前的代码实现。&lt;/p>
&lt;p>测试同学一般都需要对重构提高警惕，这是因为&lt;/p>
&lt;ul>
&lt;li>重构中如果没有单元测试进行辅助的话，代码可能会隐藏问题&lt;/li>
&lt;li>重构的需求往往安排较少的测试进行回归，测试力度可能不够&lt;/li>
&lt;/ul>
&lt;h3 id="利用已有的用例文件">利用已有的用例文件&lt;/h3>
&lt;p>不出意外你应该拥有名为&lt;code>case001.txt&lt;/code>的文本文件，内容如下:&lt;/p>
&lt;pre tabindex="0">&lt;code>用例编号: itest001
用例名称: 登录成功
测试数据: 用户名:example;密码:example
测试步骤: 略
测试断言: 应该可以正确跳转到www.itest.info
&lt;/code>&lt;/pre>&lt;h3 id="代码实现">代码实现&lt;/h3>
&lt;p>新建名为&lt;code>read_case01.py&lt;/code>的文件，内容如下&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">sys&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">argv&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">script&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">file_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">argv&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">read_file&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file_name&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">file_obj&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file_name&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file_obj&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">read&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">file_obj&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">close&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;读取文件: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">file_path&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">read_file&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file_path&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行">运行&lt;/h3>
&lt;p>在命令行中使用下面的命令去执行代码&lt;/p>
&lt;pre tabindex="0">&lt;code>$ python read_case01.py case001.txt
&lt;/code>&lt;/pre>&lt;h3 id="你应该可以看到">你应该可以看到&lt;/h3>
&lt;p>按照下面展示的情况进行输入，如果没有出错的话，你应该可以看到命令行窗口显示如下的内容&lt;/p>
&lt;pre tabindex="0">&lt;code>读取文件: case001.txt

用例编号: itest001
用例名称: 登录成功
测试数据: 用户名:example;密码:example
测试步骤: 略
测试断言: 应该可以正确跳转到www.itest.info
&lt;/code>&lt;/pre>&lt;h3 id="动手时间">动手时间&lt;/h3>
&lt;ul>
&lt;li>如果要求你不能在&lt;code>read_file&lt;/code>中进行打印，要完成上面的内容，你应该怎么做？&lt;/li>
&lt;li>搜索一下什么是函数的返回值，了解一下基本概念&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1523289333742-be1143f6b766?w=300"
 data-srcset="https://images.unsplash.com/photo-1523289333742-be1143f6b766?w=300, https://images.unsplash.com/photo-1523289333742-be1143f6b766?w=300 1.5x, https://images.unsplash.com/photo-1523289333742-be1143f6b766?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1523289333742-be1143f6b766?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（十三）多表单切换</title><link>https://itest2025.pages.dev/tutorials/19-013-%E5%8D%81%E4%B8%89%E5%A4%9A%E8%A1%A8%E5%8D%95%E5%88%87%E6%8D%A2/</link><pubDate>Tue, 27 Jun 2017 07:37:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/19-013-%E5%8D%81%E4%B8%89%E5%A4%9A%E8%A1%A8%E5%8D%95%E5%88%87%E6%8D%A2/</guid><description>&lt;br>
在 Web 应用中经常会遇到 frame/iframe 表单嵌套页面的应用， WebDriver 只能在一个页面上对元素识别与
定位， 对于 frame/iframe 表单内嵌页面上的元素无法直接定位。 这时就需要通过 switchTo().frame()方法将当前定
位的主体切换为 frame/iframe 表单的内嵌页面中。
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">html&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">body&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">iframe&lt;/span> &lt;span class="na">id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;x-URS-iframe&amp;#34;&lt;/span> &lt;span class="err">...&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">html&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">body&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">input&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;email&amp;#34;&lt;/span> &lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>126邮箱登录框的结构大概是这样子的，想要操作登录框必须要先切换到iframe表单。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.By&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.WebDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.WebElement&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.chrome.ChromeDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">MailLogin&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ChromeDriver&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;http://www.126.com&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebElement&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">xf&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">xpath&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;//*[@id=&amp;#39;loginDiv&amp;#39;]/iframe&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">switchTo&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="na">frame&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">xf&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;email&amp;#34;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">clear&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;email&amp;#34;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;username&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;password&amp;#34;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">clear&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;password&amp;#34;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;password&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;dologin&amp;#34;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">click&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">switchTo&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="na">defaultContent&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//……&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果完成了在当前表单上的操作，则可以通过switchTo().defaultContent()方法跳出表单。&lt;/p></description></item><item><title>（十三）警告框处理</title><link>https://itest2025.pages.dev/tutorials/24-013-%E5%8D%81%E4%B8%89%E8%AD%A6%E5%91%8A%E6%A1%86%E5%A4%84%E7%90%86/</link><pubDate>Sun, 18 Jun 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/24-013-%E5%8D%81%E4%B8%89%E8%AD%A6%E5%91%8A%E6%A1%86%E5%A4%84%E7%90%86/</guid><description>&lt;br>
在WebDriver中处理JavaScript所生成的alert、confirm以及prompt十分简单，具体做法是使用 switch_to.alert 方法定位到 alert/confirm/prompt，然后使用text/accept/dismiss/ send_keys等方法进行操作。
&lt;ul>
&lt;li>
&lt;p>text：返回 alert/confirm/prompt 中的文字信息。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>accept()：接受现有警告框。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>dismiss()：解散现有警告框。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>send_keys(keysToSend)：发送文本至警告框。keysToSend：将文本发送至警告框。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>如下图，百度搜索设置弹出的窗口是不能通过前端工具对其进行定位的，这个时候就可以通过switch_to_alert()方法接受这个弹窗。
&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://orru5lls3.bkt.clouddn.com/alert_windows.png"
 data-srcset="http://orru5lls3.bkt.clouddn.com/alert_windows.png, http://orru5lls3.bkt.clouddn.com/alert_windows.png 1.5x, http://orru5lls3.bkt.clouddn.com/alert_windows.png 2x"
 data-sizes="auto"
 alt="http://orru5lls3.bkt.clouddn.com/alert_windows.png"
 title="http://orru5lls3.bkt.clouddn.com/alert_windows.png" />&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">webdriver&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium.webdriver.common.action_chains&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">ActionChains&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">time&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">webdriver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Firefox&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">implicitly_wait&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;http://www.baidu.com&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 鼠标悬停至“设置”链接&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">link&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_element_by_link_text&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;设置&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">ActionChains&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">move_to_element&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">link&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">perform&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 打开搜索设置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_element_by_link_text&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;搜索设置&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">click&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 保存设置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_element_by_class_name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;prefpanelgo&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">click&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 接受警告框&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">switch_to&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">alert&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">accept&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">quit&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>通过switch_to_alert()方法获取当前页面上的警告框，并使用accept()方法接受警告框。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1459213599465-03ab6a4d5931?w=300"
 data-srcset="https://images.unsplash.com/photo-1459213599465-03ab6a4d5931?w=300, https://images.unsplash.com/photo-1459213599465-03ab6a4d5931?w=300 1.5x, https://images.unsplash.com/photo-1459213599465-03ab6a4d5931?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1459213599465-03ab6a4d5931?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（十四）Docker Machine基本使用</title><link>https://itest2025.pages.dev/tutorials/30-014-%E5%8D%81%E5%9B%9Bdocker-machine%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8/</link><pubDate>Mon, 22 Jan 2018 14:18:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/30-014-%E5%8D%81%E5%9B%9Bdocker-machine%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8/</guid><description>&lt;p>这一小节演示Machine的基本使用。&lt;/p>
&lt;p>以 &lt;strong>macOS&lt;/strong> 系统为例：&lt;/p>
&lt;h5 id="创建一个machine">创建一个machine&lt;/h5>
&lt;p>指令：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="err">$&lt;/span> &lt;span class="n">docker&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">machine&lt;/span> &lt;span class="n">create&lt;/span> &lt;span class="o">--&lt;/span>&lt;span class="n">driver&lt;/span> &lt;span class="n">virtualbox&lt;/span> &lt;span class="n">my&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">machine&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Creating&lt;/span> &lt;span class="n">CA&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="o">/&lt;/span>&lt;span class="n">Users&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">fnngj&lt;/span>&lt;span class="o">/.&lt;/span>&lt;span class="n">docker&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">machine&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">certs&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">ca&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pem&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Creating&lt;/span> &lt;span class="n">client&lt;/span> &lt;span class="n">certificate&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="o">/&lt;/span>&lt;span class="n">Users&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">fnngj&lt;/span>&lt;span class="o">/.&lt;/span>&lt;span class="n">docker&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">machine&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">certs&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">cert&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pem&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Running&lt;/span> &lt;span class="n">pre&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">create&lt;/span> &lt;span class="n">checks&lt;/span>&lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Creating&lt;/span> &lt;span class="n">machine&lt;/span>&lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="n">my&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">machine&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">Copying&lt;/span> &lt;span class="o">/&lt;/span>&lt;span class="n">Users&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">fnngj&lt;/span>&lt;span class="o">/.&lt;/span>&lt;span class="n">docker&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">machine&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">cache&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">boot2docker&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">iso&lt;/span> &lt;span class="n">to&lt;/span> &lt;span class="o">/&lt;/span>&lt;span class="n">Users&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">fnngj&lt;/span>&lt;span class="o">/.&lt;/span>&lt;span class="n">docker&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">machine&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">machines&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">my&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">machine&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">boot2docker&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">iso&lt;/span>&lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="n">my&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">machine&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">Creating&lt;/span> &lt;span class="n">VirtualBox&lt;/span> &lt;span class="n">VM&lt;/span>&lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="n">my&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">machine&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">Creating&lt;/span> &lt;span class="n">SSH&lt;/span> &lt;span class="n">key&lt;/span>&lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="n">my&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">machine&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">Starting&lt;/span> &lt;span class="n">the&lt;/span> &lt;span class="n">VM&lt;/span>&lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="n">my&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">machine&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">Check&lt;/span> &lt;span class="n">network&lt;/span> &lt;span class="n">to&lt;/span> &lt;span class="n">re&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">create&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="n">needed&lt;/span>&lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="n">my&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">machine&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">Found&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="n">new&lt;/span> &lt;span class="n">host&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">only&lt;/span> &lt;span class="n">adapter&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;vboxnet0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="n">my&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">machine&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">Waiting&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">an&lt;/span> &lt;span class="n">IP&lt;/span>&lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Waiting&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">machine&lt;/span> &lt;span class="n">to&lt;/span> &lt;span class="n">be&lt;/span> &lt;span class="n">running&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">this&lt;/span> &lt;span class="n">may&lt;/span> &lt;span class="n">take&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="n">few&lt;/span> &lt;span class="n">minutes&lt;/span>&lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Detecting&lt;/span> &lt;span class="n">operating&lt;/span> &lt;span class="n">system&lt;/span> &lt;span class="n">of&lt;/span> &lt;span class="n">created&lt;/span> &lt;span class="n">instance&lt;/span>&lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Waiting&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">SSH&lt;/span> &lt;span class="n">to&lt;/span> &lt;span class="n">be&lt;/span> &lt;span class="n">available&lt;/span>&lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Detecting&lt;/span> &lt;span class="n">the&lt;/span> &lt;span class="n">provisioner&lt;/span>&lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Provisioning&lt;/span> &lt;span class="k">with&lt;/span> &lt;span class="n">boot2docker&lt;/span>&lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Copying&lt;/span> &lt;span class="n">certs&lt;/span> &lt;span class="n">to&lt;/span> &lt;span class="n">the&lt;/span> &lt;span class="n">local&lt;/span> &lt;span class="n">machine&lt;/span> &lt;span class="n">directory&lt;/span>&lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Copying&lt;/span> &lt;span class="n">certs&lt;/span> &lt;span class="n">to&lt;/span> &lt;span class="n">the&lt;/span> &lt;span class="n">remote&lt;/span> &lt;span class="n">machine&lt;/span>&lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Setting&lt;/span> &lt;span class="n">Docker&lt;/span> &lt;span class="n">configuration&lt;/span> &lt;span class="n">on&lt;/span> &lt;span class="n">the&lt;/span> &lt;span class="n">remote&lt;/span> &lt;span class="n">daemon&lt;/span>&lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Checking&lt;/span> &lt;span class="n">connection&lt;/span> &lt;span class="n">to&lt;/span> &lt;span class="n">Docker&lt;/span>&lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Docker&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="n">up&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="n">running&lt;/span>&lt;span class="err">!&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">To&lt;/span> &lt;span class="n">see&lt;/span> &lt;span class="n">how&lt;/span> &lt;span class="n">to&lt;/span> &lt;span class="n">connect&lt;/span> &lt;span class="n">your&lt;/span> &lt;span class="n">Docker&lt;/span> &lt;span class="n">Client&lt;/span> &lt;span class="n">to&lt;/span> &lt;span class="n">the&lt;/span> &lt;span class="n">Docker&lt;/span> &lt;span class="n">Engine&lt;/span> &lt;span class="n">running&lt;/span> &lt;span class="n">on&lt;/span> &lt;span class="n">this&lt;/span> &lt;span class="n">virtual&lt;/span> &lt;span class="n">machine&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">run&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">docker&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">machine&lt;/span> &lt;span class="n">env&lt;/span> &lt;span class="n">my&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">machine&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="查看machine列表">查看machine列表&lt;/h4>
&lt;p>指令：&lt;/p>
&lt;pre tabindex="0">&lt;code>$ docker-machine ls

NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
my-machine - virtualbox Running tcp://192.168.99.100:2376 v18.01.0-ce 
&lt;/code>&lt;/pre>&lt;p>可以看到我们刚创建的“my-machine”已出现在 machine 的列表当中。&lt;/p>
&lt;h4 id="查看-machine-的环境变量的配置信息">查看 machine 的环境变量的配置信息。&lt;/h4>
&lt;p>指令：&lt;/p>
&lt;pre tabindex="0">&lt;code>$ docker-machine env my-machine

export DOCKER_TLS_VERIFY=&amp;#34;1&amp;#34;
export DOCKER_HOST=&amp;#34;tcp://192.168.99.100:2376&amp;#34;
export DOCKER_CERT_PATH=&amp;#34;/Users/fnngj/.docker/machine/machines/my-machine&amp;#34;
export DOCKER_MACHINE_NAME=&amp;#34;my-machine&amp;#34;
# Run this command to configure your shell:
# eval $(docker-machine env my-machine)
&lt;/code>&lt;/pre>&lt;h4 id="连接到machine的shell">连接到machine的shell。&lt;/h4>
&lt;p>指令：&lt;/p></description></item><item><title>requests如何处理二进制的响应内容？</title><link>https://itest2025.pages.dev/tutorials/42-014-requests%E5%A6%82%E4%BD%95%E5%A4%84%E7%90%86%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%9A%84%E5%93%8D%E5%BA%94%E5%86%85%E5%AE%B9/</link><pubDate>Wed, 22 Nov 2017 03:23:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/42-014-requests%E5%A6%82%E4%BD%95%E5%A4%84%E7%90%86%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%9A%84%E5%93%8D%E5%BA%94%E5%86%85%E5%AE%B9/</guid><description>&lt;p>&lt;a href="http://docs.python-requests.org/en/master/user/quickstart/#binary-response-content" target="_blank" rel="noopener noreffer ">官方文档&lt;/a>&lt;/p>
&lt;p>有时候服务器返回的数据不是文本的，而是二进制的，这时候我们就需要处理二进制的内容。&lt;/p>
&lt;p>Requests中可以使用content方法来返回二进制的响应内容，比如&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; r.content
b&amp;#39;[{&amp;#34;repository&amp;#34;:{&amp;#34;open_issues&amp;#34;:0,&amp;#34;url&amp;#34;:&amp;#34;https://github.com/...
&lt;/code>&lt;/pre>&lt;p>如果响应是gzip压缩过的，Requests会自动解压。&lt;/p>
&lt;p>下面这个例子演示了如何从服务器返回的二进制内容创建图片。&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; from PIL import Image
&amp;gt;&amp;gt;&amp;gt; from io import BytesIO

&amp;gt;&amp;gt;&amp;gt; i = Image.open(BytesIO(r.content))
&lt;/code>&lt;/pre>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1501556466850-7c9fa1fccb4c?w=300"
 data-srcset="https://images.unsplash.com/photo-1501556466850-7c9fa1fccb4c?w=300, https://images.unsplash.com/photo-1501556466850-7c9fa1fccb4c?w=300 1.5x, https://images.unsplash.com/photo-1501556466850-7c9fa1fccb4c?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1501556466850-7c9fa1fccb4c?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>14. 项目相关概念（新用户必看）</title><link>https://itest2025.pages.dev/tutorials/37-014-14-%E9%A1%B9%E7%9B%AE%E7%9B%B8%E5%85%B3%E6%A6%82%E5%BF%B5%E6%96%B0%E7%94%A8%E6%88%B7%E5%BF%85%E7%9C%8B/</link><pubDate>Sun, 15 Oct 2017 23:00:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/37-014-14-%E9%A1%B9%E7%9B%AE%E7%9B%B8%E5%85%B3%E6%A6%82%E5%BF%B5%E6%96%B0%E7%94%A8%E6%88%B7%E5%BF%85%E7%9C%8B/</guid><description>&lt;h1 id="intellij-idea-项目相关的几个重要概念介绍">IntelliJ IDEA 项目相关的几个重要概念介绍&lt;/h1>
&lt;h2 id="必备材料介绍">必备材料介绍&lt;/h2>
&lt;blockquote>
&lt;ul>
&lt;li>IntelliJ IDEA 对其他 IDE 转过来的用户有特别优待，对其专门整理了非常棒的资料，还请其他 IDE 过来的用户抽时间查看，会有很大帮助：&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;ul>
&lt;li>Eclipse 用户可以看：&lt;a href="https://www.jetbrains.com/idea/help/eclipse.html" target="_blank" rel="noopener noreffer ">https://www.jetbrains.com/idea/help/eclipse.html&lt;/a>&lt;/li>
&lt;li>NetBeans 用户可以看：&lt;a href="https://www.jetbrains.com/idea/help/netbeans.html" target="_blank" rel="noopener noreffer ">https://www.jetbrains.com/idea/help/netbeans.html&lt;/a>&lt;/li>
&lt;/ul>&lt;/blockquote>&lt;/blockquote>
&lt;h2 id="project-和-module-介绍">Project 和 Module 介绍&lt;/h2>
&lt;p>这两个概念是 IntelliJ IDEA 的必懂知识点之一，请务必要学会。&lt;/p>
&lt;p>如果你是 Eclipse 用户，并且已经看了上面给的链接，那 IntelliJ IDEA 首先告诉你一个非常重要的事情：IntelliJ IDEA 没有类似 Eclipse 工作空间（workspace）的概念的。很多从 Eclipse 转过来的人总是下意识地要再同一个窗口管理 n 个项目，这在 IntelliJ IDEA 是无法得到。IntelliJ IDEA 提供的体验是：一个 Project 打开一个 Window 窗口。&lt;/p>
&lt;p>对于 Project，IntelliJ IDEA 是这样解释的：&lt;/p>
&lt;blockquote>
&lt;ul>
&lt;li>Whatever you do in IntelliJ IDEA, you do that in the context of a project. A project is an organizational unit that represents a complete software solution. It serves as a basis for coding assistance, bulk refactoring, coding style consistency, etc.&lt;/li>
&lt;li>Your finished product may be decomposed into a series of discrete, isolated modules, but it&amp;rsquo;s a project definition that brings them together and ties them into a greater whole.&lt;/li>
&lt;li>Projects don&amp;rsquo;t themselves contain development artifacts such as source code, build scripts, or documentation. They are the highest level of organization in the IDE, and they define project-wide settings as well as collections of what IntelliJ IDEA refers to as modules and libraries.&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;ul>
&lt;li>20170630 更新新地址：&lt;a href="https://www.jetbrains.com/help/idea/about-projects.html" target="_blank" rel="noopener noreffer ">https://www.jetbrains.com/help/idea/about-projects.html&lt;/a>&lt;/li>
&lt;/ul>&lt;/blockquote>&lt;/blockquote>
&lt;p>对于 Module，IntelliJ IDEA 是这样解释的：&lt;/p></description></item><item><title>（十四）处理下拉列表 select</title><link>https://itest2025.pages.dev/tutorials/20-014-%E5%8D%81%E5%9B%9B%E5%A4%84%E7%90%86%E4%B8%8B%E6%8B%89%E5%88%97%E8%A1%A8-select/</link><pubDate>Tue, 01 Aug 2017 01:49:18 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/20-014-%E5%8D%81%E5%9B%9B%E5%A4%84%E7%90%86%E4%B8%8B%E6%8B%89%E5%88%97%E8%A1%A8-select/</guid><description>&lt;h3 id="什么是下拉列表">什么是下拉列表&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">select&lt;/span> &lt;span class="na">id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;select&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">optgroup&lt;/span> &lt;span class="na">label&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;Option Group&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">option&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Option One&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">option&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">option&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Option Two&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">option&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">option&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Option Three&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">option&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">optgroup&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">select&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>下拉列表的标签是select，如上所示，其中&lt;/p>
&lt;ul>
&lt;li>select表示下拉列表&lt;/li>
&lt;li>option表示列表里的子项&lt;/li>
&lt;/ul>
&lt;p>上面的html里，这个下拉列表中一共有3项，分别是Option One, Option Two和Option Three。&lt;/p>
&lt;h3 id="目的">目的&lt;/h3>
&lt;ul>
&lt;li>学会选择下拉列表里的特定项目&lt;/li>
&lt;li>学会使用层级定位&lt;/li>
&lt;/ul>
&lt;h3 id="场景">场景&lt;/h3>
&lt;p>选择上面html代码所示的下拉列表的最后一项，也就是Option Three。&lt;/p>
&lt;h3 id="代码">代码&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;path&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">webdriver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;selenium-webdriver&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">By&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">testFile&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;file://&amp;#34;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="nx">path&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">__dirname&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;index.html&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">dr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Builder&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">forBrowser&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;chrome&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">build&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">testFile&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;select&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">then&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">select&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElements&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">css&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;option&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">then&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">options&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">options&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nx">options&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">length&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">].&lt;/span>&lt;span class="nx">click&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行结果">运行结果&lt;/h3>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://wx4.sinaimg.cn/mw1024/726a2979gy1fhp1kxp8qdj20f606kaa6.jpg"
 data-srcset="http://wx4.sinaimg.cn/mw1024/726a2979gy1fhp1kxp8qdj20f606kaa6.jpg, http://wx4.sinaimg.cn/mw1024/726a2979gy1fhp1kxp8qdj20f606kaa6.jpg 1.5x, http://wx4.sinaimg.cn/mw1024/726a2979gy1fhp1kxp8qdj20f606kaa6.jpg 2x"
 data-sizes="auto"
 alt="http://wx4.sinaimg.cn/mw1024/726a2979gy1fhp1kxp8qdj20f606kaa6.jpg"
 title="http://wx4.sinaimg.cn/mw1024/726a2979gy1fhp1kxp8qdj20f606kaa6.jpg" />&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1450631835004-9b95ff5cd66f?w=300"
 data-srcset="https://images.unsplash.com/photo-1450631835004-9b95ff5cd66f?w=300, https://images.unsplash.com/photo-1450631835004-9b95ff5cd66f?w=300 1.5x, https://images.unsplash.com/photo-1450631835004-9b95ff5cd66f?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1450631835004-9b95ff5cd66f?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（十四）多窗口切换</title><link>https://itest2025.pages.dev/tutorials/19-014-%E5%8D%81%E5%9B%9B%E5%A4%9A%E7%AA%97%E5%8F%A3%E5%88%87%E6%8D%A2/</link><pubDate>Tue, 27 Jun 2017 07:37:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/19-014-%E5%8D%81%E5%9B%9B%E5%A4%9A%E7%AA%97%E5%8F%A3%E5%88%87%E6%8D%A2/</guid><description>&lt;br>
在页面操作过程中有时候点击某个链接会弹出新的窗口， 这时就需要主机切换到新打开的窗口上进行操作。WebDriver提供了switchTo().window()方法可以实现在不同的窗口之间切换。
&lt;p>以百度首页和百度注册页为例，在两个窗口之间的切换如下图。
&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://orru5lls3.bkt.clouddn.com/more_windows_n.png"
 data-srcset="http://orru5lls3.bkt.clouddn.com/more_windows_n.png, http://orru5lls3.bkt.clouddn.com/more_windows_n.png 1.5x, http://orru5lls3.bkt.clouddn.com/more_windows_n.png 2x"
 data-sizes="auto"
 alt="http://orru5lls3.bkt.clouddn.com/more_windows_n.png"
 title="http://orru5lls3.bkt.clouddn.com/more_windows_n.png" />&lt;/p>
&lt;p>实现窗口切换的代码如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">java.util.Set&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.By&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.WebDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.chrome.ChromeDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">MoreWindows&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">arge&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">throws&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">InterruptedException&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ChromeDriver&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;https://www.baidu.com&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//获得当前窗口句柄&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">search_handle&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">getWindowHandle&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//打开百度注册窗口&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">linkText&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;登录&amp;#34;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">click&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">3000&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">linkText&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;立即注册&amp;#34;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">click&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//获得所有窗口句柄&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Set&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">handles&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">getWindowHandles&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//判断是否为注册窗口， 并操作注册窗口上的元素&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">handle&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">handles&lt;/span>&lt;span class="p">){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">handle&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">equals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">search_handle&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">==&lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="p">){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//切换到注册页面&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">switchTo&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="na">window&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">handle&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;now register window!&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2000&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;userName&amp;#34;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">clear&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;userName&amp;#34;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;user name&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;phone&amp;#34;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">clear&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;phone&amp;#34;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;phone number&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//......&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2000&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//关闭当前窗口&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">close&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2000&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">quit&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在本例中所涉及的新方法如下：&lt;/p></description></item><item><title>（十四）下拉框选择</title><link>https://itest2025.pages.dev/tutorials/24-014-%E5%8D%81%E5%9B%9B%E4%B8%8B%E6%8B%89%E6%A1%86%E9%80%89%E6%8B%A9/</link><pubDate>Sat, 17 Jun 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/24-014-%E5%8D%81%E5%9B%9B%E4%B8%8B%E6%8B%89%E6%A1%86%E9%80%89%E6%8B%A9/</guid><description>&lt;br>
有时我们会碰到下拉框，WebDriver提供了Select类来处理下拉框。
如百度搜索设置的下拉框，如下图：
![](http://orru5lls3.bkt.clouddn.com/select.png)
```python
from selenium import webdriver
from selenium.webdriver.support.select import Select
from time import sleep
&lt;p>driver = webdriver.Chrome()
driver.implicitly_wait(10)
driver.get(&amp;lsquo;&lt;a href="http://www.baidu.com" target="_blank" rel="noopener noreffer ">http://www.baidu.com&lt;/a>&amp;rsquo;)&lt;/p>
&lt;h1 id="鼠标悬停至设置链接">鼠标悬停至“设置”链接&lt;/h1>
&lt;p>driver.find_element_by_link_text(&amp;lsquo;设置&amp;rsquo;).click()
sleep(1)&lt;/p>
&lt;h1 id="打开搜索设置">打开搜索设置&lt;/h1>
&lt;p>driver.find_element_by_link_text(&amp;ldquo;搜索设置&amp;rdquo;).click()
sleep(2)&lt;/p>
&lt;h1 id="搜索结果显示条数">搜索结果显示条数&lt;/h1>
&lt;p>sel = driver.find_element_by_xpath(&amp;quot;//select[@id=&amp;lsquo;nr&amp;rsquo;]&amp;quot;)
Select(sel).select_by_value(&amp;lsquo;50&amp;rsquo;) # 显示50条&lt;/p>
&lt;h1 id="heading">……&lt;/h1>
&lt;p>driver.quit()&lt;/p>
&lt;pre tabindex="0">&lt;code>Select类用于定位select标签。
select_by_value() 方法用于定位下接选项中的value值。




原始封面

![课程图片](https://images.unsplash.com/photo-1431887773042-803ed52bed26?w=300)
&lt;/code>&lt;/pre></description></item><item><title>requests中如何设置请求的超时时间?</title><link>https://itest2025.pages.dev/tutorials/42-015-requests%E4%B8%AD%E5%A6%82%E4%BD%95%E8%AE%BE%E7%BD%AE%E8%AF%B7%E6%B1%82%E7%9A%84%E8%B6%85%E6%97%B6%E6%97%B6%E9%97%B4/</link><pubDate>Wed, 22 Nov 2017 03:23:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/42-015-requests%E4%B8%AD%E5%A6%82%E4%BD%95%E8%AE%BE%E7%BD%AE%E8%AF%B7%E6%B1%82%E7%9A%84%E8%B6%85%E6%97%B6%E6%97%B6%E9%97%B4/</guid><description>&lt;p>使用timeout 参数可以设定等待连接的秒数，如果等待超时，Requests会抛出异常&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; requests.get(&amp;#39;http://github.com&amp;#39;, timeout=0.001)
Traceback (most recent call last):
 File &amp;#34;&amp;lt;stdin&amp;gt;&amp;#34;, line 1, in &amp;lt;module&amp;gt;
requests.exceptions.Timeout: HTTPConnectionPool(host=&amp;#39;github.com&amp;#39;, port=80): Request timed out. (timeout=0.001)
&lt;/code>&lt;/pre>&lt;p>timeout 仅对连接过程有效，与响应体的下载无关。 timeout 并不是整个下载响应的时间限制，而是如果服务器在 timeout 秒内没有应答，将会引发一个异常（更精确地说，是在 timeout 秒内没有从基础套接字上接收到任何字节的数据时)。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1498758536662-35b82cd15e29?w=300"
 data-srcset="https://images.unsplash.com/photo-1498758536662-35b82cd15e29?w=300, https://images.unsplash.com/photo-1498758536662-35b82cd15e29?w=300 1.5x, https://images.unsplash.com/photo-1498758536662-35b82cd15e29?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1498758536662-35b82cd15e29?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（十五）切换窗口(标签)</title><link>https://itest2025.pages.dev/tutorials/20-015-%E5%8D%81%E4%BA%94%E5%88%87%E6%8D%A2%E7%AA%97%E5%8F%A3%E6%A0%87%E7%AD%BE/</link><pubDate>Mon, 31 Jul 2017 23:49:18 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/20-015-%E5%8D%81%E4%BA%94%E5%88%87%E6%8D%A2%E7%AA%97%E5%8F%A3%E6%A0%87%E7%AD%BE/</guid><description>&lt;h3 id="切换窗口">切换窗口&lt;/h3>
&lt;p>有时候我们点击链接会弹出新窗口，我们需要去新窗口继续定位和操作元素，这时候就需要用到切换窗口的操作了。&lt;/p>
&lt;p>switchTo().window(name_or_handle)方法可以切换到目标窗口。&lt;/p>
&lt;p>一般来说，不建议大家直接使用上面的方法去切换，更明智的做法是获取要打开的窗口的链接，然后直接用get访问该链接，这样就不需要写切换窗口的代码了。&lt;/p>
&lt;h3 id="switchtowindowname_or_handle">switchTo().window(name_or_handle)&lt;/h3>
&lt;p>该方法的参数有可以是&lt;/p>
&lt;ul>
&lt;li>窗口的name，这是为了兼容以前的实现，至于窗口的name是什么，我不太清楚&lt;/li>
&lt;li>窗口句柄，使用driver.getAllWindowHandles()句柄就可以返回浏览器中所有的打开的标签句柄了&lt;/li>
&lt;/ul>
&lt;h3 id="目的">目的&lt;/h3>
&lt;p>学会使用switchTo().window(name_or_handle)方法&lt;/p>
&lt;h3 id="示例代码">示例代码&lt;/h3>
&lt;p>下面代码演示了如何遍历浏览器所有的标签，并逐一切换过去&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">getAllWindowHandles&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">then&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">handles&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">}{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kd">var&lt;/span> &lt;span class="nx">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="nx">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="nx">handles&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">length&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="nx">i&lt;/span>&lt;span class="o">++&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">switchTo&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nb">window&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">handles&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nx">i&lt;/span>&lt;span class="p">]);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1483356256511-b48749959172?w=300"
 data-srcset="https://images.unsplash.com/photo-1483356256511-b48749959172?w=300, https://images.unsplash.com/photo-1483356256511-b48749959172?w=300 1.5x, https://images.unsplash.com/photo-1483356256511-b48749959172?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1483356256511-b48749959172?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（十五）下拉框选择</title><link>https://itest2025.pages.dev/tutorials/19-015-%E5%8D%81%E4%BA%94%E4%B8%8B%E6%8B%89%E6%A1%86%E9%80%89%E6%8B%A9/</link><pubDate>Mon, 26 Jun 2017 07:37:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/19-015-%E5%8D%81%E4%BA%94%E4%B8%8B%E6%8B%89%E6%A1%86%E9%80%89%E6%8B%A9/</guid><description>&lt;br>
有时我们会碰到下拉框，WebDriver提供了Select类来处理下接框。
&lt;p>如百度搜索设置的下拉框，如下图：
&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://orru5lls3.bkt.clouddn.com/select.png"
 data-srcset="http://orru5lls3.bkt.clouddn.com/select.png, http://orru5lls3.bkt.clouddn.com/select.png 1.5x, http://orru5lls3.bkt.clouddn.com/select.png 2x"
 data-sizes="auto"
 alt="http://orru5lls3.bkt.clouddn.com/select.png"
 title="http://orru5lls3.bkt.clouddn.com/select.png" />
搜索下拉框实现代码如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">select&lt;/span> &lt;span class="na">id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;nr&amp;#34;&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;NR&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">option&lt;/span> &lt;span class="na">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;10&amp;#34;&lt;/span> &lt;span class="na">selected&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>每页显示 10 条&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">option&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">option&lt;/span> &lt;span class="na">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;20&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>每页显示 20 条&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">option&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">option&lt;/span> &lt;span class="na">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;50&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>每页显示 50 条&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">option&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">select&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>操作下接框代码如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.By&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.WebDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.WebElement&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.chrome.ChromeDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.support.ui.Select&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">SelectDemo&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">throws&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">InterruptedException&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ChromeDriver&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;https://www.baidu.com&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">linkText&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;设置&amp;#34;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">click&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">linkText&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;搜索设置&amp;#34;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">click&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2000&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//&amp;lt;select&amp;gt;标签的下拉框选择&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebElement&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">el&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">xpath&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;//select&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Select&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">sel&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Select&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">el&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">sel&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">selectByValue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;20&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2000&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">quit&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Select类用于定位select标签。
selectByValue()方法符用于选取&amp;lt;&lt;strong>option&lt;/strong>&amp;gt;标签的value值。&lt;/p></description></item><item><title>（十五）文件上传</title><link>https://itest2025.pages.dev/tutorials/24-015-%E5%8D%81%E4%BA%94%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0/</link><pubDate>Fri, 16 Jun 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/24-015-%E5%8D%81%E4%BA%94%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0/</guid><description>&lt;br>
对于通过input标签实现的上传功能，可以将其看作是一个输入框，即通过send_keys()指定本地文件路径的方式实现文件上传。
&lt;p>创建upfile.html文件，代码如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">html&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">head&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">http-equiv&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;content-type&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;text/html;charset=utf-8&amp;#34;&lt;/span> &lt;span class="p">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>upload_file&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">link&lt;/span> &lt;span class="na">href&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;http://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.css&amp;#34;&lt;/span> &lt;span class="na">rel&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;stylesheet&amp;#34;&lt;/span> &lt;span class="p">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">head&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">body&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">div&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;row-fluid&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">div&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;span6 well&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">h3&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>upload_file&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">h3&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	 &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">input&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;file&amp;#34;&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;file&amp;#34;&lt;/span> &lt;span class="p">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">div&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">div&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">body&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">script&lt;/span> &lt;span class="na">src&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;http://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.js&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>&lt;span class="err">&amp;lt;/scrip&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">html&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>通过浏览器打开upfile.html文件，功能如下图。
&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://orru5lls3.bkt.clouddn.com/upfile.png"
 data-srcset="http://orru5lls3.bkt.clouddn.com/upfile.png, http://orru5lls3.bkt.clouddn.com/upfile.png 1.5x, http://orru5lls3.bkt.clouddn.com/upfile.png 2x"
 data-sizes="auto"
 alt="http://orru5lls3.bkt.clouddn.com/upfile.png"
 title="http://orru5lls3.bkt.clouddn.com/upfile.png" />&lt;/p>
&lt;p>接下来通过send_keys()方法来实现文件上传。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">webdriver&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">os&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">webdriver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Firefox&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">file_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;file:///&amp;#39;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">path&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">abspath&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;upfile.html&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file_path&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 定位上传按钮，添加本地文件&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_element_by_name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;file&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">send_keys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;D:&lt;/span>&lt;span class="se">\\&lt;/span>&lt;span class="s1">upload_file.txt&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">quit&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1445964047600-cdbdb873673d?w=300"
 data-srcset="https://images.unsplash.com/photo-1445964047600-cdbdb873673d?w=300, https://images.unsplash.com/photo-1445964047600-cdbdb873673d?w=300 1.5x, https://images.unsplash.com/photo-1445964047600-cdbdb873673d?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1445964047600-cdbdb873673d?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>requests中如何上传文件?</title><link>https://itest2025.pages.dev/tutorials/42-016-requests%E4%B8%AD%E5%A6%82%E4%BD%95%E4%B8%8A%E4%BC%A0%E6%96%87%E4%BB%B6/</link><pubDate>Wed, 22 Nov 2017 03:23:57 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/42-016-requests%E4%B8%AD%E5%A6%82%E4%BD%95%E4%B8%8A%E4%BC%A0%E6%96%87%E4%BB%B6/</guid><description>&lt;p>最简单的方式&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; url = &amp;#39;http://httpbin.org/post&amp;#39;
&amp;gt;&amp;gt;&amp;gt; files = {&amp;#39;file&amp;#39;: open(&amp;#39;report.xls&amp;#39;, &amp;#39;rb&amp;#39;)}

&amp;gt;&amp;gt;&amp;gt; r = requests.post(url, files=files)
&amp;gt;&amp;gt;&amp;gt; r.text
{
 ...
 &amp;#34;files&amp;#34;: {
 &amp;#34;file&amp;#34;: &amp;#34;&amp;lt;censored...binary...data&amp;gt;&amp;#34;
 },
 ...
}
&lt;/code>&lt;/pre>&lt;p>你可以显式地设置文件名，文件类型和请求头：&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; url = &amp;#39;http://httpbin.org/post&amp;#39;
&amp;gt;&amp;gt;&amp;gt; files = {&amp;#39;file&amp;#39;: (&amp;#39;report.xls&amp;#39;, open(&amp;#39;report.xls&amp;#39;, &amp;#39;rb&amp;#39;), &amp;#39;application/vnd.ms-excel&amp;#39;, {&amp;#39;Expires&amp;#39;: &amp;#39;0&amp;#39;})}

&amp;gt;&amp;gt;&amp;gt; r = requests.post(url, files=files)
&amp;gt;&amp;gt;&amp;gt; r.text
{
 ...
 &amp;#34;files&amp;#34;: {
 &amp;#34;file&amp;#34;: &amp;#34;&amp;lt;censored...binary...data&amp;gt;&amp;#34;
 },
 ...
}
&lt;/code>&lt;/pre>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1500989145603-8e7ef71d639e?w=300"
 data-srcset="https://images.unsplash.com/photo-1500989145603-8e7ef71d639e?w=300, https://images.unsplash.com/photo-1500989145603-8e7ef71d639e?w=300 1.5x, https://images.unsplash.com/photo-1500989145603-8e7ef71d639e?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1500989145603-8e7ef71d639e?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（十六）执行javascript</title><link>https://itest2025.pages.dev/tutorials/20-016-%E5%8D%81%E5%85%AD%E6%89%A7%E8%A1%8Cjavascript/</link><pubDate>Mon, 31 Jul 2017 02:49:18 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/20-016-%E5%8D%81%E5%85%AD%E6%89%A7%E8%A1%8Cjavascript/</guid><description>&lt;h3 id="执行javascript">执行javascript&lt;/h3>
&lt;p>使用driver.executeScript(js)方法会在当前的定位上下文里执行相应的js脚本。&lt;/p>
&lt;h3 id="传参">传参&lt;/h3>
&lt;p>executeScript方法支持向脚本中传入参数，所有参数的参数都可以在脚本中通过&lt;code>arguments&lt;/code>对象来引用。我们可以传入下列类型的参数:&lt;/p>
&lt;ul>
&lt;li>boolean&lt;/li>
&lt;li>number&lt;/li>
&lt;li>string&lt;/li>
&lt;li>WebElement:也就是我们定位到的页面对象&lt;/li>
&lt;li>Array或者是Object: 只要里面的每一项都是上面的类型就好了&lt;/li>
&lt;/ul>
&lt;h3 id="返回值">返回值&lt;/h3>
&lt;p>同样的，我们可以接收js脚本的返回值，返回值有下面一些情况&lt;/p>
&lt;ul>
&lt;li>如果js返回HTML元素，那么该元素会自动被封装成WebElement&lt;/li>
&lt;li>null 或者 undefined会被转成null&lt;/li>
&lt;li>boolean, number, string 不做转换&lt;/li>
&lt;li>function会被转成相应的字符串表示&lt;/li>
&lt;li>Array和Object中的每一项都按照上面的规则转换&lt;/li>
&lt;/ul>
&lt;h3 id="目的">目的&lt;/h3>
&lt;ul>
&lt;li>学会使用executeScript(js)方法&lt;/li>
&lt;li>学会向js脚本中传参&lt;/li>
&lt;li>学会从js脚本中接收返回值&lt;/li>
&lt;/ul>
&lt;h3 id="场景">场景&lt;/h3>
&lt;p>打开&lt;a href="http://www.baidu.com/" target="_blank" rel="noopener noreffer ">百度首页&lt;/a>&lt;/p>
&lt;ul>
&lt;li>先隐藏掉&lt;strong>百度一下&lt;/strong>按钮&lt;/li>
&lt;li>然后返回页面上所有导航链接的文本&lt;/li>
&lt;li>最后把页面背景变成黑色&lt;/li>
&lt;/ul>
&lt;h3 id="代码">代码&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;path&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">webdriver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;selenium-webdriver&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">By&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">url&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;http://www.baidu.com/&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">dr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Builder&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">forBrowser&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;chrome&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">build&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">url&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 先隐藏掉百度一下按钮
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 通过arguments[0]传入百度一下按钮
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kd">var&lt;/span> &lt;span class="nx">hideBtn&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;arguments[0].style.display=&amp;#39;none&amp;#39;;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">executeScript&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">hideBtn&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;su&amp;#39;&lt;/span>&lt;span class="p">)));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 然后返回页面上所有导航链接的文本
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 通过return返回需要的结果
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kd">var&lt;/span> &lt;span class="nx">linkTexts&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;return $(&amp;#39;.mnav&amp;#39;).text()&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">executeScript&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">linkTexts&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">then&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">texts&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">texts&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 最后把页面背景变成黑色
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">executeScript&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;document.body.style.backgroundColor=&amp;#39;black&amp;#39;&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行结果">运行结果&lt;/h3>
&lt;p>浏览器&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://wx4.sinaimg.cn/mw1024/726a2979gy1fhp354hg8ij21ku0xegop.jpg"
 data-srcset="http://wx4.sinaimg.cn/mw1024/726a2979gy1fhp354hg8ij21ku0xegop.jpg, http://wx4.sinaimg.cn/mw1024/726a2979gy1fhp354hg8ij21ku0xegop.jpg 1.5x, http://wx4.sinaimg.cn/mw1024/726a2979gy1fhp354hg8ij21ku0xegop.jpg 2x"
 data-sizes="auto"
 alt="http://wx4.sinaimg.cn/mw1024/726a2979gy1fhp354hg8ij21ku0xegop.jpg"
 title="http://wx4.sinaimg.cn/mw1024/726a2979gy1fhp354hg8ij21ku0xegop.jpg" />&lt;/p></description></item><item><title>（十六）警告框处理</title><link>https://itest2025.pages.dev/tutorials/19-016-%E5%8D%81%E5%85%AD%E8%AD%A6%E5%91%8A%E6%A1%86%E5%A4%84%E7%90%86/</link><pubDate>Sun, 25 Jun 2017 07:37:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/19-016-%E5%8D%81%E5%85%AD%E8%AD%A6%E5%91%8A%E6%A1%86%E5%A4%84%E7%90%86/</guid><description>&lt;br>
在 WebDriver中处理JavaScript所生成的alert、confirm以及prompt十分简单，具体做法是使用switch_to_alert()方法定位到alert/confirm/prompt，然后使用text/accept/dismiss/sendKeys等方法进行操作。
&lt;ul>
&lt;li>
&lt;p>getText()： 返回 alert/confirm/prompt 中的文字信息。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>accept()： 接受现有警告框。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>dismiss()： 解散现有警告框。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>sendKeys(keysToSend)： 发送文本至警告框。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>keysToSend： 将文本发送至警告框。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>如下图，百度搜索设置弹出的窗口是不能通过前端工具对其进行定位的，这个时候就可以通过switchTo().alert()方法接受这个弹窗。
&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://orru5lls3.bkt.clouddn.com/alert_windows.png"
 data-srcset="http://orru5lls3.bkt.clouddn.com/alert_windows.png, http://orru5lls3.bkt.clouddn.com/alert_windows.png 1.5x, http://orru5lls3.bkt.clouddn.com/alert_windows.png 2x"
 data-sizes="auto"
 alt="http://orru5lls3.bkt.clouddn.com/alert_windows.png"
 title="http://orru5lls3.bkt.clouddn.com/alert_windows.png" />&lt;/p>
&lt;p>接受一个警告框的代码如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.By&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.WebDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.chrome.ChromeDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">AlertDemo&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">throws&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">InterruptedException&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ChromeDriver&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;https://www.baidu.com&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">linkText&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;设置&amp;#34;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">click&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">linkText&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;搜索设置&amp;#34;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">click&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2000&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//保存设置&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">className&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;prefpanelgo&amp;#34;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">click&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//接收弹窗&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">switchTo&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="na">alert&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="na">accept&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2000&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">quit&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p></description></item><item><title>（十六）cookie操作</title><link>https://itest2025.pages.dev/tutorials/24-016-%E5%8D%81%E5%85%ADcookie%E6%93%8D%E4%BD%9C/</link><pubDate>Thu, 15 Jun 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/24-016-%E5%8D%81%E5%85%ADcookie%E6%93%8D%E4%BD%9C/</guid><description>&lt;br>
有时候我们需要验证浏览器中cookie是否正确，因为基于真实cookie的测试是无法通过白盒和集成测试进行的。WebDriver提供了操作Cookie的相关方法，可以读取、添加和删除cookie信息。
&lt;p>WebDriver操作cookie的方法：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>get_cookies()：			获得所有cookie信息。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>get_cookie(name)：		返回字典的key为“name”的cookie信息。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>add_cookie(cookie_dict)	：	添加cookie。“cookie_dict”指字典对象，必须有name 和value 值。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>delete_cookie(name,optionsString)：删除cookie信息。“name”是要删除的cookie的名称，“optionsString”是该cookie的选项，目前支持的选项包括“路径”，“域”。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>delete_all_cookies()：		删除所有cookie信息。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>下面通过get_cookies()来获取当前浏览器的cookie信息。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">webdriver&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">webdriver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Firefox&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;http://www.youdao.com&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 获得cookie信息&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">cookie&lt;/span>&lt;span class="o">=&lt;/span> &lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_cookies&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 将获得cookie的信息打印&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cookie&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">quit&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>从执行结果可以看出，cookie数据是以字典的形式进行存放的。知道了cookie的存放形式，接下来我们就可以按照这种形式向浏览器中写入cookie信息。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">webdriver&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">webdriver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Firefox&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;http://www.youdao.com&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 向cookie的name 和value中添加会话信息&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add_cookie&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="s1">&amp;#39;name&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;key-aaaaaaa&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;value&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;value-bbbbbb&amp;#39;&lt;/span>&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 遍历cookies中的name 和value信息并打印，当然还有上面添加的信息&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">cookie&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_cookies&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">%s&lt;/span>&lt;span class="s2"> -&amp;gt; &lt;/span>&lt;span class="si">%s&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">cookie&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;name&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">cookie&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;value&amp;#39;&lt;/span>&lt;span class="p">]))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">quit&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">输出结果&lt;/span>&lt;span class="err">：&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">========================&lt;/span> &lt;span class="n">RESTART&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="o">=========================&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">YOUDAO_MOBILE_ACCESS_TYPE&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="mi">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">_PREF_ANONYUSER__MYTH&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">aGFzbG9nZ2VkPXRydWU&lt;/span>&lt;span class="o">=&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">OUTFOX_SEARCH_USER_ID&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mi">1046383847&lt;/span>&lt;span class="o">@&lt;/span>&lt;span class="mf">218.17.158.115&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">JSESSIONID&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">abc7qSE_SBGsVgnVLBvcu&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">key&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">aaaaaaa&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">bbbbbb&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>从执行结果可以看到，最后一条cookie信息是在脚本执行过程中通过add_cookie()方法添加的。通过遍历得到所有的cookie信息，从而找到key为“name”和“value”的特定cookie的value。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/uploads/1412026095116d2b0c90e/3bf33993?w=300"
 data-srcset="https://images.unsplash.com/uploads/1412026095116d2b0c90e/3bf33993?w=300, https://images.unsplash.com/uploads/1412026095116d2b0c90e/3bf33993?w=300 1.5x, https://images.unsplash.com/uploads/1412026095116d2b0c90e/3bf33993?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/uploads/1412026095116d2b0c90e/3bf33993?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（十七）alert confirm 和 prompt</title><link>https://itest2025.pages.dev/tutorials/20-017-%E5%8D%81%E4%B8%83alert-confirm-%E5%92%8C-prompt/</link><pubDate>Mon, 31 Jul 2017 01:49:18 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/20-017-%E5%8D%81%E4%B8%83alert-confirm-%E5%92%8C-prompt/</guid><description>&lt;h3 id="alert-confirm-prompt">alert confirm prompt&lt;/h3>
&lt;p>原生的javascript弹出框，各个浏览器的实现不一样，外观也不太一样。&lt;/p>
&lt;p>这些弹出框会阻止页面上的所有操作，因此每次这些框弹出来以后，我们必须想办法让这些东西消失掉，否则脚本无法往下进行下去。&lt;/p>
&lt;h3 id="一般的处理方式">一般的处理方式&lt;/h3>
&lt;p>当alert弹出之后，我们可以通过类似下面的代码去处理alert&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="nx">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">switchTo&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">alert&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">dismiss&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">switchTo&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">alert&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">accept&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>切换到alert/confirm/prompt之后，我们可以进行如下的后续动作&lt;/p>
&lt;ul>
&lt;li>accept(): 接受,点ok&lt;/li>
&lt;li>dismiss(): 点取消&lt;/li>
&lt;li>getText(): 拿到提示文本&lt;/li>
&lt;li>sendKeys( text ): 如果是prompt的话，可以用该方法输入一些内容&lt;/li>
&lt;li>authenticateAs( username, password ): 如果是&lt;a href="https://en.wikipedia.org/wiki/Basic_access_authentication" target="_blank" rel="noopener noreffer ">basic authentication&lt;/a>的话，可以通过该方法来输入用户名和密码&lt;/li>
&lt;/ul>
&lt;h3 id="一劳永逸的处理方式">一劳永逸的处理方式&lt;/h3>
&lt;p>如果我们不在乎alert上提示的内容，只想页面上不弹出alert/confirm/prompt的话，可以通过js来覆盖这些方法的原生实现，从而达到&lt;strong>禁用&lt;/strong>弹出框的效果，比如下面的代码就演示了如何禁用alert。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">banAlert&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;window.alert = function(msg){}&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">executeScript&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">banAlert&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这样在测试过程中，所有的alert都不会弹出。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1527467779599-34448b3fa6a7?w=300"
 data-srcset="https://images.unsplash.com/photo-1527467779599-34448b3fa6a7?w=300, https://images.unsplash.com/photo-1527467779599-34448b3fa6a7?w=300 1.5x, https://images.unsplash.com/photo-1527467779599-34448b3fa6a7?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1527467779599-34448b3fa6a7?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（十七）文件上传</title><link>https://itest2025.pages.dev/tutorials/19-017-%E5%8D%81%E4%B8%83%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0/</link><pubDate>Sat, 24 Jun 2017 07:37:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/19-017-%E5%8D%81%E4%B8%83%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0/</guid><description>&lt;br>
对于通过input标签实现的上传功能，可以将其看作是一个输入框，即通过sendKeys()指定本地文件路径的方式实现文件上传。
&lt;p>创建upfile.html文件，代码如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">html&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">head&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">http-equiv&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;content-type&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;text/html;charset=utf-8&amp;#34;&lt;/span> &lt;span class="p">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>upload_file&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">link&lt;/span> &lt;span class="na">href&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;http://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.css&amp;#34;&lt;/span> &lt;span class="na">rel&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;stylesheet&amp;#34;&lt;/span> &lt;span class="p">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">head&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">body&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">div&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;row-fluid&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">div&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;span6 well&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">h3&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>upload_file&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">h3&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	 &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">input&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;file&amp;#34;&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;file&amp;#34;&lt;/span> &lt;span class="p">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">div&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">div&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">body&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">script&lt;/span> &lt;span class="na">src&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;http://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.js&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>&lt;span class="err">&amp;lt;/scrip&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">html&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>通过浏览器打开upfile.html文件，功能如下图。
&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://orru5lls3.bkt.clouddn.com/upfile.png"
 data-srcset="http://orru5lls3.bkt.clouddn.com/upfile.png, http://orru5lls3.bkt.clouddn.com/upfile.png 1.5x, http://orru5lls3.bkt.clouddn.com/upfile.png 2x"
 data-sizes="auto"
 alt="http://orru5lls3.bkt.clouddn.com/upfile.png"
 title="http://orru5lls3.bkt.clouddn.com/upfile.png" />&lt;/p>
&lt;p>接下来通过sendKeys()方法来实现文件上传。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">java.io.File&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.By&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.WebDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.chrome.ChromeDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">UpFileDemo&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">throws&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">InterruptedException&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ChromeDriver&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">File&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">File&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;./HTMLFile/upfile.html&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">filePath&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">getAbsolutePath&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">filePath&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//定位上传按钮， 添加本地文件&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;file&amp;#34;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;D:\\upload_file.txt&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">5000&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">quit&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p></description></item><item><title>（十七）调用JavaScript代码</title><link>https://itest2025.pages.dev/tutorials/24-017-%E5%8D%81%E4%B8%83%E8%B0%83%E7%94%A8javascript%E4%BB%A3%E7%A0%81/</link><pubDate>Wed, 14 Jun 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/24-017-%E5%8D%81%E4%B8%83%E8%B0%83%E7%94%A8javascript%E4%BB%A3%E7%A0%81/</guid><description>&lt;br>
虽然WebDriver提供了操作浏览器的前进和后退方法，但对于浏览器滚动条并没有提供相应的操作方法。在这种情况下，就可以借助JavaScript来控制浏览器的滚动条。WebDriver提供了execute_script()方法来执行JavaScript代码。
&lt;p>用于调整浏览器滚动条位置的JavaScript代码如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- window.scrollTo(左边距,上边距); --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">window.scrollTo(0,450);
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>window.scrollTo()方法用于设置浏览器窗口滚动条的水平和垂直位置。方法的第一个参数表示水平的左间距，第二个参数表示垂直的上边距。其代码如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">webdriver&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">time&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">sleep&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 访问百度&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">webdriver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Firefox&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;http://www.baidu.com&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 设置浏览器窗口大小&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">set_window_size&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">500&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">500&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 搜索&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_element_by_id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;kw&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">send_keys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;selenium&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find_element_by_id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;su&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">click&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 通过javascript设置浏览器窗口的滚动条位置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">js&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;window.scrollTo(100,450);&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">execute_script&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">js&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">quit&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>通过浏览器打开百度进行搜索，并且提前通过set_window_size()方法将浏览器窗口设置为固定宽高显示，目的是让窗口出现水平和垂直滚动条。然后通过execute_script()方法执行JavaScripts代码来移动滚动条的位置。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1464039397811-476f652a343b?w=300"
 data-srcset="https://images.unsplash.com/photo-1464039397811-476f652a343b?w=300, https://images.unsplash.com/photo-1464039397811-476f652a343b?w=300 1.5x, https://images.unsplash.com/photo-1464039397811-476f652a343b?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1464039397811-476f652a343b?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（十八）截图</title><link>https://itest2025.pages.dev/tutorials/20-018-%E5%8D%81%E5%85%AB%E6%88%AA%E5%9B%BE/</link><pubDate>Sun, 30 Jul 2017 02:49:18 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/20-018-%E5%8D%81%E5%85%AB%E6%88%AA%E5%9B%BE/</guid><description>&lt;h3 id="截图">截图&lt;/h3>
&lt;p>在测试用例失败的时候进行截图，这是大家经常会遇到的需求。&lt;/p>
&lt;h3 id="目的">目的&lt;/h3>
&lt;ul>
&lt;li>学会使用takeScreenshot()方法&lt;/li>
&lt;/ul>
&lt;h3 id="场景">场景&lt;/h3>
&lt;p>下面我们就用代码实现打开&lt;a href="http://www.testclass.net/selenium_javascript/" target="_blank" rel="noopener noreffer ">测试教程网 selenium javascript教程&lt;/a>，然后截图的功能&lt;/p>
&lt;h3 id="代码">代码&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">webdriver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;selenium-webdriver&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">By&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">Key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Key&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">dr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Builder&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">forBrowser&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;chrome&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">build&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;http://www.testclass.net/selenium_javascript/&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">takeScreenshot&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">then&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">data&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;fs&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">writeFile&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;pic.png&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">data&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;base64&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">quit&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行结果">运行结果&lt;/h3>
&lt;p>脚本目录下会出现pic.png文件。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1504966981333-1ac8809be1ca?w=300"
 data-srcset="https://images.unsplash.com/photo-1504966981333-1ac8809be1ca?w=300, https://images.unsplash.com/photo-1504966981333-1ac8809be1ca?w=300 1.5x, https://images.unsplash.com/photo-1504966981333-1ac8809be1ca?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1504966981333-1ac8809be1ca?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（十八）浏览器cookie操作</title><link>https://itest2025.pages.dev/tutorials/19-018-%E5%8D%81%E5%85%AB%E6%B5%8F%E8%A7%88%E5%99%A8cookie%E6%93%8D%E4%BD%9C/</link><pubDate>Fri, 23 Jun 2017 07:37:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/19-018-%E5%8D%81%E5%85%AB%E6%B5%8F%E8%A7%88%E5%99%A8cookie%E6%93%8D%E4%BD%9C/</guid><description>&lt;br>
有时候我们需要验证浏览器中Cookie是否正确， 因为基于真实Cookie的测试是__无法通过白盒测试和集成测试进行的__。WebDriver提供了操作Cookie的相关方法可以读取、 添加和删除Cookie信息。
&lt;p>WebDriver 操作Cookie的方法：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>getCookies() 获得所有 cookie 信息。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>getCookieNamed(String name) 返回字典的key为“name”的Cookie信息。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>addCookie(cookie dict) 添加Cookie。“cookie_dict”指字典对象，必须有 name和value值。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>deleteCookieNamed(String name) 删除Cookie 信息。 “name”是要删除的 cookie的名称；
“optionsString” 是该Cookie的选项，目前支持的选项包括“路径” ， “域” 。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>deleteAllCookies() 删除所有 cookie 信息。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>下面通过 geCookies()来获取当前浏览器的 cookie 信息。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">java.util.Set&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.chrome.ChromeDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.WebDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.Cookie&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">CookieDemo&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ChromeDriver&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;https://www.baidu.com&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Cookie&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">c1&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Cookie&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;key-aaaaaaa&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Cookie&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">c2&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Cookie&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;value&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;value-bbbbbb&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">manage&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="na">addCookie&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">c1&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">manage&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="na">addCookie&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">c2&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//获得 cookie&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Set&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Cookie&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">coo&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">manage&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="na">getCookies&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">coo&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//删除所有 cookie&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//driver.manage().deleteAllCookies();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">quit&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>打印结果：&lt;/p></description></item><item><title>（十八）窗口截图</title><link>https://itest2025.pages.dev/tutorials/24-018-%E5%8D%81%E5%85%AB%E7%AA%97%E5%8F%A3%E6%88%AA%E5%9B%BE/</link><pubDate>Tue, 13 Jun 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/24-018-%E5%8D%81%E5%85%AB%E7%AA%97%E5%8F%A3%E6%88%AA%E5%9B%BE/</guid><description>&lt;br>
自动化用例是由程序去执行的，因此有时候打印的错误信息并不十分明确。如果在脚本执行出错的时候能对当前窗口截图保存，那么通过图片就可以非常直观地看出出错的原因。WebDriver提供了截图函数get_screenshot_as_file()来截取当前窗口。
```python
from selenium import webdriver
from time import sleep
&lt;p>driver = webdriver.Firefox()
driver.get(&amp;lsquo;&lt;a href="http://www.baidu.com" target="_blank" rel="noopener noreffer ">http://www.baidu.com&lt;/a>&amp;rsquo;)&lt;/p>
&lt;p>driver.find_element_by_id(&amp;lsquo;kw&amp;rsquo;).send_keys(&amp;lsquo;selenium&amp;rsquo;)
driver.find_element_by_id(&amp;lsquo;su&amp;rsquo;).click()
sleep(2)&lt;/p>
&lt;h1 id="截取当前窗口并指定截图图片的保存位置">截取当前窗口，并指定截图图片的保存位置&lt;/h1>
&lt;p>driver.get_screenshot_as_file(&amp;ldquo;D:\baidu_img.jpg&amp;rdquo;)&lt;/p>
&lt;p>driver.quit()&lt;/p>
&lt;pre tabindex="0">&lt;code>脚本运行完成后打开D盘，就可以找到baidu_img.jpg图片文件了。




原始封面

![课程图片](https://images.unsplash.com/photo-1513836279014-a89f7a76ae86?w=300)
&lt;/code>&lt;/pre></description></item><item><title>（十九）wait和sleep</title><link>https://itest2025.pages.dev/tutorials/20-019-%E5%8D%81%E4%B9%9Dwait%E5%92%8Csleep/</link><pubDate>Sat, 29 Jul 2017 02:48:18 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/20-019-%E5%8D%81%E4%B9%9Dwait%E5%92%8Csleep/</guid><description>&lt;h3 id="wait-condition-opt_timeout-opt_message-">wait&lt;T>( condition, opt_timeout, opt_message )&lt;/h3>
&lt;p>wait方法一般用来等待页面上某些条件得到满足后才继续执行脚本。比如等待页面上某个弹出框出现，等某个元素可以被定位到之类。&lt;/p>
&lt;p>wait方法中可以传入&lt;a href="http://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_Condition.html" target="_blank" rel="noopener noreffer ">Condition&lt;/a>表示一般性条件和&lt;a href="http://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebElementCondition.html" target="_blank" rel="noopener noreffer ">WebElementCondition&lt;/a>。&lt;/p>
&lt;p>如果传入的元素级条件被满足，那么wait方法会返回&lt;a href="http://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_WebElementPromise.html" target="_blank" rel="noopener noreffer "> WebElementPromise&lt;/a>，也就是说可以直接返回满足条件的元素。&lt;/p>
&lt;p>如果在规定的时间内(也就是第2个参数)没有等到条件被满足，那么该方法会抛出异常。&lt;/p>
&lt;p>一般性用法示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 在10s内id是foo的元素被定位到，然后点击之
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kd">var&lt;/span> &lt;span class="nx">button&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">wait&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">until&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">elementLocated&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;foo&amp;#39;&lt;/span>&lt;span class="p">)),&lt;/span> &lt;span class="mi">10000&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">button&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">click&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>另外wait还可以将执行中的脚本暂停住一段时间，直到第1个参数中的异步操作处理完毕，如下所示&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">started&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">startTestServer&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">wait&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">started&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">1000&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Server should start within 5 seconds&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">getServerUrl&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="sleep">sleep&lt;/h3>
&lt;p>sleep可以不管任何情况直接将执行中的脚本直接暂停一段时间。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;start&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">css&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;.kls&amp;#39;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="nx">click&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 等待3s
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3000&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">quit&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>sleep在某些时候非常好用，但是希望大家不要乱用，因为这会拖慢脚本的执行速度。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1454817481404-7e84c1b73b4a?w=300"
 data-srcset="https://images.unsplash.com/photo-1454817481404-7e84c1b73b4a?w=300, https://images.unsplash.com/photo-1454817481404-7e84c1b73b4a?w=300 1.5x, https://images.unsplash.com/photo-1454817481404-7e84c1b73b4a?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1454817481404-7e84c1b73b4a?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（十九）调用JavaScript代码</title><link>https://itest2025.pages.dev/tutorials/19-019-%E5%8D%81%E4%B9%9D%E8%B0%83%E7%94%A8javascript%E4%BB%A3%E7%A0%81/</link><pubDate>Thu, 22 Jun 2017 07:37:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/19-019-%E5%8D%81%E4%B9%9D%E8%B0%83%E7%94%A8javascript%E4%BB%A3%E7%A0%81/</guid><description>&lt;br>
虽然WebDriver提供了操作浏览器的前进和后退方法，但对于浏览器滚动条并没有提供相应的操作方法。在这种情况下，就可以借助JavaScript来控制浏览器的滚动条。WebDriver提供了executeScript()方法来执行JavaScript代码。
&lt;p>用于调整浏览器滚动条位置的JavaScript代码如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- window.scrollTo(左边距,上边距); --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">window.scrollTo(0,450);
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>window.scrollTo()方法用于设置浏览器窗口滚动条的水平和垂直位置。方法的第一个参数表示水平的左间距，第二个参数表示垂直的上边距。其代码如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.By&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.WebDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.Dimension&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.chrome.ChromeDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.JavascriptExecutor&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">JSDemo&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">throws&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">InterruptedException&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ChromeDriver&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//设置浏览器窗口大小&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">manage&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="na">window&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="na">setSize&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Dimension&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">700&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">600&lt;/span>&lt;span class="p">));&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;https://www.baidu.com&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//进行百度搜索&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;kw&amp;#34;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">sendKeys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;webdriver api&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">findElement&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">By&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;su&amp;#34;&lt;/span>&lt;span class="p">)).&lt;/span>&lt;span class="na">click&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">2000&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">//将页面滚动条拖到底部&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="n">JavascriptExecutor&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="na">executeScript&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;window.scrollTo(100,450);&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">Thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">3000&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">quit&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>通过浏览器打开百度进行搜索，并且提前通过window().setSize()方法将浏览器窗口设置为固定宽高显示，目的是让窗口出现水平和垂直滚动条。然后通过executeScript()方法执行JavaScripts代码来移动滚动条的位置。&lt;/p></description></item><item><title>（十九）关闭浏览器</title><link>https://itest2025.pages.dev/tutorials/24-019-%E5%8D%81%E4%B9%9D%E5%85%B3%E9%97%AD%E6%B5%8F%E8%A7%88%E5%99%A8/</link><pubDate>Mon, 12 Jun 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/24-019-%E5%8D%81%E4%B9%9D%E5%85%B3%E9%97%AD%E6%B5%8F%E8%A7%88%E5%99%A8/</guid><description>&lt;br>
在前面的例子中我们一直使用quit()方法，其含义为退出相关的驱动程序和关闭所有窗口。除此之外，WebDriver还提供了close()方法，用来关闭当前窗口。例多窗口的处理，在用例执行的过程中打开了多个窗口，我们想要关闭其中的某个窗口，这时就要用到close()方法进行关闭了。
&lt;ul>
&lt;li>
&lt;p>close() 关闭单个窗口&lt;/p>
&lt;/li>
&lt;li>
&lt;p>quit() 关闭所有窗口&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1532274402911-5a369e4c4bb5?w=300"
 data-srcset="https://images.unsplash.com/photo-1532274402911-5a369e4c4bb5?w=300, https://images.unsplash.com/photo-1532274402911-5a369e4c4bb5?w=300 1.5x, https://images.unsplash.com/photo-1532274402911-5a369e4c4bb5?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1532274402911-5a369e4c4bb5?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>JMeter官方文档：20. 函数</title><link>https://itest2025.pages.dev/tutorials/22-020-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A320-%E5%87%BD%E6%95%B0/</link><pubDate>Thu, 24 Aug 2017 06:05:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/22-020-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A320-%E5%87%BD%E6%95%B0/</guid><description>&lt;p>&lt;a href="https://itest2025.pages.dev/2017/08/24/jmeter-translation-plans/" rel="">《JMeter官方文档&amp;ndash;翻译计划》&lt;/a> &lt;a href="http://jmeter.apache.org/usermanual/functions.html" target="_blank" rel="noopener noreffer ">原文地址&lt;/a>&lt;/p>
&lt;h3 id="20-函数和变量">20. 函数和变量&lt;/h3>
&lt;hr>
&lt;p>JMeter 的函数是一些特殊值，它们可以填充在测试树的任何采样器或其他元件中。函数调用的语法如下：&lt;/p>
&lt;p>&lt;code>${__functionName(var1,var2,var3)}&lt;/code>&lt;/p>
&lt;p>其中“__functionName” 匹配函数的名称。&lt;br>
圆括号内为函数参数，不同函数的参数也不同，例如 &lt;code>${__time(YMD)}&lt;/code>。没有参数的函数可以不需要圆括号，例如 &lt;code>${__threadNum}&lt;/code>。&lt;/p>
&lt;p>如果函数的参数包含逗号，需要加上“&lt;code>\&lt;/code>”来转义，否则 JMeter 会把逗号当做参数的分隔符。例如：&lt;/p>
&lt;pre tabindex="0">&lt;code>${__time(EEE\, d MMM yyyy)}
&lt;/code>&lt;/pre>&lt;p>如果逗号没有被转义——例如 &lt;code>${__javaScript(Math.max(2,5))}&lt;/code> ——你会得到像这样的错误信息：&lt;/p>
&lt;pre>&lt;code>ERROR - jmeter.functions.JavaScript: Error processing Javascript: [Math.max(2]
org.mozilla.javascript.EvaluatorException: missing ) after argument list (&amp;lt;cmd&amp;gt;#1)
&lt;/code>&lt;/pre>
&lt;p>这是因为字符串“&lt;code>Math.max(2,5)&lt;/code>”被当做&lt;code>__javascript&lt;/code> 函数的两个参数：&lt;br>
&lt;code>Math.max(2&lt;/code> 和 &lt;code>5)&lt;/code>&lt;br>
其他错误信息也是有可能的。&lt;/p>
&lt;p>变量的引用如下：&lt;/p>
&lt;pre>&lt;code>${VARIABLE}
&lt;/code>&lt;/pre>
&lt;p>&lt;strong>如果引用了未定义的变量或函数，那么 JMeter 并不会报告或者记录错误信息——引用返回值就是引用自身。例如，如果 &lt;code>UNDEF&lt;/code> 没有被定义为变量，&lt;code>${UNDEF}&lt;/code> 的返回值就是 &lt;code>${UNDEF}&lt;/code>。&lt;/strong> 变量和函数（包括属性）都是区分大小写的。&lt;strong>JMeter 会剔除变量名称中的空格，例如 &lt;code>${__Random(1,63, LOTTERY )}&lt;/code> 中的变量‘　&lt;code>LOTTERY &lt;/code>　’会被‘&lt;code>LOTTERY&lt;/code>’取代。&lt;/strong>&lt;/p>
&lt;blockquote>
&lt;p>属性与变量不一样。变量对线程而言是局部的；属性是针对所有线程的，属性需要使用 &lt;code>__P&lt;/code> 或 &lt;code>__property&lt;/code> 函数来引用。&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>在 Windows 路径变量（例如 &lt;code>C:\test\${test}&lt;/code>）前使用 &lt;code>\&lt;/code> 时，要确保加上 &lt;code>\&lt;/code> 来转义，否则 JMeter 将不能解释变量，所以要这样写：&lt;code>C:\\test\\${test}&lt;/code>。&lt;br>
还有一种方法，就是使用 &lt;code>/&lt;/code> 作为路径分隔符，例如 &lt;code>C:/test/${test}&lt;/code>——Windows 的 Java 虚拟机在必要时会将它转换成路径分隔符。&lt;/p></description></item><item><title>（二十）until</title><link>https://itest2025.pages.dev/tutorials/20-020-%E4%BA%8C%E5%8D%81until/</link><pubDate>Thu, 27 Jul 2017 02:49:18 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/20-020-%E4%BA%8C%E5%8D%81until/</guid><description>&lt;h3 id="until">until&lt;/h3>
&lt;p>until一般跟wait一起用，用于等待页面上的一些条件被满足&lt;/p>
&lt;h3 id="条件一览">条件一览&lt;/h3>
&lt;ul>
&lt;li>ableToSwitchToFrame(frame): 直到selenium可以将定位上下文切换到frame里&lt;/li>
&lt;li>alertIsPresent(): 直到alert出现&lt;/li>
&lt;li>elementIsDisabled(element): 直到元素灰掉，不能被点击&lt;/li>
&lt;li>elementIsEnabled(element): 直到元素可以被点击&lt;/li>
&lt;li>elementIsNotSelected(element): 直到元素不可选&lt;/li>
&lt;li>elementIsNotVisible(element): 直到元素不可见&lt;/li>
&lt;li>elementIsSelected(element): 直到元素可选&lt;/li>
&lt;li>elementIsVisible(element): 直到元素可见&lt;/li>
&lt;li>elementLocated(locator): 最常用，直到元素可以被定位&lt;/li>
&lt;li>elementTextContains(element, substr): 直到元素的text包含substr&lt;/li>
&lt;li>elementTextIs(element, expected_text): 直到元素的text是expected_text&lt;/li>
&lt;li>elementTextMatches(element,regex): 直到元素的text满足正则表达式regex&lt;/li>
&lt;li>elementsLocated(locator): 直到一组元素被定位&lt;/li>
&lt;li>stalenessOf(element): 直到元素被dom树移除或页面刷新&lt;/li>
&lt;li>titleContains(substr): 直到页面title包含substr&lt;/li>
&lt;li>titleIs(expected_title): 直到页面的title是expected_title&lt;/li>
&lt;li>titleMatches(regex): 直到页面的title满足正则表达式regex&lt;/li>
&lt;li>urlContains(substrUrl): 直到页面url包含substrUrl&lt;/li>
&lt;li>urlIs(expected_url): 直到页面的url是expected_url&lt;/li>
&lt;li>urlMatches(regex): 直到页面的url满足正则表达式regex&lt;/li>
&lt;/ul>
&lt;h3 id="自定义条件">自定义条件&lt;/h3>
&lt;p>until还允许我们自定义条件。我们只需要传入1个回调，该回调返回真值(true)就代表等待的条件被满足。&lt;/p>
&lt;p>在javascript，真值表示所有&lt;strong>不是&lt;/strong>null, undefined, false, 0, 或 空字符串的值。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="nx">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">wait&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nx">driver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">getTitle&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">then&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">title&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nx">title&lt;/span> &lt;span class="o">===&lt;/span> &lt;span class="s1">&amp;#39;测试教程网&amp;#39;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">},&lt;/span> &lt;span class="mi">1000&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1463780324318-d1a8ddc05a11?w=300"
 data-srcset="https://images.unsplash.com/photo-1463780324318-d1a8ddc05a11?w=300, https://images.unsplash.com/photo-1463780324318-d1a8ddc05a11?w=300 1.5x, https://images.unsplash.com/photo-1463780324318-d1a8ddc05a11?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1463780324318-d1a8ddc05a11?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（二十）获取窗口截图</title><link>https://itest2025.pages.dev/tutorials/19-020-%E4%BA%8C%E5%8D%81%E8%8E%B7%E5%8F%96%E7%AA%97%E5%8F%A3%E6%88%AA%E5%9B%BE/</link><pubDate>Wed, 21 Jun 2017 07:37:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/19-020-%E4%BA%8C%E5%8D%81%E8%8E%B7%E5%8F%96%E7%AA%97%E5%8F%A3%E6%88%AA%E5%9B%BE/</guid><description>&lt;br>
自动化用例是由程序去执行，因此有时候打印的错误信息并不十分明确。如果在脚本执行出错的时候能对当前窗口截图保存，那么通过图片就可以非常直观地看出出错的原因。 WebDriver提供了截图函数getScreenshotAs()来截取当前窗口。
```java
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.TakesScreenshot;
&lt;p>public class GetImg {&lt;/p>
&lt;p>public static void main(String[] arge){&lt;/p>
&lt;pre>&lt;code>WebDriver driver = new ChromeDriver();
driver.get(&amp;quot;https://www.baidu.com&amp;quot;);

File srcFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
try {
 FileUtils.copyFile(srcFile,new File(&amp;quot;d:\\screenshot.png&amp;quot;));
} catch (IOException e) {
 e.printStackTrace();
}

driver.quit();
&lt;/code>&lt;/pre>
&lt;p>}
}&lt;/p>
&lt;pre tabindex="0">&lt;code>脚本运行完成后打开D盘，就可以找到screenshot.png图片文件了。




原始封面

![课程图片](https://images.unsplash.com/photo-1527689368864-3a821dbccc34?w=300)
&lt;/code>&lt;/pre></description></item><item><title>JMeter官方文档：21. 正则表达式</title><link>https://itest2025.pages.dev/tutorials/22-021-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A321-%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/</link><pubDate>Thu, 24 Aug 2017 05:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/22-021-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A321-%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/</guid><description>&lt;p>&lt;a href="https://itest2025.pages.dev/2017/08/24/jmeter-translation-plans/" rel="">《JMeter官方文档&amp;ndash;翻译计划》&lt;/a> &lt;a href="http://jmeter.apache.org/usermanual/regular_expressions.html" target="_blank" rel="noopener noreffer ">原文地址&lt;/a>&lt;/p>
&lt;h2 id="21-正则表达式">21. 正则表达式&lt;/h2>
&lt;hr>
&lt;h3 id="211-概述">21.1 概述&lt;/h3>
&lt;hr>
&lt;p>JMeter 包含模式匹配软件 &lt;a href="http://attic.apache.org/projects/jakarta-oro.html" target="_blank" rel="noopener noreffer ">Apache Jakarta ORO&lt;/a> 。&lt;br>
在 Jakarta 网上有一些关于它的文档，例如：&lt;a href="http://archimedes.fas.harvard.edu/scrapbook/jakarta-oro-2.0.6/docs/api/org/apache/oro/text/regex/package-summary.html" target="_blank" rel="noopener noreffer ">模式匹配字符摘要&lt;/a>。&lt;/p>
&lt;p>在 &lt;a href="http://www.savarese.org/oro/docs/OROMatcher/index.html" target="_blank" rel="noopener noreffer ">OROMatcher 用户指南&lt;/a>上还有一个关于该产品旧版本的文档 ，也许会有些用处。&lt;/p>
&lt;p>模式匹配与 Perl 中的模式匹配非常类似。Perl 的完整安装会包含大量关于正则表达式的文档——查找 &lt;strong>perlrequick&lt;/strong>， &lt;strong>perlretut&lt;/strong>， &lt;strong>perlre&lt;/strong> 和 &lt;strong>perlreref&lt;/strong>。&lt;/p>
&lt;p>有必要强调“包含（contains）”和“匹配（matches）”之间的区别，它们被用在响应断言测试原件上：&lt;/p>
&lt;p>&amp;ldquo;&lt;em>包含（contains）&lt;/em>&amp;rdquo; 意味着正则表达式至少与目标的某个部分相匹配，所以 &amp;lsquo;&lt;strong>alphabet&lt;/strong>&amp;rsquo; “包含” &amp;lsquo;&lt;strong>ph.b.&lt;/strong>&amp;rsquo;，因为正则表达式匹配子字符串 &amp;lsquo;&lt;strong>phabe&lt;/strong>&amp;rsquo;。&lt;/p>
&lt;p>&amp;ldquo;&lt;em>匹配（matches）&lt;/em>&amp;rdquo; 意味着正则表达式匹配整个目标。所以 &amp;lsquo;&lt;strong>alphabet&lt;/strong>&amp;rsquo; 和 &amp;lsquo;&lt;strong>al.*t&lt;/strong>&amp;rsquo; 是“匹配”的 。&lt;br>
这种情况下，它相当于将正则表达式封装在 &lt;strong>^&lt;/strong> 和 &lt;strong>$&lt;/strong> 中，即 &amp;lsquo;&lt;strong>^al.*t$&lt;/strong>&amp;rsquo;。&lt;/p>
&lt;p>然而，情况并非总是如此。例如，正则表达式 &amp;lsquo;&lt;strong>alp|.lp.*&lt;/strong>&amp;rsquo; “包含”于 &amp;lsquo;&lt;strong>alphabet&lt;/strong>&amp;rsquo;，但并不“匹配” &amp;lsquo;&lt;strong>alphabet&lt;/strong>&amp;rsquo;。&lt;/p>
&lt;p>这是为什么？原因是当模式匹配器在 &amp;lsquo;&lt;strong>alphabet&lt;/strong>&amp;rsquo; 中找到序列 &amp;lsquo;&lt;strong>alp&lt;/strong>&amp;rsquo; 时，它将停止尝试其他组合——而 &amp;lsquo;&lt;strong>alp&lt;/strong>&amp;rsquo; 与 &amp;lsquo;&lt;strong>alphabet&lt;/strong>&amp;rsquo; 不同，它不包含 &amp;lsquo;&lt;strong>habet&lt;/strong>&amp;rsquo;。&lt;/p>
&lt;blockquote>
&lt;p>不同于 Perl，没有必要将正则表达式用 // 封装。&lt;/p></description></item><item><title>（二十一）断言</title><link>https://itest2025.pages.dev/tutorials/20-021-%E4%BA%8C%E5%8D%81%E4%B8%80%E6%96%AD%E8%A8%80/</link><pubDate>Thu, 20 Jul 2017 02:49:18 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/20-021-%E4%BA%8C%E5%8D%81%E4%B8%80%E6%96%AD%E8%A8%80/</guid><description>&lt;h3 id="测试用例与断言">测试用例与断言&lt;/h3>
&lt;p>测试用例中至少需要包含1个断言，没有断言的测试脚本不能称为测试用例。&lt;/p>
&lt;p>断言就是预期和实际的比较，如果预期不等于实际，脚本将会报错。&lt;/p>
&lt;h3 id="selenium-自带断言">selenium 自带断言&lt;/h3>
&lt;p>selenium 自带了一些断言，具体看&lt;a href="http://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/testing/assert_exports_Assertion.html" target="_blank" rel="noopener noreffer ">断言&lt;/a>。&lt;/p>
&lt;h3 id="场景">场景&lt;/h3>
&lt;p>我们下面实现打开&lt;a href="http://www.testclass.net/" target="_blank" rel="noopener noreffer ">测试教程网&lt;/a>并做2个断言&lt;/p>
&lt;ul>
&lt;li>页面title包含测试教程网几个字&lt;/li>
&lt;li>页面url包含testclass几个字&lt;/li>
&lt;/ul>
&lt;h3 id="代码">代码&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">webdriver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;selenium-webdriver&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">By&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">By&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">assert&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;selenium-webdriver/testing/assert&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">dr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nx">webdriver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Builder&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">forBrowser&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;chrome&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">build&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;http://www.testclass.net/&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">getTitle&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">then&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">title&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">assert&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">title&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">contains&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;测试教程网&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">getCurrentUrl&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">then&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">url&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">assert&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">url&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">contains&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;testclass&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">quit&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行结果">运行结果&lt;/h3>
&lt;p>上面断言全部通过的时候看不到任何的结果，大家可以试着修改一下断言，让断言失败，这时候就应该可以看到类似下面的信息&lt;/p>
&lt;pre tabindex="0">&lt;code>AssertionError: 测试教程网 · 测试教程网.indexOf(测试教程网12443) !== -1
&lt;/code>&lt;/pre>&lt;h3 id="测试框架">测试框架&lt;/h3>
&lt;p>在做真实的测试时，我们一般会用测试框架配合selenium一起来实现复杂的场景测试和测试报告的生成，在这里向大家推荐一些测试框架&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/mochajs/mocha" target="_blank" rel="noopener noreffer ">mocha&lt;/a>: 强烈推荐，灵活简单，可以配合selenium断言一起用&lt;/li>
&lt;li>&lt;a href="https://github.com/qunitjs/qunit" target="_blank" rel="noopener noreffer ">qunit&lt;/a>: 简单好用&lt;/li>
&lt;li>&lt;a href="https://github.com/facebook/jest" target="_blank" rel="noopener noreffer ">jest&lt;/a>: facebook出品，大树底下好乘凉&lt;/li>
&lt;li>&lt;a href="https://github.com/substack/tape" target="_blank" rel="noopener noreffer ">tape&lt;/a>: 足够简单&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1502957291543-d85480254bf8?w=300"
 data-srcset="https://images.unsplash.com/photo-1502957291543-d85480254bf8?w=300, https://images.unsplash.com/photo-1502957291543-d85480254bf8?w=300 1.5x, https://images.unsplash.com/photo-1502957291543-d85480254bf8?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1502957291543-d85480254bf8?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（一）JMeter介绍与安装</title><link>https://itest2025.pages.dev/tutorials/22-051-%E4%B8%80jmeter%E4%BB%8B%E7%BB%8D%E4%B8%8E%E5%AE%89%E8%A3%85/</link><pubDate>Sun, 30 Jul 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/22-051-%E4%B8%80jmeter%E4%BB%8B%E7%BB%8D%E4%B8%8E%E5%AE%89%E8%A3%85/</guid><description>&lt;br>
#### Jmeter介绍
----
Apache JMeter™应用开源软件，100%纯Java应用程序,设计用于负载功能测试和性能测试。它最初是为测试Web应用程序而设计的，但后来扩展到其他测试函数中。
&lt;p>Apache JMeter 功能包括:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>能够加载和测试许多不同的应用程序/服务器/协议类型：&lt;/p>
&lt;ul>
&lt;li>Web的HTTP，HTTPS（java，Nodejs，PHP，ASP.NET，…）&lt;/li>
&lt;li>SOAP / REST Webservices&lt;/li>
&lt;li>FTP 文件传输协议&lt;/li>
&lt;li>Database via JDBC&lt;/li>
&lt;li>LDAP&lt;/li>
&lt;li>Message-oriented middleware (MOM) via JMS&lt;/li>
&lt;li>邮件传输协议 - SMTP(S), POP3(S) 和 IMAP(S)&lt;/li>
&lt;li>本地命令或Shell 脚本&lt;/li>
&lt;li>TCP&lt;/li>
&lt;li>Java Objects&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>全功能测试IDE，允许快速记录测试计划（来自浏览器或本地应用程序），构建和
调试。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>基于Java开发，支持Linux、Windows、MAC OSX等平台。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>可以生成完整的动态HTML报告。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>通过从最流行的响应格式、HTML、JSON、XML或任何文本格式提取数据的能力，可以轻松地进行相关性。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>全多线程框架允许多线程并发采样，同时通过不同的线程组进行不同功能的同时采样。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>缓存和离线分析/重放测试结果。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>高度可扩展内核。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;br>
#### Jmeter安装
----
前面已经介绍了Jmeter是基于Java开发的，它的运行同样依赖于Java环境。
&lt;p>1、首先，&lt;a href="https://itest2025.pages.dev/selenium_java/install-java/" rel="">安装Java&lt;/a>。&lt;/p>
&lt;p>2、然后，&lt;a href="http://jmeter.apache.org/download_jmeter.cgi" target="_blank" rel="noopener noreffer ">下载Jmeter&lt;/a>。&lt;/p>
&lt;p>3、解压下载的__apache-jmeter-3.2.zip__包.&lt;/p>
&lt;p>4、进入&amp;hellip;\apache-jmeter-3.2\bin\解压目录，双击__ApacheJMeter.jar__启动（注：一定要配置Java环境）。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://oriphg3yh.bkt.clouddn.com/jmeter_main.png"
 data-srcset="http://oriphg3yh.bkt.clouddn.com/jmeter_main.png, http://oriphg3yh.bkt.clouddn.com/jmeter_main.png 1.5x, http://oriphg3yh.bkt.clouddn.com/jmeter_main.png 2x"
 data-sizes="auto"
 alt="http://oriphg3yh.bkt.clouddn.com/jmeter_main.png"
 title="http://oriphg3yh.bkt.clouddn.com/jmeter_main.png" />
如果可以看到上图，说明你的Jmeter已经安装好了。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1616610865799-a65c191d5355?w=300"
 data-srcset="https://images.unsplash.com/photo-1616610865799-a65c191d5355?w=300, https://images.unsplash.com/photo-1616610865799-a65c191d5355?w=300 1.5x, https://images.unsplash.com/photo-1616610865799-a65c191d5355?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1616610865799-a65c191d5355?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（二）JMeter插件管理</title><link>https://itest2025.pages.dev/tutorials/22-052-%E4%BA%8Cjmeter%E6%8F%92%E4%BB%B6%E7%AE%A1%E7%90%86/</link><pubDate>Sat, 29 Jul 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/22-052-%E4%BA%8Cjmeter%E6%8F%92%E4%BB%B6%E7%AE%A1%E7%90%86/</guid><description>&lt;br>
#### Jmeter插件管理
----
JMeter 插件管理器的使用方法很简单：不要手动安装各种插件，它提供了友好的用户界面来完成：安装、升级、卸载。
&lt;p>它管理插件包括 &lt;a href="https://www.jmeter-plugins.org/" target="_blank" rel="noopener noreffer ">jmeter-plugins.org&lt;/a> 上面常用的插件，和各种第三方插件甚至核心JMeter插件。&lt;/p>
&lt;br>
#### 安装插件管理：
----
1、下载 [plugins-manager.jar](http://www.jmeter-plugins.org/get/)
&lt;p>2、将 &lt;strong>plugins-manager.jar&lt;/strong> 放到 _&lt;em>&amp;hellip;\apache-jmeter-3.2\lib\ext_&lt;/em> 目录下。&lt;/p>
&lt;p>3、双击 &lt;strong>ApacheJMeter.jar&lt;/strong> 启动Jmeter。&lt;/p>
&lt;p>4、菜单栏“选项”会多出一个“Plugins Manager”的选项。
&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/plugins_manager_01.png"
 data-srcset="http://img.testclass.net/plugins_manager_01.png, http://img.testclass.net/plugins_manager_01.png 1.5x, http://img.testclass.net/plugins_manager_01.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/plugins_manager_01.png"
 title="http://img.testclass.net/plugins_manager_01.png" />&lt;/p>
&lt;p>点击 “Plugins Manager” 选项打开 Jmeter 插件管理
&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/plugins_manager_02.png"
 data-srcset="http://img.testclass.net/plugins_manager_02.png, http://img.testclass.net/plugins_manager_02.png 1.5x, http://img.testclass.net/plugins_manager_02.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/plugins_manager_02.png"
 title="http://img.testclass.net/plugins_manager_02.png" />&lt;/p>
&lt;p>插件管理窗口分三个标签页：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;code>Installed Plugins&lt;/code>：显示已安装的插件。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>Available Plugins&lt;/code>: 显示可安装的插件。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>Upgrades&lt;/code>: 显示可以升级的插件。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>通过__勾选/取消勾选__插件，并点击右下角 &amp;ldquo;Apply Changes and Restart JMeter&amp;rdquo; 按钮来__卸载、安装、升级__插件。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1482406611936-43ea538e39d4?w=300"
 data-srcset="https://images.unsplash.com/photo-1482406611936-43ea538e39d4?w=300, https://images.unsplash.com/photo-1482406611936-43ea538e39d4?w=300 1.5x, https://images.unsplash.com/photo-1482406611936-43ea538e39d4?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1482406611936-43ea538e39d4?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>（三）JMeter录制与回放</title><link>https://itest2025.pages.dev/tutorials/22-053-%E4%B8%89jmeter%E5%BD%95%E5%88%B6%E4%B8%8E%E5%9B%9E%E6%94%BE/</link><pubDate>Fri, 28 Jul 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/22-053-%E4%B8%89jmeter%E5%BD%95%E5%88%B6%E4%B8%8E%E5%9B%9E%E6%94%BE/</guid><description>&lt;br>
### 关于录制和回放功能
&lt;p>在JMeter2.1版本之前，JMeter应该是不支持录制和回放功能的，那时候如果需要录制jmeter的性能测试脚本的话，就需要使用第三方工具——&lt;a href="http://www.badboysoftware.biz/docs/jmeter.htm" target="_blank" rel="noopener noreffer ">badboy&lt;/a>。&lt;/p>
&lt;p>现在jmeter已经支持脚本的录制功能了，但录制的体验相对于badboy来说还是差了一些。不过聊胜于无，对于性能测试的入门者来说，录制回放功能可以让大家对性能测试脚本开发的过程有个非常感性的认识。&lt;/p>
&lt;p>不过录制脚本始终只是减轻工作量的一个手段，新手同学千万不要认为学会了录制回放就等于是学会了性能测试，学会录制回放只能代表你有机会真正的入门性能测试，这只是起点，而不是终点。&lt;/p>
&lt;h3 id="测试场景">测试场景&lt;/h3>
&lt;p>在本节中，我们的测试场景是：在必应(bing)搜索引擎中搜索关键字&lt;code>乙醇 selenium&lt;/code>。我们对搜索的结果并不关心，只要请求返回的状态码是200，我们就认为该请求是成功的，有效的。&lt;/p>
&lt;h3 id="准备录制">准备录制&lt;/h3>
&lt;ul>
&lt;li>打开jmeter&lt;/li>
&lt;li>工具栏点击&lt;strong>Templates&amp;hellip;&lt;/strong> ，选择&lt;strong>Recording&lt;/strong>模版&lt;/li>
&lt;li>点击WorkBench节点下的&lt;strong>HTTP(S) Test Script Recorder&lt;/strong>&lt;/li>
&lt;li>点击&lt;strong>启动&lt;/strong>按钮，如下图所示&lt;/li>
&lt;/ul>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/recorder.png"
 data-srcset="http://img.testclass.net/recorder.png, http://img.testclass.net/recorder.png 1.5x, http://img.testclass.net/recorder.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/recorder.png"
 title="recorder" />&lt;/p>
&lt;p>&lt;strong>此时应该会出现下图所示的警告对话框，我们可以简单的忽略掉，此警告不影响我们本节内容的准确性&lt;/strong>&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/warning.png"
 data-srcset="http://img.testclass.net/warning.png, http://img.testclass.net/warning.png 1.5x, http://img.testclass.net/warning.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/warning.png"
 title="warning" />&lt;/p>
&lt;p>完成了以上的步骤之后，我们就成功的启动了jmeter的http代理，下面我们需要对配置系统，使得系统的http请求都通过jmeter代理发出。&lt;/p>
&lt;p>&lt;em>注意：如果启动代理的过程中遇到了一些意外情况，请参考&lt;a href="https://wiki.apache.org/jmeter/TestRecording210" target="_blank" rel="noopener noreffer ">这里&lt;/a>解决&lt;/em>&lt;/p>
&lt;br>
### 配置HTTP代理
----
#### Mac OS 系统
&lt;ul>
&lt;li>
&lt;p>系统偏好设置 -&amp;gt; 网络 -&amp;gt; 代理 -&amp;gt; Web代理(HTTP)&lt;/p>
&lt;/li>
&lt;li>
&lt;p>web代理服务器填写&lt;code>localhost&lt;/code>，端口填写&lt;code>8888&lt;/code>，如下图所示&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/mac_http_proxy.png"
 data-srcset="http://img.testclass.net/mac_http_proxy.png, http://img.testclass.net/mac_http_proxy.png 1.5x, http://img.testclass.net/mac_http_proxy.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/mac_http_proxy.png"
 title="mac http proxy" />&lt;/p>
&lt;ul>
&lt;li>保存配置&lt;/li>
&lt;/ul>
&lt;h4 id="windows-系统">Windows 系统&lt;/h4>
&lt;p>Windows 10&lt;/p></description></item><item><title>（四）创建一个简单的性能测试</title><link>https://itest2025.pages.dev/tutorials/22-054-%E5%9B%9B%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E7%AE%80%E5%8D%95%E7%9A%84%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/</link><pubDate>Mon, 24 Jul 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/22-054-%E5%9B%9B%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E7%AE%80%E5%8D%95%E7%9A%84%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/</guid><description>&lt;br>
请先参考[Jmeter介绍与安装](/jmeter/install-jmeter/) ，启动Jmeter。
&lt;ul>
&lt;li>建立测试计划
启动jmeter后，jmeter会自动生成一个空的测试计划，用户可以基于该测试计划建立自己的测试计划。&lt;/li>
&lt;/ul>
&lt;br>
#### 添加线程组
----
一个性能测试请求负载是基于一个线程组完成的。一个测试计划必须有一个线程组。测试计划添加线程组非常简单。在测试计划右键弹出下拉菜单（添加-->Threads(Users)--->线程组）中选择线程组即可。
&lt;p>jmeter中 每个测试计划至少需要包含一个线程组，当然也可以在一个计划中创建多个线程组，那么多个线程组之间又会怎样的顺序执行（串行还是并行）？在测试计划下面多个线程是并行执行的，也就是说这些线程组是同时被初始化并同时执行线程组下的Sampler的。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/add_thread.png"
 data-srcset="http://img.testclass.net/add_thread.png, http://img.testclass.net/add_thread.png 1.5x, http://img.testclass.net/add_thread.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/add_thread.png"
 title="http://img.testclass.net/add_thread.png" />&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/thread_group.png"
 data-srcset="http://img.testclass.net/thread_group.png, http://img.testclass.net/thread_group.png 1.5x, http://img.testclass.net/thread_group.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/thread_group.png"
 title="http://img.testclass.net/thread_group.png" />&lt;/p>
&lt;p>线程组主要包含三个参数：线程数、准备时长（Ramp-Up Period(in seconds)）、循环次数。&lt;/p>
&lt;p>&lt;strong>线程数：&lt;/strong> 虚拟用户数。一个虚拟用户占用一个进程或线程。设置多少虚拟用户数在这里也就是设置多少个线程数。&lt;/p>
&lt;p>&lt;strong>准备时长：&lt;/strong> 设置的虚拟用户数需要多长时间全部启动。如果线程数为20 ，准备时长为10 ，那么需要10秒钟启动20个线程。也就是每秒钟启动2个线程。&lt;/p>
&lt;p>&lt;strong>循环次数:&lt;/strong> 每个线程发送请求的次数。如果线程数为20 ，循环次数为100 ，那么每个线程发送100次请求。总请求数为20*100=2000 。如果勾选了“永远”，那么所有线程会一直发送请求，直到选择停止运行脚本。&lt;/p>
&lt;p>设置合理的线程数对于能否达到测试目标有决定性的影响。除了上面介绍的固定循环次数与永远外；也可以灵活的选择设定测试运行时间。勾选“调度器”，进行调度器配置。&lt;/p>
&lt;ul>
&lt;li>设置：线程数为10，其它参数默认。&lt;/li>
&lt;/ul>
&lt;br>
#### 添加HTTP请求
----
添加完成线程组后，在线程组上右键菜单（添加--->Sampler--->HTTP请求）选择HTTP请求。对于jmeter来说，取样器（Sampler）是与服务器进行交互的单元。一个取样器通常进行三部分的工作：
```
1、向服务器发送请求
&lt;p>2、记录服务器的响应数据&lt;/p>
&lt;p>3、记录响应时间信息&lt;/p>
&lt;pre tabindex="0">&lt;code>
![](http://img.testclass.net/add_http.png)

![](http://img.testclass.net/http_request.png)

一个HTTP请求有着许多的配置参数，下面将详细介绍：

__名称：__ 本属性用于标识一个取样器，建议使用一个有意义的名称。

__注释：__ 对于测试没有任何作用，仅用户记录用户可读的注释信息。

__服务器名称或IP ：__ HTTP请求发送的目标服务器名称或IP地址。

__端口号：__ 目标服务器的端口号，默认值为80 。

__协议：__ 向目标服务器发送HTTP请求时的协议，可以是http或者是https ，默认值为http 。

__方法：__ 发送HTTP请求的方法，可用方法包括GET、POST、HEAD、PUT、OPTIONS、TRACE、DELETE等。

__Content encoding ：__ 内容的编码方式，默认值为iso8859

__路径：__ 目标URL路径（不包括服务器地址和端口）

__自动重定向：__ 如果选中该选项，当发送HTTP请求后得到的响应是302/301时，JMeter 自动重定向到新的页面。

__Use keep Alive ：__ 当该选项被选中时，jmeter 和目标服务器之间使用 Keep-Alive方式进行HTTP通信，默认选中。

__Use multipart/from-data for HTTP POST ：__ 当发送HTTP POST 请求时，使用Use multipart/from-data方法发送，默认不选中。

* 在这里我们添加一个HTTP请求: http://www.testclass.net

&amp;lt;br&amp;gt;
#### 添加监听器（Listener）
----

脚本的主要部分设置完成后，需要通过某种方式获得性能测试中的测试结果，在本例中，我们关心的是请求的响应时间。

Jmeter 中使用监听器元件收集取样器记录的数据并以可视化的方式来呈现。Jmeter有各种不同的监听器类型，因为上面添加的为HTTP请求，这里添加聚合报告，更为直观的查看测试结果。

添加聚合报告，右键点击线程组，在弹的菜单（添加---&amp;gt;监听器---&amp;gt;聚合报告）中选择聚合报告。

![](http://img.testclass.net/add_report.png)

点击工具栏上的 ```绿色运行按钮``` 或者通过菜单栏（运行---&amp;gt;启动）来运行测试。

查看 __&amp;#34;聚合报告&amp;#34;__ 的运行结果：

![](http://img.testclass.net/test_report.png)

__Label：__ 请求的名称，就是我们在进行测试的httprequest sampler的名称

__Samples：__ 总共发给服务器的请求数量

__Average：__ 单个请求的平均响应时间，单位是毫秒

__Median：__ 50%的请求的响应时间

__90%Line：__ 90%的请求的响应时间

__95%Line：__ 95%的请求的响应时间

__99%Line：__ 99%的请求的响应时间

__Min：__ 最小的响应时间

__Max：__ 最大的响应时间

__Error%：__ 错误率=错误的请求的数量/请求的总数

__Throughput：__ 吞吐量即表示每秒完成的请求数

__Received KB/sec：__ 每秒从服务器端接收到的数据量

__Sent KB/Sec：__ 每秒从发送到服务器端的数据量

&amp;lt;br&amp;gt;
到此，一个简单的性能测试完成了。




原始封面

![课程图片](https://images.unsplash.com/photo-1508081803367-63a3f657e987?w=300)
&lt;/code>&lt;/pre></description></item><item><title>（五）JMeter基础元件介绍</title><link>https://itest2025.pages.dev/tutorials/22-055-%E4%BA%94jmeter%E5%9F%BA%E7%A1%80%E5%85%83%E4%BB%B6%E4%BB%8B%E7%BB%8D/</link><pubDate>Sun, 23 Jul 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/22-055-%E4%BA%94jmeter%E5%9F%BA%E7%A1%80%E5%85%83%E4%BB%B6%E4%BB%8B%E7%BB%8D/</guid><description>&lt;br>
### 测试计划
----
&lt;h4 id="test-plan-测试计划">Test Plan (测试计划)&lt;/h4>
&lt;p>用来描述一个性能测试，包含与本次性能测试所有相关的功能。也就说JMeter创建性能测试的所有内容是于基于一个计划的。&lt;/p>
&lt;p>下面看看一个计划下面都有哪些功能模块（右键单击“测试计划”弹出菜单）。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/test_plan.png"
 data-srcset="http://img.testclass.net/test_plan.png, http://img.testclass.net/test_plan.png 1.5x, http://img.testclass.net/test_plan.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/test_plan.png"
 title="http://img.testclass.net/test_plan.png" />&lt;/p>
&lt;h4 id="threads-users线程-用户">Threads （Users）线程 用户&lt;/h4>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/threads_user.png"
 data-srcset="http://img.testclass.net/threads_user.png, http://img.testclass.net/threads_user.png 1.5x, http://img.testclass.net/threads_user.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/threads_user.png"
 title="http://img.testclass.net/threads_user.png" />&lt;/p>
&lt;p>虽然有三个添加线程组的选项，名字不一样， 创建之后，其界面是完全一样的。在Jmeter之前的版本只有一个线程组的名字。现在多一个 &lt;strong>setUp theread Group&lt;/strong> 与 &lt;strong>tearDown Thread Group&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>setup thread group&lt;/li>
&lt;/ul>
&lt;p>一种特殊类型的ThreadGroup的，可用于执行预测试操作。这些线程的行为完全像一个正常的线程组元件。不同的是，这些类型的线程执行 &lt;strong>测试前&lt;/strong> 进行定期线程组的执行。&lt;/p>
&lt;ul>
&lt;li>teardown thread group&lt;/li>
&lt;/ul>
&lt;p>一种特殊类型的ThreadGroup的，可用于执行测试后动作。这些线程的行为完全像一个正常的线程组元件。不同的是，这些类型的线程执行 &lt;strong>测试结束后&lt;/strong> 进行定期的线程组。&lt;/p>
&lt;p>可能你还是不太理解他们与普通的线程组有什么不同。 如果您用过Junit单元测试框架，想必你不会对setUp(before) ，tearDown(after) 这两个关键字不陌生。 即使没用过，也没关系。 熟悉loadrunner的应该知道，loadrunner的脚本除了action里是真正的脚本核心内容，还有初始化“环境”的初始化脚本和测试完毕后对应的清除信息的脚本块。 那么这里 setup thread group 和 teardown thread group 就是分别指这两部分。 其实从本质上来看，他们并没有什么不同。&lt;/p>
&lt;ul>
&lt;li>thread group(线程组)&lt;/li>
&lt;/ul>
&lt;p>这个就是我们通常添加运行的线程。通俗的讲一个线程组，可以看做一个虚拟用户组，线程组中的每个线程都可以理解为一个虚拟用户。线程组中包含的线程数量在测试执行过程中是不会发生改变的。&lt;/p>
&lt;h4 id="测试片段test-fragment">测试片段（Test Fragment）&lt;/h4>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/test_fragment.png"
 data-srcset="http://img.testclass.net/test_fragment.png, http://img.testclass.net/test_fragment.png 1.5x, http://img.testclass.net/test_fragment.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/test_fragment.png"
 title="http://img.testclass.net/test_fragment.png" />&lt;/p></description></item><item><title>（六）JMeter元件的作用域与执行顺序</title><link>https://itest2025.pages.dev/tutorials/22-056-%E5%85%ADjmeter%E5%85%83%E4%BB%B6%E7%9A%84%E4%BD%9C%E7%94%A8%E5%9F%9F%E4%B8%8E%E6%89%A7%E8%A1%8C%E9%A1%BA%E5%BA%8F/</link><pubDate>Sun, 23 Jul 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/22-056-%E5%85%ADjmeter%E5%85%83%E4%BB%B6%E7%9A%84%E4%BD%9C%E7%94%A8%E5%9F%9F%E4%B8%8E%E6%89%A7%E8%A1%8C%E9%A1%BA%E5%BA%8F/</guid><description>&lt;br>
### 元件的作用域
----
先来讨论一下元件有作用域。《[JMeter基础元件介绍](/jmeter/base-element/)》一节中，我们介绍了8类可被执行的元件（测试计划与线程组不属于元件），这些元件中，__取样器__ 是典型的不与其它元件发生交互作用的元件，__逻辑控制器__ 只对其子节点的取样器有效，而其它元件（config elements 、timers 、post-processors、assertions、listeners）需要与取样器（sampler）等元件交互。
&lt;ul>
&lt;li>&lt;strong>配置元件（config elements）&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>元件会影响其作用范围内的所有元件。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>前置处理程序（Per-processors）&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>元件在其作用范围内的每一个sampler元件之前执行。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>定时器（timers ）&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>元件对其作用范围内的每一个sampler有效。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>后置处理程序（Post-processors）&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>元件在其作用范围内的每一个sampler元件之后执行。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>断言（Assertions）&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>元件对其作用范围内的每一个sampler元件执行后的结果执行校验。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>监听器（Listeners）&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>元件收集其作用范围的每一个sampler元件的信息并呈现。&lt;/p>
&lt;br>
在JMeter中，元件的作用域是靠测试计划的的树型结构中元件的父子关系来确定的，作用域的原则是：
&lt;ul>
&lt;li>
&lt;p>取样器（sampler）元件不和其它元件相互作用，因此不存在作用域的问题。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>逻辑控制器（Logic Controller）元件只对其子节点中的取样器 和 逻辑控制器作用。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>除取样器和逻辑控制器元件外，其他6类元件，如果是某个sampler的子节点，则该元件会对其父子节点起作用。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>除取样器和逻辑控制器元件外，其他6类元件，如果其父节点不是sampler ，则其作用域是该元件父节点下的其他所有后代节点（包括子节点，子节点的子节点等）。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>讲了这些，你可能迷糊了，到底是肿么个情况呀！？通过两个栗子（例子）来理解一下他们的作用域。&lt;/p>
&lt;p>&lt;strong>例一&lt;/strong>&lt;/p>
&lt;p>&lt;font color=#FF6347 >注：下图只是为了说明作用域，无法正常运行。&lt;/font>&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/element_scope_demo1.png"
 data-srcset="http://img.testclass.net/element_scope_demo1.png, http://img.testclass.net/element_scope_demo1.png 1.5x, http://img.testclass.net/element_scope_demo1.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/element_scope_demo1.png"
 title="http://img.testclass.net/element_scope_demo1.png" />&lt;/p>
&lt;p>&lt;strong>取样器：&lt;/strong> HTTP请求 、FTP请求 、TCP取样器；&lt;strong>逻辑控制器：&lt;/strong> 循环控制器；&lt;strong>监听器：&lt;/strong> 图形结果、聚合报告。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>HTTP请求、FTP请求、TCP取样器 元件没有作用域的概念。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>循环控制器 元件作用域是其子节点FTP请求 、TCP取样器 。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>图形结果 元件的作用域是FTP请求 、TCP取样器。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>聚合报告 元作的作用域是HTTP请求 、FTP请求 、TCP取样器。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>例二&lt;/strong>&lt;/p>
&lt;p>&lt;font color=#FF6347 >注：下图只是为了说明作用域，无法正常运行。&lt;/font>&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/element_scope_demo2.png"
 data-srcset="http://img.testclass.net/element_scope_demo2.png, http://img.testclass.net/element_scope_demo2.png 1.5x, http://img.testclass.net/element_scope_demo2.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/element_scope_demo2.png"
 title="http://img.testclass.net/element_scope_demo2.png" />&lt;/p></description></item><item><title>（七）JMeter基础知识点：参数化</title><link>https://itest2025.pages.dev/tutorials/22-057-%E4%B8%83jmeter%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86%E7%82%B9%E5%8F%82%E6%95%B0%E5%8C%96/</link><pubDate>Sat, 22 Jul 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/22-057-%E4%B8%83jmeter%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86%E7%82%B9%E5%8F%82%E6%95%B0%E5%8C%96/</guid><description>&lt;br>
### 参数化
----
简单的来理解一下，我们录制了一个脚本，这个脚本中有登录操作，需要输入用户名和密码，假如系统不允许相同的用户名和密码同时登录，或者想更好的模拟多个用户来登录系统。
&lt;p>这个时候就需要对用户名和密码进行参数化，使每个虚拟用户都使用不同的用户名和密码进行访问。&lt;/p>
&lt;p>&lt;strong>前提需求：&lt;/strong>&lt;/p>
&lt;p>我们有一个嘉宾管理系统，该系统需要登录。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/guest_systme_login.png"
 data-srcset="http://img.testclass.net/guest_systme_login.png, http://img.testclass.net/guest_systme_login.png 1.5x, http://img.testclass.net/guest_systme_login.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/guest_systme_login.png"
 title="http://img.testclass.net/guest_systme_login.png" />&lt;/p>
&lt;p>在Jmeter中添加一个登录HTTP请求，设置登录的用户名和密码。如下：&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/login_http_request.png"
 data-srcset="http://img.testclass.net/login_http_request.png, http://img.testclass.net/login_http_request.png 1.5x, http://img.testclass.net/login_http_request.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/login_http_request.png"
 title="http://img.testclass.net/login_http_request.png" />&lt;/p>
&lt;p>配置参数：&lt;/p>
&lt;pre tabindex="0">&lt;code>* 协议：http
* IP（网址）：127.0.0.1
* 端口号：8000
* 请求方法：POST
* 请求路径：/login_action/
* 自动重定向
* 同请求一起发送参数: username=admin, password=admin123456
&lt;/code>&lt;/pre>&lt;br>
#### 设置参数化
&lt;p>&lt;strong>第一步：&lt;/strong>&lt;/p>
&lt;p>我们需要“参数化”的数据，这里我用CSV格式的文件创建了五个用户名/密码，保存为.csv格式的文件。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/login_user_csv.png"
 data-srcset="http://img.testclass.net/login_user_csv.png, http://img.testclass.net/login_user_csv.png 1.5x, http://img.testclass.net/login_user_csv.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/login_user_csv.png"
 title="http://img.testclass.net/login_user_csv.png" />&lt;/p>
&lt;p>将文件放在：&lt;strong>D:\login_user.csv&lt;/strong> 。关于如何得到成百上千的用户名和密码，可以使用SQL语句在数据库中创建，并将数据导出保存，这里就不深究。&lt;/p>
&lt;p>&lt;strong>第二步：&lt;/strong>&lt;/p>
&lt;p>好，我们要编写函数来调用这个login_user.csv文件，点击菜单栏“选项”&amp;mdash;-&amp;gt;“函数助手对话框”，如下图。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/function_helper.png"
 data-srcset="http://img.testclass.net/function_helper.png, http://img.testclass.net/function_helper.png 1.5x, http://img.testclass.net/function_helper.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/function_helper.png"
 title="http://img.testclass.net/function_helper.png" />&lt;/p>
&lt;p>&lt;font color=#FF6347 >注：.csv文件第一列从0开始取得。&lt;/font>&lt;/p></description></item><item><title>（八）JMeter基础知识点：检查点</title><link>https://itest2025.pages.dev/tutorials/22-058-%E5%85%ABjmeter%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86%E7%82%B9%E6%A3%80%E6%9F%A5%E7%82%B9/</link><pubDate>Sat, 22 Jul 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/22-058-%E5%85%ABjmeter%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86%E7%82%B9%E6%A3%80%E6%9F%A5%E7%82%B9/</guid><description>&lt;br>
### 检查点
----
检查点不是太专的叫法，不管是在自动化测试还是性能测试工具中，应该叫：__断言__
&lt;p>简单的来理解一下，在《&lt;a href="https://itest2025.pages.dev/jmeter/jmeter-parameterize/" rel="">JMeter基础知识点：参数化&lt;/a>》中，我们对用户名和密码进行了参数化，那么怎样来判断JMeter参数化的用户有没真正的登录成功呢？或者有没有返回登录成功的页面。这就需要用到 &lt;strong>断言&lt;/strong> 了。&lt;/p>
&lt;p>&lt;strong>前提需求：&lt;/strong>&lt;/p>
&lt;p>我们有一个嘉宾管理系统，该系统登录成功的页面。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/guest_systme_login_success.png"
 data-srcset="http://img.testclass.net/guest_systme_login_success.png, http://img.testclass.net/guest_systme_login_success.png 1.5x, http://img.testclass.net/guest_systme_login_success.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/guest_systme_login_success.png"
 title="http://img.testclass.net/guest_systme_login_success.png" />&lt;/p>
&lt;br>
#### 添加断言
----
&lt;p>&lt;strong>第一步&lt;/strong>&lt;/p>
&lt;p>右键点击“HTTP请求”&amp;mdash;-&amp;gt;添加&amp;mdash;-&amp;gt;断言&amp;mdash;-&amp;gt;响应断言。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/add_assertion.png"
 data-srcset="http://img.testclass.net/add_assertion.png, http://img.testclass.net/add_assertion.png 1.5x, http://img.testclass.net/add_assertion.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/add_assertion.png"
 title="http://img.testclass.net/add_assertion.png" />&lt;/p>
&lt;p>&lt;strong>第二步&lt;/strong>&lt;/p>
&lt;p>打开响应断言，进行设置。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/assert_login_info.png"
 data-srcset="http://img.testclass.net/assert_login_info.png, http://img.testclass.net/assert_login_info.png 1.5x, http://img.testclass.net/assert_login_info.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/assert_login_info.png"
 title="http://img.testclass.net/assert_login_info.png" />&lt;/p>
&lt;p>&lt;strong>要测试的响应字段：&lt;/strong> 响应文本、Document(text)、URL样本、响应信息、Response Headers、Lgnore Staus
等选项。虽然接口返回的是HTML页面，但对于JMeter来说返回数据为文本，所以，这里可以勾选“响应文本”。&lt;/p>
&lt;p>&lt;strong>模式匹配规则：&lt;/strong> 包括、 匹配、 Equals、 Substring。这里只需要验证返回数据中是否包含主要的关键字，所
以， 这里勾选“包括” 。&lt;/p>
&lt;p>&lt;strong>要测试的模式：&lt;/strong> 其实就是断言的数据。 点击“添加” 按钮， 输入要断言的数据。&lt;/p>
&lt;p>&lt;font color=#FF6347 > 我们怎么 &lt;strong>证明&lt;/strong> 登录是成功的？肯定是从登录成功的页面上抓取信息来判断了。那么，&lt;strong>Guest Manage System&lt;/strong> 和 &lt;strong>退出&lt;/strong> 看来不错，因为只有登录成功的页面上才有。&lt;/font>&lt;/p></description></item><item><title>（九）JMeter基础知识点：集合点</title><link>https://itest2025.pages.dev/tutorials/22-059-%E4%B9%9Djmeter%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86%E7%82%B9%E9%9B%86%E5%90%88%E7%82%B9/</link><pubDate>Sat, 22 Jul 2017 12:59:10 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/22-059-%E4%B9%9Djmeter%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86%E7%82%B9%E9%9B%86%E5%90%88%E7%82%B9/</guid><description>&lt;br>
### 集合点
----
&lt;p>简单来理解一下，虽然我们的“性能测试”理解为“多用户并发测试”，但真正的并发是不存在的，为了更真实的实现并发的操作，我们可以在需要压力的地方设置集合点。&lt;/p>
&lt;p>关联阅读：
《&lt;a href="https://itest2025.pages.dev/jmeter/jmeter-parameterize/" rel="">JMeter基础知识点：参数化&lt;/a>》
《&lt;a href="https://itest2025.pages.dev/jmeter/jmeter-assertions/" rel="">JMeter基础知识点：检查点&lt;/a>》&lt;/p>
&lt;p>还拿前面用户和密码的功能，每到输入用户名和密码登录的地方，所有的虚拟用户都相互之间等一等，然后一起访问。（连长说一声令下，大家一起冲啊！这样给敌人的压力会很大。）&lt;/p>
&lt;p>&lt;strong>第一步&lt;/strong>&lt;/p>
&lt;p>接着在之前创建的脚本的基础上，右键点击 HTTP请求&amp;mdash;-&amp;gt;定时器&amp;mdash;-&amp;gt;Synchronizing Timer。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/add_synchronizing_time.png"
 data-srcset="http://img.testclass.net/add_synchronizing_time.png, http://img.testclass.net/add_synchronizing_time.png 1.5x, http://img.testclass.net/add_synchronizing_time.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/add_synchronizing_time.png"
 title="http://img.testclass.net/add_synchronizing_time.png" />&lt;/p>
&lt;p>&lt;strong>第二步&lt;/strong>&lt;/p>
&lt;p>设置集合点：&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/synchronizing_time_setting.png"
 data-srcset="http://img.testclass.net/synchronizing_time_setting.png, http://img.testclass.net/synchronizing_time_setting.png 1.5x, http://img.testclass.net/synchronizing_time_setting.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/synchronizing_time_setting.png"
 title="http://img.testclass.net/synchronizing_time_setting.png" />&lt;/p>
&lt;p>&lt;strong>Number of Simulated Users to Group by：&lt;/strong> 每次释放的线程数量。如果设置为0，等同于线程组中设置的线程数量。&lt;/p>
&lt;p>&lt;strong>Timeout in milliseconds：&lt;/strong> 如果设置为0，Timer将会等待线程数达到了&amp;quot;Number of Simultaneous Users to Group&amp;quot;中设置的值才释放。如果大于0，那么超过Timeout in milliseconds中设置的最大等待时间(毫秒为单位)后还没达到&amp;quot;Number of Simultaneous Users to Group&amp;quot;中设置的值，Timer将不再等待，释放已到达的线程。&lt;/p>
&lt;p>&lt;strong>注意：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>如果设置Timeout in milliseconds为0，且线程数量无法达到&amp;quot;Number of Simultaneous Users to Group by&amp;quot;中设置的值，那么Test将无限等待，除非手动终止。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Synchronizing timer 仅作用于同一个JVM中的线程,所以，如果使用并发测试，确保&amp;quot;Number of Simultaneous Users to Group by&amp;quot;中设置的值不大于它所在线程组包含的用户数。&lt;/p></description></item><item><title>1天通过3家技术面试是什么样的一种体验</title><link>https://itest2025.pages.dev/tutorials/47-000-1%E5%A4%A9%E9%80%9A%E8%BF%873%E5%AE%B6%E6%8A%80%E6%9C%AF%E9%9D%A2%E8%AF%95%E6%98%AF%E4%BB%80%E4%B9%88%E6%A0%B7%E7%9A%84%E4%B8%80%E7%A7%8D%E4%BD%93%E9%AA%8C/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-1%E5%A4%A9%E9%80%9A%E8%BF%873%E5%AE%B6%E6%8A%80%E6%9C%AF%E9%9D%A2%E8%AF%95%E6%98%AF%E4%BB%80%E4%B9%88%E6%A0%B7%E7%9A%84%E4%B8%80%E7%A7%8D%E4%BD%93%E9%AA%8C/</guid><description>&lt;p>今天有个同学很兴奋的告诉我，她今天一天就通过了3家公司的技术面试。&lt;/p>
&lt;p>我得知这个消息也非常开心，顺便就问了一下她的心得体会，如何才能做到一天之内三战三捷的。&lt;/p>
&lt;p>首先应该是学习。&lt;/p>
&lt;p>互联网行业或者是it企业知识是不断更新迭代的，之前的经验在很多时候很可能不是优势，而是会局限你的认知。就拿我自己举例子，当年在angular js/vue js/react js刚诞生的时候，我还是拘泥于之前的jquery思维，认为开发玩转jquery基本上就可以搞定一切了，但如今jquery基本上是属于上古的技术了，vue js和react js基本上在前端领域处于统治地位。持续的以空杯心态进行学习很重要，之前的经验也许有帮助，但不能过于拘泥，技术革命总是很残酷，新事物的崛起总会让一些守旧的人付出代价。花点时间去学习一些你难以理解的东西，这种投资其实非常值得。&lt;/p>
&lt;p>但是学习和尝试意味着要花费大量的时间，如何高效持续的进行学习呢？这位同学的做法我觉得是很可取的，那就是把学到的东西运用在项目里。&lt;/p>
&lt;p>举个例子，假如你测试的项目/产品有微信端的小程序，那么你可以学习接口的自动化测试，因为微信小程序会调用后端接口，加上一定的前端逻辑之后将页面渲染出来展示给用户。这种前后端分离的模式是现在的主流开发方式，分离之后前端管交互和展示，后端管逻辑和数据。数据和逻辑相对于用户看到的复杂页面来说本身就屏蔽了很多无用的信息，自动化验证和比对的难度也会降低不少，给自动化带来了不错的落地机会，很适合在项目中进行尝试。这种尝试的过程其实就是学习的过程，不要怕最终的结果达不到预期，这种追求的过程其实才是最重要的。&lt;/p>
&lt;p>然后就是给团队安全感。&lt;/p>
&lt;p>一般情况下，那些被认可的测试同学往往会给团队很强的安全感，这种安全感体现在方方面面，比如线上问题的定位，发布流程的保障，文档的整理，质量问题的总结等。&lt;/p>
&lt;p>这位同学很显然是不经意间做到了这一点。她说自己主动一点，做一些看似鸡肋的工作，比如业务文档整理，自己复盘，同样的问题不出现两次；最后做好业务支撑和质量把控，坚持做下去，团队会对你产生信赖甚至是依赖，也会给你带来不错的话语权，有了话语权你才能去推动一些看上去费力不讨好但在工程技术层面很重要的事情，比如持续集成，单元测试等等。&lt;/p>
&lt;p>这位同学的经历其实很典型，是属于厚积薄发的例子。每天都进步一点点，日积月累以后竞争力就会比较明显了。&lt;/p>
&lt;p>最终她拿3份offer都顺利拿到，不过她最心仪的一家给的薪资涨幅是最少的，但也达到了18k。其实也有给到20k的，不过考虑到发展，还是去了18k的那一家。&lt;/p>
&lt;p>最后还是真诚的祝贺这位同学，当学习成了一种习惯，后面的事情就会水到渠成了。&lt;/p>
&lt;p>大家一起继续加油吧。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1445712525433-eba07da78bd2?w=300"
 data-srcset="https://images.unsplash.com/photo-1445712525433-eba07da78bd2?w=300, https://images.unsplash.com/photo-1445712525433-eba07da78bd2?w=300 1.5x, https://images.unsplash.com/photo-1445712525433-eba07da78bd2?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1445712525433-eba07da78bd2?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>2020年了，终于可以让siri帮我们做自动化测试了</title><link>https://itest2025.pages.dev/tutorials/47-000-2020%E5%B9%B4%E4%BA%86%E7%BB%88%E4%BA%8E%E5%8F%AF%E4%BB%A5%E8%AE%A9siri%E5%B8%AE%E6%88%91%E4%BB%AC%E5%81%9A%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E4%BA%86/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-2020%E5%B9%B4%E4%BA%86%E7%BB%88%E4%BA%8E%E5%8F%AF%E4%BB%A5%E8%AE%A9siri%E5%B8%AE%E6%88%91%E4%BB%AC%E5%81%9A%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E4%BA%86/</guid><description>&lt;p>2020年是一个魔幻的年份，那么在这一年里，我们不妨玩的更科幻一点。&lt;/p>
&lt;p>在下面这个视频里，我们看看怎么样使用siri帮我们做自动化测试吧。&lt;/p>
&lt;h3 id="原理分析">原理分析&lt;/h3>
&lt;p>原理其实很简单。首先用语音唤醒siri，调用ios的快捷指令，自动给在公司的小伙伴打电话，让他们配合表演，做一阵各种操作，把测试结果返回。&lt;/p>
&lt;p>当然，这是开玩笑的。&lt;/p>
&lt;p>真正的原理如下图所示&lt;/p>
&lt;p>其实就是用语音唤醒siri之后调用ios的快捷操作app，通过ssh到远程服务器的方式，调用远程服务器上的测试脚本，运行用例，并将结果返回。&lt;/p>
&lt;h3 id="用到的设备">用到的设备&lt;/h3>
&lt;ul>
&lt;li>一台ios机器，iphone和ipad都可以，升级到最新版本&lt;/li>
&lt;li>一台云服务器，能ssh访问&lt;/li>
&lt;/ul>
&lt;h3 id="测试用例">测试用例&lt;/h3>
&lt;p>因为偷懒的关系，我就没有写特别复杂的用例了，这里我就用python简单测试了一下重定向科技的所有课程页面，属于简单的界面UI测试范畴。&lt;/p>
&lt;p>不过这里没有用到selenium，而是直接发送1个get请求拿到页面的html，然后从html标签中分离出我想要的关键信息做断言。&lt;/p>
&lt;p>先写自然语言的用例&lt;/p>
&lt;ul>
&lt;li>发GET请求到http://www.itest.info/courses&lt;/li>
&lt;li>拿到html后用css选择器.servive-block-in &amp;gt; h4拿到所有课程的名称&lt;/li>
&lt;li>课程名称里包含&lt;strong>全栈测试开发班&lt;/strong>这个课程，这里用包含断言，提升了用例的鲁棒性，也就是说跑多次不容易报错&lt;/li>
&lt;/ul>
&lt;p>再用python去实现一遍&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">requests&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="nn">unittest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">bs4&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">BeautifulSoup&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">url&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;http://www.itest.info/courses&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">html&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">requests&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">soup&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">BeautifulSoup&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">html&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;html.parser&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">titles&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">soup&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">select&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;.servive-block-in &amp;gt; h4&amp;#39;&lt;/span>&lt;span class="p">)]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">course_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;全栈测试开发班&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">assert&lt;/span> &lt;span class="n">course_name&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">titles&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s1">不在课程列表中&amp;#39;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">course_name&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">titles&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;All good&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这里用到了2个第三方库&lt;/p>
&lt;ul>
&lt;li>requests：简化http的各种操作&lt;/li>
&lt;li>BeautifulSoup4: html parser，方便我们从html标签中分离出各种有效信息&lt;/li>
&lt;/ul>
&lt;p>用例的整体思路借鉴了多年前google提出的测试降级思路，也就是如果页面上的一些元素可能是干扰项，那么就需要在用例中去掉这些干扰，实际上这个脚本其实就是一个简单的爬虫，只是加了断言而已。&lt;/p>
&lt;h3 id="确保可以远程运行">确保可以远程运行&lt;/h3>
&lt;p>将脚本放到云服务器上，运行&lt;/p>
&lt;pre tabindex="0">&lt;code>python itest.info.py
&lt;/code>&lt;/pre>&lt;p>结果应该如下&lt;/p>
&lt;pre tabindex="0">&lt;code>[&amp;#39;全栈测试开发班&amp;#39;, &amp;#39;性能测试班&amp;#39;, &amp;#39;接口自动化测试开发--Python班&amp;#39;, &amp;#39;Selenium自动化测试--Python班&amp;#39;]
All good
&lt;/code>&lt;/pre>&lt;h3 id="配置快捷指令">配置快捷指令&lt;/h3>
&lt;p>一步一步按图来配置就好了。&lt;/p>
&lt;p>这里我配置了&lt;/p>
&lt;ul>
&lt;li>通过ssh运行脚本，在这里选择ssh到了远程服务器，并执行了shell脚本&lt;/li>
&lt;li>播放声音，这个纯属为了好玩&lt;/li>
&lt;li>最后显示shell脚本结果，把运行的结果返回回来&lt;/li>
&lt;/ul>
&lt;p>配置好快捷指令之后就可以用siri去运行这个指令了。&lt;/p>
&lt;h3 id="最后">最后&lt;/h3>
&lt;p>用siri去执行自动化测试脚本，听上去感觉脑洞很大，但只要了解了原理，就会发现其实并不算困难。&lt;/p>
&lt;p>整个过程看上去很简单，但其实包含了一些值得分享的思路。&lt;/p>
&lt;ul>
&lt;li>能在命令行里跑的都在命令行里跑&lt;/li>
&lt;li>能在云服务器跑的都在云服务器上跑&lt;/li>
&lt;li>工作中其实有很多地方都可以用到自动化，主要看脑洞够不够大&lt;/li>
&lt;/ul>
&lt;p>通过siri + 快捷操作的方式，你还可以实现&lt;/p>
&lt;ul>
&lt;li>通过siri去部署&lt;/li>
&lt;li>通过siri去运行爬虫&lt;/li>
&lt;li>通过siri去执行jenkins任务，ssh到一台跳板机，然后通过curl运行jenkins api&lt;/li>
&lt;li>其他更多&amp;hellip;.&lt;/li>
&lt;/ul>
&lt;p>有兴趣的同学不妨亲自动手试一下，跑通了流程以后也许可以在面试的时候表演一下，比如假装收到告警短信，然后低调的语音唤醒siri，说跑一下现网的监控测试，然后就优雅的等待测试结果或翻车，总之，人生如戏，全靠演技。&lt;/p></description></item><item><title>2021年春节国外程序员在忙什么？</title><link>https://itest2025.pages.dev/tutorials/47-000-2021%E5%B9%B4%E6%98%A5%E8%8A%82%E5%9B%BD%E5%A4%96%E7%A8%8B%E5%BA%8F%E5%91%98%E5%9C%A8%E5%BF%99%E4%BB%80%E4%B9%88/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-2021%E5%B9%B4%E6%98%A5%E8%8A%82%E5%9B%BD%E5%A4%96%E7%A8%8B%E5%BA%8F%E5%91%98%E5%9C%A8%E5%BF%99%E4%BB%80%E4%B9%88/</guid><description>&lt;p>2021年的春节就这样平平淡淡的过去了。&lt;/p>
&lt;p>经历了2020年春节的惊心动魄和焦虑挣扎，现在才发现平淡其实才是幸福的所在。&lt;/p>
&lt;p>因为平时喜欢逛github，喜欢在trending里翻一些最近热门的开源项目，从而洞察一些基本的技术走向和猎奇一些有意思的项目工具，经过多年的观察，我发现github的python语言趋势相当接地气，我们可以从中看到国外的主流技术圈最近在关注些什么，思考些什么以及忙些什么。&lt;/p>
&lt;p>2021年2月的python趋势的现实意义格外的明显，我们可以看到国外的程序员大概在关注下面一些技术以及热点。&lt;/p>
&lt;h3 id="数据可视化">数据可视化&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>apache/superset这个项目热度排在python榜单的首位，该项目主要做的是数据可视化，支持多种数据库和各种图形图表，是数据分析以及展示的一大利器。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>streamlit/streamlit也是数据可视化工具， 可以用python代码来直接实现基于数据展示的app，实用性也非常的高。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>fishtown-analytics/dbt应该也是数据可视化工具，不过具体怎么使用我也不是很清楚。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="数字货币">数字货币&lt;/h3>
&lt;p>freqtrade / freqtrade, CoinAlpha / hummingbot, CryptoSignal / Crypto-Signal, bitcoinbook / bitcoinbook, sammchardy/python-binance, yasinkuyu/binance-trader
,pyca/cryptography等项目上榜。&lt;/p>
&lt;p>这些项目涉及数字货币的自动交易，数字货币教程等方面，榜单的24个项目中数字货币相关的项目占到了7个，占比为30%左右，呈屠榜态势，这个2月数字货币炙手可热。&lt;/p>
&lt;h3 id="金融市场">金融市场&lt;/h3>
&lt;p>2021年的金融市场有酒有故事，魔幻而浪漫。&lt;/p>
&lt;p>榜单中mrjbq7 / ta-lib, ranaroussi / yfinance为金融相关项目，稍微看了一下这两个项目的api，基本的作用就是看盘和分析，春节期间看来不少老外在忙着炒股。&lt;/p>
&lt;h3 id="机器学习以及人工智能">机器学习以及人工智能&lt;/h3>
&lt;p>机器学习类的项目一直在python热榜中占比很高，这次 PaddlePaddle / PaddleOCR, microsoft / DeepSpeed, eriklindernoren / ML-From-Scratch上榜，加上之前的榜单中一直霸榜的tensorflow等项目，机器学习这些年热度一直颇高，值得大家学习。&lt;/p>
&lt;h3 id="新冠病毒">新冠病毒&lt;/h3>
&lt;p>owid/covid-19-data这个项目每日实时更新新冠的一些数据，比如确诊数等，结合上面的数据可视化工具应该可以做出各种图表，帮助我们了解目前疫情在全球的蔓延情况。&lt;/p>
&lt;h3 id="其他">其他&lt;/h3>
&lt;p>其他还有诸如&lt;/p>
&lt;ul>
&lt;li>python/mypy这是python的静态类型检查工具，可以简单的理解为typescript之于javascript，为python做静态类型分析，从而减少运行时的一些低级错误&lt;/li>
&lt;li>qutebrowser/qutebrowser一个有意思的浏览器，支持vim键位，极客的选择，不过不知道可用性如何，毕竟是使用python开发的，运行效率可能是瓶颈&lt;/li>
&lt;/ul>
&lt;h3 id="总结">总结&lt;/h3>
&lt;p>从python热榜中我们可以得到下面的一些关键字&lt;/p>
&lt;ul>
&lt;li>大数据与机器学习&lt;/li>
&lt;li>数字货币&lt;/li>
&lt;li>股票市场&lt;/li>
&lt;li>新冠疫情&lt;/li>
&lt;/ul>
&lt;p>这些是春节期间国外程序员关注的点，其中大数据与机器学习是长期趋势，股票市场只是近期热度飙升，数字货币浮浮沉沉，不定期屠榜。&lt;/p>
&lt;h3 id="完整榜单">完整榜单&lt;/h3>
&lt;pre tabindex="0">&lt;code>1 &amp;#34; apache / superset&amp;#34;
2 &amp;#34; freqtrade / freqtrade&amp;#34;
3 &amp;#34; PaddlePaddle / PaddleOCR&amp;#34;
4 &amp;#34; CoinAlpha / hummingbot&amp;#34;
5 &amp;#34; microsoft / DeepSpeed&amp;#34;
6 &amp;#34; CryptoSignal / Crypto-Signal&amp;#34;
7 &amp;#34; sammchardy / python-binance&amp;#34;
8 &amp;#34; owid / covid-19-data&amp;#34;
9 &amp;#34; bitcoinbook / bitcoinbook&amp;#34;
10 &amp;#34; mrjbq7 / ta-lib&amp;#34;
11 &amp;#34; qutebrowser / qutebrowser&amp;#34;
12 &amp;#34; ranaroussi / yfinance&amp;#34;
13 &amp;#34; yasinkuyu / binance-trader&amp;#34;
14 &amp;#34; streamlit / streamlit&amp;#34;
15 &amp;#34; netbox-community / netbox&amp;#34;
16 &amp;#34; microsoft / cascadia-code&amp;#34;
17 &amp;#34; fishtown-analytics / dbt&amp;#34;
18 &amp;#34; kangvcar / InfoSpider&amp;#34;
19 &amp;#34; explosion / spaCy&amp;#34;
20 &amp;#34; python / mypy&amp;#34;
21 &amp;#34; eriklindernoren / ML-From-Scratch&amp;#34;
22 &amp;#34; psf / black&amp;#34;
23 &amp;#34; FengQuanLi / ResnetGPT&amp;#34; //中文项目，剔除
24 &amp;#34; pyca / cryptography&amp;#34;
25 &amp;#34; dask / dask&amp;#34;
&lt;/code>&lt;/pre>&lt;p>原始封面&lt;/p></description></item><item><title>2021年的第一个flag--cypress实战教程</title><link>https://itest2025.pages.dev/tutorials/47-000-2021%E5%B9%B4%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AAflag--cypress%E5%AE%9E%E6%88%98%E6%95%99%E7%A8%8B/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-2021%E5%B9%B4%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AAflag--cypress%E5%AE%9E%E6%88%98%E6%95%99%E7%A8%8B/</guid><description>&lt;p>cypress的目的是为前端开发同学降低日常工作中重复的end to end测试工作量，提高测试效率，尽管是面向开发，但测试同学花时间去学习还是非常值得的。&lt;/p>
&lt;p>会测试的开发其实是受欢迎的，会开发的测试竞争力也是有目共睹的。&lt;/p>
&lt;p>前几天听到一个理论，要想达到高收入，那么你可能需要在某一个领域技能达到90或100分，显然这是很难的。&lt;/p>
&lt;p>但是你也可以跨界，为自己多开辟一个赛道，你可以在某个领域做到50分，然后另一个领域也是50分，这样合起来也是竞争力比某个领域精通的90分其实也不差，测试学习开发技能的底层逻辑也就这里。&lt;/p>
&lt;p>既然对于大多数人来说，炒房资金不足，又不想去股市币圈当韭菜，那么把有限的时间和金钱花在投资自己身上，其实是明智的决定。&lt;/p>
&lt;p>随手在搜索引擎上找了一下，发现结构良好的cypress教程还是屈指可数的。&lt;/p>
&lt;p>新的一年到来了，不如先立个flag，写一套cypress的实用教程吧。&lt;/p>
&lt;p>那我为什么要写教程呢？&lt;/p>
&lt;ul>
&lt;li>写教程也是学习的过程，我需要持续学习来提升自己的竞争力&lt;/li>
&lt;li>写教程让人痛苦，不过有痛苦才会有进步，撸铁的同学肯定有类似的体验&lt;/li>
&lt;li>我乐于分享，而且坚持了好久，成了习惯&lt;/li>
&lt;li>有了文字教程就可以尝试视频教程，剪辑制作高质量的视频教程也是我2021年想提高的点&lt;/li>
&lt;/ul>
&lt;p>既然是实用教程，那么一定要从实际项目开始，好在cypress非常贴心的提供了cypress realworld项目，尽管这个项目没啥现实生活中的实际实用意义，不过有前端，有后台，有单元测试用例，接口测试用例以及ui测试用例，五脏俱全，工整优雅，来源于学习的目的，但实际上对我们的测试思路还是有很好的指导效果的。所以cypress教程不如换个思路来做，直接看别人的项目是怎么做自动化测试的，用例怎么选取的，断言如何写的，项目目录结构是怎么样的，从实战中去补充基础知识，这样效果也许会更好一点，或者是更功利一点。&lt;/p>
&lt;h3 id="整体思路">整体思路&lt;/h3>
&lt;p>分析cypress realworld项目，地址：https://github.com/cypress-io/cypress-realworld-app，从项目中学会&lt;/p>
&lt;ul>
&lt;li>typescript的简单语法，因为项目是typescript写的，会一点简单的语法方便我们进行源码阅读&lt;/li>
&lt;li>体验cypress realworld项目，梳理出主要功能，这是熟悉需求&lt;/li>
&lt;li>梳理后端接口和数据结构，这一步是了解后台逻辑实现&lt;/li>
&lt;li>了解express,lowdb的简单使用，这一步的目的是为了让我们能看懂项目的后台代码&lt;/li>
&lt;li>了解react,xstate的简单使用，为了看懂前端代码，这两个框架的时间投入还是值得的&lt;/li>
&lt;li>了解cypress功能&lt;/li>
&lt;li>了解前后端分离app的工作模式&lt;/li>
&lt;li>单元测试怎么写?看一下实际项目中的单元测试实现&lt;/li>
&lt;li>接口用例怎么写？看一下高水平的开发者的接口测试思路&lt;/li>
&lt;li>ui测试用例怎么写？这里很难一言以蔽之&lt;/li>
&lt;li>database seeding是什么？为什么会降低ui测试的难度？&lt;/li>
&lt;li>cypress怎么做ci/cd的？了解ci/cd的工作原理与工作流程&lt;/li>
&lt;/ul>
&lt;h3 id="大纲草稿">大纲草稿&lt;/h3>
&lt;ul>
&lt;li>ts语法简介，主要参考微软官方文档:https://www.typescriptlang.org/docs/handbook/intro.html&lt;/li>
&lt;li>cypress realdworld项目部署(也可以不用部署)&lt;/li>
&lt;li>cypress realworld项目初体验，输出主要功能文档&lt;/li>
&lt;li>cypress的主要功能，参考https://docs.cypress.io/guides/core-concepts/introduction-to-cypress.html#Cypress-Can-Be-Simple-Sometimes
&lt;ul>
&lt;li>重试机制&lt;/li>
&lt;li>元素的交互&lt;/li>
&lt;li>分支测试&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>cypress relaworld的后台接口分析&lt;/li>
&lt;li>如何使用express+lowdb实现后台接口
&lt;ul>
&lt;li>数据库设计&lt;/li>
&lt;li>鉴权&lt;/li>
&lt;li>路由及持久化实现&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>分析cypress relaworld的单元测试实现&lt;/li>
&lt;li>分析cypress relaworld的接口测试实现&lt;/li>
&lt;li>如何使用react+xstate实现前端功能
&lt;ul>
&lt;li>react简介以及页面的渲染&lt;/li>
&lt;li>路由实现&lt;/li>
&lt;li>状态机实现&lt;/li>
&lt;li>与后台的交互&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>分析ui测试用例
&lt;ul>
&lt;li>如何选取用例&lt;/li>
&lt;li>断言怎么写&lt;/li>
&lt;li>什么是db seeding，有什么好处&lt;/li>
&lt;li>怎么调试&lt;/li>
&lt;li>怎么截图和录视频&lt;/li>
&lt;li>怎么设置环境变量&lt;/li>
&lt;li>如何使用test runner去命令行跑指定用例&lt;/li>
&lt;li>怎么做多浏览器兼容性测试&lt;/li>
&lt;li>怎么做ci/cd&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>随便列了一下，发现内容还是相当丰富的，如果一周出一篇的话，基本上半年大半年就过去了。&lt;/p></description></item><item><title>2021年最适合测试同学学习的技术</title><link>https://itest2025.pages.dev/tutorials/47-000-2021%E5%B9%B4%E6%9C%80%E9%80%82%E5%90%88%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E5%AD%A6%E4%B9%A0%E7%9A%84%E6%8A%80%E6%9C%AF/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-2021%E5%B9%B4%E6%9C%80%E9%80%82%E5%90%88%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E5%AD%A6%E4%B9%A0%E7%9A%84%E6%8A%80%E6%9C%AF/</guid><description>&lt;p>2021年已经悄无声息的快过去1个月了，大家已经开始立年度flag了吗？如果没有的话先不急，等我们盘点完2021年最值得测试同学学习和了解的技术之后，也许大家就有立flag的冲动了。&lt;/p>
&lt;p>在这里我推荐的技术都是遵循性价比高，也就是投入时间相对较少而产出相对较高这个原则来的，因为我们时间有限，相对来说容易掌握，变动性小，投入时间相对少的技术是大家可以去涉猎的。&lt;/p>
&lt;h3 id="语言类">语言类&lt;/h3>
&lt;p>测试同学掌握一门编程语言应该是以后的大趋势所在了，会一门语言意味着你有机会将一些需要花费大量人工做的事情用自动化的方式去处理，这会提高效率，简而言之就是提升了生产力，一个人可以干多个人的活，相对来说内卷的趋势也不会特别明显。前几天看了一本名为《闪电式扩张》的书，里面也提到了自动化一切是让公司在发展时候尽量不受到人力规模因素钳制的重要活动。&lt;/p>
&lt;p>语言分为脚本类语言和编译型语言，理想的情况下，两种都会是最好，没有时间的话可以只会脚本类语言。&lt;/p>
&lt;p>脚本类语言里推荐2门语言。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>python。没有时间精力有限就学python，除了做前端，python现在基本上是十项全能了，前些天在语言排行版上，python已经超过了老将java，并且有可能以后一直压java一筹。语言这个东西很有意思，用的人越多需求量就越大，找到合适工作和岗位的机会就越大，因此学习python对我们的工作和求职都是一定益处的。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>JavaScript。有余力的同学可以学一下js，js在前端领域还是强势的选择，不过应用范围比python确实是小很多，但在测试上，我们可以用js调用selenium，appium，cypress，k6,postman等主流工具，日常使用还是绰绰有余的。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>编译型的语言推荐2门。&lt;/p>
&lt;ul>
&lt;li>java。老将java市场保有量还是很大的，而已在一些中小型公司仍然是担当主力，市场长期需求相对有保障。而且java基本上也是啥事都可以做，应用范围没有问题，java语法也相对稳定，跨平台和生态都很完善，看重既得利益的话学习java是完全没有问题的。&lt;/li>
&lt;li>go。go跟java比可能更着眼于未来一些。相对java来说，go更加现代化，语法也更简单，在一些传统java占优势的领域，比如中间件开发上，go的势头非常强劲，go入门简单精通相对难一些，这个特点很适合一些寻找工具开发语言的测试同学，毕竟很多时候自动化工作只需要简单的调用一些现有库，把流程串起来就好了。&lt;/li>
&lt;/ul>
&lt;p>最后的总结就是：没有时间只学python就好了，时间很多可以再学一下go。&lt;/p>
&lt;h3 id="测试技术类">测试技术类&lt;/h3>
&lt;p>我把测试技术狭义的分为工具使用和工具开发。&lt;/p>
&lt;p>用现成的工具去解决眼下的问题，对代码的要求相对较低；工具开发其实就是开发了，只是开发的产出物是测试工具而已。&lt;/p>
&lt;p>这里我们只讨论前者，我们看一下在各种测试场景或者专项测试上都有哪些工具是值得我们掌握的。&lt;/p>
&lt;h4 id="ui自动化测试">ui自动化测试&lt;/h4>
&lt;ul>
&lt;li>web端的自动化测试首推还是selenium，毕竟市场保有量大，需求较为强烈。cypress是一个不错的学习对象，有时间也是强烈推荐学习的。&lt;/li>
&lt;li>app自动化目前还是appium的应用相对广泛一些，推荐重点关注。&lt;/li>
&lt;/ul>
&lt;h4 id="接口自动化测试">接口自动化测试&lt;/h4>
&lt;ul>
&lt;li>postman。对于http+json的简单接口，postman+newman的组合基本上是可以搞定大部分需求的，强烈推荐，不过要想用的好还是得会一点点的js。我记得我在b站有一套postman的视频，讲的比较清楚了，大家可以去B站搜索测试圈TC去学习一下。&lt;/li>
&lt;li>自己写代码去实现。自己写代码实现会更加灵活一些，另外一些rpc或者是私有协议的接口我们也可以比较方便的进行测试。这里需要注意的是断言和数据准备相对比较重要，大家可以去github上搜索一个叫做cypress realworld的项目，看看他们是怎么做接口自动化的，当然他们用的是cypress做接口自动化，工具其实不算特别重要，思路和用例组织才是关键。&lt;/li>
&lt;/ul>
&lt;h4 id="单元测试">单元测试&lt;/h4>
&lt;ul>
&lt;li>各种语言内建或者标准的单元测试库。python有unittest，java有相对标准的junit，go有testing库，这些框架的优势是简单易用，用来做单元测试基本上问题不大，但缺点是过于简单，有时候需要深度定制；&lt;/li>
&lt;li>各种语言的高级测试库。python有pytest，java有testNG等，这些框架相对功能全面很多，可以满足大家更高级的需求。&lt;/li>
&lt;/ul>
&lt;h4 id="服务端性能测试">服务端性能测试&lt;/h4>
&lt;ul>
&lt;li>k6。k6是一个比较新的性能测试工具，支持http和grpc，对开发人员非常友好，而且官方文档讲了很多测试理念的东西，讲招式的同时又传授内功，这点跟cypress很像，推荐一下；&lt;/li>
&lt;li>wrk。只支持http协议，但是性能强大使用简单，居家常备的性能测试利器；&lt;/li>
&lt;li>jmeter。干啥都可以，但都有点麻烦的老牌性能测试工具，有ui，入门相对简单&lt;/li>
&lt;/ul>
&lt;h4 id="移动端性能测试工具">移动端性能测试工具&lt;/h4>
&lt;ul>
&lt;li>perfdog。支持ios和android的性能指标采集，非常适合小白，强力推荐的工具；&lt;/li>
&lt;li>系统自带性能测试套件。比如ios的instrument，在专业场景上有巨大的优势，比如看memory leak之类，这也还是需要掌握的；&lt;/li>
&lt;/ul>
&lt;h4 id="pentest工具">pentest工具&lt;/h4>
&lt;p>这里我也不是很了解，等以后学会了再分享给大家。&lt;/p>
&lt;h3 id="通用技术类">通用技术类&lt;/h3>
&lt;p>通用技术可以让你了解你的被测系统是如何工作的，可能在哪里会存在潜在问题，也是打通跟开发交流次元壁的重要方式。&lt;/p>
&lt;p>传统的通用技术这里就不列举了，不过从目前来看，机器学习技术可能是需要大家重点关注的，因为长期来看，机器学习的应用范围会越来越广，相应的测试活动应该也会有更多的市场需求。&lt;/p>
&lt;h3 id="总结">总结&lt;/h3>
&lt;p>总之技术对于测试同学来说只是日常工作的一部分，在很多时候我们的工作重心可能还是沟通，协调，深刻理解好需求，做好质量管理和线上问题跟踪，这些可能会占据我们大部分的时间和精力。不过从内在的核心竞争力来看，技术驱动自身价值增长应该是不变的趋势。&lt;/p>
&lt;p>前几天看到个视频，讲股票投资的，里面有一些观点其实比较主流。&lt;/p>
&lt;ul>
&lt;li>当外卖送餐员可能不是一个好主意，因为在这个岗位上你无法得到提升。同样的当点来点去的测试员可能也不是好主意，没有技术壁垒和核心竞争力，长期来看成长是不足的；&lt;/li>
&lt;li>散户投资股票长期来看是亏，投资自己收获能力提升才是普通人应该去关注的事情；&lt;/li>
&lt;/ul>
&lt;p>以上观点感触很深，所以跟大家分享一下，我们还学的动，还有时间，一起加油吧。&lt;/p>
&lt;p>顺便立个flag，今年希望可以把机器学习给整明白，然后与大家分享。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1494935362342-566c6d6e75b5?w=300"
 data-srcset="https://images.unsplash.com/photo-1494935362342-566c6d6e75b5?w=300, https://images.unsplash.com/photo-1494935362342-566c6d6e75b5?w=300 1.5x, https://images.unsplash.com/photo-1494935362342-566c6d6e75b5?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1494935362342-566c6d6e75b5?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>2021年最值得测试同学使用的python库</title><link>https://itest2025.pages.dev/tutorials/47-000-2021%E5%B9%B4%E6%9C%80%E5%80%BC%E5%BE%97%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E4%BD%BF%E7%94%A8%E7%9A%84python%E5%BA%93/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-2021%E5%B9%B4%E6%9C%80%E5%80%BC%E5%BE%97%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E4%BD%BF%E7%94%A8%E7%9A%84python%E5%BA%93/</guid><description>&lt;p>2021年不期而至了，我们不妨盘点一下2021年最值得测试同学使用的python库/工具吧。&lt;/p>
&lt;h3 id="validation">Validation&lt;/h3>
&lt;h4 id="jsonschema-another-implementation-of-json-schema-for-python">jsonschema: An(other) implementation of JSON Schema for Python&lt;/h4>
&lt;p>jsonschema可以用来进行json数据的校验。试想一下这样的场景，我们需要验证api返回的json字符串的正确性，但如果一个字段一个字段去校验效率自然是不高的，这时候jasonsschema就可以大展身手了。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;gt;&amp;gt;&amp;gt;&lt;/span> &lt;span class="kn">from&lt;/span> &lt;span class="nn">jsonschema&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">validate&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;gt;&amp;gt;&amp;gt;&lt;/span> &lt;span class="c1"># A sample schema, like what we&amp;#39;d get from json.load()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;gt;&amp;gt;&amp;gt;&lt;/span> &lt;span class="n">schema&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">...&lt;/span> &lt;span class="s2">&amp;#34;type&amp;#34;&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;object&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">...&lt;/span> &lt;span class="s2">&amp;#34;properties&amp;#34;&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">...&lt;/span> &lt;span class="s2">&amp;#34;price&amp;#34;&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;type&amp;#34;&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;number&amp;#34;&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">...&lt;/span> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;type&amp;#34;&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;string&amp;#34;&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">...&lt;/span> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">...&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;gt;&amp;gt;&amp;gt;&lt;/span> &lt;span class="c1"># If no exception is raised by validate(), the instance is valid.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;gt;&amp;gt;&amp;gt;&lt;/span> &lt;span class="n">validate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">instance&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Eggs&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;price&amp;#34;&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="mf">34.99&lt;/span>&lt;span class="p">},&lt;/span> &lt;span class="n">schema&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">schema&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;gt;&amp;gt;&amp;gt;&lt;/span> &lt;span class="n">validate&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">...&lt;/span> &lt;span class="n">instance&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Eggs&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;price&amp;#34;&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Invalid&amp;#34;&lt;/span>&lt;span class="p">},&lt;/span> &lt;span class="n">schema&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">schema&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">...&lt;/span> &lt;span class="p">)&lt;/span> &lt;span class="c1"># doctest: +IGNORE_EXCEPTION_DETAIL&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Traceback&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">most&lt;/span> &lt;span class="n">recent&lt;/span> &lt;span class="n">call&lt;/span> &lt;span class="n">last&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">ValidationError&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;Invalid&amp;#39;&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">of&lt;/span> &lt;span class="nb">type&lt;/span> &lt;span class="s1">&amp;#39;number&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>我们可以自定义schema，如果api返回的结果满足schema定义的规则的话，那么用例就通过，否则失败，用例的编写效率和准确性都可以得到提升。&lt;/p>
&lt;p>项目地址:https://github.com/Julian/jsonschema&lt;/p>
&lt;h3 id="算法">算法&lt;/h3>
&lt;h4 id="algorithmsminimal-examples-of-data-structures-and-algorithms-in-python">algorithms:Minimal examples of data structures and algorithms in Python。&lt;/h4>
&lt;p>库如其名，用python实现了各种常见算法，实现优雅，例子相对简单，适合学习。
项目地址：https://github.com/keon/algorithms&lt;/p>
&lt;h3 id="命令行工具">命令行工具&lt;/h3>
&lt;h4 id="howdoiinstant-coding-answers-via-the-command-line">howdoi:instant coding answers via the command line&lt;/h4>
&lt;p>写代码的时候经常会不知道某个功能怎么实现或者代码报错需要去搜索一下解决方案，但每次打开浏览器搜索的话还是比较麻烦的，这时候howdoi就有用武之地了。&lt;/p></description></item><item><title>2021年最值得测试同学使用的四种编程语言</title><link>https://itest2025.pages.dev/tutorials/47-000-2021%E5%B9%B4%E6%9C%80%E5%80%BC%E5%BE%97%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E4%BD%BF%E7%94%A8%E7%9A%84%E5%9B%9B%E7%A7%8D%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-2021%E5%B9%B4%E6%9C%80%E5%80%BC%E5%BE%97%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E4%BD%BF%E7%94%A8%E7%9A%84%E5%9B%9B%E7%A7%8D%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/</guid><description>&lt;p>2021年马上就要到了，那么新的一年哪些编程语言值得测试同学学习和使用呢？我们不妨简单来看一下。&lt;/p>
&lt;h3 id="python">python&lt;/h3>
&lt;p>python目前基本上成为了一门通用语言，有点像是英语在世界语言中的地位。&lt;/p>
&lt;p>我们可以这么认为，在工作中不使用python其实没什么大问题，不过如果能熟练使用python，那么工作效率和效果将有极大的提升。&lt;/p>
&lt;p>python因为语法简单执行效率尚可，扩展性强等优势在一些传统领域和新兴领域都备受推崇，使用python我们可以&lt;/p>
&lt;ul>
&lt;li>做web开发&lt;/li>
&lt;li>做自动化构建&lt;/li>
&lt;li>玩一下计算机视觉相关的东西&lt;/li>
&lt;li>做一些科学计算&lt;/li>
&lt;li>数据统计与可视化&lt;/li>
&lt;li>深度学习&lt;/li>
&lt;li>自动化测试及网络爬虫&lt;/li>
&lt;li>开发各种cli工具等&lt;/li>
&lt;li>游戏开发&lt;/li>
&lt;li>文本处理&lt;/li>
&lt;/ul>
&lt;p>所以如果大家只有时间掌握一门脚本语言的话，python是非常好的选择。&lt;/p>
&lt;h3 id="javascript">javascript&lt;/h3>
&lt;p>因为nodejs的出现，js在应用场景上有了巨大的扩充，之前只能在浏览器上做一些前端效果的js如今基本上成为了一门非常方便的脚本语言，我们可以使用js进行&lt;/p>
&lt;ul>
&lt;li>web开发，包含前后端&lt;/li>
&lt;li>移动端开发，比如使用rn&lt;/li>
&lt;li>cli工具开发&lt;/li>
&lt;li>自动化构建&lt;/li>
&lt;li>游戏开发&lt;/li>
&lt;li>文本处理&lt;/li>
&lt;li>自动化测试&lt;/li>
&lt;li>GUI开发，比如vscode就是js开发的&lt;/li>
&lt;/ul>
&lt;p>如果大家从事的工作跟前端有很多交集，那么js是一门值得掌握的脚本语言。&lt;/p>
&lt;h3 id="java">java&lt;/h3>
&lt;p>老当益壮的java在编译性语言里目前还是有着不错的表现的。java目前在一些领域还是有着比较大的保有量&lt;/p>
&lt;ul>
&lt;li>web后端开发&lt;/li>
&lt;li>通用后台开发，比如java有一些不错的微服务框架&lt;/li>
&lt;li>分布式编程&lt;/li>
&lt;li>GUI开发&lt;/li>
&lt;li>中间件开发，比如es, zk&lt;/li>
&lt;li>自动化测试，比如selenium&lt;/li>
&lt;/ul>
&lt;p>作为一门优秀的编译型语言，java基本可以满足大多数测试同学的需求。&lt;/p>
&lt;h3 id="go">go&lt;/h3>
&lt;p>golang凭借着简单易学的语言元素以及不错的开发效率和执行效率，近几年变得越发流行。&lt;/p>
&lt;p>如果大家有时间学习一门编译型语言，我可能会更推荐go而不是java。go可以做这些事情&lt;/p>
&lt;ul>
&lt;li>cli工具开发，docker的cli就是go写的&lt;/li>
&lt;li>各种中间件，比如promethus就是go实现的&lt;/li>
&lt;li>分布式系统&lt;/li>
&lt;li>web后台开发，通用后台开发&lt;/li>
&lt;li>性能测试以及接口测试&lt;/li>
&lt;li>gui开发&lt;/li>
&lt;li>游戏开发&lt;/li>
&lt;/ul>
&lt;p>go的学习曲线在编译型语言里应该是比较平滑的，很适合测试同学写一些小工具和后台。&lt;/p>
&lt;h3 id="总结">总结&lt;/h3>
&lt;p>总之测试同学可能学习两种语言就可以了，一种是编译型，另一种是非编译型的脚本语言。&lt;/p>
&lt;p>时间充足都学，时间不够，只学脚本语言，而且无脑选择python就好了。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1465056836041-7f43ac27dcb5?w=300"
 data-srcset="https://images.unsplash.com/photo-1465056836041-7f43ac27dcb5?w=300, https://images.unsplash.com/photo-1465056836041-7f43ac27dcb5?w=300 1.5x, https://images.unsplash.com/photo-1465056836041-7f43ac27dcb5?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1465056836041-7f43ac27dcb5?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>curl太难用？试试httpie吧</title><link>https://itest2025.pages.dev/tutorials/47-000-curl%E5%A4%AA%E9%9A%BE%E7%94%A8%E8%AF%95%E8%AF%95httpie%E5%90%A7/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-curl%E5%A4%AA%E9%9A%BE%E7%94%A8%E8%AF%95%E8%AF%95httpie%E5%90%A7/</guid><description>&lt;p>curl是功能非常强大的命令行http客户端，也许是正是因为强大吧，所以很多同学记不太住curl的一些常用参数，再加上curl的命令行参数形式又比较老派，所以日常用起来还是有一点点略显啰嗦的。&lt;/p>
&lt;p>既然curl太难用？那我们就试试httpie吧。&lt;/p>
&lt;p>项目地址：https://github.com/jakubroztocil/httpie。&lt;/p>
&lt;p>一句话介绍，我就不翻译了。&lt;/p>
&lt;blockquote>
&lt;p>As easy as HTTPie /aitch-tee-tee-pie/ 🥧 Modern command line HTTP client – user-friendly curl alternative with intuitive UI, JSON support, syntax highlighting, wget-like downloads, extensions, etc.&lt;/p>&lt;/blockquote>
&lt;p>httpie的特点&lt;/p>
&lt;ul>
&lt;li>用户友好&lt;/li>
&lt;li>非反直觉的ui&lt;/li>
&lt;li>支持JSON&lt;/li>
&lt;li>支持语法高亮&lt;/li>
&lt;li>支持文件下载&lt;/li>
&lt;li>支持插件&lt;/li>
&lt;/ul>
&lt;p>一图以蔽之&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://raw.githubusercontent.com/jakubroztocil/httpie/master/httpie.gif"
 data-srcset="https://raw.githubusercontent.com/jakubroztocil/httpie/master/httpie.gif, https://raw.githubusercontent.com/jakubroztocil/httpie/master/httpie.gif 1.5x, https://raw.githubusercontent.com/jakubroztocil/httpie/master/httpie.gif 2x"
 data-sizes="auto"
 alt="https://raw.githubusercontent.com/jakubroztocil/httpie/master/httpie.gif"
 title="https://raw.githubusercontent.com/jakubroztocil/httpie/master/httpie.gif" />&lt;/p>
&lt;h3 id="安装">安装&lt;/h3>
&lt;p>&lt;strong>Mac&lt;/strong>&lt;/p>
&lt;pre tabindex="0">&lt;code>$ brew install httpie
# or
$ port install httpie
&lt;/code>&lt;/pre>&lt;p>&lt;strong>Linux&lt;/strong>&lt;/p>
&lt;pre tabindex="0">&lt;code># Debian, Ubuntu, etc.
$ apt-get install httpie

# Fedora
$ dnf install httpie

# CentOS, RHEL, ...
$ yum install httpie

# Arch Linux
$ pacman -S httpie
&lt;/code>&lt;/pre>&lt;p>&lt;strong>Windows&lt;/strong>*&lt;/p></description></item><item><title>puppeteer生态一览</title><link>https://itest2025.pages.dev/tutorials/47-000-puppeteer%E7%94%9F%E6%80%81%E4%B8%80%E8%A7%88/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-puppeteer%E7%94%9F%E6%80%81%E4%B8%80%E8%A7%88/</guid><description>&lt;p>puppeteer是chrome官方出品的无界面浏览器，我们一般称为无头浏览器。&lt;/p>
&lt;p>这种浏览器具有普通版浏览器的完备功能，并且可以运行在无界面的服务端，比如远程的linux服务器上，是做ui自动化测试的一个不错的选择。&lt;/p>
&lt;p>我们今天就来看一下puppeteer的生态，看看除了自动化测试这个工具还能做什么吧。&lt;/p>
&lt;h3 id="puppetron">Puppetron&lt;/h3>
&lt;p>&lt;a href="https://github.com/cheeaun/puppetron" target="_blank" rel="noopener noreffer ">https://github.com/cheeaun/puppetron&lt;/a>，这个项目的功能非常简单，就是使用puppeteer来渲染页面并且进行截图或者是将页面保存成pdf文件。&lt;/p>
&lt;p>你可以通过api调用来完成上述的3个功能，渲染/截图以及保存pdf都支持宽高设置，所以你可以很容易的实现模拟不同大小屏幕的功能。&lt;/p>
&lt;p>比如你可以通过设置不同的宽高来得到某个网站在小屏手机/大屏手机/平板以及电脑上的屏幕截图。&lt;/p>
&lt;h3 id="pupperender">pupperender&lt;/h3>
&lt;p>&lt;a href="https://github.com/LasaleFamine/pupperender" target="_blank" rel="noopener noreffer ">https://github.com/LasaleFamine/pupperender&lt;/a>，pupperender是一个express中间件，它的功能是如果探测到这次页面的访问是来自搜索引擎的机器人或者是爬虫，那么就自动使用puppeteer来渲染页面，返回完整的html。&lt;/p>
&lt;p>该工具就解决了一些前后端分离的站点对搜索引擎不友好的问题，因为如果是纯js实现的前端页面，那么搜索机器人爬到的页面仅仅包含一些基本的html，页面的具体内容是没办法正确渲染出来并返回的。&lt;/p>
&lt;p>该库的使用也非常的简单，几行代码就可以搞定了。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">express&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;express&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">pupperender&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;pupperender&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">app&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">express&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">app&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">use&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">pupperender&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">makeMiddleware&lt;/span>&lt;span class="p">({}));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">app&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">use&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">express&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="kr">static&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;files&amp;#39;&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">app&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">listen&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">8080&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3>&lt;/h3>
&lt;p>有困惑的同学可以搜索PWA进行更深入的学习。&lt;/p>
&lt;h3 id="headless-chrome-crawler">headless-chrome-crawler&lt;/h3>
&lt;p>&lt;a href="https://github.com/yujiosaka/headless-chrome-crawler" target="_blank" rel="noopener noreffer ">https://github.com/yujiosaka/headless-chrome-crawler&lt;/a>，是使用puppeteer实现的爬虫。&lt;/p>
&lt;p>它的一些功能还是非常有特色的，比如&lt;/p>
&lt;ul>
&lt;li>支持分布式爬取&lt;/li>
&lt;li>实现了深度优先和广度优先算法&lt;/li>
&lt;li>支持csv和json line格式导出&lt;/li>
&lt;li>插件式的结果存储，比如支持redis&lt;/li>
&lt;li>自动插入jquery，可以使用jquery语法进行结果处理&lt;/li>
&lt;li>支持截图作为爬取证据&lt;/li>
&lt;li>支持模拟不同的设备&lt;/li>
&lt;/ul>
&lt;p>简单看一个例子&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">HCCrawler&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;headless-chrome-crawler&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="kr">async&lt;/span> &lt;span class="p">()&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">crawler&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kr">await&lt;/span> &lt;span class="nx">HCCrawler&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">launch&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Function to be evaluated in browsers
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">evaluatePage&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">(()&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">title&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">$&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;title&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">text&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">})),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Function to be called with evaluated results from browsers
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">onSuccess&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nx">result&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">result&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Queue a request
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kr">await&lt;/span> &lt;span class="nx">crawler&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">queue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;https://example.com/&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Queue multiple requests
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kr">await&lt;/span> &lt;span class="nx">crawler&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">queue&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="s1">&amp;#39;https://example.net/&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;https://example.org/&amp;#39;&lt;/span>&lt;span class="p">]);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Queue a request with custom options
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kr">await&lt;/span> &lt;span class="nx">crawler&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">queue&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">url&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;https://example.com/&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Emulate a tablet device
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">device&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;Nexus 7&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Enable screenshot by passing options
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">screenshot&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">path&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;./tmp/example-com.png&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">await&lt;/span> &lt;span class="nx">crawler&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">onIdle&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// Resolved when no queue is left
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kr">await&lt;/span> &lt;span class="nx">crawler&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">close&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// Close the crawler
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">})();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上面的例子就演示了使用jquery语法&lt;code>title: $('title').text()&lt;/code> 获取页面信息以及模拟特定的设备Nexus 7进行爬取以及截图的功能。&lt;/p></description></item><item><title>Selenium踩坑指北</title><link>https://itest2025.pages.dev/tutorials/47-000-selenium%E8%B8%A9%E5%9D%91%E6%8C%87%E5%8C%97/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-selenium%E8%B8%A9%E5%9D%91%E6%8C%87%E5%8C%97/</guid><description>&lt;p>最近在翻selenium的官方文档，秃然发现了一份官方的selenium踩坑指南，不敢独享，拿出来给大家分享一下。&lt;/p>
&lt;p>众所周知，我们应该把合适的工具用在合适的场景，这跟杀鸡的时候不需要用到宰牛刀是一样的道理。&lt;/p>
&lt;p>selenium比较好的使用场景是验收测试/回归测试/TDD/BDD，一些同学喜欢把selenium用到某些selenium难以承受的场景，这种方式官方是不推荐的。&lt;/p>
&lt;p>下面这些是官方给出的各种神坑，有兴趣的同学可以亲自踩一下。&lt;/p>
&lt;h3 id="验证码">验证码&lt;/h3>
&lt;p>一般来说我们不需要用selenium去处理各种验证码，有兴趣的同学可以逆向思维，亲自试试。&lt;/p>
&lt;p>那么遇到验证码怎么办？&lt;/p>
&lt;ul>
&lt;li>测试环境就关掉验证码&lt;/li>
&lt;li>留个后门，比如万能验证码&lt;/li>
&lt;/ul>
&lt;h3 id="下载文件">下载文件&lt;/h3>
&lt;p>尽管我们可以使用selenium去点击下载按钮，从而达到下载文件的目的，但是这样做其实并不好。首先处理起来可能比较麻烦，另外关于下载时间下载速度以及下载完整性的验证我们是不太好做的。&lt;/p>
&lt;p>一般来说，建议用selenium拿到下载链接，然后使用libcurl之类的库去直接处理下载比较好。用python的同学可以用requests库去处理下载了。&lt;/p>
&lt;h3 id="http-请求的响应码">HTTP 请求的响应码&lt;/h3>
&lt;p>这一part官方苦口婆心的解释了很多，大意是selenium是站在用户角度去自动化测试，对于终端用户来说，他们并不直接关注请求的返回码，他们关注的是能不能看到404的错误页面之类的可以直接感受到信息。&lt;/p>
&lt;p>下面是非官方的建议，嗯，也就是我的建议&lt;/p>
&lt;ul>
&lt;li>如果你真的关注响应的状态码，那么别在ui自动化层去做，试着去在非ui层，比如接口层做&lt;/li>
&lt;li>放弃在ui自动化用例中断言状态码的努力，有舍才有得嘛&lt;/li>
&lt;/ul>
&lt;h3 id="第三方登陆">第三方登陆&lt;/h3>
&lt;p>使用selenium去自动化第三方登陆原则上是不推荐的。因为&lt;/p>
&lt;ul>
&lt;li>增加了用例的复杂度和运行时间，用例容易跑失败&lt;/li>
&lt;li>第三方登录是不稳定的，这会让你的登录变得不稳定&lt;/li>
&lt;/ul>
&lt;p>在国外一般第三方登录的提供方会提供对应的API，我们可以把登录API集成到用例里，这些API相当稳定，比用selenium去自动化登录过程要好。&lt;/p>
&lt;p>国内可以通过类似的思路去做，比如微信登录就有自己的API，这种实现比较硬核，并且跟ui自动化结合起来也有一定难度，有需求的同学可以尝试一下。&lt;/p>
&lt;h3 id="用例依赖">用例依赖&lt;/h3>
&lt;p>这个问题甚合我意，终于有官方文档背书了。&lt;/p>
&lt;p>selenium team说了，用例直接不要有依赖，要可以用任意顺序运行，原因我之前的文章里有大量说明，大家可以去翻一下。&lt;/p>
&lt;h3 id="性能测试">性能测试&lt;/h3>
&lt;p>简而言之，selenium不适合做性能测试，原因我就不详细说了，总之不合适的话咱就不要强求，有情人总会终成眷属。&lt;/p>
&lt;p>如果需要做性能测试，可以看看jmeter，官方推荐，值得信赖。&lt;/p>
&lt;h3 id="链接爬虫">链接爬虫&lt;/h3>
&lt;p>用selenium去遍历一些链接从而达到爬虫的效果官方是不推荐的，理由是慢，有很多更好的替代方案。&lt;/p>
&lt;p>这里我持有保留意见，对于一些反爬虫很厉害的网站，用selenium做爬虫其实是不错的选择，具体原因就不说明了，大家尝试之后也许就会理解。&lt;/p>
&lt;p>对于学习selenium的同学来说，用selenium做爬虫其实是非常好的练习方式，尽管爬内容的效率不高，但咱们的目的是多写代码，多练习selenium的api，所以其实我是推荐大家把selenium当练习性的爬虫来用的。&lt;/p>
&lt;p>好了，上面这些官方坑是大家可能会经常遇到的，你在使用selenium还遇到过哪些坑呢？欢迎评论留言。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1469474968028-56623f02e42e?w=300"
 data-srcset="https://images.unsplash.com/photo-1469474968028-56623f02e42e?w=300, https://images.unsplash.com/photo-1469474968028-56623f02e42e?w=300 1.5x, https://images.unsplash.com/photo-1469474968028-56623f02e42e?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1469474968028-56623f02e42e?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>安利一下pytest的mark用法</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%AE%89%E5%88%A9%E4%B8%80%E4%B8%8Bpytest%E7%9A%84mark%E7%94%A8%E6%B3%95/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%AE%89%E5%88%A9%E4%B8%80%E4%B8%8Bpytest%E7%9A%84mark%E7%94%A8%E6%B3%95/</guid><description>&lt;p>昨天有同事分享了pytest的相关内容，忽然想起pytest在运行用例时有非常大的灵活性，很适合跟jenkins任务结合起来实现一些动态用例运行的效果。&lt;/p>
&lt;p>我们以下面这个非常简单的测试用例为例，说明一下如何使用pytest实现一些动态的测试策略&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># runner_example.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">pytest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@pytest.mark.p1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">test_1&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@pytest.mark.p2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">test_2&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@pytest.mark.p3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">test_3&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="mi">3&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@pytest.mark.p0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">test_4&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="s1">&amp;#39;abc&amp;#39;&lt;/span>&lt;span class="p">[::&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;cba&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上面例子里，我们使用&lt;code>@pytest.mark&lt;/code>装饰器定义了4种类型的用例，分别是p0/p1/p2/p3。按惯例，p0的用例是优先级最高的用例，p3优先级最低。&lt;/p>
&lt;h3 id="场景1-只运行p0的测试用例">场景1: 只运行p0的测试用例&lt;/h3>
&lt;p>这个非常简单，在命令行中输入&lt;/p>
&lt;pre tabindex="0">&lt;code>pytest runner_example.py -m p0
&lt;/code>&lt;/pre>&lt;p>这里runner_example.py是包含测试用例的名字，默认情况下pytest会认为所有名称以&lt;code>test_&lt;/code>开头的函数都是测试用例。&lt;/p>
&lt;p>运行结果&lt;/p>
&lt;pre tabindex="0">&lt;code>================================================================ test session starts =================================================================
platform darwin -- Python 2.7.15, pytest-4.6.3, py-1.8.0, pluggy-0.12.0
rootdir: /Users/yichun.han/code/testclass.net/src/pytest
collected 4 items / 3 deselected / 1 selected

runner_example.py . [100%]
&lt;/code>&lt;/pre>&lt;p>符合预期。&lt;/p>
&lt;h3 id="场景2-只运行p0和p1的用例">场景2: 只运行p0和p1的用例&lt;/h3>
&lt;p>可以用or来实现。&lt;/p>
&lt;pre tabindex="0">&lt;code>pytest runner_example.py -m &amp;#34;p0 or p1&amp;#34;
&lt;/code>&lt;/pre>&lt;p>-m参数后面可以接python的表达式，所以用or关键字就可以实现多选的效果了。&lt;/p>
&lt;p>运行结果&lt;/p>
&lt;pre tabindex="0">&lt;code>================================================================ test session starts =================================================================
platform darwin -- Python 2.7.15, pytest-4.6.3, py-1.8.0, pluggy-0.12.0
rootdir: /Users/yichun.han/code/testclass.net/src/pytest
collected 4 items / 2 deselected / 2 selected

runner_example.py .. [100%]

================================================================== warnings summary ==================================================================
&lt;/code>&lt;/pre>&lt;p>可以看到运行了2个用例。&lt;/p></description></item><item><title>保持危机感，等到背锅闪人就晚了</title><link>https://itest2025.pages.dev/tutorials/47-000-%E4%BF%9D%E6%8C%81%E5%8D%B1%E6%9C%BA%E6%84%9F%E7%AD%89%E5%88%B0%E8%83%8C%E9%94%85%E9%97%AA%E4%BA%BA%E5%B0%B1%E6%99%9A%E4%BA%86/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E4%BF%9D%E6%8C%81%E5%8D%B1%E6%9C%BA%E6%84%9F%E7%AD%89%E5%88%B0%E8%83%8C%E9%94%85%E9%97%AA%E4%BA%BA%E5%B0%B1%E6%99%9A%E4%BA%86/</guid><description>&lt;p>我的车油箱很小，经常开两天油就见底了，因此现在养成了经过加油站就顺道加油的习惯。&lt;/p>
&lt;p>这跟我们持续提升自己是一个道理，学到的东西就像是油箱里的油，总有用完的时候。&lt;/p>
&lt;p>经常自学充电才能持久续航，等到想换工作的时候才发现要学的东西太多，时间不够用，那时候大概就有点晚了吧。&lt;/p>
&lt;p>我经常开玩笑说，测试同学的求生欲其实很强。&lt;/p>
&lt;p>前几天我坚持半夜发了个hotfix版本，其实就是求生欲强的最好表现，因为如果不去强发，那么某个比较影响用户体验的缺陷会遗留到线上，等到用户投诉过来的时候那就晚了。&lt;/p>
&lt;p>不过hotfix终究是亡羊补牢，是剑走偏峰，是七伤拳，杀敌一千自损八百；是葵花宝典，欲练神功，你懂的。&lt;/p>
&lt;p>提前保持危机感其实是个不错的方式。&lt;/p>
&lt;p>举个例子，现在我们在发布前拜关公拜服务器其实就是有危机感的表现，但如果只是临时抱佛脚，效果始终有限，在发布之前的反复测试和调优可能效果会更好一些。&lt;/p>
&lt;p>测试也是一样，等到发现线上问题以后再去临时修修补补始终是&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=300"
 data-srcset="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=300, https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=300 1.5x, https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>比selenium体验更好的ui自动化测试工具: cypress介绍</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%AF%94selenium%E4%BD%93%E9%AA%8C%E6%9B%B4%E5%A5%BD%E7%9A%84ui%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7-cypress%E4%BB%8B%E7%BB%8D/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%AF%94selenium%E4%BD%93%E9%AA%8C%E6%9B%B4%E5%A5%BD%E7%9A%84ui%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7-cypress%E4%BB%8B%E7%BB%8D/</guid><description>&lt;p>不小心发现了一个新的ui自动化测试工具:cypress，仔细品了一下之后，发现还是有很多有意思的地方的，我们也许可以从cypress里借鉴很多下一代测试工具的设计思想。&lt;/p>
&lt;p>进入cypress的官网(&lt;a href="https://www.cypress.io/" target="_blank" rel="noopener noreffer ">https://www.cypress.io/&lt;/a>)，引入眼帘的一句话让人血脉喷张。&lt;/p>
&lt;p>&lt;strong>The web has evolved. Finally, testing has too.&lt;/strong>&lt;/p>
&lt;p>web已经进化了，最终，测试也会。&lt;/p>
&lt;p>确实相较于这些年前端技术井喷式的增长来说，自动化测试技术的发展是相对缓慢的。&lt;/p>
&lt;p>selenium一套api基本稳定了好多年，最终越走越抽象，由工具下沉到了协议，再由协议变成了各大浏览器厂商都公认的标准，尽快步子不大，但走的相当坚定。从招式套路演变成了内功心法，由懵懂少年变成了武林盟主，目前基本上母仪天下，催生了一些很有特点的测试工具。&lt;/p>
&lt;p>selenium项目对web自动化测试最大的贡献就是统一了标准，曾几何时webdriver刚出道的时候，各大浏览器厂家对webdriver的支持力度是完全不一样的，比如在之前的很多年，官方维护的driver似乎只有google的chrome，微软的IE浏览器一直用的是民间的IE Driver。后来chrome把IE挤到了历史的垃圾堆里，微软的edge浏览器最终推出了官方维护的edge driver，safari的driver也由苹果官方推出，主流浏览器厂商全部支持了webdriver协议，江山一统，天下舍selenium其谁。&lt;/p>
&lt;p>不过selenium的体验对于纯测试同学来说还是有一些硬核的，比如&lt;/p>
&lt;ul>
&lt;li>首先必须安装一门语言，比如java/python/nodejs/ruby之类，这个过程如今在windows上面不算特别难，不过十多年前在windows上安装ruby确实不是一件轻松的事情&lt;/li>
&lt;li>安装selenium。这时候大家会接触到诸如maven/pip(python -m pip/pip3)/rubygems/npm/yarn之类的概念，对于完全没有经验的同学来说，是有一定的挑战的，当然了，如果你具备基本的学习的自我学习能力，这个过程应该不会特别的难，除非你遇到了复杂的网络问题，那个另说&lt;/li>
&lt;li>折腾IDE。很多同学喜欢折腾IDE，比如pycharm/IntelliJ之类的，搞完安装搞破解，搞好破解搞字体，搞到后来又去弄IDE内执行代码，各种一键配置，全套体验完，大好青春年华就白驹过隙了。另外IDE是为了提升开发效率的，代码写的越多效率提升越高，但是新手往往憋大招半天也写不出几行可以一次性运行通过的代码，IDE的优势基本发挥不出来，所以有这个时间去惆怅去彷徨，不如随便找个编辑器老老实实多敲几行代码吧。我基本上从来不去折腾IDE，因为这是可选项，并非必选，而且我智商有限，IDE的强大功能基本用不上，一直老实巴交的用文本编辑器加命令行，够用了&lt;/li>
&lt;li>下载浏览器驱动。当年的selenium安装包里包含了firefox的驱动，稳定而高效，所以如果你用firefox做测试，那么安装好selenium就可以愉快的做自动化了。不过后来firefox换成了gecko引擎，并且由官方维护驱动后，下载浏览器驱动就成了必选项了。&lt;/li>
&lt;li>写代码。这个相对简单，网上一堆教程。&lt;/li>
&lt;/ul>
&lt;p>所以虫师的selenium自动化测试书籍那么受欢迎是有很充分理由的，有他在前面带路，起码更多的人可以尝试着去用上selenium，至于用例能不能坚持写下去另说，但是入门的门槛是相对低了不少的。&lt;/p>
&lt;p>上面列举了selenium的硬核操作，不知道大家会不会产生这样一个观点，那就是selenium似乎对手工测试同学不太友好。&lt;/p>
&lt;p>这个想法其实在一定程度上是对的。selenium本身的使用对象就是有一定编程能力的测试同学，因为selenium是国外项目，它的诞生是符合国外的一些实际情况的，比如在国外有些地方，测试是懂开发的，同样开发也是做测试的。&lt;/p>
&lt;p>所以selenium其实不是硬核，只是对于我们一些国内的测试同学来说，selenium有点曲高和寡了，并不是到手就用的傻瓜式的开源测试工具。另外selenium的一些核心用户其实是做会做自动化测试的开发同学，selenium的这种工具形态对于开发来说，相对是非常友好的。&lt;/p>
&lt;p>所以我们可能忽略了一个事情，在自动化测试发展的很长一段时间内，开发其实是自动化测试的主力军，一些测试工具的设计风格偏开发的路子就很容易理解了。&lt;/p>
&lt;p>今天介绍的cypress是一个比selenium还亲开发的自动化测试工具。&lt;/p>
&lt;p>在官方文档的Testing Your App章节(&lt;a href="https://docs.cypress.io/guides/getting-started/testing-your-app.html#Step-1-Start-your-server" target="_blank" rel="noopener noreffer ">https://docs.cypress.io/guides/getting-started/testing-your-app.html#Step-1-Start-your-server&lt;/a>)，有这样的一段话，原文很长，摘几句重点&lt;/p>
&lt;pre tabindex="0">&lt;code>The last, and probably most important reason why you want to test against local servers, is the ability to control them. When your application is running in production you can’t control it.

When it’s running in development you can:

take shortcuts
seed data by running executable scripts
expose test environment specific routes
disable security features which make automation difficult
reset state on the server / database

With that said - you still have the option to have it both ways.

Many of our users run the majority of their integration tests against a local development server, but then reserve a smaller set of smoke tests that run only against a deployed production app.
&lt;/code>&lt;/pre>&lt;p>大概意思是自动化测试要想做的爽，那么你就要在开发环境上做，这样你就可以随意控制你的测试环境，并且做一些可以让自动化测试进行的更加顺利的修改。当然了，你也可以在部署好的环境上做自动化测试，不过那样会比较难，可以考虑在这样的环境上执行一部分简单的冒烟测试用例。&lt;/p></description></item><item><title>编程笔试题(二)插入排序</title><link>https://itest2025.pages.dev/tutorials/47-000-%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AF%95%E9%A2%98%E4%BA%8C%E6%8F%92%E5%85%A5%E6%8E%92%E5%BA%8F/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AF%95%E9%A2%98%E4%BA%8C%E6%8F%92%E5%85%A5%E6%8E%92%E5%BA%8F/</guid><description>&lt;p>继续我们的简单排序之旅。&lt;/p>
&lt;h3 id="题目">题目&lt;/h3>
&lt;p>看一下这道编程题。&lt;/p>
&lt;blockquote>
&lt;p>使用python对list中的元素进行插入排序，并编写unittest单元测试用例来进行验证。&lt;/p>&lt;/blockquote>
&lt;p>插入排序的过程如下图所示。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/Insertion-sort-example-300px.gif"
 data-srcset="http://img.testclass.net/Insertion-sort-example-300px.gif, http://img.testclass.net/Insertion-sort-example-300px.gif 1.5x, http://img.testclass.net/Insertion-sort-example-300px.gif 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/Insertion-sort-example-300px.gif"
 title="http://img.testclass.net/Insertion-sort-example-300px.gif" />&lt;/p>
&lt;p>盯着上面的图看2分钟，把排序的来龙去脉看清楚。&lt;/p>
&lt;p>插入排序的过程是&lt;/p>
&lt;ul>
&lt;li>首先假设队列左边的元素是已经排序过的元素&lt;/li>
&lt;li>依次遍历已排序过的元素右边的元素，将该元素与左边已排序的元素做比较，这样左侧已排序的元素个数就会依次增加&lt;/li>
&lt;li>重复第二步，直到所有的元素全部排序完成&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>简单来说，插入排序很像是打扑克的理牌过程。我们手里的牌是已经排序过的，每次新抓一张牌，就将牌插入到手里已排序的牌中的合适位置，保证手里的牌一直是排序过的。&lt;/strong>&lt;/p>
&lt;h3 id="参考答案">参考答案&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">unittest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">insertion_sort&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">arr&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">length&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">arr&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="c1"># 从位置1开始向右遍历，因为我们假设位置0上的元素是已经排序好了的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">length&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="c1"># 开始抓牌&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">j&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="c1"># j代表当前已排序的数字的结束位置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="n">j&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="c1"># j &amp;lt; 0时证明已经遍历完了已排序的部分&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">arr&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">j&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">arr&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">arr&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">j&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">arr&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">arr&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">arr&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">j&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># 找到合适的位置插入&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">j&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">j&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="c1"># 持续遍历已排序的部分&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="c1"># 持续抓牌&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">SortTestCase&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TestCase&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">test_insertion_sort&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">test_data_1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">7&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">6&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">test_data_2&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">9&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">7&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">copy_of_data_1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">test_data_1&lt;/span>&lt;span class="p">[:]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">copy_of_data_2&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">test_data_2&lt;/span>&lt;span class="p">[:]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">insertion_sort&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">test_data_1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">insertion_sort&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">test_data_2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">copy_of_data_1&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sort&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">copy_of_data_2&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sort&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">test_data_1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">copy_of_data_1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">test_data_2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">copy_of_data_2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">main&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="思考">思考&lt;/h3>
&lt;p>大家可以思考下面一些问题&lt;/p>
&lt;ul>
&lt;li>插入排序的时间复杂度最好的情况和最坏的情况分别是多少？平均复杂度是多少？&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1419332552192-47d29e59b1e0?w=300"
 data-srcset="https://images.unsplash.com/photo-1419332552192-47d29e59b1e0?w=300, https://images.unsplash.com/photo-1419332552192-47d29e59b1e0?w=300 1.5x, https://images.unsplash.com/photo-1419332552192-47d29e59b1e0?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1419332552192-47d29e59b1e0?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>编程笔试题(六)单向链表及链表反转</title><link>https://itest2025.pages.dev/tutorials/47-000-%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AF%95%E9%A2%98%E5%85%AD%E5%8D%95%E5%90%91%E9%93%BE%E8%A1%A8%E5%8F%8A%E9%93%BE%E8%A1%A8%E5%8F%8D%E8%BD%AC/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AF%95%E9%A2%98%E5%85%AD%E5%8D%95%E5%90%91%E9%93%BE%E8%A1%A8%E5%8F%8A%E9%93%BE%E8%A1%A8%E5%8F%8D%E8%BD%AC/</guid><description>&lt;p>链表是常用的数据结构，简单起见，我们这里只讨论单向链表。&lt;/p>
&lt;h3 id="定义">定义&lt;/h3>
&lt;p>在一些静态语言中，我们可以用数组去存储一组数据，然而数组的大小是固定是，当数组存满了之后，再往里存东西就会有数组越界的错误。&lt;/p>
&lt;p>链表可以解决这个问题，我们可以动态的添加和删除链表中的元素，而不需要考虑链表的容量。&lt;/p>
&lt;p>链表长下面这个样子。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://ww1.sinaimg.cn/large/726a2979gy1g0n4sftxf4j21va0qcq7l.jpg"
 data-srcset="http://ww1.sinaimg.cn/large/726a2979gy1g0n4sftxf4j21va0qcq7l.jpg, http://ww1.sinaimg.cn/large/726a2979gy1g0n4sftxf4j21va0qcq7l.jpg 1.5x, http://ww1.sinaimg.cn/large/726a2979gy1g0n4sftxf4j21va0qcq7l.jpg 2x"
 data-sizes="auto"
 alt="http://ww1.sinaimg.cn/large/726a2979gy1g0n4sftxf4j21va0qcq7l.jpg"
 title="http://ww1.sinaimg.cn/large/726a2979gy1g0n4sftxf4j21va0qcq7l.jpg" />&lt;/p>
&lt;p>对于链表来说，链表中的每一个节点我们称之为Node，Node包含1个指针，指向下一个Node节点，链表就是按照一定的顺序把Node给组合起来。其中排在第1位的节点我们称之为链表的头，也就是Head。&lt;/p>
&lt;p>在链表中查找数据的过程实际上就是从链表的头开始，然后通过Node的下一个节点指针，一节一节的向后查找。&lt;/p>
&lt;h3 id="基本操作">基本操作&lt;/h3>
&lt;p>增加一个节点&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://ww1.sinaimg.cn/large/726a2979gy1g0n53hdgnej20za172n6g.jpg"
 data-srcset="http://ww1.sinaimg.cn/large/726a2979gy1g0n53hdgnej20za172n6g.jpg, http://ww1.sinaimg.cn/large/726a2979gy1g0n53hdgnej20za172n6g.jpg 1.5x, http://ww1.sinaimg.cn/large/726a2979gy1g0n53hdgnej20za172n6g.jpg 2x"
 data-sizes="auto"
 alt="http://ww1.sinaimg.cn/large/726a2979gy1g0n53hdgnej20za172n6g.jpg"
 title="http://ww1.sinaimg.cn/large/726a2979gy1g0n53hdgnej20za172n6g.jpg" />&lt;/p>
&lt;p>删除节点&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://ww1.sinaimg.cn/large/726a2979gy1g0n5avuzqej20ro09u771.jpg"
 data-srcset="http://ww1.sinaimg.cn/large/726a2979gy1g0n5avuzqej20ro09u771.jpg, http://ww1.sinaimg.cn/large/726a2979gy1g0n5avuzqej20ro09u771.jpg 1.5x, http://ww1.sinaimg.cn/large/726a2979gy1g0n5avuzqej20ro09u771.jpg 2x"
 data-sizes="auto"
 alt="http://ww1.sinaimg.cn/large/726a2979gy1g0n5avuzqej20ro09u771.jpg"
 title="http://ww1.sinaimg.cn/large/726a2979gy1g0n5avuzqej20ro09u771.jpg" />&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://ww1.sinaimg.cn/large/726a2979gy1g0n5b8slbpj213g0c0juv.jpg"
 data-srcset="http://ww1.sinaimg.cn/large/726a2979gy1g0n5b8slbpj213g0c0juv.jpg, http://ww1.sinaimg.cn/large/726a2979gy1g0n5b8slbpj213g0c0juv.jpg 1.5x, http://ww1.sinaimg.cn/large/726a2979gy1g0n5b8slbpj213g0c0juv.jpg 2x"
 data-sizes="auto"
 alt="http://ww1.sinaimg.cn/large/726a2979gy1g0n5b8slbpj213g0c0juv.jpg"
 title="http://ww1.sinaimg.cn/large/726a2979gy1g0n5b8slbpj213g0c0juv.jpg" />&lt;/p>
&lt;h3 id="使用python实现">使用python实现&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Node&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">elm&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">elm&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">next&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">get_value&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">data&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">SinglyLinkedList&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">head&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">size&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># https://www.programiz.com/python-programming/generator&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__iter__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">current&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">head&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="n">current&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">yield&lt;/span> &lt;span class="n">current&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">current&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">current&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">next&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">StopIteration&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__contains__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">elm&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">found&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">current&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">head&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="n">current&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">current&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_value&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">elm&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">found&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">break&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">current&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">current&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">next&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">found&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">get_tail&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tail&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">head&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">tail&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="n">tail&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">next&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tail&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tail&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">next&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">tail&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">get_head&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">head&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">is_empty&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">size&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">get_size&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">size&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">elm&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">node&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Node&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">elm&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tail&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_tail&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">tail&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tail&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">next&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">node&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">head&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">node&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">size&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">size&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">node&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">delete&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">elm&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">head&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">current&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">head&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prev&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="n">current&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">current&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_value&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">elm&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">prev&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prev&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">next&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">current&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">next&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">head&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">current&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">next&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">size&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">size&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prev&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">current&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">current&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">current&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">next&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">unittest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">SinglyLinkedListTestCase&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TestCase&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">test_append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">l&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">SinglyLinkedList&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertTrue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">is_empty&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_size&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_head&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_value&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_tail&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_value&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 1 2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_size&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_head&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_value&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_tail&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_value&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 1 2 3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_size&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_head&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_value&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_tail&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_value&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">test_in&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">l&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">SinglyLinkedList&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertTrue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">is_empty&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertTrue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">l&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertTrue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">l&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertTrue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">5&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">l&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertFalse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">l&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertFalse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">l&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertFalse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">6&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">l&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">test_delete&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">l&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">SinglyLinkedList&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertTrue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">is_empty&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 1 3 5 -&amp;gt; 3 5&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">delete&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_head&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_value&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_tail&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_value&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_size&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">delete&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_head&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_value&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_tail&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_value&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_size&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 3 5 -&amp;gt; 3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">delete&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_head&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_value&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_size&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 3 -&amp;gt; None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">delete&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_size&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertTrue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_head&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">delete&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_size&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertTrue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_head&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;__main__&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">main&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="问题">问题&lt;/h3>
&lt;p>针对上面的单向列表，实现列表的反转。&lt;/p></description></item><item><title>编程笔试题(三)二分查找</title><link>https://itest2025.pages.dev/tutorials/47-000-%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AF%95%E9%A2%98%E4%B8%89%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AF%95%E9%A2%98%E4%B8%89%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE/</guid><description>&lt;h3 id="题目">题目&lt;/h3>
&lt;p>看一下这道编程题。&lt;/p>
&lt;blockquote>
&lt;p>使用python对已排序的list中的元素进行二分查找，如果找到返回True，否则返回False，并编写unittest单元测试用例来进行验证。&lt;/p>&lt;/blockquote>
&lt;p>二分查找的算法复杂度比直接遍历列表中元素进行查找的复杂度要低，具体是多少大家可以去看一下。&lt;/p>
&lt;p>二分查找是这样工作的。&lt;/p>
&lt;ul>
&lt;li>首先找到列表中排在中间的元素，比较目标元素与该元素的大小，如果中间的元素等于目标元素，则返回True，否则返回False&lt;/li>
&lt;li>如果目标元素比该元素大，则在中间元素与最后一个元素之间重复步骤1&lt;/li>
&lt;li>如果目标元素比该元素小，则在中间元素与第一个元素之间重复步骤1&lt;/li>
&lt;/ul>
&lt;p>拿下面一组数组为例。&lt;/p>
&lt;p>[1, 2, 3, 4, 5, 6, 7, 8, 9]，假设我们需要查找7。那么我们的步骤是&lt;/p>
&lt;ul>
&lt;li>先找到[1, 2, 3, 4, 5, 6, 7, 8, 9]的中间数字5&lt;/li>
&lt;li>7 &amp;gt; 5，于是在[6, 7, 8, 9]中进行二分查找&lt;/li>
&lt;li>[6, 7, 8, 9]的中间数字是8&lt;/li>
&lt;li>7 &amp;lt; 8 于是在[6, 7]也就是左半边二分查找&lt;/li>
&lt;li>[6, 7]的中间元素是7，等于目标元素，于是找到，返回True&lt;/li>
&lt;/ul>
&lt;p>可以看到我们只查找了3次就找到了7，如果是遍历的化，我们需要遍历6次，也就是1到6，二分的优势是很明显的。&lt;/p>
&lt;h3 id="参考答案">参考答案&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">unittest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">bin_search&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">arr&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">target&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">length&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">arr&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">mid&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">length&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="c1"># 找到中间元素&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">arr&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">mid&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">target&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="c1"># 如果该元素等于目标元素&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">length&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="n">arr&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="n">target&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="c1"># 目标元素不存在&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">target&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">arr&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">mid&lt;/span>&lt;span class="p">]:&lt;/span> &lt;span class="c1"># 如果目标元素大于中间元素&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">bin_search&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">arr&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">mid&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">:],&lt;/span> &lt;span class="n">target&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 在列表的右半边递归进行二分查找&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="c1"># 小于的情况&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">bin_search&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">arr&lt;/span>&lt;span class="p">[:&lt;/span>&lt;span class="n">mid&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">target&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 在列表的左半边递归进行二分查找&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">BinSearchTestCase&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TestCase&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">test_bin_search&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">test_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">9&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">7&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># 测试数据&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">test_data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sort&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1"># 先排序&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bin_search&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">test_data&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bin_search&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">test_data&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">9&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bin_search&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">test_data&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="kc">False&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bin_search&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">test_data&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">999&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="kc">False&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">main&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="思考">思考&lt;/h3>
&lt;p>这里我们使用了递归的方式实现了二分查找，使用递归的好处是逻辑相对简单直观，当然我们也可以使用循环的方式来实现相同的功能。&lt;/p></description></item><item><title>编程笔试题(四)栈</title><link>https://itest2025.pages.dev/tutorials/47-000-%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AF%95%E9%A2%98%E5%9B%9B%E6%A0%88/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AF%95%E9%A2%98%E5%9B%9B%E6%A0%88/</guid><description>&lt;p>栈是常用的数据结构。尽管一般的面试里不会让你直接写一个栈的实现，不过跟栈有关的编程题还是有的。&lt;/p>
&lt;h3 id="定义">定义&lt;/h3>
&lt;p>首先看一下栈的定义。栈是一个集合，具有下面的2种基本操作&lt;/p>
&lt;ul>
&lt;li>push: 把元素加入集合，这个过程我们叫做压入&lt;/li>
&lt;li>pop: 把最后加入集合的元素从集合中移除，这个过程我们叫做推出&lt;/li>
&lt;/ul>
&lt;p>所以栈在移除元素的时候是遵循LIFO(last in, first out)，也就是后进先出的原则的。&lt;/p>
&lt;p>下图演示了依次将1, 2, 3, 4, 5, 6加入到栈中并推出的过程。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://ww1.sinaimg.cn/large/726a2979gy1g0f6k5w3mxj20jg0dl763.jpg"
 data-srcset="http://ww1.sinaimg.cn/large/726a2979gy1g0f6k5w3mxj20jg0dl763.jpg, http://ww1.sinaimg.cn/large/726a2979gy1g0f6k5w3mxj20jg0dl763.jpg 1.5x, http://ww1.sinaimg.cn/large/726a2979gy1g0f6k5w3mxj20jg0dl763.jpg 2x"
 data-sizes="auto"
 alt="http://ww1.sinaimg.cn/large/726a2979gy1g0f6k5w3mxj20jg0dl763.jpg"
 title="http://ww1.sinaimg.cn/large/726a2979gy1g0f6k5w3mxj20jg0dl763.jpg" />&lt;/p>
&lt;h3 id="使用python-list来实现栈">使用python list来实现栈&lt;/h3>
&lt;p>我们主要是实现pop和push操作，另外再实现is_empty()方法来判断栈是否为空。&lt;/p>
&lt;p>栈为空的意思是栈内没有任何元素了。&lt;/p>
&lt;p>我们使用python的list来实现栈，这样比较简单。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Stack&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__len__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">elm&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">elm&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">pop&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pop&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">is_empty&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="fm">__len__&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">unittest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">StackTestCase&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TestCase&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">test_push_and_pop&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">s&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Stack&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">s&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pop&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertTrue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">is_empty&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">s&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">s&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pop&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pop&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">main&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>可以看出,push()实际就是调用list.append()实现的，而pop()则是调用list.pop()来实现。&lt;/p></description></item><item><title>编程笔试题(五)队列</title><link>https://itest2025.pages.dev/tutorials/47-000-%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AF%95%E9%A2%98%E4%BA%94%E9%98%9F%E5%88%97/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AF%95%E9%A2%98%E4%BA%94%E9%98%9F%E5%88%97/</guid><description>&lt;p>队列也是是常用的数据结构。尽管一般的面试里不会让你直接写一个队列的实现，不过了解队列是必须的。&lt;/p>
&lt;h3 id="定义">定义&lt;/h3>
&lt;p>队列在现实生活中非常常见。&lt;/p>
&lt;p>比如去一些餐厅吃饭是需要排队的，先来的先吃，这就是一个等待的队列。&lt;/p>
&lt;p>队列是先到先出的,FIFO(first in, first out)。队列有下面一些主要操作。&lt;/p>
&lt;ul>
&lt;li>enqueue: 将元素加入队列&lt;/li>
&lt;li>dequeue: 将排在最前面的元素推出队列&lt;/li>
&lt;/ul>
&lt;p>下面的图演示了这两个过程。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://ww1.sinaimg.cn/large/726a2979gy1g0fe87h8ayj20go0ax3yk.jpg"
 data-srcset="http://ww1.sinaimg.cn/large/726a2979gy1g0fe87h8ayj20go0ax3yk.jpg, http://ww1.sinaimg.cn/large/726a2979gy1g0fe87h8ayj20go0ax3yk.jpg 1.5x, http://ww1.sinaimg.cn/large/726a2979gy1g0fe87h8ayj20go0ax3yk.jpg 2x"
 data-sizes="auto"
 alt="http://ww1.sinaimg.cn/large/726a2979gy1g0fe87h8ayj20go0ax3yk.jpg"
 title="http://ww1.sinaimg.cn/large/726a2979gy1g0fe87h8ayj20go0ax3yk.jpg" />&lt;/p>
&lt;h3 id="使用python-deque来实现队列">使用python deque来实现队列&lt;/h3>
&lt;p>python内置了deque(发音是deck)实现。&lt;/p>
&lt;p>所谓的deque实际上就是double end queue的意思。&lt;/p>
&lt;p>普通的queue只能在尾部推入元素，从头部移除元素，而deque可以从任意方向推入和移除元素。&lt;/p>
&lt;p>在命令行里使用&lt;code>pydoc collections.deque&lt;/code>可以查看deque类的内置方法。&lt;/p>
&lt;p>比较重要的一些方法有&lt;/p>
&lt;pre tabindex="0">&lt;code>| append(...)
| Add an element to the right side of the deque.
|
| appendleft(...)
| Add an element to the left side of the deque.
| extend(...)
| Extend the right side of the deque with elements from the iterable
|
| extendleft(...)
| Extend the left side of the deque with elements from the iterable
|
| pop(...)
| Remove and return the rightmost element.
|
| popleft(...)
| Remove and return the leftmost element.
|
| remove(...)
| D.remove(value) -- remove first occurrence of value.
|
| reverse(...)
| D.reverse() -- reverse *IN PLACE*
|
| rotate(...)
| Rotate the deque n steps to the right (default n=1). If n is negative, rotates left.
&lt;/code>&lt;/pre>&lt;p>下面是queue的具体实现&lt;/p></description></item><item><title>编程笔试题(一)冒泡排序</title><link>https://itest2025.pages.dev/tutorials/47-000-%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AF%95%E9%A2%98%E4%B8%80%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AF%95%E9%A2%98%E4%B8%80%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F/</guid><description>&lt;p>最近了解到很多测试同学在面试做笔试题的时候都会遇到编程题，总的看来测试同学的编程题都不是很困难，主要在考察大家的代码基本功，一般以简单的算法为主。这里就给大家介绍一些最基本的算法，希望对大家的面试有一些帮助。&lt;/p>
&lt;p>在阅读文章之前，希望大家有这样的一些知识积累。&lt;/p>
&lt;ul>
&lt;li>能看懂简单的python代码&lt;/li>
&lt;li>能写一些简单的python代码并运行起来&lt;/li>
&lt;li>知道python的一些简单数据结构，比如list&lt;/li>
&lt;/ul>
&lt;p>基本算法里总是离不开排序。所谓的排序就是把一组乱序的数据从大到小或者从小到大的排列出来。&lt;/p>
&lt;p>比如一组数字，9，5，2，7，我们按照生序排列的结果就是2,5,7,9。&lt;/p>
&lt;h3 id="题目">题目&lt;/h3>
&lt;p>首先看这道编程题。&lt;/p>
&lt;blockquote>
&lt;p>使用python对list中的元素进行冒泡排序，并编写unittest单元测试用例来进行验证。&lt;/p>&lt;/blockquote>
&lt;p>排序算法里最简单的就是冒泡排序。冒牌排序的过程用下面这张图来解释是最合适不过了。&lt;/p>
&lt;p>![http://img.testclass.net/Bubble-sort-example-300px.gif]&lt;/p>
&lt;p>盯着上面的图看2分钟，把排序的来龙去脉看清楚。&lt;/p>
&lt;p>从上面的图里我们可以知道&lt;/p>
&lt;ul>
&lt;li>首先比较每个相邻的元素，把大的元素换到右边，这样每次比较完一行就可以把最大的数字移动到最右边，这就是所谓的冒泡了&lt;/li>
&lt;li>重复上面的过程，把每次找到的最大的元素换到当前比较队列的最右&lt;/li>
&lt;/ul>
&lt;p>这样一来当所有的循环完成之后排序就自然完成了。&lt;/p>
&lt;p>下面就是代码实现了。实现代码的时候我们需要先想明白代码运行的次数。&lt;/p>
&lt;p>我们可以把冒泡排序分成2个小的任务,假设有n个数字需要排序&lt;/p>
&lt;ul>
&lt;li>A: 找到当前未排序的数字中最大的数字，将其移动到未排序数字的最右边，具体做法遍历当前未排序的数字，将该数字与右边的数字进行比较&lt;/li>
&lt;li>B: 循环n次A&lt;/li>
&lt;/ul>
&lt;p>对于B来说，循环次数很明确了，就是n次。对于A来说，第1次循环的最后应该是比较第n-1与第n个元素，如果有比较就进行移动，第2次循环是比较第n-2个元素和第n-1个元素，因为第n个元素是&lt;strong>当前最大的已经排序的元素了&lt;/strong>，所以没有必要与第n个元素进行比较。依次类推可知A其实就是从n-1开始，到1结束。&lt;/p>
&lt;p>这里其实有2个变量控制循环逻辑&lt;/p>
&lt;ul>
&lt;li>未排序元素的结束位置，A使用&lt;/li>
&lt;li>已经找到的最大元素的个数, B使用&lt;/li>
&lt;/ul>
&lt;h3 id="参考答案">参考答案&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">unittest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">bubble_sort&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">arr&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">length&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">arr&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">length&lt;/span>&lt;span class="p">):&lt;/span> &lt;span class="c1"># i 就是当前已经找到的最大元素个数，从0开始，表示找到了0到n个&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">j&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">length&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">):&lt;/span> &lt;span class="c1"># 任务A的具体实现，每次循环的结束点都是比较当前未排序元素的倒数第2个和最后1个&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">arr&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">arr&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">j&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">arr&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">arr&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">arr&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">arr&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># python中交换变量值的语法糖，面试里这样写大概能加分把&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># tmp = arr[j] 这样交换也可以，不过没有上面写法显得老练&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># arr[j] = arr[j+1]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># arr[j+1] = tmp&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">SortTestCase&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TestCase&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">test_bubble_sort&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">test_data_1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">7&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">6&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">test_data_2&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">9&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">7&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">copy_of_data_1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">test_data_1&lt;/span>&lt;span class="p">[:]&lt;/span> &lt;span class="c1"># 拷贝test_data_1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">copy_of_data_2&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">test_data_2&lt;/span>&lt;span class="p">[:]&lt;/span> &lt;span class="c1"># 拷贝test_data_2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bubble_sort&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">test_data_1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bubble_sort&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">test_data_2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">copy_of_data_1&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sort&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1"># 把copy_of_data_1进行排序&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">copy_of_data_2&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sort&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1"># 把copy_of_data_2进行排序&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">test_data_1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">copy_of_data_1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">test_data_2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">copy_of_data_2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">main&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="思考">思考&lt;/h3>
&lt;p>大家可以思考下面一些问题&lt;/p></description></item><item><title>不服就来跑个分鸭</title><link>https://itest2025.pages.dev/tutorials/47-000-%E4%B8%8D%E6%9C%8D%E5%B0%B1%E6%9D%A5%E8%B7%91%E4%B8%AA%E5%88%86%E9%B8%AD/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E4%B8%8D%E6%9C%8D%E5%B0%B1%E6%9D%A5%E8%B7%91%E4%B8%AA%E5%88%86%E9%B8%AD/</guid><description>&lt;p>前几天跟朋友聊天的时候了解到python有个名为sanic的框架有着不错的性能。&lt;/p>
&lt;p>一时技痒，于是顺便写了一些没有用的(这是真没有用的)hello world程序来跑个分，看看这个sanic框架是否真的是性能上佳。&lt;/p>
&lt;p>这里我们用到的性能测试工具(跑分工具)是wrk，安装方便，使用简单，效率爆表，扩展性强，是http服务benchmark(跑分)的不二选择。&lt;/p>
&lt;h3 id="flask">Flask&lt;/h3>
&lt;p>sanic看上去跟flask很像，当然了，只是看上去。没有对比就没有伤害，于是我便先开始对flask开始跑个分，以flask的得分作为基准，从而看看sanic对比flask在性能上是否有显著提升(这就是基准测试，划重点，面试可能要考的)。&lt;/p>
&lt;p>先写个flask的hello world程序。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">flask&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Flask&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">jsonify&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">app&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Flask&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="vm">__name__&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@app.route&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;/&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">hello_world&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">jsonify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">hello&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;world&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>再跑起来。&lt;/p>
&lt;pre tabindex="0">&lt;code>env FLASK_APP=flask_test.py flask run
&lt;/code>&lt;/pre>&lt;p>wrk去压一下。我其实压了几次，逐步加压，最后得到了一个最大的qps。&lt;/p>
&lt;pre tabindex="0">&lt;code>wrk -c 40 -t 10 http://localhost:5000/
Running 10s test @ http://localhost:5000/
 10 threads and 40 connections
 Thread Stats Avg Stdev Max +/- Stdev
 Latency 56.77ms 153.66ms 1.16s 95.32%
 Req/Sec 126.38 36.43 240.00 74.08%
 11442 requests in 10.06s, 1.79MB read
Requests/sec: 1137.51
Transfer/sec: 182.18KB
&lt;/code>&lt;/pre>&lt;p>flask的qps就是1137，我们把qps当作得分，最终得分1137。&lt;/p>
&lt;h3 id="sanic">sanic&lt;/h3>
&lt;p>sanic出场。首先是祖传的hello world代码。&lt;/p>
&lt;pre tabindex="0">&lt;code>from sanic import Sanic
from sanic.response import json

app = Sanic()

@app.route(&amp;#34;/&amp;#34;)
async def test(request):
 return json({&amp;#34;hello&amp;#34;: &amp;#34;world&amp;#34;})

if __name__ == &amp;#34;__main__&amp;#34;:
 app.run(host=&amp;#34;0.0.0.0&amp;#34;, port=12306)
&lt;/code>&lt;/pre>&lt;p>运行起来&lt;/p></description></item><item><title>测试的各种类型你都了然于胸么</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E7%9A%84%E5%90%84%E7%A7%8D%E7%B1%BB%E5%9E%8B%E4%BD%A0%E9%83%BD%E4%BA%86%E7%84%B6%E4%BA%8E%E8%83%B8%E4%B9%88/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E7%9A%84%E5%90%84%E7%A7%8D%E7%B1%BB%E5%9E%8B%E4%BD%A0%E9%83%BD%E4%BA%86%E7%84%B6%E4%BA%8E%E8%83%B8%E4%B9%88/</guid><description>&lt;h3 id="验收测试">验收测试&lt;/h3>
&lt;p>进行这种类型的测试是为了确定产品的功能是否符合产品需求了。这通常涉及客户的反馈或具体的产品规格。&lt;/p>
&lt;p>对于Web应用程序，可以通过模拟用户期望的行为直接使用Selenium来完成此测试的自动化。可以通过记录/回放或通过需求文档中说明的不同受支持的语言来完成此模拟。注意：验收测试是功能测试的子类型，某些人可能还会提到。&lt;/p>
&lt;h3 id="功能测试">功能测试&lt;/h3>
&lt;p>进行这种类型的测试是为了确定产品的功能是否正常运行而没有问题。&lt;/p>
&lt;p>这通常包括：系统可以正常运行（正确的重定向），没有错误（404，异常…），
以及产品的实现符合需求的具体要求（请参见上面的验收测试）。&lt;/p>
&lt;p>对于Web应用程序，可以通过模拟具体返回的方式直接使用Selenium来完成此测试的自动化。
可以通过记录/回放或通过本文档中介绍的不同受支持的语言来完成此模拟。&lt;/p>
&lt;h3 id="性能测试">性能测试&lt;/h3>
&lt;p>顾名思义，进行性能测试是为了衡量应用程序的性能。&lt;/p>
&lt;p>性能测试有两种主要的子类型：&lt;/p>
&lt;h3 id="负载测试">负载测试&lt;/h3>
&lt;p>进行了负载测试，以验证应用程序在不同定义的负载（通常是一次连接的特定数量的用户）下的运行状况。&lt;/p>
&lt;h3 id="压力测试">压力测试&lt;/h3>
&lt;p>进行了压力测试，以验证应用程序在压力下（或高于最大支持负载）的运行状况。&lt;/p>
&lt;p>通常，性能测试是通过执行一些Selenium用例来完成的，这些测试模拟了不同的用户使用Web应用程序的特定功能并收集了一些有意义的指标。&lt;/p>
&lt;p>通常，这是由其他获取指标的工具完成的。 JMeter就是这样一种工具。&lt;/p>
&lt;p>对于Web应用程序，要测量的详细信息包括吞吐量，延迟，数据丢失，单个组件加载时间…&lt;/p>
&lt;p>注意1：所有浏览器的开发人员工具部分均具有“性能”标签（可通过按F12进行访问）&lt;/p>
&lt;p>注2：是非功能测试的子类型，因为它通常是按系统而不是按功能/功能进行测试。&lt;/p>
&lt;h3 id="回归测试">回归测试&lt;/h3>
&lt;p>该测试通常在更改，修复或添加功能之后进行。&lt;/p>
&lt;p>为了确保所做的更改没有破坏任何现有功能，将再次执行一些已经执行的测试。&lt;/p>
&lt;p>重新执行的测试集可以是全部或部分，并且可以包括几种不同的类型，具体取决于应用程序和开发团队。&lt;/p>
&lt;h3 id="测试驱动开发tdd">测试驱动开发（TDD）&lt;/h3>
&lt;p>TDD本身不是测试类型，而是一种迭代开发方法，其中测试驱动功能的设计。&lt;/p>
&lt;p>每个周期都从创建一组最终应通过该功能的单元测试开始（它们应该在首次执行时失败）。&lt;/p>
&lt;p>此后，进行开发以使测试通过。再次执行测试，开始另一个循环，此过程一直持续到所有测试通过为止。&lt;/p>
&lt;p>这样做的目的是基于这样的事实，即缺陷越早发现成本越低，从而加快了应用程序的开发。&lt;/p>
&lt;h3 id="行为驱动开发bdd">行为驱动开发（BDD）&lt;/h3>
&lt;p>BDD还是基于上述TDD的迭代开发方法，其目的是让所有各方参与到应用程序的开发中。&lt;/p>
&lt;p>每个周期都从开发一些需求开始（应该失败）。然后创建失败的单元测试（也应该失败），然后进行开发。&lt;/p>
&lt;p>重复此循环，直到所有类型的测试通过。&lt;/p>
&lt;p>为此就要使用领域特定的规范语言。各方都应该理解它，这种语言必须简单，标准和明确。大多数工具都使用Gherkin作为这种语言。&lt;/p>
&lt;p>测试的目标是通过也针对潜在的接受错误，并使各方之间的通信更加顺畅，能够检测出比TDD甚至更多的错误。&lt;/p>
&lt;p>当前有一组工具可用于编写规范并将其与代码功能（例如Cucumber或SpecFlow）匹配。&lt;/p>
&lt;p>在Selenium之上构建了一组工具，可通过将BDD规范直接转换为可执行代码来使此过程更快。其中一些是JBehave，Capybara和Robot Framework。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1418985991508-e47386d96a71?w=300"
 data-srcset="https://images.unsplash.com/photo-1418985991508-e47386d96a71?w=300, https://images.unsplash.com/photo-1418985991508-e47386d96a71?w=300 1.5x, https://images.unsplash.com/photo-1418985991508-e47386d96a71?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1418985991508-e47386d96a71?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>测试开发可以开发些什么</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%BC%80%E5%8F%91%E5%8F%AF%E4%BB%A5%E5%BC%80%E5%8F%91%E4%BA%9B%E4%BB%80%E4%B9%88/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%BC%80%E5%8F%91%E5%8F%AF%E4%BB%A5%E5%BC%80%E5%8F%91%E4%BA%9B%E4%BB%80%E4%B9%88/</guid><description>&lt;p>最近参与了公司级的测试项目评审，发现测试同学自主进行开发的项目很多，但也是有规律可循的，这里简单给大家分享一下目前我们可以看到的一些测试项目。大概分为下面几类。&lt;/p>
&lt;h3 id="api自动化测试类">api自动化测试类&lt;/h3>
&lt;p>这一类的项目很多，主要的目的是让api的测试更加高效，并与ci/cd结合，降低回归测试的工作量，并对接口做持续的测试和监控。&lt;/p>
&lt;p>具体的套路有这样一些&lt;/p>
&lt;ul>
&lt;li>api自动化测试框架，使用者通过go/python等编程语言进行用例的编写，持续维护用例库的增长；&lt;/li>
&lt;li>api自动化测试平台。使用者可以用自然语言或者dsl进行用例编写，平台提供ui和用例执行方法，提升用例编写效率；&lt;/li>
&lt;li>api测试工具类。比如支持私有协议转http协议的工具等，屏蔽一些技术细节和实现，让用例编写更为容易；&lt;/li>
&lt;/ul>
&lt;h3 id="ui自动化测试类">ui自动化测试类&lt;/h3>
&lt;p>这类的项目相信大家会比较熟悉，主要是通过ui自动化测试覆盖一些主要的回归场景，提升测试效率，降低人力投入。也可以跟ci/cd结合起来进行持续测试。&lt;/p>
&lt;ul>
&lt;li>app自动化测试。通过脚本编写用例进行回归；&lt;/li>
&lt;li>web自动化测试。通过dsl或者脚本进行用例的编写以及回归；&lt;/li>
&lt;/ul>
&lt;h3 id="质量以及研发效率度量类">质量以及研发效率度量类&lt;/h3>
&lt;p>所谓的质量度量是指通过数据统计的方式对一段时间的测试/开发的质量进行度量，从而找出质量提升/腐化的原因，并进行相应的调整。通过一系列的指标标的出质量红线，从而持续监控质量情况。&lt;/p>
&lt;p>常用的指标有&lt;/p>
&lt;ul>
&lt;li>千行代码bug率&lt;/li>
&lt;li>研发周期产生的bug&lt;/li>
&lt;li>线上bug数&lt;/li>
&lt;li>提测通过率&lt;/li>
&lt;/ul>
&lt;p>目前常见的bug管理平台可能无法比较方便的获取到上面的一些指标，因此需要进行二次开发，以便周期性的拿到上面的数据。&lt;/p>
&lt;p>效率度量平台是度量研发/测试的效率，比如之前一个标准大小需求的开发上线周期是30天，在进行了一系列的效能提升和赋能之后可能会提升到25天。再比如之前回归测试的周期是3天，在进行了效能提升后周期缩短至2天。&lt;/p>
&lt;p>这些平台的开发难度总体来说不大，另外产出的意义也比较明显。&lt;/p>
&lt;h3 id="流程管理类">流程管理类&lt;/h3>
&lt;p>定制研发生命周期中的各种流程，比如用例评审流程，提测流程，发布流程等，做到流程透明，可控，规范，统一，流程中的产出物清晰合规，流程参与者方便对流程进行推动和复盘。&lt;/p>
&lt;p>这类需求的产生是因为每个团队的研发周期总是有一些定制性的场景，常见的普适性的流程管理工具可能没有比较好的方式进行定制和满足。&lt;/p>
&lt;h3 id="测试支持工具">测试支持工具&lt;/h3>
&lt;p>这类工具最灵活也最有意思，小而美，能有好用是主要目标。&lt;/p>
&lt;p>比如通过用户id生成鉴权token的工具，简单的文字识别工具等。&lt;/p>
&lt;h3 id="总结">总结&lt;/h3>
&lt;p>测试开发领域目前总的来说处于瓶颈期，后面新技术和新思路的引入可能会带来不一样的感觉和惊喜。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1530569673472-307dc017a82d?w=300"
 data-srcset="https://images.unsplash.com/photo-1530569673472-307dc017a82d?w=300, https://images.unsplash.com/photo-1530569673472-307dc017a82d?w=300 1.5x, https://images.unsplash.com/photo-1530569673472-307dc017a82d?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1530569673472-307dc017a82d?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>测试妹子们的朋友圈到底长什么样子？</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%A6%B9%E5%AD%90%E4%BB%AC%E7%9A%84%E6%9C%8B%E5%8F%8B%E5%9C%88%E5%88%B0%E5%BA%95%E9%95%BF%E4%BB%80%E4%B9%88%E6%A0%B7%E5%AD%90/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%A6%B9%E5%AD%90%E4%BB%AC%E7%9A%84%E6%9C%8B%E5%8F%8B%E5%9C%88%E5%88%B0%E5%BA%95%E9%95%BF%E4%BB%80%E4%B9%88%E6%A0%B7%E5%AD%90/</guid><description>&lt;p>因为工作和分享的关系，我的微信里加了一些测试妹子，没仔细数，几十人应该是有的吧。今天就不妨带大家看一下测试妹子们的朋友圈到底是什么样子的吧。&lt;/p>
&lt;p>下面的展示照片均已经过本人同意。&lt;/p>
&lt;h3 id="美人如花隔云端">美人如花隔云端&lt;/h3>
&lt;p>作为妹子，朋友圈里晒美照自然是天经地义的了。&lt;/p>
&lt;p>既有闲来无事的自拍，也有出游之余的惊鸿一瞥，不禁让人感叹，一颦一笑皆含情，淡妆浓抹总相宜。&lt;/p>
&lt;h3 id="稚子阶前戏">稚子阶前戏&lt;/h3>
&lt;p>有时候在工作中，测试妹子会开玩笑说自己是被测项目/产品的老母亲，为各种问题操碎了心；在生活中，妹子们在家中也是母仪天下，尽管有时候抱怨带娃不易，但在朋友圈晒娃的时候，大体应该是心情舒畅的吧。&lt;/p>
&lt;h3 id="狗吠深巷中鸡鸣桑树颠">狗吠深巷中，鸡鸣桑树颠&lt;/h3>
&lt;p>在城市中养鸡需要太多的硬核技能，往往都能把鸡养成段子，所以一般情况下不会有人尝试了。&lt;/p>
&lt;p>不过养犬吸猫的却是大有人在。&lt;/p>
&lt;p>很多测试妹子都喜欢在朋友圈晒猫猫狗狗，经常会被各种萌到。&lt;/p>
&lt;p>我们公司就有专门的宠物群，我猜里面的开发/测试/产品妹子应该是数量不少的。&lt;/p>
&lt;p>猫犬相闻，岁月静好。&lt;/p>
&lt;h3 id="缓歌慢舞凝丝竹尽日君王看不足">缓歌慢舞凝丝竹,尽日君王看不足&lt;/h3>
&lt;p>有些妹子平常在工作中可能不显山不露水，但在生活中却是各中高手，深藏不露。&lt;/p>
&lt;p>有健身达人，一口气跑个几公里只能算是健身，也有绘画大师，令人印象深刻，还有舞林高手，舞低杨柳楼心月，歌尽桃花扇底风。&lt;/p>
&lt;h3 id="生命不息代购不止">生命不息，代购不止&lt;/h3>
&lt;p>我开动我记忆力秃出的大脑，搜肠刮肚也找不出一句古诗来跟代购沾上边的，所以标题里混入了一些奇怪的东西。&lt;/p>
&lt;p>应该加了不少的开发(汉子为主)和测试同学(汉子妹子都有)，测试妹子的代购信息在朋友圈里还是配的上一席之地的。&lt;/p>
&lt;p>其实也好理解，很有妹子对测试这个职位有天生的不安全感，提前布局代购市场也算是为今后的华丽转身埋下伏笔，另外可能测试妹子拿的确实不算多，需要发展一些其他的选项来补贴家用。&lt;/p>
&lt;h3 id="青浮卵碗槐芽饼红点冰盘藿叶鱼">青浮卵碗槐芽饼，红点冰盘藿叶鱼&lt;/h3>
&lt;p>读万卷书，行万里路，吃百家饭。美食和旅行是朋友圈永恒的话题了，测试妹子们的足迹也是遍布天南地北，经常也有舌尖上的中国的既视感。&lt;/p>
&lt;h3 id="最后">最后&lt;/h3>
&lt;p>其实测试妹子们的朋友圈跟普通人的朋友圈差不太多，宠物，亲子，旅行，美食，撒狗粮，业余爱好，并不能免俗。可能会偶尔抱怨一下工作的烦恼，感叹一下生活的不易，但生活总在继续，在平淡中寻找短暂的快乐，用镜头去抓住美好的回忆，时间白驹过隙，把跟自己梦想中的生活接近的瞬间留在朋友圈里，别人欣赏也好，鄙夷也罢，我的生活，也许与各位看客并不相关。&lt;/p>
&lt;p>测试是一份工作，工作永远只是生活的一部分。尽管妹子们的朋友圈偶有戾气，但我看到更多的是快乐，情趣，从容，平静。这大概是因为做测试工作确实是需要保持良好的心态吧。&lt;/p>
&lt;p>总之测试妹子们的朋友圈是生活的，接地气的，真实的，也许是职业习惯的关系，妹子们朋友圈的错别字似乎特别的少，选图也更为严谨，意识流的情况很少发生。嗯，说到错别字，连文章标题都会写错的我秃然陷入了沉思。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1482192596544-9eb780fc7f66?w=300"
 data-srcset="https://images.unsplash.com/photo-1482192596544-9eb780fc7f66?w=300, https://images.unsplash.com/photo-1482192596544-9eb780fc7f66?w=300 1.5x, https://images.unsplash.com/photo-1482192596544-9eb780fc7f66?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1482192596544-9eb780fc7f66?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>测试人，请珍惜自己的生命吧</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E4%BA%BA%E8%AF%B7%E7%8F%8D%E6%83%9C%E8%87%AA%E5%B7%B1%E7%9A%84%E7%94%9F%E5%91%BD%E5%90%A7/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E4%BA%BA%E8%AF%B7%E7%8F%8D%E6%83%9C%E8%87%AA%E5%B7%B1%E7%9A%84%E7%94%9F%E5%91%BD%E5%90%A7/</guid><description>&lt;p>最近对于大部分人来说，是很艰难的一段时期。&lt;/p>
&lt;p>前几天听说有位测试同学选择了自己结束生命，就在30岁左右的黄金年龄。&lt;/p>
&lt;p>事情的详细情况我并不清楚，只是大约知道他之前心气很高，现在有抑郁症，最后在隔离的那段时间选择离开这个世界。&lt;/p>
&lt;p>RIP&lt;/p>
&lt;p>在群里跟大家聊起这件事的时候，有几个同学说他们有焦虑症，心悸，失眠，脱发，整天没有精神。&lt;/p>
&lt;p>秃然想起几年前，我似乎也有类似的情况。&lt;/p>
&lt;p>那时候压力很大，每天吃不好，睡不着，做梦都在写代码。早上5点就醒，醒来第一件事就是打开电脑写代码，不过我没意识到那是焦虑，过了一段时间功能发布之后，自然而然的就好了。&lt;/p>
&lt;p>后来有一阵子带了几个项目，外部压力很大，但是内部资源紧张，很难达到领导定的指标，那段时间每天晚上几乎都是失眠，担心项目没办法达到预期，绩效很差，最后连累了大家。最终到底是不堪重负，我还是选择离开。没有了不切实际的压力之后，焦虑自然而然就好了。&lt;/p>
&lt;p>作为过来人，我想，我们的焦虑或者抑郁大概来源于这些方面吧。&lt;/p>
&lt;h4 id="外部巨大的压力">外部巨大的压力&lt;/h4>
&lt;p>我是赞成有适当的压力的，没有压力往往就会没有动力，失去前进的方向，但我不赞同巨大的压力。&lt;/p>
&lt;p>有人喜欢拿小草在春天发芽的例子来类比压力，说野草有韧性，哪怕地面上有一块石头，它也能坚韧不拔，从缝隙里破茧而出。这就证明只要自己足够努力，哪怕再大的压力，我们都能克服。这就有点耍流氓了，如果地面上覆盖的是几十吨的钢筋水泥，我想再坚强的野草也只能频繁的呼喊自己的名字，并不能茁壮成长吧。&lt;/p>
&lt;p>现在大部分企业的KPI文化，有时候就是把压力放大的工具。合理的KPI能带来动力，这点我承认，但很多时候KPI可能变成了政治工具和隐暴力的压迫手段，一些KPI放的比卫星还高，明显就是完成不了的，这时候除了给当事人带来焦虑和无助之外，对整体的业绩也许并没有多少帮助。&lt;/p>
&lt;p>人的能力在某段时间内是有限的。一些不切实际的KPI看起来是积极向上的，令人感到努力一下是可以达到的。但这种流氓KPI往往忽略了时间因素，欠下的债最终只能通过各种福报来偿还了。&lt;/p>
&lt;p>努力让自己变强吧，这样暴力KPI下来之后，你可以说我做不到。你都做不到那别人更做不到，就算有人怼你说做不到就换人，那他换就任他换吧，毕竟他也换不到更好的。&lt;/p>
&lt;h4 id="自身的巨大压力">自身的巨大压力&lt;/h4>
&lt;p>我努力奔跑只是为了追上曾经被寄予厚望的自己。&lt;/p>
&lt;p>我的生活不应该只是现在的这个样子。&lt;/p>
&lt;p>这些想法其实都没错了，不过还是要加上时间因子。很多事情不能一蹴而就的，缩短了时间，就会给自己带来的瞬时压力，最终导致崩溃或放弃。&lt;/p>
&lt;p>不如这样想。&lt;/p>
&lt;p>我这么多年(10年20年一辈子？)努力奔跑只是为了追上曾经被寄予厚望的自己。&lt;/p>
&lt;p>我的生活不应该只是现在的这个样子，我会持续努力(10年20年一辈子？)，从而让自己和家人过的更好。&lt;/p>
&lt;p>我要偷偷的努力呀(10年20年一辈子？)，最终惊艳这个世界。&lt;/p>
&lt;p>所以我们不要一阵子突然努力，而是要坚持下去，春风化雨，持之以恒。&lt;/p>
&lt;h4 id="纷繁的各种压力">纷繁的各种压力&lt;/h4>
&lt;p>柴米油盐酱醋茶，吃喝住行，凡是要花钱的地方有时候都会给我们带来焦虑和压力，毕竟入不敷出多少是会让人产生不适感的。&lt;/p>
&lt;p>这里其实大家不用被消费主义的一些说辞给带偏了，能不买的就不买，买了用不上几次的也不买，能提升自己的钱就花，只能给自己带来短暂满足的就一毛不拔，这样先节流，以后再想办法去开源好了。&lt;/p>
&lt;p>举个例子，有一阵子我很想办个健身卡，比如是2000块一年。综合考虑到我工作很忙，经常早上6点多出发，晚上10点到家，周末我还要上课，所以我一年能挤出100天去健身房就已经很不错了。然后再考虑到临时有事，各种不便，自己懒惰的因素，我能去20次就不错了。这样算下来每次去要100块钱，不划算，坚决不办。&lt;/p>
&lt;p>另一个例子，我要买台macbook pro, 8800。我每天都会用到，学习也好，工作也罢，mbp至少能用5年，这样算下来8000 / 365 / 5 = 4.3。大概每天4块钱，不算特别贵，可以考虑分24期免息买一个。&lt;/p>
&lt;p>理性支出，缓解焦虑，提升自己，为以后的开源带来可能。&lt;/p>
&lt;p>另外我们也有一些可以缓解压力和焦虑的办法。&lt;/p>
&lt;h4 id="早睡早起">早睡早起&lt;/h4>
&lt;p>睡的早，第二天都会快乐不少。&lt;/p>
&lt;h4 id="坚持运动">坚持运动&lt;/h4>
&lt;p>偶尔运动我觉得有时候会很痛苦，不过如果是经常运动的话，每次运动都会很开心。&lt;/p>
&lt;p>可以去爬山，徒步，骑车，打球，选择很多。&lt;/p>
&lt;h4 id="培养一个爱好">培养一个爱好&lt;/h4>
&lt;p>有的同学喜欢读书，读书可以让人快乐。&lt;/p>
&lt;p>有的同学喜欢玩魔方，指尖的速度和激情。&lt;/p>
&lt;p>我前两年花在路上的时间很多，于是学会了吹口琴，也算是塞翁失马，失之东隅，收之桑榆。&lt;/p>
&lt;p>去年因为带娃逗娃，学会了尤克里里的弹唱。偶尔玩一下乐器还是让人心情舒畅不少的。&lt;/p>
&lt;h4 id="少刷信息流">少刷信息流&lt;/h4>
&lt;p>一些信息流，短视频也好，各种自媒体文章也罢，总是无意间贩卖焦虑，或者让人攀比。这时候信息闭塞一点也许更好，毕竟自己的生活往往不需要陌生人进来参合。&lt;/p>
&lt;p>我应该也算是曾经焦虑过，抑郁过。一个有着相同经历的生命的离去让人唏嘘和惋惜。&lt;/p>
&lt;p>哀悼的同时，我还是期待着这个世界。&lt;/p>
&lt;pre tabindex="0">&lt;code> 曾经我也想过一了百了
　　就因为看著海鸥在码头上悲鸣
　　随波逐流浮沉的海鸟啊
　　也将我的过去啄食 展翅飞去吧
　　曾经我也想过一了百了
　　因为生日那天杏花绽放
　　在那筛落阳光的树荫下小睡
　　大概就会像未能转生的虫 就此适应於土里长眠了吧
　　薄荷糖 渔港的灯塔
 生锈的拱桥 被丢弃的自行车
　　杵立在木造车站的暖炉前
　　心却哪儿都不能就此启程
　　今日和昨日相同
　　想要更好的明天 今天就须有所行动
　　我知道 我都知道 但是
　　曾经我也想过一了百了
　　因为心早就被掏空
　　心不能被填满的哭泣著
　　因为我仍渴望著什麼
　　曾经我也想过一了百了
　　因为那松开的鞋带
　　我无法好好将它系紧
　　如同不懂得系紧某人一般
　　曾经我也想过一了百了
　　因为少年凝视著我
　　跪著在床上谢罪吧
　　向过去的我说声抱歉
　　电脑透出淡淡的光
　　楼上房间传来的动静
　　门口对讲机的声音
　　困在鸟笼中的少年捣住耳朵
　　与无形的敌人战斗著
　　他是三坪房间里的唐吉诃德
　　最后的结局 却是抖丑陋不堪
　　曾经我也想过一了百了
　　因为有人说我是冷漠的人
　　想要被爱的哭泣著
　　是因为终於尝到人间温暖
　　曾经我也想过一了百了
　　你美丽的笑著
　　满脑子想著自我了结
　　终究因为活著这事太过於刻骨
　　曾经我也想过一了百了
　　我还没有遇见「你」
　　因为有像你一样的人存在
　　我稍稍喜欢上这个世界了
　　因为有像你一样的人存在
　　我开始稍稍期待著这个世界
&lt;/code>&lt;/pre>&lt;p>原始封面&lt;/p></description></item><item><title>测试同学必会系列之如何进行幂等性的测试</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E5%BF%85%E4%BC%9A%E7%B3%BB%E5%88%97%E4%B9%8B%E5%A6%82%E4%BD%95%E8%BF%9B%E8%A1%8C%E5%B9%82%E7%AD%89%E6%80%A7%E7%9A%84%E6%B5%8B%E8%AF%95/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E5%BF%85%E4%BC%9A%E7%B3%BB%E5%88%97%E4%B9%8B%E5%A6%82%E4%BD%95%E8%BF%9B%E8%A1%8C%E5%B9%82%E7%AD%89%E6%80%A7%E7%9A%84%E6%B5%8B%E8%AF%95/</guid><description>&lt;p>很多同学都应该听过幂等这个概念，但如果在面试中真的被问起来什么是幂等，你有信心去解释清楚么？&lt;/p>
&lt;p>首先看看幂等的定义。&lt;/p>
&lt;blockquote>
&lt;p>一个HTTP方法是幂等的，指的是同样的请求被执行一次与连续执行多次的效果是一样的，服务器的状态也是一样的。换句话说就是，幂等方法不应该具有副作用（统计用途除外）。在正确实现的条件下，GET，HEAD，PUT和DELETE 等方法都是幂等的，而 POST 方法不是。所有的 safe 方法也都是幂等的。&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>幂等性只与后端服务器的实际状态有关，而每一次请求接收到的状态码不一定相同。例如，第一次调用DELETE 方法有可能返回 200，但是后续的请求可能会返回404。DELETE 的言外之意是，开发者不应该使用DELETE方法实现具有删除最后条目功能的 RESTful API。&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>需要注意的是，服务器不一定会确保请求方法的幂等性，有些应用可能会错误地打破幂等性约束。&lt;/p>&lt;/blockquote>
&lt;p>是不是有点抽象？&lt;/p>
&lt;p>再看看英文的定义&lt;/p>
&lt;blockquote>
&lt;p>Idempotence (UK: /ˌɪdɛmˈpoʊtəns/,[1] US: /ˌaɪdəm-/)[2] is the property of certain operations in mathematics and computer science whereby they can be applied multiple times without changing the result beyond the initial application. The concept of idempotence arises in a number of places in abstract algebra (in particular, in the theory of projectors and closure operators) and functional programming (in which it is connected to the property of referential transparency).&lt;/p></description></item><item><title>测试同学的打怪升级之路</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E7%9A%84%E6%89%93%E6%80%AA%E5%8D%87%E7%BA%A7%E4%B9%8B%E8%B7%AF/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E7%9A%84%E6%89%93%E6%80%AA%E5%8D%87%E7%BA%A7%E4%B9%8B%E8%B7%AF/</guid><description>&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://ww1.sinaimg.cn/large/726a2979gy1g2w09sf681j20m80jewg6.jpg"
 data-srcset="http://ww1.sinaimg.cn/large/726a2979gy1g2w09sf681j20m80jewg6.jpg, http://ww1.sinaimg.cn/large/726a2979gy1g2w09sf681j20m80jewg6.jpg 1.5x, http://ww1.sinaimg.cn/large/726a2979gy1g2w09sf681j20m80jewg6.jpg 2x"
 data-sizes="auto"
 alt="http://ww1.sinaimg.cn/large/726a2979gy1g2w09sf681j20m80jewg6.jpg"
 title="http://ww1.sinaimg.cn/large/726a2979gy1g2w09sf681j20m80jewg6.jpg" />&lt;/p>
&lt;p>上面是某大型互联网公司某部门定义的测试同学能力模型。&lt;/p>
&lt;p>大体上这个能力模型将测试同学分成了4个等级，分别是1级到4级，其中1级能力最弱，4级最强。&lt;/p>
&lt;p>在打怪升级的途中，该模型还定义了一些技能点，分别是&lt;/p>
&lt;ul>
&lt;li>测试用例：大概是指用例的设计能力吧&lt;/li>
&lt;li>探索性测试：应该是指的测试经验，有经验才能探索，毕竟探索性测试又叫老司机测试&lt;/li>
&lt;li>测试自动化：大概是指的测试效率这块，通过自动化技术去提升测试效率&lt;/li>
&lt;li>分析定位：帮开发定位bug&lt;/li>
&lt;li>后台开发：后台开发能力。为什么没有前端和客户端开发呢？所以这个应该改成开发能力会更合理一点&lt;/li>
&lt;li>创造力：顾名思义了&lt;/li>
&lt;/ul>
&lt;p>每个级别都对应了6个不同维度的指标描述，作者水平有限，觉得密密麻麻的文字看得不是特别清晰，所以斗胆用一些简单的关键字来概括一下，一家之言，不用过分解读。&lt;/p>
&lt;h3 id="第一级入门-学习-模仿">第一级：入门 学习 模仿&lt;/h3>
&lt;ul>
&lt;li>测试用例设计需要入门&lt;/li>
&lt;li>探索性测试在有经验同学的指导下可以完成&lt;/li>
&lt;li>测试自动化维护现有的东西&lt;/li>
&lt;li>尝试一下分析定位&lt;/li>
&lt;li>学一些开发技能&lt;/li>
&lt;li>不要求创造力，但要有能力去模仿&lt;/li>
&lt;/ul>
&lt;h3 id="第二级-独立-担当-熟练">第二级： 独立 担当 熟练&lt;/h3>
&lt;ul>
&lt;li>独立设计用例，要求熟练&lt;/li>
&lt;li>独立探索&lt;/li>
&lt;li>独立做模块级的自动化测试&lt;/li>
&lt;li>努力分析定位&lt;/li>
&lt;li>掌握一些基本的技术技能&lt;/li>
&lt;li>可以独立工作和成长了&lt;/li>
&lt;/ul>
&lt;h3 id="第三级-精通-深入-独当一面">第三级： 精通 深入 独当一面&lt;/h3>
&lt;ul>
&lt;li>用例方面要对质量结果负责，就是说以前是一个人在战斗，现在是要带领大家战斗&lt;/li>
&lt;li>业务熟练&lt;/li>
&lt;li>框架级的自动化测试开发&lt;/li>
&lt;li>精通某个方向的分析定位&lt;/li>
&lt;li>具有架构能力&lt;/li>
&lt;li>有优秀的创造力&lt;/li>
&lt;/ul>
&lt;h3 id="第四级兼济天下-高屋建瓴-格局">第四级：兼济天下 高屋建瓴 格局&lt;/h3>
&lt;ul>
&lt;li>测试专家&lt;/li>
&lt;li>业务专家，并且可以指导他人&lt;/li>
&lt;li>自动化做成体系&lt;/li>
&lt;li>开发专家，基础扎实&lt;/li>
&lt;li>架构专家&lt;/li>
&lt;li>指导力max&lt;/li>
&lt;/ul>
&lt;p>前两级个人是觉得中规中矩的，没有太多的分歧。第三级其实就是带管理责任的测试专家，有点问题，但至少逻辑上是可以自洽的。第四级基本上属于斗战胜佛，江湖很少有此类的传说，最简单的反驳逻辑就是都有这个能力了，做点啥不好，为什么还要做测试？&lt;/p>
&lt;p>所以当我第一眼看到这个图时，我觉得前两级是我们可以去企及和努力的。第三级看机缘，第四级有点玄幻，大家看看就好。&lt;/p>
&lt;p>总之测试同学打怪升级之路是有方向的，满级之路比较遥远，我们一起加油。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1508108712903-49b7ef9b1df8?w=300"
 data-srcset="https://images.unsplash.com/photo-1508108712903-49b7ef9b1df8?w=300, https://images.unsplash.com/photo-1508108712903-49b7ef9b1df8?w=300 1.5x, https://images.unsplash.com/photo-1508108712903-49b7ef9b1df8?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1508108712903-49b7ef9b1df8?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>测试同学如何学习前端</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E5%A6%82%E4%BD%95%E5%AD%A6%E4%B9%A0%E5%89%8D%E7%AB%AF/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E5%A6%82%E4%BD%95%E5%AD%A6%E4%B9%A0%E5%89%8D%E7%AB%AF/</guid><description>&lt;p>最近发现很多测试同学有学习前端开发技术的需求，理由无外乎如下&lt;/p>
&lt;ul>
&lt;li>前后端分离以后如果不了解前端技术那么测试起来可能找不到问题的症结所在&lt;/li>
&lt;li>一些测试工具需要前端展示和操作，因为测试工具的前端操作可能比较复杂，所以一般会选用前后端分离的方案去专心搞前端&lt;/li>
&lt;li>专业前端越来越多，不会一点前端技术可能都不好交流&lt;/li>
&lt;/ul>
&lt;h3 id="总路线图">总路线图&lt;/h3>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://raw.githubusercontent.com/kamranahmedse/developer-roadmap/master/images/frontend-v2.png"
 data-srcset="https://raw.githubusercontent.com/kamranahmedse/developer-roadmap/master/images/frontend-v2.png, https://raw.githubusercontent.com/kamranahmedse/developer-roadmap/master/images/frontend-v2.png 1.5x, https://raw.githubusercontent.com/kamranahmedse/developer-roadmap/master/images/frontend-v2.png 2x"
 data-sizes="auto"
 alt="https://raw.githubusercontent.com/kamranahmedse/developer-roadmap/master/images/frontend-v2.png"
 title="https://raw.githubusercontent.com/kamranahmedse/developer-roadmap/master/images/frontend-v2.png" />&lt;/p>
&lt;p>好了，看到路线图可能大家觉得凉凉了，其实不用怕，那测试同学怎么学前端呢？这里推荐一条相对路径较短的线路&lt;/p>
&lt;h3 id="知识储备阶段">知识储备阶段&lt;/h3>
&lt;p>我们首先要把前端知识的粗略的过一遍，不要求全部弄明白，起码混个脸熟。&lt;/p>
&lt;p>* 学习html语法，最好能自己手动写一些静态的页面，丑一点没关系&lt;/p>
&lt;ul>
&lt;li>css基础，主要是学语法和布局，不需要纠结与细节和动画&lt;/li>
&lt;li>JavaScript基础，主要是学语法，操作dom&lt;/li>
&lt;li>要了解什么是Ajax以及如何用代码发起ajax请求，如何在浏览器里查看ajax请求&lt;/li>
&lt;li>如果对web ui自动化很感兴趣，可以学习jquery&lt;/li>
&lt;/ul>
&lt;h3 id="进阶">进阶&lt;/h3>
&lt;ul>
&lt;li>学会使用1个package manager，比如npm/yarn&lt;/li>
&lt;li>学会使用package manager与安装依赖&lt;/li>
&lt;li>学习css预处理器，比如sass/PostCss等&lt;/li>
&lt;li>学会使用1个css框架，比如bootstrap/bulma之类&lt;/li>
&lt;/ul>
&lt;h3 id="继续进阶">继续进阶&lt;/h3>
&lt;ul>
&lt;li>学会使用构建工具，比如webpack/rollup/parcel/gulp/npm scripts/eslint等&lt;/li>
&lt;li>学习1个js框架，比如react/angular/vue&lt;/li>
&lt;li>学会使用某个js框架做1个todo list。这个github上有同名项目，大家可以搜索一下&lt;/li>
&lt;/ul>
&lt;p>基本上到这里对于入门来说就差不多了，要学的东西看上去很多，但实际上却是比较聚焦的。&lt;/p>
&lt;p>根据经验，大家一般会在知识储备阶段放弃，毕竟万事开头难。&lt;/p>
&lt;p>其实大家可以使用目标导向的方式，比如给自己定个目标，3个月以后看懂todo list的源码并自己实现1个，那么学起来可能会有更多动力。&lt;/p>
&lt;p>点击阅读原文可以查看&lt;a href="http://todomvc.com/" target="_blank" rel="noopener noreffer ">todo list&lt;/a>的源码。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1437652633673-cc02b9c67a1b?w=300"
 data-srcset="https://images.unsplash.com/photo-1437652633673-cc02b9c67a1b?w=300, https://images.unsplash.com/photo-1437652633673-cc02b9c67a1b?w=300 1.5x, https://images.unsplash.com/photo-1437652633673-cc02b9c67a1b?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1437652633673-cc02b9c67a1b?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>测试同学是否需要买一台mac</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E6%98%AF%E5%90%A6%E9%9C%80%E8%A6%81%E4%B9%B0%E4%B8%80%E5%8F%B0mac/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E6%98%AF%E5%90%A6%E9%9C%80%E8%A6%81%E4%B9%B0%E4%B8%80%E5%8F%B0mac/</guid><description>&lt;p>前几天我卖掉了跟随我多年的macbook pro 15。&lt;/p>
&lt;p>如果没记错的化，那应该是我2013年左右购入的，应该是第一代使用retina屏幕的macbook pro版本。&lt;/p>
&lt;p>掐指一算，这台电脑已经使用了7年。处理器是第4代i7，内存8g，硬盘256G，现在用起来速度还是比较快速的，跟我办公用的16款macbook pro速度差不太多，只是因为公司标配了mac，家里的2013款mbp出场率实在有限，不得不忍痛先出掉了。&lt;/p>
&lt;p>这台mbp当时是我为了学习ios开发而购入的，后来稍微学习一段时间过后，转岗成为了一名ios开发工程师，也算是得偿所愿。&lt;/p>
&lt;p>后来又在这台机器上捣鼓ruby/python/js等一系列语言，期间接了一些私活，算来早就已经回本了，现在出掉给它找一个好归宿，在他人手上继续夕阳红，也算是一个标准的快乐结局。&lt;/p>
&lt;p>那么话说回来，测试同学是不是需要买一台mac呢？&lt;/p>
&lt;p>其实这个问题并没有什么标准答案，购买与否还是要看自己的需求。&lt;/p>
&lt;p>分享一下我当时的心路历程吧，时隔多年记得不是很清楚了，模模糊糊的记得有下面的原因&lt;/p>
&lt;ul>
&lt;li>我想要有一台mac，因为当时去参加一些ruby的线下交流会，发现大家都是拿的mac，无形中种草了&lt;/li>
&lt;li>当时ios的开发很火，没有mac就没办法做ios开发，而我想学一下ios开发，不如买一台吧&lt;/li>
&lt;li>ruby的整套开发环境在mac上部署比较友好，我正好会一点点ruby开发，有台mac会好一点&lt;/li>
&lt;li>15寸的mac开始标配retina屏幕，显示效果惊艳，正好会一点点ps的我还是有一丢丢需求的&lt;/li>
&lt;/ul>
&lt;p>作为一个7年来一直使用mac作为主力办公/学习设备的中老年人，我列出一些场景，作为大家购买的参考&lt;/p>
&lt;h3 id="我想学习一门脚本语言比如python">我想学习一门脚本语言，比如python&lt;/h3>
&lt;p>如果只是想学习一门脚本语言，不考虑做一些正式的产品或项目的化，用windows也是没问题的，毕竟只是学习，入门级的使用，mac和windows并没有太大区别。&lt;/p>
&lt;p>不过如果你有深度的python或其他脚本语言的使用需求的化，mac可能是更好的选择了。因为python的一些第三方库可能只支持linux或mac，windows是鞭长莫及的。&lt;/p>
&lt;p>总之，入门级的学习，买不买mac都可以。&lt;/p>
&lt;h3 id="我想学习linux命令">我想学习linux命令&lt;/h3>
&lt;p>纯粹学习linux命令的话，可以在windows上安装一个虚拟机，或者win10似乎已经自带ubuntu了，用windows学的话问题也不大，又或者花一点钱买一台云服务器，速度更快，还有公网ip，能折腾出更多花样，参考我之前用siri做自动化测试的文章。&lt;/p>
&lt;p>mac的命令跟linux是差不多的，如果你学会了在mac中重度使用terminal，那么linux你就自然会了一些了。&lt;/p>
&lt;p>如果只是单纯学习linux，云服务器应该是最佳选择。&lt;/p>
&lt;h3 id="我想学习ui自动化测试">我想学习ui自动化测试&lt;/h3>
&lt;p>如果只是学习selenium，那么windows是没有问题的。&lt;/p>
&lt;p>在mac上跑selenium速度会更快一点，但周边生态相比windows其实并没有质的提升。&lt;/p>
&lt;h3 id="我想看电影打游戏">我想看电影打游戏&lt;/h3>
&lt;p>我很少在mac上看电影，所以机器上也只装了vlc播放器，这个播放器易用性一般，但是功能强大，基本上大多数格式都支持，不过不知道是不是我的错觉，总感觉播放一段时间以后mac会发烫。&lt;/p>
&lt;p>如果你只是在网页上看视频或追剧的话，mac的chrome非常消耗系统资源，而且基于flash的播放器插件会让你的mac跟电饼档一样，弄一套煎饼果子是问题不大的。如果用safari配上html5的播放器，这个问题基本上可以解决，不过国内很多视频网站只支持flash播放器，这时候老老实实使用windows才是明智之举。&lt;/p>
&lt;p>steam平台支持mac，按道理说可以玩一些dota2之类的游戏了，我没在mac上玩过游戏，所以mac的游戏体验如何我是没有主观感受的，不过从各种渠道得到的反馈大体上都是mac其实并不适合玩游戏。&lt;/p>
&lt;h3 id="我想修图剪辑视频">我想修图/剪辑视频&lt;/h3>
&lt;p>mac支持adobe全家桶，用ps修个图啥的问题不大，不过很多mac机型没有独立显卡，这点是需要注意的。&lt;/p>
&lt;p>mac自带了imovie软件，用来做简单的视频剪辑是一个不错的选择。&lt;/p>
&lt;p>另外mac自带了库乐队应用，可以用来做简单的编曲。&lt;/p>
&lt;p>不过这些事情windows/ipad也全都可以做了。&lt;/p>
&lt;h3 id="我只是简单办公上网">我只是简单办公上网&lt;/h3>
&lt;p>mac自带了免费办公三件套，numbers/keynote/pages，跟office功能差不多，甚至更强大，这点keynote的重度用户罗老师就很有发言权。&lt;/p>
&lt;p>safari浏览器在mac上反应迅速而且资源占用少，在用电池的情况下，我曾经一台macbook air用safari可以连续上网10小时左右，续航能力真的很强悍。&lt;/p>
&lt;p>当然windows电脑办公上网也不在话下了，mac其实并没有巨大的优势&lt;/p>
&lt;h3 id="我想在星巴克拿出一台可以用一天的电脑">我想在星巴克拿出一台可以用一天的电脑&lt;/h3>
&lt;p>这点我是推荐mac的，颜值高续航能力强，星巴克的绝佳伴侣。&lt;/p>
&lt;h3 id="我想获得更好的用户体验">我想获得更好的用户体验&lt;/h3>
&lt;p>mac的触摸板是一种用了就回不去的东西，基本秒杀一切windows笔记本的触摸板。&lt;/p>
&lt;p>如果你追求美感和更好的用户体验，那么mac是不错的选择。&lt;/p>
&lt;h3 id="总结">总结&lt;/h3>
&lt;p>从学习/生产力工具的角度总结一下，mac有这样一些优点&lt;/p>
&lt;ul>
&lt;li>基本兼容大多数的linux软件，适合做初学/深度的编程工作&lt;/li>
&lt;li>有着专业完备的软件生态环境，比如音频/视频的制作，专业性非常强&lt;/li>
&lt;li>打游戏体验不好，适合聚焦在学习或者生产上&lt;/li>
&lt;li>系统相对稳定，体验更好&lt;/li>
&lt;/ul>
&lt;p>mac的缺点也很明显&lt;/p>
&lt;ul>
&lt;li>贵&lt;/li>
&lt;li>软件贵&lt;/li>
&lt;li>硬件周边贵&lt;/li>
&lt;li>有一些windows可以做的事情mac就是做不到，比如使用ie打开网银之类的&lt;/li>
&lt;/ul>
&lt;h3 id="那么我该买什么型号的mac">那么我该买什么型号的mac&lt;/h3>
&lt;p>如果你想选择一款mac，那么&lt;/p>
&lt;ul>
&lt;li>没有移动的需求可以选择mac mini，毕竟是最便宜的mac产品&lt;/li>
&lt;li>只是办公上网，追求续航和轻便，那么可以选择macbook air&lt;/li>
&lt;li>啥都想干一点，追求均衡，那么macbook pro会更合适&lt;/li>
&lt;li>专攻设计，屏幕一定要好，imac的5k屏幕也许是个不错的选择&lt;/li>
&lt;li>性能怪兽，追求极致又不差钱，mac pro了解一下？&lt;/li>
&lt;/ul>
&lt;p>根据经验，mac mini的吃灰率应该是最高的，macbook air因为散热的问题，在某些时候会比较烫，macbook pro应该是需求最不明确时候的较好选择。&lt;/p></description></item><item><title>测试同学需要了解的redi的常见使用场景</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E9%9C%80%E8%A6%81%E4%BA%86%E8%A7%A3%E7%9A%84redi%E7%9A%84%E5%B8%B8%E8%A7%81%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E9%9C%80%E8%A6%81%E4%BA%86%E8%A7%A3%E7%9A%84redi%E7%9A%84%E5%B8%B8%E8%A7%81%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF/</guid><description>&lt;p>Redis 是速度非常快的非关系型（NoSQL）内存键值数据库，可以存储键和五种不同类型的值之间的映射。&lt;/p>
&lt;p>键的类型只能为字符串，值支持五种数据类型：字符串、列表、集合、散列表、有序集合。&lt;/p>
&lt;p>Redis 支持很多特性，例如将内存中的数据持久化到硬盘中，使用复制来扩展读性能，使用分片来扩展写性能。&lt;/p>
&lt;p>Redis的使用非常广泛，是测试同学需要了解的中间件之一，对我们设计测试场景和定位问题有比较大的帮助。&lt;/p>
&lt;h3 id="redis的基本特点">Redis的基本特点&lt;/h3>
&lt;ul>
&lt;li>读写速度快： 比一般的数据库快&lt;/li>
&lt;li>可以持久化： 尽管redis可以持久化，但是不使用其持久化的场景也很多&lt;/li>
&lt;/ul>
&lt;h3 id="redis的数据类型">Redis的数据类型&lt;/h3>
&lt;ul>
&lt;li>STRING: 字符串、整数或者浮点数，对整个字符串或者字符串的其中一部分执行操作，对整数和浮点数执行自增或者自减操作&lt;/li>
&lt;li>LIST: 列表，从两端压入或者弹出元素,对单个或者多个元素进行修剪，只保留一个范围内的元素&lt;/li>
&lt;li>SET: 无序集合&lt;/li>
&lt;li>HASH: 包含键值对的无序散列表&lt;/li>
&lt;li>ZSET: 有序集合,添加、获取、删除元素,根据分值范围或者成员来获取元素，计算一个键的排名，这个是支持排序的&lt;/li>
&lt;/ul>
&lt;h3 id="使用场景">使用场景&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>计数器：比如某公众号推送一篇文章给几千万的粉丝，我们需要记录阅读量。由于每个用户都会产生一次的阅读记录，假设有上万的用户在同1秒产生了阅读数，那么1秒要写入上万次，对于数据库来说这个写入次数是比较巨大的，会带来比较大的性能压力。这时候就可以把阅读数先保存在redis里面，由于redis的吞吐量比较大，扛住的可能性会更高一些。等数据写入的差不多了在持久化到数据库就好了；&lt;/p>
&lt;/li>
&lt;li>
&lt;p>缓存：将热点数据放到内存中，设置内存的最大使用量以及淘汰策略来保证缓存的命中率。比如站点的一些全局配置，每个用户都需要来拉一次，而且内容变化的频率很低，如果放数据库的话会对数据库宝贵的计算资源造成浪费，所以可以放到redis里，用户去redis缓存里读，降低了对数据库的访问量的同学要加速了配置拉取的速度；&lt;/p>
&lt;/li>
&lt;li>
&lt;p>查找表：例如 DNS 记录就很适合使用 Redis 进行存储。查找表和缓存类似，也是利用了 Redis 快速的查找特性。但是查找表的内容不能失效，而缓存的内容可以失效，因为缓存不作为可靠的数据来源。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>消息队列：List 是一个双向链表，可以通过 lpush 和 rpop 写入和读取消息。比如可以把发送邮件的场景，因为邮件服务器的qps一般来说都不是特别高，如果同时发送很多邮件的话，对邮件服务器可能产生很大的压力。我们可以把邮件发送的消息放到redis里，让邮件服务器从redis一个接一个的读取和处理。不过更专业的消息队列场景最好使用 Kafka、RabbitMQ 等消息中间件。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>会话缓存： 可以使用 Redis 来统一存储多台应用服务器的会话信息。应用服务器不再存储用户的会话信息，也就不再具有状态，一个用户可以请求任意一个应用服务器，从而更容易实现高可用性以及可伸缩性。简单来说可以把登录态的一些信息也放redis里。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>共同好友： Set 可以实现交集、并集等操作，从而实现共同好友等功能；&lt;/p>
&lt;/li>
&lt;li>
&lt;p>排行榜： ZSet 可以实现有序性操作，从而实现排行榜等功能；&lt;/p>
&lt;/li>
&lt;li>
&lt;p>限制验证码的发送频率：一般我们收到短信验证码的时候，应用都会限制说60秒之后重新获取，这是为了防止有人恶意刷短信验证码，毕竟发验证码是要花钱的。用redis可以非常方便的实现这个功能。我们可以把用户id记录到redis里，并设置过期时间是60秒，这样60秒内用户再请求发送的时候就会发现该用户的发送记录已存在，60秒以后由于缓存自动过期，那么就可以重新再发送了；&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>以上是redis的一些非常简单的使用场景了，有兴趣的同学可以跟开发同学再多探讨一下自己业务里redis的具体使用方式。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1484591974057-265bb767ef71?w=300"
 data-srcset="https://images.unsplash.com/photo-1484591974057-265bb767ef71?w=300, https://images.unsplash.com/photo-1484591974057-265bb767ef71?w=300 1.5x, https://images.unsplash.com/photo-1484591974057-265bb767ef71?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1484591974057-265bb767ef71?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>测试同学需要了解的序列化和反序列化</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E9%9C%80%E8%A6%81%E4%BA%86%E8%A7%A3%E7%9A%84%E5%BA%8F%E5%88%97%E5%8C%96%E5%92%8C%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E9%9C%80%E8%A6%81%E4%BA%86%E8%A7%A3%E7%9A%84%E5%BA%8F%E5%88%97%E5%8C%96%E5%92%8C%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/</guid><description>&lt;p>经常看到有同学弄不清楚序列化和反序列化，从而造成了很多困扰。&lt;/p>
&lt;p>从工作上的现实意义来说，了解序列化和反序列化是相当有必要的，在一些场景下可以指导测试用例的编写，另外也可以帮助我们了解被测产品/项目的一些实现细节。&lt;/p>
&lt;h3 id="定义">定义&lt;/h3>
&lt;p>序列化(Serialization)&lt;/p>
&lt;p>In computer science, in the context of data storage, serialization (or serialisation) is the process of translating data structures or object state into a format that can be stored (for example, in a file or memory buffer) or transmitted (for example, across a network connection link) and reconstructed later (possibly in a different computer environment).&lt;/p>
&lt;p>简单来说，序列化是一个过程，是把一些数据结构或对象转换成是可以存储(比如保存到文件，内存，数据库)或者是可以传输(比如网络传输)的格式。当然，这个格式的数据是可以反过来还原成数据结构或对象的。&lt;/p>
&lt;p>是不是有点绕？举个具体的例子。&lt;/p>
&lt;p>For an everyday example, say you want to tell your friend over the phone about your puppy. You are not able to send the entire living dog over the phone, but are restricted to describe the dog in a format that can be conveyed over the phone, in a serialized form: You say &amp;ldquo;It&amp;rsquo;s black, small, 5 months old&amp;hellip;&amp;rdquo; Your friend will then deserialize the information into a form that is feasible on his side: a mental image of the black, little dog. Likewise, a computer program cannot just send its compiled objects to another computer - objects from a Windows compiler won&amp;rsquo;t do on MacOS for instance. Instead it serializes the object MyPuppy to an XML or JSON string ({&amp;ldquo;color&amp;rdquo;:&amp;ldquo;black&amp;rdquo;, &amp;ldquo;size&amp;rdquo;:&amp;ldquo;small&amp;rdquo;&amp;hellip;}) that can be sent and easily interpreted, or deserialized, into another system&amp;rsquo;s dog object as a black, little puppy.&lt;/p></description></item><item><title>测试同学学历不好应该怎么办？</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E5%AD%A6%E5%8E%86%E4%B8%8D%E5%A5%BD%E5%BA%94%E8%AF%A5%E6%80%8E%E4%B9%88%E5%8A%9E/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E5%AD%A6%E5%8E%86%E4%B8%8D%E5%A5%BD%E5%BA%94%E8%AF%A5%E6%80%8E%E4%B9%88%E5%8A%9E/</guid><description>&lt;p>我写东西的灵感经常来源于群聊或者，嗯，还是群聊。&lt;/p>
&lt;p>最近的因为事情特别多，基本上是没时间聊天的了，灵感有一些青黄不接，不过今天秃然想到了一个可以跟大家分享的点。&lt;/p>
&lt;p>那就是测试同学学历不好怎么办？&lt;/p>
&lt;p>事情的经过是这样的。因为我们公司最近在大量招聘，所以我通过一些方式去收集了部分简历，但是这些简历大部分都被hr给pass掉了，深究其原因，无非就是学历不过关。&lt;/p>
&lt;p>我们公司基本上是个小公司，知名度一般，跟一线大公司比，其实学历要求相对还是低一点的。不过今年明显可以感到，我们对学历的要求开始水涨船高。之前二本可以通过hr删选，现在则要求一本及以上学历。简而言之就是211985的本科以及硕士以上学历以及相关专业。&lt;/p>
&lt;p>这种要求基本上挡住了80%左右的求职者。为什么呢？&lt;/p>
&lt;h3 id="很大一部分测试同学的学历其实不算特别有竞争力">很大一部分测试同学的学历其实不算特别有竞争力&lt;/h3>
&lt;p>长江后浪推前浪。最近b站特别火的后浪视频就说明了这一点。对于从业比较早的测试同学来说，很多同学可能是大专/专升本/三本的学历。在当初，也就是前些年，这些学历去找一份测试的工作可能不难，不过现在应届生越来越多，行业岗位其实并没有爆发式的增长，就造成了后浪跟前浪一起竞争的情况。后浪的学历水平很可能是高于前浪的，毕竟现在高考升学率其实比之前可能是要高的，毕业生的绝对数量也比之前要大，真的拼学历，后浪应该有一些优势。&lt;/p>
&lt;h3 id="很多测试同学不是相关专业">很多测试同学不是相关专业&lt;/h3>
&lt;p>众所周知，很多开发/测试同学是培训机构出来的，这些同学可能往往不是计算机相关专业，而一些一线互联网企业其实很看重相关专业，毕竟好的基础代表着更大的提升空间。&lt;/p>
&lt;p>当然我说这些其实不是让大家增加焦虑，只是说明很多情况下，就业的压力和上升的通道可能跟这些因素有关系。但事在人为，我觉得测试同学是有不少的努力方向可以持续提升和自我发展的。毕竟专业不能代表一切，学历也只是一个快速过滤的选项。&lt;/p>
&lt;p>如果大家学历不够，或者不是相关专业，那怎么进行自我提升呢？&lt;/p>
&lt;p>之前看到过一个老外对于程序员成长的建议，我觉得是有参考价值的。&lt;/p>
&lt;p>原文在这里。&lt;/p>
&lt;pre tabindex="0">&lt;code>As a developer, your 9-5 shouldn’t be your sole focus.

Find time for projects outside your regular job:

- Write blog posts
- Attend conferences
- Build something just for fun
- Network with other developers

Expanding in this way leads to huge opportunities.
&lt;/code>&lt;/pre>&lt;h3 id="开始写博客吧">开始写博客吧&lt;/h3>
&lt;p>写博客意味着总结，有总结就有提升。之前有位同学学历也是一般，后来他坚持写博客，终于在面试的时候产生了效果，于是职业生涯迎来了一些新的机会。他还专门私信跟我说了这件事，我也是衷心为他感到高兴。&lt;/p>
&lt;p>另外虫师也是很好的例子，起点不高的他通过博客记录了他的技术成长过程，也通过博客帮助和鼓励了很多人。&lt;/p>
&lt;p>有稳定的输出的博客会给面试官带来候选人有独立思考和持续学习的印象，是不错的加分项目。&lt;/p>
&lt;h3 id="做一些自己感兴趣的项目">做一些自己感兴趣的项目&lt;/h3>
&lt;p>我是强烈建议测试学习一些开发能力的，这样与开发的沟通会更顺畅一些，也不会被开发技术降纬打击，说人话就是不会被忽悠。&lt;/p>
&lt;p>我就学过很多技术，但性价比最高的还是基础的东西，因为越基础的东西变化的可能性越小，学一次可以用十几年，何乐而不为。&lt;/p>
&lt;p>哪些东西是基础的呢？&lt;/p>
&lt;ul>
&lt;li>操作系统的原理&lt;/li>
&lt;li>网络原理&lt;/li>
&lt;li>算法&lt;/li>
&lt;/ul>
&lt;p>看起来越无聊的东西其实越基础，有趣的东西往往都是应用了。这里知道为什么大家喜欢招相关专业了吧。&lt;/p>
&lt;p>测试同学可以结合自己的工作，做这样一些有意思的项目。&lt;/p></description></item><item><title>沉迷折腾，无法自拔</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B2%89%E8%BF%B7%E6%8A%98%E8%85%BE%E6%97%A0%E6%B3%95%E8%87%AA%E6%8B%94/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B2%89%E8%BF%B7%E6%8A%98%E8%85%BE%E6%97%A0%E6%B3%95%E8%87%AA%E6%8B%94/</guid><description>&lt;p>最近在抽屉里翻出了某品牌的一个专业运动手环，应该是之前跟该品牌合作的时候甲方大大赠予的。正好最近一直在关注iwatch，于是就桃僵李代，把手环当iwatch来用吧，反正功能也差不太多。&lt;/p>
&lt;p>带上去以后的几天，感觉还是很不错的。&lt;/p>
&lt;ul>
&lt;li>首先是翻腕亮屏功能，这个功能基本保证了这个手环可以当手表用，正好我以前有戴表的习惯，只是因为祖传的那块表时间总是不准所以放弃了，这次也算是无缝衔接了；&lt;/li>
&lt;li>记步功能。戴了手环以后发现我每天差不多要走7000步，挺有成就感的。不过ios的健康app里也有同样的功能，只是因为要打开app查看，所以很多时候就忙忘记了；这次天天在手腕上进行提醒，实用性增强了很多；&lt;/li>
&lt;li>心跳监控。实话实说，没啥用。&lt;/li>
&lt;li>防水功能，这个是必须的，我有时候洗澡都戴着，完全没啥问题。&lt;/li>
&lt;li>超长待机。一天10%的电就够了，大概2周一充，比iwatch强一些。&lt;/li>
&lt;li>睡眠监控。不用不知道，一用吓一跳。用了以后才发现原来自己的睡眠质量那么差，每天深睡的时间非常短。&lt;/li>
&lt;/ul>
&lt;h3 id="关于手环的睡眠质量">关于手环的睡眠质量&lt;/h3>
&lt;p>一天好多天，我都被手环检测出的睡眠质量困扰。&lt;/p>
&lt;p>其实我身体上没有特别明显的缺觉感觉，但是手环却告诉我，你的睡眠质量差，需要改进。&lt;/p>
&lt;p>我直觉上感到应该研究一下手环检测睡眠质量的原理，简单查了一下，发现手环是根据运动感应和心跳来判断是否是深度睡眠的。&lt;/p>
&lt;p>简单来说就是，如果你睡觉的时候没有翻身而且心跳频率变低的话，那么手环就认为是深睡，反之就是浅睡。这样如果睡觉不老实的人，比如频繁翻身之类的，那么得出的睡眠质量一定是不高的。&lt;/p>
&lt;p>所以手环的值只是参考，它不代表你睡的好不好，它只能证明你睡觉老不老实。&lt;/p>
&lt;p>所以睡觉监控，看看就好，不要往心里去。&lt;/p>
&lt;p>也终于想起了当年为什么不戴这个手环了，因为当年也是频繁显示我睡眠质量低，为了免去烦恼，还是不戴为好。&lt;/p>
&lt;h3 id="提升睡眠质量">提升睡眠质量&lt;/h3>
&lt;p>当然，尽管嘴上说值只是参考，但我身体上还是很诚实，我查了一下如何去改善睡眠质量，下面是我从某视频网站的高点击率视频里学到的技巧。&lt;/p>
&lt;ul>
&lt;li>睡觉前10小时不要摄入咖啡因。这个简单，因为我不喝咖啡；&lt;/li>
&lt;li>睡满8个小时，而不是在床上躺8小时；这条放弃了，我大概7个小时就会醒，勉强不来；&lt;/li>
&lt;li>睡觉前1小时不看任何的屏幕，比如手机/pad/电脑。这点只能说尽量做到，因为睡觉之前还是会看一下手机消息和告警的；&lt;/li>
&lt;/ul>
&lt;p>简而言之，睡觉之前不要玩手机，可以看看书，做一下拉伸之类的。但道理我们都懂，做到确实太难。&lt;/p>
&lt;h3 id="提升音质">提升音质&lt;/h3>
&lt;p>因为经常需要录制教程，所以对于录屏和录音我还是自认较为熟悉的，直到近期有一天我用耳机听之前录制的视频，我惊奇的发现声音质量原来这么差，不仅底噪高，而且声音的还原度也很差。&lt;/p>
&lt;p>于是我决定要提升课程直播和录制时的声音质量。&lt;/p>
&lt;p>经过调研，我发现比较靠谱的方式是弄个外置声卡，而后接个心型指向的电容麦，这样应该就可以有较大的改善了，具体效果应该是这个样子的。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=111306544,3098698641&amp;amp;fm=26&amp;amp;gp=0.jpg"
 data-srcset="https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=111306544%2c3098698641&amp;amp;fm=26&amp;amp;gp=0.jpg, https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=111306544%2c3098698641&amp;amp;fm=26&amp;amp;gp=0.jpg 1.5x, https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=111306544%2c3098698641&amp;amp;fm=26&amp;amp;gp=0.jpg 2x"
 data-sizes="auto"
 alt="https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=111306544,3098698641&amp;amp;fm=26&amp;amp;gp=0.jpg"
 title="https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=111306544,3098698641&amp;amp;fm=26&amp;amp;gp=0.jpg" />&lt;/p>
&lt;p>不过这套装备的问题是占用的空间比较大，而我的桌面空间有限，放这套装备有点勉强。&lt;/p>
&lt;p>于是选来选去，我决定使用录音笔+胸麦的方案，我买的是zoom的h1n录音笔，pdd大概600块左右，送一堆配件。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2546461933,2534573188&amp;amp;fm=26&amp;amp;gp=0.jpg"
 data-srcset="https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2546461933%2c2534573188&amp;amp;fm=26&amp;amp;gp=0.jpg, https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2546461933%2c2534573188&amp;amp;fm=26&amp;amp;gp=0.jpg 1.5x, https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2546461933%2c2534573188&amp;amp;fm=26&amp;amp;gp=0.jpg 2x"
 data-sizes="auto"
 alt="https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2546461933,2534573188&amp;amp;fm=26&amp;amp;gp=0.jpg"
 title="https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2546461933,2534573188&amp;amp;fm=26&amp;amp;gp=0.jpg" />&lt;/p>
&lt;p>这个录音笔的玩法比较多，比如&lt;/p>
&lt;ul>
&lt;li>直接连电脑作为声卡+外接麦克风&lt;/li>
&lt;li>支持连接其他外接麦克风&lt;/li>
&lt;li>支持直接录音，录制乐器的还原度很高，音质在线&lt;/li>
&lt;li>支持连单反作为单反的外接麦克风使用&lt;/li>
&lt;li>支持连手机作为手机的外接麦克风使用&lt;/li>
&lt;/ul>
&lt;p>所以胸麦+录音笔的组合满足了我直播/录播的需求，还满足了我录制乐器声音的需求，一举两得，目前看来是行得通的。&lt;/p>
&lt;p>不过由于我家附近的噪声比较大，每次直播的时候我都会把麦克风的增益调小，这样可以比较好的控制背景噪音，但是带来的问题是录制的视频声音比较小。&lt;/p>
&lt;p>为了解决这个问题，我使用ffmpeg+audacity来做声音后期。&lt;/p>
&lt;p>步骤是使用ffmpeg把声音分离出来放到audacity去做降噪/标准化/提升音量等处理，然后再把处理好的声音用ffmpeg合并到之前的视频里去，基本上几条命令加几个宏操作就好了，复杂度不高，效果目前看来是可以的。&lt;/p>
&lt;h3 id="学习剪辑">学习剪辑&lt;/h3>
&lt;p>十一出去玩的时候拍了很多娃的视频和照片，这里就需要剪辑一下，变成游记vlog，优化回忆。&lt;/p>
&lt;p>之前的剪辑都是使用imovie，简单实用而且免费，不过只能用在mac上，而我的mac经常放公司不带回去，家里只有一台祖传的windows笔记本，所以我需要找到在windows进行&lt;em>免费&lt;/em>的视频剪辑方案。&lt;/p>
&lt;p>研究了很多前人的推荐以后，我这里试用了3个软件&lt;/p>
&lt;ul>
&lt;li>Davinci relove: 专业的剪辑工具，学会以后基本上啥都能搞定，据说好莱坞大片也用这个工具剪，学习成本高，但是收益也大，关键是免费，绝对神器；不过因为我的笔记本配置实在太差，所以放弃了；&lt;/li>
&lt;li>Blender: 专业的3D动画建模工具，视频剪辑只是辅助功能，不过完全够用，免费，推荐；&lt;/li>
&lt;li>Openshot: 免费简单的剪辑工具，基本的剪辑字幕和加转场可以轻易实现，快捷键很好用，不过没有调色功能，而且项目复杂一点各种调整都很麻烦，但简单的视频用来剪剪是完全没问题的；&lt;/li>
&lt;/ul>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.blackmagicdesign.com/images/products/davinciresolve/landing/hero/hero-md.jpg?_v=1558065057"
 data-srcset="https://images.blackmagicdesign.com/images/products/davinciresolve/landing/hero/hero-md.jpg?_v=1558065057, https://images.blackmagicdesign.com/images/products/davinciresolve/landing/hero/hero-md.jpg?_v=1558065057 1.5x, https://images.blackmagicdesign.com/images/products/davinciresolve/landing/hero/hero-md.jpg?_v=1558065057 2x"
 data-sizes="auto"
 alt="https://images.blackmagicdesign.com/images/products/davinciresolve/landing/hero/hero-md.jpg?_v=1558065057"
 title="https://images.blackmagicdesign.com/images/products/davinciresolve/landing/hero/hero-md.jpg?_v=1558065057" />&lt;/p></description></item><item><title>都9102年了，是时候该学会python了</title><link>https://itest2025.pages.dev/tutorials/47-000-%E9%83%BD9102%E5%B9%B4%E4%BA%86%E6%98%AF%E6%97%B6%E5%80%99%E8%AF%A5%E5%AD%A6%E4%BC%9Apython%E4%BA%86/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E9%83%BD9102%E5%B9%B4%E4%BA%86%E6%98%AF%E6%97%B6%E5%80%99%E8%AF%A5%E5%AD%A6%E4%BC%9Apython%E4%BA%86/</guid><description>&lt;p>写在2019年的尾巴。&lt;/p>
&lt;p>2019年11月的编程语言排行榜上，python排名第3，前5名的排名分别是&lt;/p>
&lt;ol>
&lt;li>java&lt;/li>
&lt;li>c&lt;/li>
&lt;li>python&lt;/li>
&lt;li>c++&lt;/li>
&lt;li>c#&lt;/li>
&lt;/ol>
&lt;p>python是排名前5的语言里唯一的动态脚本语言，而且python是2007/2010/2018年的年度编程语言，该语言的流程程度不言而喻。&lt;/p>
&lt;p>对测试同学来说，学会一门编程语言基本上属于必备技能了，这点应该争议不大了。python应该是众多编程语言里比较平易近人的一门，所以是推荐大家优先学习的。&lt;/p>
&lt;p>另外前几年看到过一本书，叫做&amp;laquo;python for kids&amp;raquo;，小孩子都在学python了，咱们社畜也不能太落后了吧。&lt;/p>
&lt;p>关于python在测试中的应用，这里就不一一列举了。在这里给大家推荐一些不错的学习资源和线路图，希望对大家有所帮助。&lt;/p>
&lt;p>众所周知，掌握一门语言不在于学，而在于练，所以测试同学学python不能仅仅停留在看语法学关键字的层面，更重要的是要动手去敲。&lt;/p>
&lt;h3 id="step-1-动手敲代码去学习语法">step 1: 动手敲代码去学习语法&lt;/h3>
&lt;p>尽管在掌握一门语言之后，语法就不是特别重要了，但在学习语言的初期，语法却是大多数同学的拦路虎。&lt;/p>
&lt;p>看语法始终是纸上得来终觉浅，比如开车，学了交规做题得了一百分不代表你能把车开好。语法还是一边练一边学比较好。&lt;/p>
&lt;p>学习python语法推荐《learn python the hard way》的最新版，中文翻译过来是笨方法学python。&lt;/p>
&lt;p>这本书深入浅出，每一章都有完整的例子，你可以先不看具体的解释，而只是把里面的代码敲一遍，运行起来，解决完各种缩进，拼写错误问题之后，python语法就大致可以掌握了。&lt;/p>
&lt;p>如果一遍掌握不了，那就再敲一遍吧。&lt;/p>
&lt;p>我自己是敲过一遍的，开始的十几节打印各种字符非常的枯燥，后面会稍微好一些。一边敲一遍看书上的解释，对以后学习其他语言都很有帮助。&lt;/p>
&lt;p>另外书的最后几个例子里用到了单元测试，对测试同学来说应该是可遇不可求的相当完美的学习资料了。&lt;/p>
&lt;h3 id="step-2-用语言去解决问题">step 2: 用语言去解决问题&lt;/h3>
&lt;p>测试同学平时用到python的机会可能不多，那么我们就需要自己创造机会去使用它。&lt;/p>
&lt;p>今天正好看到一个项目挺有意思的，推荐给大家做练习使用。&lt;/p>
&lt;p>项目地址: &lt;a href="https://github.com/zhiwehu/Python-programming-exercises" target="_blank" rel="noopener noreffer ">https://github.com/zhiwehu/Python-programming-exercises&lt;/a>&lt;/p>
&lt;p>这里面列举了100个可以用python编程去解决的问题，分为3个难度&lt;/p>
&lt;ul>
&lt;li>Level 1	Beginner means someone who has just gone through an introductory Python course. He can solve some problems with 1 or 2 Python classes or functions. Normally, the answers could directly be found in the textbooks. 完全小白。&lt;/li>
&lt;li>Level 2	Intermediate means someone who has just learned Python, but already has a relatively strong programming background from before. He should be able to solve problems which may involve 3 or 3 Python classes or functions. The answers cannot be directly be found in the textbooks. 有其他编程经验的python初学者。&lt;/li>
&lt;li>Level 3	Advanced. He should use Python to solve more complex problem using more rich libraries functions and data structures and algorithms. He is supposed to solve the problem using several Python standard packages and advanced techniques. python进阶使用者。&lt;/li>
&lt;/ul>
&lt;p>下面这道题就是属于level 1完全小白难度的。&lt;/p></description></item><item><title>关于成长</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%85%B3%E4%BA%8E%E6%88%90%E9%95%BF/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%85%B3%E4%BA%8E%E6%88%90%E9%95%BF/</guid><description>&lt;p>2020年的春节，比以往时候来的更早一些。&lt;/p>
&lt;p>不知不觉离过年就2个月了。&lt;/p>
&lt;p>2019年似乎特别的短，上半年过完就期盼着国庆长期，国庆回来没几个月又是春节，在这匆匆忙忙的一年中，我们是不是有所成长呢？&lt;/p>
&lt;p>从工作的角度上看，成长可以分为这样几个方面吧。&lt;/p>
&lt;h3 id="业务的成长">业务的成长&lt;/h3>
&lt;p>你负责的业务/产品跟去年相比是不是有成长呢？&lt;/p>
&lt;p>比如一年前产品刚上线，一穷二白。现在产品在线上稳定运行了一年，各项运营指标都很不错，业务稳定增长。&lt;/p>
&lt;p>又比如之前产品/项目风风火火，不料今年突生变数，原本数十人的团队现在只有几个人，裁的裁走的走，这是业务衰退的典型例子了。&lt;/p>
&lt;p>业务有增长代表了有向上的空间，是有经验的测试同学所需要着重考虑的；对于经验尚浅的同学来说，业务增长代表了能接触到的东西变多，挑战尽管较大，但成长的速度也会相应快一点。&lt;/p>
&lt;h3 id="个人技能的成长">个人技能的成长&lt;/h3>
&lt;p>一般来说技能成长是一个重复的过程。&lt;/p>
&lt;p>比如写代码，重复的次数多了自然就熟练了。&lt;/p>
&lt;p>再比如linux命令，多敲几遍此然就记住了。&lt;/p>
&lt;p>因为测试很多时间是一个重复的过程，所以一直重复一件事情，点来点去这个技能是可以得到增强的。不过如果只在一个地方点来点去，那么不仅无聊，而且得到的技能成长也是有限的。&lt;/p>
&lt;p>所以除了重复之外，个人技能成长跟接触面有关系。接触的东西越多，或者对同一件事情有更深的挖掘，个人技能也是可以有不错的提升的。&lt;/p>
&lt;p>深度和广度可以配合着来，相辅相成。&lt;/p>
&lt;h3 id="软技能的成长">软技能的成长&lt;/h3>
&lt;p>沟通能力，表达能力之类的软技能对于测试同学来说也是挺重要的。&lt;/p>
&lt;p>好的测试同学往往有不错的沟通能力和表达能力，在项目组中承担润滑剂的角色。&lt;/p>
&lt;p>另外测试同学还需要有一定的分析问题和解决问题的能力，这些能力可以为我们的决策提供良好的支持。比如线上出了一个问题，是紧急停机发版本修复还只是修复错误数据继续提供服务？这些决策往往由测试同学给出会比较可信。&lt;/p>
&lt;h3 id="其他成长">其他成长&lt;/h3>
&lt;p>比如薪资的增长，体重的增长，生活中角色的变化等等，工作只是生活的一部分，平衡好工作和生活，每个人都有自己的生活(生存)方式，知道自己想要什么，努力保持内心的平静，不盲目被鸡血，不轻易被洗脑，别人得到了很多的同时，大概也失去了不少，懂得了这些，也许就是人生中比较重要的成长吧。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/uploads/1412026095116d2b0c90e/3bf33993?w=300"
 data-srcset="https://images.unsplash.com/uploads/1412026095116d2b0c90e/3bf33993?w=300, https://images.unsplash.com/uploads/1412026095116d2b0c90e/3bf33993?w=300 1.5x, https://images.unsplash.com/uploads/1412026095116d2b0c90e/3bf33993?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/uploads/1412026095116d2b0c90e/3bf33993?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>关于双十二崩盘的一些思考</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%85%B3%E4%BA%8E%E5%8F%8C%E5%8D%81%E4%BA%8C%E5%B4%A9%E7%9B%98%E7%9A%84%E4%B8%80%E4%BA%9B%E6%80%9D%E8%80%83/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%85%B3%E4%BA%8E%E5%8F%8C%E5%8D%81%E4%BA%8C%E5%B4%A9%E7%9B%98%E7%9A%84%E4%B8%80%E4%BA%9B%E6%80%9D%E8%80%83/</guid><description>&lt;p>双十二的时候我们的一个重要业务崩盘了。&lt;/p>
&lt;p>原因其实很简单，就一句话，流量太大导致某个中间件接入层的HA proxy满载，中间件不可用，整个业务基本瘫痪。&lt;/p>
&lt;p>从测试的角度去总结一下，大概以后可以有如下的改进。&lt;/p>
&lt;h3 id="技术方案评审时就考虑高并发问题">技术方案评审时就考虑高并发问题&lt;/h3>
&lt;p>我们这次的事故是因为比较乐观，可能技术方案评审的时候就开始盲目乐观了。&lt;/p>
&lt;p>其实流量增长的速度有可能是我们难以去精确预估的，所以技术架构设计的时候我们就要提前准备。&lt;/p>
&lt;p>对于测试同学来说，大家可以简单记住下面一些要点。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>降级。在大流量的情况下，是否能通过一些机制让服务降级，从而保护整个系统的稳定性。举个例子，可能一般情况下，用户购买商品下一个订单就可以马上看到订单的详情，但是在秒杀场景中，用户可能在下单很长时间之后才能看到订单，这就是一种服务降级的表现。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>削峰。把流量的高峰削平，不让突如其来的大流量对系统产生破坏性的影响。举个例子，12306抢票的时间点是分散的，大概每个小时抢一次，这就防止了一次性放出所有票导致所有用户同时抢票带来的流量高峰，这是一种业务上的削峰。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>限流。这个很好理解。一些第三方api会限制每分钟调用的次数就是这个道理。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>熔断。高并发时,如果一些api无法访问后，能不能自动不去访问这些有故障的api，从而保证主流程的顺畅和稳定。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>故障摘除。一些容器如果被击垮，能不能动态去摘除这些节点，从而保证整个系统可用。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="了解架构">了解架构&lt;/h3>
&lt;p>事故之前，我们其实对整个架构能支撑的容量做了计算，结论是在当前架构下是可以撑住双12的峰值的。但是千算万算却没想到中间件在接入层之前有HA做负载均衡。这个ha实际上是单点，容量有限，如果提前了解该架构，并且进行扩容的话，事故大概也不会发生。&lt;/p>
&lt;p>测试同学在看架构的时候可以先无脑关注单点问题。某个服务或中间件是不是单点？如果是，那么单点挂掉之后对整个系统可用性会不会造成影响？搞清楚这个问题的答案对系统高可用非常关键。&lt;/p>
&lt;h3 id="提前做好紧急预案">提前做好紧急预案&lt;/h3>
&lt;p>问题总会有可能发生的，因此提前准备好预案非常重要。&lt;/p>
&lt;p>这次事故发生之前，我们并没有准备应急预案，因此，当临时发现了无法动态扩容的HA单点时，我们基本上只能眼睁睁的看着系统挂掉，什么事情都做不了。&lt;/p>
&lt;h3 id="不要迷信动态扩容">不要迷信动态扩容&lt;/h3>
&lt;p>动态扩容属于亡羊补牢，在问题发生时候的那几秒，扩容往往是无法迅速完成的，因此提前计算好容量才是关键。&lt;/p>
&lt;p>最后，下次的活动是在明年的双十一，嗯，这个锅要背一年了。&lt;/p>
&lt;p>惭愧，惭愧。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1501854140801-50d01698950b?w=300"
 data-srcset="https://images.unsplash.com/photo-1501854140801-50d01698950b?w=300, https://images.unsplash.com/photo-1501854140801-50d01698950b?w=300 1.5x, https://images.unsplash.com/photo-1501854140801-50d01698950b?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1501854140801-50d01698950b?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>过气测试网红的自我隔离14天</title><link>https://itest2025.pages.dev/tutorials/47-000-%E8%BF%87%E6%B0%94%E6%B5%8B%E8%AF%95%E7%BD%91%E7%BA%A2%E7%9A%84%E8%87%AA%E6%88%91%E9%9A%94%E7%A6%BB14%E5%A4%A9/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E8%BF%87%E6%B0%94%E6%B5%8B%E8%AF%95%E7%BD%91%E7%BA%A2%E7%9A%84%E8%87%AA%E6%88%91%E9%9A%94%E7%A6%BB14%E5%A4%A9/</guid><description>&lt;p>我是乙醇，一个过气了的测试网红。&lt;/p>
&lt;p>那天早上我拿到了出入证明，一路向南，穿越江西广东，孤身一人直达深圳。&lt;/p>
&lt;p>原本车流不息的高速那天门口罗雀，经常开上一个小时才能看到一台车。路边倒是能看到小憩的倦鸟和不知哪里上来的牛群。&lt;/p>
&lt;p>整个世界好像只有我一台车，一个人。&lt;/p>
&lt;p>我这是在哪？一路上都是这么不确信。&lt;/p>
&lt;p>14个小时后顺利到达深圳，办理好个人申报就可以进小区了。&lt;/p>
&lt;p>然后便是半夜清洗冰箱，修热水器，那时候我意识到，冰箱啊，其实我是恨你的。&lt;/p>
&lt;p>第二天中午鼓起勇气，全副武装下楼大采购。买了一些酒精，水果，鸡蛋，牛奶，不带叶子的蔬菜，比如土豆番茄之类，一点点鸡肉，油盐酱醋。买面粉的时候发现几个超市的面粉全部被搬空了，后来找到一家粮油专卖店，拿了10斤，买了5袋限购的酵母，把酒精抵押在超市，借了台需要200块押金的推车，把食物一股脑的运送回去。&lt;/p>
&lt;p>还车的时候拿回酒精，超市工作人员赞许的目光让我无比舒适，仿佛有了酒精便能高枕无忧延年益寿。&lt;/p>
&lt;p>至此需要自我隔离14天才去上班了。&lt;/p>
&lt;p>那这14天里，除了远程办公我还能做什么呢？&lt;/p>
&lt;h3 id="远程办公">远程办公&lt;/h3>
&lt;p>首先大量的时间都被远程办公占用了，尽管不需要通勤，但远程办公的时候往往需要及时响应，后面渐渐变成了随时响应，所以整体的办公时间其实还是不少的。&lt;/p>
&lt;p>另外远程办公也需要提升效率，好的协作工作可以带来事半功倍的效果。&lt;/p>
&lt;h3 id="养活自己">养活自己&lt;/h3>
&lt;p>作为一个生活能力极端低下的中年留守儿童 ，这14天最大的挑战就是养活自己。&lt;/p>
&lt;p>因为远程办公的关系，每天基本上没有多少时间来仔细做饭，所以必须用最少的时间来生产尽可能多的食物。&lt;/p>
&lt;p>冰箱里有不少从老家带过来的咸肉和卤菜，做为热菜小能手的我来说，肉类问题应该是可以解决了。&lt;/p>
&lt;p>有鸡蛋和番茄，而且处理起来比较迅速，可以番茄鸡蛋汤/西红柿炒鸡蛋/番茄鸡蛋面几种形态间自由切换，是不错的快手菜选择。&lt;/p>
&lt;p>有土豆和四季豆，干煸土豆，干煸四季豆啥的，应该能吃。&lt;/p>
&lt;p>有一些榨菜和鸡肉，可以做榨菜肉丝面吧。&lt;/p>
&lt;p>最后就是亮出我面点王的身份了。作为面包机达人，我可以用面包机发面，然后随便切切就做成馒头，一次性多做些，蒸出来用保鲜袋装好放到冰箱里，可以吃很久。&lt;/p>
&lt;p>因为需要多喝水增强抵抗力，我决定多吃稀饭，这样就等于是一边吃饭一边喝水，就不会总是忘记喝水了。早餐可以吃稀饭，晚上可以喝粥，看起来很合理的样子。&lt;/p>
&lt;p>稍微计算了一下，粮食储备应该可以坚持14天不出门。&lt;/p>
&lt;h3 id="想办法丢垃圾">想办法丢垃圾&lt;/h3>
&lt;p>出门就意味着风险和损失口罩，所以要尽可能少的出门丢垃圾，先把垃圾收集起来整理好放到走道，隔几天夜深人静的时候再去丢掉，目前也只能这么办了。&lt;/p>
&lt;h3 id="练习口语">练习口语&lt;/h3>
&lt;p>作为英文口语的困难户，这次孤身隔离其实是练习口语的最好时机，反正有时间就在家里唧唧歪歪，就算打扰到了邻居他也不会上门理论，不知道闭关14天之后我的哑巴英语是不是会进阶成结巴英语。加油加油。&lt;/p>
&lt;h3 id="锻炼">锻炼&lt;/h3>
&lt;p>在电梯间里看到宣传画上说，希望大家不要出门，加强锻炼，于是问题就来了，不出门怎么锻炼？&lt;/p>
&lt;p>首先是多喝水，水喝的多应该比有一颗向往锻炼的心更重要吧。&lt;/p>
&lt;p>俯卧撑和仰卧起坐，不受场地的限制。&lt;/p>
&lt;p>瑜伽。我练过一点阿斯汤伽，在家里可以练，顺便缓解颈椎病的困扰。&lt;/p>
&lt;h3 id="读书">读书&lt;/h3>
&lt;p>之前攒的那些书终于有时间拿来出来翻一翻了。&lt;/p>
&lt;h3 id="最后">最后&lt;/h3>
&lt;p>这样看来其实14天应该是忙碌且有挑战的。&lt;/p>
&lt;p>宅下去不乱跑，吃饱睡好，等到出关的时候，大概就岁月静好了吧。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1459695452562-46cc57bef5f6?w=300"
 data-srcset="https://images.unsplash.com/photo-1459695452562-46cc57bef5f6?w=300, https://images.unsplash.com/photo-1459695452562-46cc57bef5f6?w=300 1.5x, https://images.unsplash.com/photo-1459695452562-46cc57bef5f6?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1459695452562-46cc57bef5f6?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>好书推荐:使用测试驱动开发的方式学习go语言</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%A5%BD%E4%B9%A6%E6%8E%A8%E8%8D%90%E4%BD%BF%E7%94%A8%E6%B5%8B%E8%AF%95%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91%E7%9A%84%E6%96%B9%E5%BC%8F%E5%AD%A6%E4%B9%A0go%E8%AF%AD%E8%A8%80/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%A5%BD%E4%B9%A6%E6%8E%A8%E8%8D%90%E4%BD%BF%E7%94%A8%E6%B5%8B%E8%AF%95%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91%E7%9A%84%E6%96%B9%E5%BC%8F%E5%AD%A6%E4%B9%A0go%E8%AF%AD%E8%A8%80/</guid><description>&lt;p>首先这本书是免费的。&lt;/p>
&lt;p>其次这本书是开源的。&lt;/p>
&lt;p>如果你想学习go和TDD（测试驱动开发）的话，这本书是不错的选择。&lt;/p>
&lt;p>就个人经历而言，学习go语言目前比较好的材料是https://gobyexample.com，通过例子学习go语言，事半功倍。&lt;/p>
&lt;p>而这本使用测试驱动开发的方式学习go语言内容则更为立体，非常适合大家在学习go语言的同时也对测试驱动开发有一定的了解。&lt;/p>
&lt;h3 id="什么是测试驱动开发">什么是测试驱动开发&lt;/h3>
&lt;p>概念很大，简单来说，测试驱动开发是一种精神，就是先写用例再写实现代码的精神。&lt;/p>
&lt;p>测试驱动开发其实是这样工作的&lt;/p>
&lt;ol>
&lt;li>先写单元测试用例，测一个不存在的功能或者函数&lt;/li>
&lt;li>运行单元测试用例，如果失败，则修改实现，直到测试用例通过&lt;/li>
&lt;li>添加更多的测试用例&lt;/li>
&lt;li>重复步骤2,3并进行重构，直到所有的功能都测试用例并且用例都运行通过&lt;/li>
&lt;/ol>
&lt;h3 id="书上的例子">书上的例子&lt;/h3>
&lt;p>通过书上的例子可以对上面的步骤有一个感性的认识。&lt;/p>
&lt;p>比如实现一个加法的函数，我们可以先写测试用例去测试这个函数，这个函数的名字是Add(int,int)，这是步骤1&lt;/p>
&lt;pre tabindex="0">&lt;code>package integers

import &amp;#34;testing&amp;#34;

func TestAdder(t *testing.T) {
 sum := Add(2, 2)
 expected := 4

 if sum != expected {
 t.Errorf(&amp;#34;expected &amp;#39;%d&amp;#39; but got &amp;#39;%d&amp;#39;&amp;#34;, expected, sum)
 }
}
&lt;/code>&lt;/pre>&lt;p>接着运行用例，此时自然是会失败，因为Add()函数我们并未实现。错误如下:&lt;/p>
&lt;pre tabindex="0">&lt;code>./adder_test.go:6:9: undefined: Add
&lt;/code>&lt;/pre>&lt;p>接下来实现Add()函数，以便让用例可以通过，这里有个规则，就是不要过度实现。&lt;/p>
&lt;p>只为测试的运行编写最少量的代码并检查失败测试的输出。&lt;/p>
&lt;p>比如你会看到这样的我们的实现是这样的&lt;/p>
&lt;pre tabindex="0">&lt;code>package integers

func Add(x, y int) int {
 return 0
}
&lt;/code>&lt;/pre>&lt;p>这可以让我们的代码编译通过，这样就可以看到到底是哪个用例出了什么问题了&lt;/p>
&lt;pre tabindex="0">&lt;code>adder_test.go:10: expected &amp;#39;4&amp;#39; but got &amp;#39;0&amp;#39;
&lt;/code>&lt;/pre>&lt;p>下面编写足够的代码使其通过。&lt;/p>
&lt;pre tabindex="0">&lt;code>func Add(x, y int) int {
 return 4
}
&lt;/code>&lt;/pre>&lt;p>呃！！！！你这是在开玩笑吗？这样可以吗？&lt;/p></description></item><item><title>记一个线上问题</title><link>https://itest2025.pages.dev/tutorials/47-000-%E8%AE%B0%E4%B8%80%E4%B8%AA%E7%BA%BF%E4%B8%8A%E9%97%AE%E9%A2%98/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E8%AE%B0%E4%B8%80%E4%B8%AA%E7%BA%BF%E4%B8%8A%E9%97%AE%E9%A2%98/</guid><description>&lt;p>正愁着这周的公众号写些什么的时候，线上就很应景的出现了问题。&lt;/p>
&lt;p>问题很简单，我们的app上有广告位，广告位的落地链接是在后台配置的。今天我们测试同学发现线上的某个广告位链接点击之后无法展示。&lt;/p>
&lt;p>经过排查，我们发现原来运营人员在配置广告位链接时候在链接后带上了一个肉眼不可见的字符&lt;code>\t&lt;/code>。&lt;/p>
&lt;p>原因找到之后处理起来就很容易了，只要要运营人员去掉后面的不可见特殊字符就好了。&lt;/p>
&lt;p>这应该是大家很常见的一个特殊字符的测试场景，在设计基于输入框用例的时候基本上大家都会做类似的用例验证。不过大家在验证的时候大部分把精力放在肉眼可见的特殊字符上，最常见的就是url encoding的时候需要转义的一些特殊字符，比如&lt;code>^%$@&lt;/code>之类，基本上就是键盘数字键上方那一些字符串。不过这样是不完备的了，一些特殊的转义字符，特别是肉眼觉察不到的转义字符也是需要考虑的。&lt;/p>
&lt;p>其实用例验证是后验式的，如果在需求评审和开发的时候就注意到的话，那么就算是漏测，也是不会发生线上问题的了。&lt;/p>
&lt;p>针对这个场景，我们在跟开发沟通设计的时候，应该是可以这样做的。&lt;/p>
&lt;ul>
&lt;li>首先前端在发送创建广告位请求的时候就应该过滤掉url首位的空字符和换行符，比如&lt;code>\t\n&lt;/code>&lt;/li>
&lt;li>其次后端在持久化url的时候也要做一样的工作，去掉无效的空字符&lt;/li>
&lt;li>最后app端(android/ios/h5/rn)在跳转url的时候也要过滤掉首尾的空字符&lt;/li>
&lt;/ul>
&lt;p>总结一下&lt;/p>
&lt;ul>
&lt;li>前端要做校验&lt;/li>
&lt;li>后端要做校验&lt;/li>
&lt;li>客户端有时候不能盲目相信服务端&lt;/li>
&lt;/ul>
&lt;p>最后大家可以牢牢记住一句话：&lt;strong>永远不要相信用户的输入&lt;/strong>&lt;/p>
&lt;p>用户的输入永远的是不可控的， 一定要对用户的输入做校验和过滤(前后端都要)，否则出线上问题或安全问题是迟早的事。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1494625927555-6ec4433b1571?w=300"
 data-srcset="https://images.unsplash.com/photo-1494625927555-6ec4433b1571?w=300, https://images.unsplash.com/photo-1494625927555-6ec4433b1571?w=300 1.5x, https://images.unsplash.com/photo-1494625927555-6ec4433b1571?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1494625927555-6ec4433b1571?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>简单的unittest runner: green</title><link>https://itest2025.pages.dev/tutorials/47-000-%E7%AE%80%E5%8D%95%E7%9A%84unittest-runner-green/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E7%AE%80%E5%8D%95%E7%9A%84unittest-runner-green/</guid><description>&lt;p>首先来个截图。&lt;/p>
&lt;p>!&lt;a href="https://raw.githubusercontent.com/CleanCut/green/master/img/screenshot.png" target="_blank" rel="noopener noreffer ">&lt;/a>&lt;/p>
&lt;p>green是unittest 众多runner中功能比较丰富的一个。&lt;/p>
&lt;p>官方的featrue介绍如下：&lt;/p>
&lt;pre tabindex="0">&lt;code>Clean - Low redundancy in output. Result statistics for each test is vertically aligned.
Colorful - Terminal output makes good use of color when the terminal supports it.
Fast - Tests run in independent processes. (One per processor by default. Does not play nicely with gevent)
Powerful - Multi-target + auto-discovery.
Traditional - Use the normal unittest classes and methods for your unit tests.
Descriptive - Multiple verbosity levels, from just dots to full docstring output.
Convenient - Bash-completion and ZSH-completion of options and test targets.
Thorough - Built-in integration with coverage.
Embedded - Can be run with a setup command without in-site installation.
Modern - Supports Python 3.5+. Additionally, PyPy is supported on a best-effort basis.
Portable - macOS, Linux, and BSDs are fully supported. Windows is supported on a best-effort basis.
Living - This project grows and changes. See the changelog
&lt;/code>&lt;/pre>&lt;p>简单来说，green的一些优势有：&lt;/p></description></item><item><title>简单讨论ELK在测试中的使用场景</title><link>https://itest2025.pages.dev/tutorials/47-000-%E7%AE%80%E5%8D%95%E8%AE%A8%E8%AE%BAelk%E5%9C%A8%E6%B5%8B%E8%AF%95%E4%B8%AD%E7%9A%84%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E7%AE%80%E5%8D%95%E8%AE%A8%E8%AE%BAelk%E5%9C%A8%E6%B5%8B%E8%AF%95%E4%B8%AD%E7%9A%84%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF/</guid><description>&lt;h3 id="什么是elk">什么是ELK&lt;/h3>
&lt;p>在高复杂度的系统中，对于定位线上问题，日志非常重要。ELK(ElasticSearch+Logstash+Kibana)，可以使用说是目前最流行的日志平台构建方案，之所以深受开发者喜爱，主要是因为它解决了大规模系统的日志收集的各种痛点。&lt;/p>
&lt;p>ELK(ElasticSearch+Logstash+Kibana)，主要包含三个组件：&lt;/p>
&lt;ul>
&lt;li>ElasticSearch&lt;/li>
&lt;li>Logstash&lt;/li>
&lt;li>Kibana&lt;/li>
&lt;/ul>
&lt;h4 id="elasticsearch">ElasticSearch&lt;/h4>
&lt;p>ElasticSearch是一个开源的分布式的搜索引擎，它主要基于Apache Lucene。在整个ELK Stack中，ElasticSearch是最核心的组件，它存储数据，并且提供了许多灵活而实用的Rest API，所以，上层应用可以根据需要去查询数据，使用数据，分析数据。在日志平台中，所有的日志数据都存储到ElasticSearch中，借助其强大的搜索能力，可以很灵活的查询日志。&lt;/p>
&lt;h4 id="logstash">Logstash&lt;/h4>
&lt;p>Logstash主要用于收集数据，并将数据保存到ElasticSearch中。&lt;/p>
&lt;p>Logstash有丰富插件，并且易于扩展，所以，可以使用Logstash收集到数据后，可以做很多处理，最终再将数据输出到ElasticSearch中。在日志平台中，它主要复杂采集应用的日志。&lt;/p>
&lt;h4 id="kibana">Kibana&lt;/h4>
&lt;p>Kibana主要负责读取ElasticSearch中的数据，并进行可视化展示。并且，它还自带Tool，可以方便调用ElasticSearch的Rest API。在日志平台中，我们通过Kibana查看日志。&lt;/p>
&lt;h3 id="使用elk存储测试报告">使用ELK存储测试报告&lt;/h3>
&lt;p>测试报告是自动化测试中非常重要的一环，测试结果的清晰展示以及归档是大家需要日常处理的问题。&lt;/p>
&lt;p>既有的经验里，我们可以通过定制一些测试模版输出一些特定格式的测试报告，比如html格式，然后保存到测试报告平台或者直接邮件发送。&lt;/p>
&lt;p>上面的做法其实没什么不好，不过可能需要一些开发工作量。另外归档和搜索之类的功能需要一定的二次开发能力，对于测试同学来说有一定的挑战。&lt;/p>
&lt;p>如果用例运行的非常频繁，那么高频次的出报告持久化以及多维度的搜索也是一件非常麻烦的事情。&lt;/p>
&lt;p>我们可以用ELK来简单粗暴的解决上面的问题。将每次的测试结果落地到日志文件里，然后使用Logstash处理并持久化到ES，最终使用Kibana来搜索，全程工作量很小，而且复杂的搜索功能开箱即用，成本低廉稳定性好，大家有兴趣可以不妨尝试一下。&lt;/p>
&lt;h3 id="使用es管理测试用例">使用ES管理测试用例&lt;/h3>
&lt;p>如果测试用例比较多的话，我们可能需要从很多的维度去搜索测试用例。假设我们开发测试用例管理系统的话，实现这些进阶搜索其实是比较大的工作量。&lt;/p>
&lt;p>我们可以将ES当作是存储引擎，把测试用例保存在ES里，ES有非常有好的RESTFUL API，使用这些API去检索数据，然后对结果进行一些可视化，就可以实现一个功能较为完备的用例管理系统了。&lt;/p>
&lt;p>如果不想二次开发就得到一个穷人版功能复杂的用例管理系统的话，可以将用例持久化成日志，然后用ELK工具链处理，最后使用kibana来查看用例，这也未尝不可。&lt;/p>
&lt;p>总之用ELK来做日志的处理和搜索是非常方便的，我们在测试过程中如果遇到有大量数据需要灵活搜索的场景都可以尝试一下ELK。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1413752362258-7af2a667b590?w=300"
 data-srcset="https://images.unsplash.com/photo-1413752362258-7af2a667b590?w=300, https://images.unsplash.com/photo-1413752362258-7af2a667b590?w=300 1.5x, https://images.unsplash.com/photo-1413752362258-7af2a667b590?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1413752362258-7af2a667b590?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>练手挑战：5个闲时挑战的python项目</title><link>https://itest2025.pages.dev/tutorials/47-000-%E7%BB%83%E6%89%8B%E6%8C%91%E6%88%985%E4%B8%AA%E9%97%B2%E6%97%B6%E6%8C%91%E6%88%98%E7%9A%84python%E9%A1%B9%E7%9B%AE/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E7%BB%83%E6%89%8B%E6%8C%91%E6%88%985%E4%B8%AA%E9%97%B2%E6%97%B6%E6%8C%91%E6%88%98%E7%9A%84python%E9%A1%B9%E7%9B%AE/</guid><description>&lt;p>python的初学者们总是会为找不到练手的项目而发愁，这几天正好碰巧在某视频网站看到有人分享一些不错的练手项目，于是就在这里大言不惭的抛砖引玉一下。&lt;/p>
&lt;h3 id="web网站使用flaskdjango">web网站(使用flask/django)&lt;/h3>
&lt;p>这是一个非常基础或者说是经典的练手项目。&lt;/p>
&lt;p>我们可以给自己简单设计一个网站，然后用python去实现它。&lt;/p>
&lt;p>当然在目前的情况下，实现网站可能会分为前端页面和后端接口这两块内容，不过使用flask或者django的话，其实你可以服务端直出html，加上一些前端的css和js，你就可以实现一些功能相对简单但视觉相对美观大方的网页了。&lt;/p>
&lt;p>这里强烈推荐大家使用flask去玩一下，如果想降低实现难度的话，可以先不实现持久化(数据库)，另外前端的css和js如果大家也没有时间从零开始写的话，推荐大家可以使用bootstrap等前端框架，这样就可以相对的将自己的精力放在python语言和后端逻辑层面。&lt;/p>
&lt;p>当然，这个项目最有魅力的是，你不仅可以学习到一些基本的web开发技巧，只要你有时间，你甚至可以通过项目学习到一系列的后端中间件，比如&lt;/p>
&lt;ul>
&lt;li>可以通过实现每日点赞数功能来玩一下redis&lt;/li>
&lt;li>可以通过学习持久化来玩一下各种数据库，比如mysql等&lt;/li>
&lt;li>可以通过实现异步发送邮件功能来玩一下消息队列&lt;/li>
&lt;/ul>
&lt;p>最后，如果你有兴趣的话，你还可以把网站部署到云服务器上，顺便可以学习到一些运维的经验。&lt;/p>
&lt;p>是不是很有意思？&lt;/p>
&lt;h3 id="改进一些流行的算法">改进一些流行的算法&lt;/h3>
&lt;p>比如自己实现一个解数独的算法或者是寻找最短路径的算法。&lt;/p>
&lt;p>视频的作者就自己现实了数独的解法，他首先实现了一个纯文本的解法，后来使用pygame实现了一个数独游戏，不仅可以正常玩耍，还可以一键解决数独，总之看上去是蛮有意思的。&lt;/p>
&lt;p>另外视频作者还可视化实现了寻找最短路径的算法，就是把动态解决问题的过程都展示了出来，让人感到非常的信服，作者应该是用pygame来实现这种可视化的。&lt;/p>
&lt;p>其实大家可以从最简单的排序开始，把排序过程用pygame可视化，由浅入深，应该会非常有意思的。&lt;/p>
&lt;h3 id="实现一个俄罗斯方块游戏">实现一个俄罗斯方块游戏&lt;/h3>
&lt;p>俄罗斯方块可以在任何时候让人欲罢不能。&lt;/p>
&lt;p>实现一个俄罗斯方块游戏应该是很多人都曾经冒出过的念头，既然有这个想法，那就去实现吧。&lt;/p>
&lt;p>网上有很多实现的思路，代码，最重要的是，有很多的静态资源，比如背景，各个方块的资源等，实现起来是困难不大的。&lt;/p>
&lt;p>另外也可以实现一个贪吃蛇，即怀旧又可以自己玩一玩打发时间。&lt;/p>
&lt;h3 id="实现一个alml项目">实现一个AL/ML项目&lt;/h3>
&lt;p>视频作者说自己在tensorflow上抄代码，反正网站上例子特别多，他就先抄完，然后跑起来，这样就开始自己的机器学习/AI的之旅。&lt;/p>
&lt;p>当你把所有例子都抄完运行成功以后，你对机器学习也就入门了吧，这时候就可以实现自己的各种脑洞了。&lt;/p>
&lt;h3 id="micorcontrol编程">micorcontrol编程&lt;/h3>
&lt;p>视频作者使用类似树莓派的microcontrol实现了会议室监控的功能，大概是通过代码控制摄像头做人脸识别，然后记录下来谁进了哪个会议室，看起来没啥用处，不过挺有意思的，也很有挑战，毕竟人脸识别也运用了ML的知识。&lt;/p>
&lt;p>树莓派加传感器可以实现很多应用，比如我就听说过某大厂用树莓派加传感器实现了手机的温度功能以及弱网IP的功能。&lt;/p>
&lt;p>树莓派本身不是很贵，有时间的同学可以去玩一下。&lt;/p>
&lt;h3 id="总结">总结&lt;/h3>
&lt;p>总之，如果你能完成上述5个项目，那么你的python运用能力基本上就可以满足日常工作的需要了。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1531168556467-80aace0d0144?w=300"
 data-srcset="https://images.unsplash.com/photo-1531168556467-80aace0d0144?w=300, https://images.unsplash.com/photo-1531168556467-80aace0d0144?w=300 1.5x, https://images.unsplash.com/photo-1531168556467-80aace0d0144?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1531168556467-80aace0d0144?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>萌新的软件入门教程</title><link>https://itest2025.pages.dev/tutorials/47-000-%E8%90%8C%E6%96%B0%E7%9A%84%E8%BD%AF%E4%BB%B6%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E8%90%8C%E6%96%B0%E7%9A%84%E8%BD%AF%E4%BB%B6%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B/</guid><description>&lt;ul>
&lt;li>
&lt;p>第一天: 求职篇&lt;/p>
&lt;ul>
&lt;li>为什么要做软件测试？&lt;/li>
&lt;li>今后的发展如何？&lt;/li>
&lt;li>经济收益如何？&lt;/li>
&lt;li>软件测试的要求是什么？&lt;/li>
&lt;li>我是不是适合做软件测试？&lt;/li>
&lt;li>招聘要求解读&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>第二天: 认识软件测试&lt;/p>
&lt;ul>
&lt;li>软件测试到底是什么&lt;/li>
&lt;li>软件测试的分类&lt;/li>
&lt;li>手工测试还有没有前途&lt;/li>
&lt;li>小白的质量控制思路&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>第三天: 软件测试流程&lt;/p>
&lt;ul>
&lt;li>开发流程&lt;/li>
&lt;li>分支管理及策略&lt;/li>
&lt;li>发布之前要做什么&lt;/li>
&lt;li>发布之后要做什么(监控)&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>第四天: 需求分析&lt;/p>
&lt;ul>
&lt;li>需求从哪里来&lt;/li>
&lt;li>需求说明书是什么&lt;/li>
&lt;li>谁来整理需求&lt;/li>
&lt;li>需求一定是合理的么&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>第五天: 测试用例&lt;/p>
&lt;ul>
&lt;li>什么是测试用例&lt;/li>
&lt;li>测试用例模版&lt;/li>
&lt;li>测试用例评审&lt;/li>
&lt;li>如何写出测不出bug的测试用例&lt;/li>
&lt;li>测试用例与测试点&lt;/li>
&lt;li>用脑图去实现测试用例&lt;/li>
&lt;li>测试用例管理平台&lt;/li>
&lt;li>测试用例的3A原则&lt;/li>
&lt;li>测试用例的编写方法(等价类啊啥的)&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>第六天: 关于缺陷的种种&lt;/p>
&lt;ul>
&lt;li>什么是缺陷&lt;/li>
&lt;li>如何提缺陷&lt;/li>
&lt;li>缺陷的生命周期&lt;/li>
&lt;li>缺陷管理工具&lt;/li>
&lt;li>缺陷与发布准出&lt;/li>
&lt;li>线上缺陷&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>第七天: 测试环境&lt;/p>
&lt;ul>
&lt;li>什么是测试环境&lt;/li>
&lt;li>什么是生产环境&lt;/li>
&lt;li>什么是类生产环境&lt;/li>
&lt;li>测试环境与分支策略&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1419064642531-e575728395f2?w=300"
 data-srcset="https://images.unsplash.com/photo-1419064642531-e575728395f2?w=300, https://images.unsplash.com/photo-1419064642531-e575728395f2?w=300 1.5x, https://images.unsplash.com/photo-1419064642531-e575728395f2?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1419064642531-e575728395f2?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>命令行里的postman? wuzz初体验</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%91%BD%E4%BB%A4%E8%A1%8C%E9%87%8C%E7%9A%84postman-wuzz%E5%88%9D%E4%BD%93%E9%AA%8C/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%91%BD%E4%BB%A4%E8%A1%8C%E9%87%8C%E7%9A%84postman-wuzz%E5%88%9D%E4%BD%93%E9%AA%8C/</guid><description>&lt;p>postman是我用的非常顺手的调试以及测试工具，界面简洁优雅，扩展性相对较强，平时使用频率还是很高的。&lt;/p>
&lt;p>不过postman有的一个比较大的问题就是没办法在服务器端使用，而使用go实现的wuzz则弥补了这一遗憾。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://github.com/asciimoo/wuzz/blob/master/docs/images/screencast.gif"
 data-srcset="https://github.com/asciimoo/wuzz/blob/master/docs/images/screencast.gif, https://github.com/asciimoo/wuzz/blob/master/docs/images/screencast.gif 1.5x, https://github.com/asciimoo/wuzz/blob/master/docs/images/screencast.gif 2x"
 data-sizes="auto"
 alt="https://github.com/asciimoo/wuzz/blob/master/docs/images/screencast.gif"
 title="https://github.com/asciimoo/wuzz/blob/master/docs/images/screencast.gif" />&lt;/p>
&lt;p>wuzz是命令行里的http请求交互工具，我们可以很清晰的看到，wuzz可以进行&lt;/p>
&lt;ul>
&lt;li>类似于postman的请求调试工作&lt;/li>
&lt;li>可以修改请求参数以及headers&lt;/li>
&lt;li>保存请求&lt;/li>
&lt;li>兼容curl&lt;/li>
&lt;li>支持搜索&lt;/li>
&lt;/ul>
&lt;p>该工具整体的操作逻辑也很简单&lt;/p>
&lt;ul>
&lt;li>使用tab键切换区域&lt;/li>
&lt;li>用上下键翻页&lt;/li>
&lt;li>类似于bash的一些操作，比如ctrl+w修改word之类的&lt;/li>
&lt;/ul>
&lt;h3 id="安装">安装&lt;/h3>
&lt;p>首先安装go，版本是1.10以上，建议直接上1.15以上。&lt;/p>
&lt;pre tabindex="0">&lt;code>$ go get github.com/asciimoo/wuzz
$ &amp;#34;$GOPATH/bin/wuzz&amp;#34; --help
&lt;/code>&lt;/pre>&lt;h3 id="使用体验">使用体验&lt;/h3>
&lt;p>稍微体验了一下，优势和不足如下&lt;/p>
&lt;p>优点&lt;/p>
&lt;ul>
&lt;li>可视化的操作&lt;/li>
&lt;li>相对清晰的操作逻辑&lt;/li>
&lt;li>确实有一些postman的意思了&lt;/li>
&lt;li>可以保存请求&lt;/li>
&lt;li>可以查看历史&lt;/li>
&lt;li>响应里的中文可以正常显示&lt;/li>
&lt;/ul>
&lt;p>不足&lt;/p>
&lt;ul>
&lt;li>在我的乞丐版云服务器上整体的操作还是有点卡的&lt;/li>
&lt;li>不支持自动补全&lt;/li>
&lt;li>安装其实有点点难度&lt;/li>
&lt;/ul>
&lt;h3 id="总结">总结&lt;/h3>
&lt;ul>
&lt;li>命令行调试操作确实是可用的&lt;/li>
&lt;li>但对于简单的请求，我可能还是会选择httpie&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1523978591478-c753949ff840?w=300"
 data-srcset="https://images.unsplash.com/photo-1523978591478-c753949ff840?w=300, https://images.unsplash.com/photo-1523978591478-c753949ff840?w=300 1.5x, https://images.unsplash.com/photo-1523978591478-c753949ff840?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1523978591478-c753949ff840?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>你好，学画流程图吗？用代码的那种</title><link>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%A0%E5%A5%BD%E5%AD%A6%E7%94%BB%E6%B5%81%E7%A8%8B%E5%9B%BE%E5%90%97%E7%94%A8%E4%BB%A3%E7%A0%81%E7%9A%84%E9%82%A3%E7%A7%8D/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%A0%E5%A5%BD%E5%AD%A6%E7%94%BB%E6%B5%81%E7%A8%8B%E5%9B%BE%E5%90%97%E7%94%A8%E4%BB%A3%E7%A0%81%E7%9A%84%E9%82%A3%E7%A7%8D/</guid><description>&lt;p>markdown现在的扩展性越来越强，也玩出了更多花样。&lt;/p>
&lt;p>我们可以使用marp来实现用markdown写ppt的功能，最近我又发现了令一款好玩的工具。&lt;/p>
&lt;p>那就是用markdown来画流程图/甘特图/类图/实体图/饼图/各种图的工具mermaid。&lt;/p>
&lt;p>该项目在github上开源，地址是https://github.com/mermaid-js/mermaid。&lt;/p>
&lt;h3 id="基本使用">基本使用&lt;/h3>
&lt;p>mermaid的使用场景有&lt;/p>
&lt;ul>
&lt;li>作为一个js库在任何网页上使用，我们可以使用mermaid API来动态把markdown文本渲染成svg图片；&lt;/li>
&lt;li>跟主流编辑器结合，在编辑器上实现一边写markdown代码一边实时预览的功能；&lt;/li>
&lt;li>在gitlab等工具上实现使用markdown画流程图的功能；&lt;/li>
&lt;li>跟主流的blog以及cms系统结合，实现用markdown画图的功能；&lt;/li>
&lt;li>在命令行实现把markdown文本转换成svg图片的功能；&lt;/li>
&lt;li>实现一个渲染server，通过请求发送markdown文本，然后server返回渲染好的图片&lt;/li>
&lt;li>&amp;hellip;&amp;hellip;还有更多场景就不列举了&lt;/li>
&lt;/ul>
&lt;p>这里我用的最多的场景是用vscode/atom来写markdown文本，然后实时预览流程图，最后把图直接截出来，保存或者到处贴，这样就能让我的大部分文档工作都使用同一个工具(vscode/atom)完成，这样就不需要安装各种工具了或者在各个工具之间反复横跳了。&lt;/p>
&lt;p>另外纯文本也非常适合直接保存在代码库里，方便多端多机器同步以及协作。&lt;/p>
&lt;h3 id="具体的例子">具体的例子&lt;/h3>
&lt;h4 id="流程图的例子">流程图的例子&lt;/h4>
&lt;pre tabindex="0">&lt;code class="language-mermaid" data-lang="mermaid">graph TD

A[双十一] --&amp;gt;|存了一年的钱| B(买点东西);
B --&amp;gt; C{买什么呢?}
C --&amp;gt; D(iphone 12)
C --&amp;gt; E(macbook 16寸)
C --&amp;gt; F(ipad 2020)
F --&amp;gt; G((买不起))
E --&amp;gt; G
D --&amp;gt; G
&lt;/code>&lt;/pre>&lt;p>上面的流程图渲染出来是这个样子的，比较简单，不过也有一定的配置能力，适用于一些相对标准的场景&lt;/p>
&lt;hr>
&lt;h4 id="甘特图的例子">甘特图的例子&lt;/h4>
&lt;p>画甘特图一般都是要装第三方工具的，mermaid可以覆盖一部分的使用场景，有一些实用性&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-mermaid" data-lang="mermaid">gantt
 title 项目计划
 dateFormat YYYY-MM-DD
 section 开发
 概要设计 :a1, 2020-11-01, 10d
 编码 :after a1 , 20d
 section 测试
 用例设计 :2020-11-01 , 30d
 功能测试 : 24d
 
&lt;/code>&lt;/pre>&lt;p>具体效果如下。&lt;/p></description></item><item><title>你可能考虑不到系统架构上的异常</title><link>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%A0%E5%8F%AF%E8%83%BD%E8%80%83%E8%99%91%E4%B8%8D%E5%88%B0%E7%B3%BB%E7%BB%9F%E6%9E%B6%E6%9E%84%E4%B8%8A%E7%9A%84%E5%BC%82%E5%B8%B8/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%A0%E5%8F%AF%E8%83%BD%E8%80%83%E8%99%91%E4%B8%8D%E5%88%B0%E7%B3%BB%E7%BB%9F%E6%9E%B6%E6%9E%84%E4%B8%8A%E7%9A%84%E5%BC%82%E5%B8%B8/</guid><description>&lt;p>对于测试同学来说，设计及执行异常场景的用例是平时工作中非常重要的一部分，因为只关注正常流程的话，那么很多情况下隐藏的缺陷并不能被完全的发现。&lt;/p>
&lt;p>很多同学经常在上线之后感到惴惴不安，心里很没底，哪怕上线之前测试的再充分，都会有这样的感觉。这是因为我们很难预见到线上系统会出现哪些我们所没有覆盖到的异常场景。&lt;/p>
&lt;p>异常场景大致可以分为下面这几类吧&lt;/p>
&lt;h3 id="业务上的异常流程">业务上的异常流程&lt;/h3>
&lt;p>比如正常的业务流程是用户先操作步骤1再操作步骤2，但是用户偏偏先做步骤2再做步骤1。因为测试同学在执行测试时，往往是对被测产品有一定的认识的。既然对被测有所了解，甚至大部分情况是非常了解，这样一来就会对被测产品的设计是有一定的认同感的，就会先入为主的认为用户一定会先做步骤1再做步骤2，这样就会忘记验证异常的场景，造成缺陷遗留到线上，产生了不太好的后果。&lt;/p>
&lt;p>所以一些有经验的测试同学会站在用户的角度上去设计测试用例。因为用户的行为永远是千奇百怪的，所以有时候我们确实要设计一些逻辑上看上去不太合理的用例，设计这些用例时往往还会伴随着 “靠，竟然有这种操作”的惊叹，这种惊叹用例往往是很有价值的，能发现程序设计或者是产品设计上的漏洞。&lt;/p>
&lt;p>永远不要相信用户的输入，永远不要认为用户的操作是感性合理有章可循的。抱着怀疑的态度去测试往往能产生意想不到的效果。&lt;/p>
&lt;h3 id="操作上的异常">操作上的异常&lt;/h3>
&lt;p>这种异常可能会比较隐蔽。比如在电商系统生成订单的时候，用户连续点击了n次提交按钮，导致产生了n个订单，这显然是我们不想看到的结果。因为用户行为的随机性，有一些操作我们真的是很难想象到，我们只能尽量借助于monkey等方式进行一些混沌测试，毕竟猴子比用户更加的不可控。&lt;/p>
&lt;h3 id="架构上异常">架构上异常&lt;/h3>
&lt;p>很多测试同学不懂架构却要为架构背锅，这大概是不合理的吧。&lt;/p>
&lt;p>在测试同学的能力模型里，业务能力的加点应该是最高的，技术能力和架构能力的技能点往往是少加甚至是不加的。如果你不需要为架构背锅，那么不了解架构应该没什么大问题，但如果线上问题的锅基本上就是你的锅，那么懂一点架构起码可以防身辟邪，多少是有用武之地的。&lt;/p>
&lt;p>架构的异常场景是我们在设计用例的时候很难想象到的。因为你没办法想象一个在你的认知里根本不存在东西究竟是什么样子，这比叶公好龙和盲人摸象更加的虚无缥缈。如果你的意识里系统架构都不存在的话，那么你怎么知道架构在什么情况下会出现异常呢？&lt;/p>
&lt;p>举个简单的缓存的例子，在我们的系统架构中，缓存是非常常见的中间件，一些需要频繁操作数据库去读写的数据我们可以放在缓存里以加速访问和存取速度。不过缓存天生有一些异常场景。&lt;/p>
&lt;p>比如我们把一些数据放到缓存里，但是用户在访问系统的时候这部分数据可能用到的很少，大部分的用户请求可能还是直接读取数据库，造成数据库压力过大，系统整体性能很差甚至崩溃。这就是缓存命中率低的场景，这种场景我们比较难设计业务用例去覆盖，只能对其进行专项测试和优化。&lt;/p>
&lt;p>另外系统在刚上线的时候缓存可能是空的，这就导致用户的请求全部击穿了缓存直接到了数据库，造成数据库崩溃，系统不可用。这就是缓存没有预热，或者是系统冷启动的问题，这种问题应该是常识，是不需要测试就能想到的，但前提是我们要对系统架构有一些了解才可以。&lt;/p>
&lt;p>还有就是如果系统频繁对某个具体key值的缓存做读写，那么该key所在的缓存实例可能就会过载，造成整个缓存集群性能下降，这就是热点key的问题，也应该是不用测试就能想到并提前防范的。&lt;/p>
&lt;p>不过缓存的过期时间和更新策略跟我们的业务相关性还是比较大的，是可以在设计的阶段就想好，然后在测试阶段去验证的。&lt;/p>
&lt;p>从上面可以看出，如果你不知道系统架构里有缓存这样一个东西，那么万一哪天缓存出了问题造成了线上问题，那这个某名奇妙的锅很可能对你产生巨大的降维打击。领导一句你为什么没有测出来，你很可能连辩解的理由都解释不清楚。&lt;/p>
&lt;p>综上，异常场景往往是我们测试的重点，业务异常和操作异常是大家可以想象到的，不过架构上的异常大家往往难以名状，出了问题却又有苦难言。所以多学一些架构知识应该是有好处的，有些问题其实可以提前防范和规避，不需要在上线之后惶惶不可终日的。不过这只是作者的一家之言了，因为水平有限，所以还请大家多多斧正。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1432958576632-8a39f6b97dc7?w=300"
 data-srcset="https://images.unsplash.com/photo-1432958576632-8a39f6b97dc7?w=300, https://images.unsplash.com/photo-1432958576632-8a39f6b97dc7?w=300 1.5x, https://images.unsplash.com/photo-1432958576632-8a39f6b97dc7?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1432958576632-8a39f6b97dc7?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>盘点2021年最值得学习的自动化测试框架</title><link>https://itest2025.pages.dev/tutorials/47-000-%E7%9B%98%E7%82%B92021%E5%B9%B4%E6%9C%80%E5%80%BC%E5%BE%97%E5%AD%A6%E4%B9%A0%E7%9A%84%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E6%A1%86%E6%9E%B6/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E7%9B%98%E7%82%B92021%E5%B9%B4%E6%9C%80%E5%80%BC%E5%BE%97%E5%AD%A6%E4%B9%A0%E7%9A%84%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E6%A1%86%E6%9E%B6/</guid><description>&lt;p>魔幻的2020年马上就要过去了，竟然有一点点猝不及防。&lt;/p>
&lt;p>我们还是要向前看，戴着口罩继续前行，这里就简单盘点一下2021年最值得学习的自动化测试框架吧。&lt;/p>
&lt;h3 id="selenium">selenium&lt;/h3>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://www.selenium.dev//images/selenium_logo_large.png"
 data-srcset="https://www.selenium.dev//images/selenium_logo_large.png, https://www.selenium.dev//images/selenium_logo_large.png 1.5x, https://www.selenium.dev//images/selenium_logo_large.png 2x"
 data-sizes="auto"
 alt="https://www.selenium.dev//images/selenium_logo_large.png"
 title="https://www.selenium.dev//images/selenium_logo_large.png" />&lt;/p>
&lt;p>毫无疑问，selenium仍然是目前市面上最值得测试同学学习的ui自动化测试框架。&lt;/p>
&lt;p>selenium拥有稳定的api，这意味着你每次的selenium版本升级都相当安全。&lt;/p>
&lt;p>selenium官方支持java/python/ruby等主流语言，另外由于webdriver协议具有很强的扩展性，因此你几乎可以找到大部分主流语言的selenium binding，比如go/javascript等，这无疑使得selenium在真实项目中的应用变得相对容易。&lt;/p>
&lt;p>selenium支持所有的主流浏览器，而且是官方支持，这使得selenium在做兼容性测试上有着天然的优势。&lt;/p>
&lt;p>selenium拥有活跃的社区，稳定的核心开发者，广泛的使用人群，这使得你可以非常容易的找到各种文档，资料，教程以及解决你实际遇到问题的各种线索。有时候我们放弃使用一个框架往往是因为我们遇到问题以后尝试各种方法都无法解决，这点在selenium上可能不会成立。&lt;/p>
&lt;p>selenium背后的webdriver协议基本上定义了各种ui自动化框架的开发规范，比如怎么开启session，如何定位元素和表示元素等等，这也孕育了一些流行的ui测试框架，比如appium等。&lt;/p>
&lt;p>想象这样一种情形：你们公司需要将web的ui自动化测试跑起来，但是测试人员对自动化测试的了解非常有限，希望尽快开始动手尝试，头绪不多，选择却很多，这时候其实就可以无脑选择python+selenium，哪怕用例最终没办法稳定跑起来，但整个学习的过程都会让团队及公司收益。这就跟我们练习跑步一样，尽管最终不是人人都可以去跑马拉松，但练习的工程却能让我们的身体受益。&lt;/p>
&lt;p>总之selenium对于测试同学来说是性价比最高的测试工具，并且除了测试，selenium在爬虫，自动化效率提升上面也有天然独特的优势。&lt;/p>
&lt;p>推荐程度：🌟🌟🌟🌟🌟，五颗星。&lt;/p>
&lt;h3 id="puppeteer">puppeteer&lt;/h3>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://user-images.githubusercontent.com/10379601/29446482-04f7036a-841f-11e7-9872-91d1fc2ea683.png"
 data-srcset="https://user-images.githubusercontent.com/10379601/29446482-04f7036a-841f-11e7-9872-91d1fc2ea683.png, https://user-images.githubusercontent.com/10379601/29446482-04f7036a-841f-11e7-9872-91d1fc2ea683.png 1.5x, https://user-images.githubusercontent.com/10379601/29446482-04f7036a-841f-11e7-9872-91d1fc2ea683.png 2x"
 data-sizes="auto"
 alt="https://user-images.githubusercontent.com/10379601/29446482-04f7036a-841f-11e7-9872-91d1fc2ea683.png"
 title="https://user-images.githubusercontent.com/10379601/29446482-04f7036a-841f-11e7-9872-91d1fc2ea683.png" />&lt;/p>
&lt;p>selenium在无界面的浏览器领域一直表现的都很挣扎，比如多年前的headless模式在面对稍微复杂的js页面时就一筹莫展，puppeterr的出现正好弥补了这一遗憾。&lt;/p>
&lt;p>关于puppteer我之前有过详细介绍，其实就是无界面的chrome浏览器，这里就不过多解释了，相对于有界面的浏览器，puppeteer有着独特的优势。&lt;/p>
&lt;ul>
&lt;li>google官方出品，chrome团队维护，稳定性相对可以得到保证&lt;/li>
&lt;li>相对简单高效的api，使用方便&lt;/li>
&lt;li>没有界面，资源占用相对可控，并且可以在浏览器端运行，天生有着云浏览器的潜力和属性&lt;/li>
&lt;li>用户众多，资料丰富，遇到一般问题都可以搜索解决；&lt;/li>
&lt;li>js语言调用，前端开发者基本没有太大的学习成本&lt;/li>
&lt;li>生态丰富&lt;/li>
&lt;/ul>
&lt;p>不过原生的pupetter在调试上相对于selenium就没有那么方便了，好在一些第三方扩展可以缓解这些问题。&lt;/p>
&lt;p>peppeteer适合这样的场景：对web页面进行持续的性能统计，一些不需要很高效但却要行为真实的爬虫，以及简单持续以及稳定的自动化验证用例。&lt;/p>
&lt;p>推荐程度：🌟🌟🌟🌟，四颗星，适合有高级需求的同学&lt;/p>
&lt;h3 id="appium">appium&lt;/h3>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://appium.io//img/appium-logo-sauce-white.png"
 data-srcset="http://appium.io//img/appium-logo-sauce-white.png, http://appium.io//img/appium-logo-sauce-white.png 1.5x, http://appium.io//img/appium-logo-sauce-white.png 2x"
 data-sizes="auto"
 alt="http://appium.io//img/appium-logo-sauce-white.png"
 title="http://appium.io//img/appium-logo-sauce-white.png" />&lt;/p>
&lt;p>appium是移动端自动化测试的领导者，是webdriver协议瓜熟蒂落的产物，它的出现看起来在意料之外，但其实也在情理之中。如果你想在andorid/ios以及移动web上都使用同一套框架的话，appium大概是目前的最佳选择。&lt;/p>
&lt;p>appium的设计思想来源于selenium，所以有着跟selenium相似的优势&lt;/p>
&lt;ul>
&lt;li>支持多种语言&lt;/li>
&lt;li>api简单而且接近selenium&lt;/li>
&lt;li>相对活跃的社区以及使用者&lt;/li>
&lt;/ul>
&lt;p>如果你对移动端自动化一无所知而且需要快速开始进行自动化测试工作的化，那么闭着眼睛用appium就可以了。 如果你对测试框架的性能以及其他方面有定制性的需求，那么你可能需要花更多的时间研究其他的框架。&lt;/p>
&lt;p>推荐程度：🌟 🌟 🌟 🌟 四颗星&lt;/p>
&lt;h3 id="cypress">cypress&lt;/h3>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://www.cypress.io//static/33498b5f95008093f5f94467c61d20ab/b65d3/cypress-logo.png"
 data-srcset="https://www.cypress.io//static/33498b5f95008093f5f94467c61d20ab/b65d3/cypress-logo.png, https://www.cypress.io//static/33498b5f95008093f5f94467c61d20ab/b65d3/cypress-logo.png 1.5x, https://www.cypress.io//static/33498b5f95008093f5f94467c61d20ab/b65d3/cypress-logo.png 2x"
 data-sizes="auto"
 alt="https://www.cypress.io//static/33498b5f95008093f5f94467c61d20ab/b65d3/cypress-logo.png"
 title="https://www.cypress.io//static/33498b5f95008093f5f94467c61d20ab/b65d3/cypress-logo.png" />&lt;/p></description></item><item><title>浅谈测试观</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%85%E8%B0%88%E6%B5%8B%E8%AF%95%E8%A7%82/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%85%E8%B0%88%E6%B5%8B%E8%AF%95%E8%A7%82/</guid><description>&lt;p>前几天看到一个关于测试的观点。&lt;/p>
&lt;blockquote>
&lt;p>We are capable of creating software systems that we are not cable of fully understanding.
Therefore we test.
We test to help us think about the design of our creations.
We test to confirm our beliefs about our creations.
We test to challenge our beliefs about our creations.&lt;/p>&lt;/blockquote>
&lt;p>大意是可以创造软件系统，但是我们可能不了解我们究竟创造了什么。&lt;/p>
&lt;p>因此我们需要进行测试。&lt;/p>
&lt;p>测试可以让思考我们的设计，让我们确定和挑战我们对系统的认知。&lt;/p>
&lt;p>第一反应是有点虚，不过仔细想想却隐含着另一层次的思考。&lt;/p>
&lt;p>那就是对于软件测试，我们的测试观是什么？&lt;/p>
&lt;p>不出意外，朴素的测试观点应该有以下几种吧。&lt;/p>
&lt;h3 id="验证">验证&lt;/h3>
&lt;p>这种观点认为：因为系统是我们设计并创造的，那么测试的目的应该就是验证设计和真实的产出是否真正的一致。&lt;/p>
&lt;p>比如我们需要系统实现3个功能，那么测试的时候我们就要验证这三个功能的实现是否符合预期。&lt;/p>
&lt;p>另外我们还需要反向的验证。我们要实现3个功能，那么正常情况下这3个功能是要没有问题的，那么除去正常情况，异常情况会更多更复杂，这些异常情况也是需要验证的。&lt;/p>
&lt;p>有经验的测试人员/开发同学往往能想到，或者是感觉到异常可能出现的地方，或者是考虑到大家都难以想象的场景。&lt;/p>
&lt;p>反向验证比正向更难，而且难很多。&lt;/p>
&lt;p>验证的测试观大致是相信正向的场景需要完全验证，异常的场景能够考虑和验证的越全面越好。&lt;/p>
&lt;p>从更大的方面去考虑，这种异常场景的验证很像是统计学上的抽样，如果需要样本越接近整体，那么采样的数量就要越多。所以没有目的的多点点有时候反而有很好的效果，chaos monkey测试就是基于这个原理， 模拟猴子乱点从而发现一些意想不到的问题。不过通过人工方式去增加异常验证的规模会比较困难，类似于fuzz testing这样的测试工程学上的探索就显得非常重要了。&lt;/p>
&lt;h3 id="怀疑">怀疑&lt;/h3>
&lt;p>怀疑的观点认为：系统肯定是有bug的，只是还没有发现而已。&lt;/p>
&lt;p>稍微扩大化一点就是开发讲的我不全信，除非你能证明你说的是对的。产品的需求也不一定合理，除非你能说服我。&lt;/p></description></item><item><title>让面试驱动成长</title><link>https://itest2025.pages.dev/tutorials/47-000-%E8%AE%A9%E9%9D%A2%E8%AF%95%E9%A9%B1%E5%8A%A8%E6%88%90%E9%95%BF/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E8%AE%A9%E9%9D%A2%E8%AF%95%E9%A9%B1%E5%8A%A8%E6%88%90%E9%95%BF/</guid><description>&lt;p>最近据说整个行业都越来越卷了，竞争日益激烈，好的机会和岗位可能会出现僧多粥少的情况，也许是时候推自己一把做一些反内卷的事情了。&lt;/p>
&lt;p>反内卷最简单的方式可能是提升自己，让自己上升一个台阶或者是给自己多一条赛道去做升维竞争或者是弯道超车的事情。&lt;/p>
&lt;p>那么如何快速的提升自己呢？&lt;/p>
&lt;p>也许可以是走出自己的舒适圈吧。不迷恋各项事务都能得心应手的沾沾自喜，走出自己熟悉的领域，探索更有挑战的事情。&lt;/p>
&lt;p>不过道理谁都懂，做起来却没那么容易。&lt;/p>
&lt;p>主动走出舒适圈最大的问题是没有动力，缺乏动力可能是因为在舒适圈不会频繁遭受社会的毒打。我记得当初我努力学习技术的契机就是开发同学说你们测试不懂技术，跟你们解释也没用，至今都清晰记得那鄙视的眼神。&lt;/p>
&lt;p>那么怎么安全的去接受社会的毒打呢？不如去面试吧，可能你不需要更换工作，但面试确实会让你短期内找到自己不足的地方以及了解现在市场的主流需求。&lt;/p>
&lt;p>下面的案例是最近发生的真实事件，据说面试官是阿里的p7，由于各种原因这是一次电话面试。&lt;/p>
&lt;p>情景：&lt;/p>
&lt;p>问：你的接口自动化和功能测试的工作日常比例是多少？
答：20%&lt;/p>
&lt;p>问：你是怎么写你的接口自动化的？
答：我说，当一个版本发布完成后，才进行补充的接口自动化；当然我也知道“Swagger”可以提前测试接口；&lt;/p>
&lt;p>问：那为什么不在开始时就直接接口呢？
答：因为项目忙，经常没有时间写（说忙，我脸都红了）；虽然也知道接口在开始的时候，其实更为快速和方便。&lt;/p>
&lt;p>问：既然更为方便，为什么不直接使用。（然后陷入死循环问我这个。。。）
答：。。。。（还是没时间的理由）
。。。&lt;/p>
&lt;p>问：好了，你的接口怎么写用例呢，（之后问了涉及到了怎么写字段检查、类型，长度，）
答：统一答（只是正常流程，并检查数据，），具体很仔细的没有涉及；
（总之问的超级细，那些点，哪些场景，当时真的打开了新世界的大门）&lt;/p>
&lt;p>最后给定义了，自动化薄弱
我感觉说的确实没错。。&lt;/p>
&lt;p>可以看到面试官的思路是：如果你要证明你做了些什么，那么就必须拿出足够多的细节，细节是魔鬼，是最难的部分。&lt;/p>
&lt;p>至于为什么会死扣细节，大致的原因可能是防止一些面霸通过死记硬背或者道听途说的方式去蒙混过关。&lt;/p>
&lt;p>因为做过必定是有思路，有细节，有过程，有结果的，所以我面试的时候喜欢就候选人简历上列出的技能项和具体项目进行较为深入的讨论，如果发现里面有细节模糊的地方，就可以作出大致的判断了。&lt;/p>
&lt;p>所以结果应该是比较明显了，没有跟上面试官的节奏，评价自然不会特别高。&lt;/p>
&lt;p>不过通过这次面试，候选人应该也会了解到一些有大厂高级别背景测试人的基本要求，也知道了人家对接口自动化的要求，总之呢，这一个电话其实不亏。后面可以在工作中根据别人给予的合理评价进行深入研究就好了。&lt;/p>
&lt;p>总之越被虐越强大，别虐的越惨，向上的动力越强。&lt;/p>
&lt;p>不过大家的时间都是有限的，所以在选择面试的时候可以注意下面一些事项&lt;/p>
&lt;ul>
&lt;li>人往高处走，大家应该去挑战那些比现在要求更高的岗位。比如现在是测试工程师，可以考虑挑战高级测试工程师，不过前提是简历别人要看得上。我的经验的简历可以多列一些关键字，一般hr都是根据关键字去匹配的，比如学校，技能，所在行业之类；&lt;/li>
&lt;li>挑战大厂。比如二线公司的同学可以去挑战一线公司的职位，只要是比自己现在的公司技术更加先进的公司就可以了；&lt;/li>
&lt;li>善于提问。一般面试结束之后，我们都会给出一些时间让候选人提问，这时候如果你能精准的问出你想要了解的问题，比如你们的接口自动化一般是怎么做的？什么时候做，遇到和善的面试官基本上会在思路上给你进行点拨，很多时候这些点拨是让人收益无穷的。比如我们当年在面试自动化测试的时候了解到某公司的qtp自动化用的是编程式的定位方式，而不是传统的纯对象库方式，当时就醍醐灌顶，从而有了新的研究方向；&lt;/li>
&lt;li>永远保持信心。有些拙劣的面试官可能会在面试过程中不自主的表现出鄙视或者其他负面信息，这时候直接忽略就好，毕竟他面试的是过去的你，以后的你很可能逆流而上让人士别三日当刮目想看；另外面试官不一定永远是对的，求同存异就好了；&lt;/li>
&lt;/ul>
&lt;p>以上希望对大家有所帮助。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1465188035480-cf3a60801ea5?w=300"
 data-srcset="https://images.unsplash.com/photo-1465188035480-cf3a60801ea5?w=300, https://images.unsplash.com/photo-1465188035480-cf3a60801ea5?w=300 1.5x, https://images.unsplash.com/photo-1465188035480-cf3a60801ea5?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1465188035480-cf3a60801ea5?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>如何设计与数据上下文无关的接口测试用例</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%A6%82%E4%BD%95%E8%AE%BE%E8%AE%A1%E4%B8%8E%E6%95%B0%E6%8D%AE%E4%B8%8A%E4%B8%8B%E6%96%87%E6%97%A0%E5%85%B3%E7%9A%84%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95%E7%94%A8%E4%BE%8B/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%A6%82%E4%BD%95%E8%AE%BE%E8%AE%A1%E4%B8%8E%E6%95%B0%E6%8D%AE%E4%B8%8A%E4%B8%8B%E6%96%87%E6%97%A0%E5%85%B3%E7%9A%84%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95%E7%94%A8%E4%BE%8B/</guid><description>&lt;p>我们在做接口测试的时候很可能设计出这样与数据关联的测试用例。比如&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">test_create_user&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">create_user&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;fred&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">age&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">29&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 调用创建用户的接口&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;name&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="s1">&amp;#39;fred&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">test_get_user&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_last_created_user&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1">#调用获取最新注册用户的接口&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;name&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="s1">&amp;#39;fred&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这样的测试用例第一眼看上去是感受不出来问题的。&lt;/p>
&lt;p>不过仔细想想，可能会存在下面的问题&lt;/p>
&lt;ul>
&lt;li>&lt;code>test_create_user&lt;/code>用例必须在&lt;code>test_get_user&lt;/code>用例执行之前执行，否则&lt;code>test_get_user(self)&lt;/code>用户是没有数据的，* &lt;code> test_get_user&lt;/code>用例没办法单独执行&lt;/li>
&lt;li>&lt;code>test_create_user&lt;/code>用例执行一次之后，&lt;code>name: fred, age: 29&lt;/code>就成了脏数据了，不删除的话之后&lt;code>test_get_user&lt;/code>用例有很大概率每次都能执行成功&lt;/li>
&lt;/ul>
&lt;p>为了解决上面的问题，我们可以这样做&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">test_create_user&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">create_user&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;fred&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">age&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">29&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 调用创建用户的接口&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">delete_user&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;id&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span> &lt;span class="c1"># 调用删除接口，将创建的用户给删除掉&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;name&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="s1">&amp;#39;fred&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">test_get_user&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">create_user&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;fred&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">age&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">29&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 调用创建用户的接口&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_last_created_user&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1">#调用获取最新注册用户的接口&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">delete_user&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;id&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span> &lt;span class="c1"># 调用删除接口，将创建的用户给删除掉&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;name&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="s1">&amp;#39;fred&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这样一来脏数据问题就解决了，不过用例里多了很多跟测试逻辑无关的代码。&lt;/p>
&lt;p>顺便留一个问题给大家思考：为什么删除数据的代码要放在断言之前执行？&lt;/p>
&lt;p>为了将数据处理代码跟测试逻辑分开来，下一步我们可以这样做，以sqlite3为例&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">sqlite3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">setUp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">conn&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sqlite3&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">connect&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;example.db&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">c&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">conn&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">cursor&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">c&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;delete * from users&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">c&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;insert into users ......&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 插入一些存量数据，这样测试翻页之类的逻辑会容易点&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">conn&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">commit&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">conn&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">close&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">test_create_user&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">create_user&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;fred&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">age&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">29&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 调用创建用户的接口&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;name&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="s1">&amp;#39;fred&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">test_get_user&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">create_user&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;fred&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">age&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">29&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 调用创建用户的接口&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_last_created_user&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1">#调用获取最新注册用户的接口&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;name&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="s1">&amp;#39;fred&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上面的例子里，&lt;code>setUp&lt;/code>方法会在每个用例执行之前执行，所以就不需要每条用例都去清理数据了。&lt;/p>
&lt;h3 id="总结">总结&lt;/h3>
&lt;ul>
&lt;li>上面的例子都是以unittest库为例，其他测试框架库原理是相同的&lt;/li>
&lt;li>上面的例子是伪代码，不能直接执行&lt;/li>
&lt;li>上面的例子里，每个用例执行之前都会插入一遍数据，如果数据量比较大，那么用例运行速度会变慢&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1501854140801-50d01698950b?w=300"
 data-srcset="https://images.unsplash.com/photo-1501854140801-50d01698950b?w=300, https://images.unsplash.com/photo-1501854140801-50d01698950b?w=300 1.5x, https://images.unsplash.com/photo-1501854140801-50d01698950b?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1501854140801-50d01698950b?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>如何做测试妹子喜欢的程序员</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%A6%82%E4%BD%95%E5%81%9A%E6%B5%8B%E8%AF%95%E5%A6%B9%E5%AD%90%E5%96%9C%E6%AC%A2%E7%9A%84%E7%A8%8B%E5%BA%8F%E5%91%98/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%A6%82%E4%BD%95%E5%81%9A%E6%B5%8B%E8%AF%95%E5%A6%B9%E5%AD%90%E5%96%9C%E6%AC%A2%E7%9A%84%E7%A8%8B%E5%BA%8F%E5%91%98/</guid><description>&lt;p>前段时间有些小伙伴反馈某些开发同学对缺陷单不太重视，比如偶现的bug老是不改，或者直接没有任何评论就修改了缺陷的状态转回到测试同学的手里，这让测试小伙伴的一些工作能难开展，当然这些开发同学自然是不受测试妹子们的欢迎的了。&lt;/p>
&lt;p>那么怎么做让测试妹子喜欢的程序员呢？&lt;/p>
&lt;h3 id="举一反三">举一反三&lt;/h3>
&lt;p>比如测试同学提了个缺陷，开发同学在修改这个缺陷的同时能够举一反三，发现这个缺陷也许可能隐藏在的其他地方，顺便一起改了，这样能节约测试同学很多的时间，自然讨人喜欢。&lt;/p>
&lt;h3 id="不改一送一">不改一送一&lt;/h3>
&lt;p>跟上面的类似，有些开发同学喜欢改一个bug送一个bug，这样测试妹子们会很不安心，惶惶不可终日。所以优秀的开发同学改bug的时候不能改一个送好几个，不过这也侧面说明改bug没那么简单，需要通盘了解上下文和影响，不然改的bug越多，送的bug越多&lt;/p>
&lt;h3 id="把问题解释清楚">把问题解释清楚&lt;/h3>
&lt;p>大部分情况下，测试妹子们都是很好学的，所以开发同学在改bug的时候最好能解释清楚这个bug是怎么产生的，如何修复的，如何验证这个问题一定是修复了的，以及修复该问题时会不会对其他的功能有所影响，相信以测试同学的理解能力这些情况他们都是可以搞清楚的，这样的开发同学自然是相当受欢迎的。&lt;/p>
&lt;p>测试妹子们最不喜欢的就是开发同学悄无声息的改了问题就提测，测完了尽管问题确实是修复了的，但是心里总是觉得不安定，因为不知道开发同学究竟改了些什么，安全感总是缺失的。&lt;/p>
&lt;h3 id="不夹带私货">不夹带私货&lt;/h3>
&lt;p>有些开发同学喜欢重构以后就马上发布，每次除了必要的需求之外还夹杂了很多的私货。大部分时候这些夹带的私货是不影响功能的，不过万一有问题了就是线上事故了。&lt;/p>
&lt;p>一个让测试妹子喜欢的程序员应该是改了什么都会告诉测试同学，一起商量回归的范围，这样男女搭配才能干活不累。&lt;/p>
&lt;h3 id="真的自测">真的自测&lt;/h3>
&lt;p>一般来说开发同学都会自测的，但有些同学自测可能只是流于形式，走走过场，测了跟没测一样。&lt;/p>
&lt;p>好的开发同学都会反复自测，保证没啥问题了再去提给qa测试，主流程一次通过，不会因为冒烟不通过而被打回，这样你好我好大家都好，提升了效率，也降低了双方的工作量&lt;/p>
&lt;h3 id="长得帅">长得帅&lt;/h3>
&lt;p>好吧，其实认真干活的开发同学都是很帅的。&lt;/p>
&lt;p>大家觉得开发同学还有哪些特质是会收到测试妹子一致好评的呢？&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=300"
 data-srcset="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=300, https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=300 1.5x, https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>如何做程序员喜欢的测试妹子</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%A6%82%E4%BD%95%E5%81%9A%E7%A8%8B%E5%BA%8F%E5%91%98%E5%96%9C%E6%AC%A2%E7%9A%84%E6%B5%8B%E8%AF%95%E5%A6%B9%E5%AD%90/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%A6%82%E4%BD%95%E5%81%9A%E7%A8%8B%E5%BA%8F%E5%91%98%E5%96%9C%E6%AC%A2%E7%9A%84%E6%B5%8B%E8%AF%95%E5%A6%B9%E5%AD%90/</guid><description>&lt;p>上一篇写了【如何做测试妹子喜欢的程序员】，这一次胡诌一个姐妹篇【如何做程序员喜欢的测试妹子】。&lt;/p>
&lt;h3 id="能描述清楚bug的重现步骤">能描述清楚bug的重现步骤&lt;/h3>
&lt;p>记得我之前写bug的时候，经常会收到一些不知道如何是好的bug。有一些我看不懂bug的标题，有一些看懂了标题又不知道怎么重现，非常苦恼。&lt;/p>
&lt;p>一般遇到看不懂的bug我都是直接打回去或者是放到最后去修复，这时候就可能出现忽略bug优先级的情况，先改能看明白的好改的bug，最后改看不懂的难以修复的bug，把一些风险高的事情最后做，实际上风险其实是更大了的。&lt;/p>
&lt;p>所以程序员喜欢的测试妹子应该是可以把问题的现象描述清楚(标题)，以及把重现步骤弄的通俗易懂。当然，这是有方法的。&lt;/p>
&lt;ul>
&lt;li>一图胜千言。好的截图加上注释可以让开发同学一目了然，立即醒悟到哪里出了问题；&lt;/li>
&lt;li>录屏胜描述。能把重现步骤录下来自然是极好的；&lt;/li>
&lt;li>描述清楚相关的上下文。比如机型呀，系统版本，程序版本之类的；&lt;/li>
&lt;li>selenium IDE。selenium ide现在尽管是不维护了，不过其当年设计的初衷就是让问题的重现变得方便。我们可以通过录制脚本的方式把bug的重现过程保存下来，然后将脚本发给开发，开发运行之后就可以实时看到重现步骤了。现在应该也有一些录制工具可以实现类似的事情吧；&lt;/li>
&lt;li>面对面操作一遍。这是大招，适用于【我的机器上是好的呀】的情况，大型打脸现场；&lt;/li>
&lt;/ul>
&lt;h3 id="尽早发现问题">尽早发现问题&lt;/h3>
&lt;p>问题发现的越早，解决成本就越低。&lt;/p>
&lt;p>如果可以在需求和开发阶段就发现需求的缺陷那将是一件功德无量的事情。&lt;/p>
&lt;p>开发同学最怕就是在上线之前忽然提一堆bug，节奏被打乱，修复的成本也高，项目的风险也是难以控制。&lt;/p>
&lt;h3 id="举一反三">举一反三&lt;/h3>
&lt;p>开发改了一个地方，如果测试同学可以指出其他相关的地方也要进行修改的话，那么大家合作起来会顺利的多。&lt;/p>
&lt;p>当然这是一件见仁见智的事情，如果开发可以自己意识到这一点，这也是没有问题的。&lt;/p>
&lt;h3 id="了解实现">了解实现&lt;/h3>
&lt;p>能了解开发每天在做什么，以及一些功能是如何实现的妹子，大概率是善解人意的妹子了吧。&lt;/p>
&lt;p>了解实现的好处就是，有些问题可以弄清楚其出现的原因到底是什么。&lt;/p>
&lt;p>因为有时候开发同学会技术性甩锅，如果测试妹子了解了实现，那么有些锅就没办法大事化小小事化了了。&lt;/p>
&lt;p>这样的测试妹子会帮助开发同学成长，长久看来是受欢迎的。&lt;/p>
&lt;h3 id="坚持底限">坚持底限&lt;/h3>
&lt;p>有问题就是有问题，不让有问题的版本/产品流出去其实对团队来说也是一种保护了。&lt;/p>
&lt;p>呃，套用之前的一个烂梗就是，有这样坚持底限的测试妹子，这是项目团队的福报。&lt;/p>
&lt;h3 id="落落大方">落落大方&lt;/h3>
&lt;p>如何做测试妹子喜欢的程序员？第一条就是有头发。好吧，这点其实挺难。&lt;/p>
&lt;p>如何做程序员喜欢的测试妹子？落落大方就好了吧？是吧？&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1444927714506-8492d94b4e3d?w=300"
 data-srcset="https://images.unsplash.com/photo-1444927714506-8492d94b4e3d?w=300, https://images.unsplash.com/photo-1444927714506-8492d94b4e3d?w=300 1.5x, https://images.unsplash.com/photo-1444927714506-8492d94b4e3d?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1444927714506-8492d94b4e3d?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>使用curl创建简单的性能监控工具</title><link>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%BF%E7%94%A8curl%E5%88%9B%E5%BB%BA%E7%AE%80%E5%8D%95%E7%9A%84%E6%80%A7%E8%83%BD%E7%9B%91%E6%8E%A7%E5%B7%A5%E5%85%B7/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%BF%E7%94%A8curl%E5%88%9B%E5%BB%BA%E7%AE%80%E5%8D%95%E7%9A%84%E6%80%A7%E8%83%BD%E7%9B%91%E6%8E%A7%E5%B7%A5%E5%85%B7/</guid><description>&lt;p>cURL，全称Command Line URL viewer，是一种命令行工具，用来发送网络请求，然后得到和提取数据，显示在标准输出（stdout）。&lt;/p>
&lt;p>我们可以使用curl来获取网页的源码，显示头信息，显示通讯过程等。&lt;/p>
&lt;p>在做基于http的接口测试的时候，curl基本上可以完成postman所具备的大部分功能，如果你习惯于使用命令行，那么curl是一个非常有用且常用的工具。&lt;/p>
&lt;h3 id="curl的基本使用">CURL的基本使用&lt;/h3>
&lt;h4 id="查看网页源码">查看网页源码&lt;/h4>
&lt;pre tabindex="0">&lt;code>curl www.itest.info
&lt;/code>&lt;/pre>&lt;h4 id="查看response的headers">查看response的headers&lt;/h4>
&lt;pre tabindex="0">&lt;code>curl -i www.itest.info
&lt;/code>&lt;/pre>&lt;h4 id="显示通讯过程">显示通讯过程&lt;/h4>
&lt;pre tabindex="0">&lt;code>curl -v www.itest.info
&lt;/code>&lt;/pre>&lt;h3 id="常用参数">常用参数&lt;/h3>
&lt;p>使用curl发送GET请求时有一些常用参数。&lt;/p>
&lt;ul>
&lt;li>-o: output，将输出的结果重定向到一个文件&lt;/li>
&lt;li>-s: slient, 不显示进度信息&lt;/li>
&lt;li>-w: 展示多维度的统计信息&lt;/li>
&lt;/ul>
&lt;h3 id="统计请求耗时">统计请求耗时&lt;/h3>
&lt;p>使用下面的这条curl命令可以统计出请求的耗时。&lt;/p>
&lt;pre tabindex="0">&lt;code>curl www.itest.info -o /dev/null -s -w &amp;#34;%{time_total}\n&amp;#34;
&lt;/code>&lt;/pre>&lt;p>其中我们把输出丢弃了(重定向到/dev/null里)，并且不显示进度信息，只展示请求的总耗时。&lt;/p>
&lt;h3 id="工具化">工具化&lt;/h3>
&lt;p>基于curl的统计请求耗时的能力，我们可以写一个简单的工具调用curl，然后打印出该请求的耗时。&lt;/p>
&lt;p>下面是我用python写的一个简单例子。&lt;/p>
&lt;pre tabindex="0">&lt;code># curl_tool.py
import subprocess
import sys

url = sys.argv[-1]

def get_cost(url):
 cmd_list = [&amp;#39;curl&amp;#39;, &amp;#39;-o&amp;#39;, &amp;#39;/dev/null&amp;#39;, &amp;#39;-s&amp;#39;, &amp;#39;-w&amp;#39;, &amp;#39;%{time_total}\n&amp;#39;]
 cmd_list.append(url)
 out = subprocess.Popen(cmd_list, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
 stdout, stderr = out.communicate()

 cost = float(stdout) * 1000
 return cost

print &amp;#34;%s %s\n&amp;#34; %(url, get_cost(url))
&lt;/code>&lt;/pre>&lt;p>使用方式: 在命令行中运行&lt;/p></description></item><item><title>挑战超低成本的NAS</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%8C%91%E6%88%98%E8%B6%85%E4%BD%8E%E6%88%90%E6%9C%AC%E7%9A%84nas/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%8C%91%E6%88%98%E8%B6%85%E4%BD%8E%E6%88%90%E6%9C%AC%E7%9A%84nas/</guid><description>&lt;p>最近发现视频和照片渐渐多了起来，我的机器储存空间有限，每次用移动硬盘去拷贝备份其实蛮麻烦的，所以想到是不是要搭建一套家用的NAS。&lt;/p>
&lt;p>那什么是NAS呢？&lt;/p>
&lt;p>我百度了一下，NAS（Network Attached Storage：网络附属存储）按字面简单说就是连接在网络上，具备资料存储功能的装置，因此也称为“网络存储器”。它是一种专用数据存储服务器。它以数据为中心，将存储设备与服务器彻底分离，集中管理数据，从而释放带宽、提高性能、降低总拥有成本、保护投资。其成本远远低于使用服务器存储，而效率却远远高于后者。目前国际著名的NAS企业有Netapp、EMC、OUO等。&lt;/p>
&lt;p>所以NAS是一个网络储存设备，在家里搭建NAS其实就是在家里搭建一个百度网盘。&lt;/p>
&lt;p>心动不如行动，先看一下这一套弄下来要多少钱吧。&lt;/p>
&lt;p>打开某东，找了一款相对便宜的nas设备，618的价格是1899，不带系统盘和存储盘。所以加上128G的系统盘和1块2T的3.5寸硬盘，大概要400多块，总的成本是2300多，这样看来还是比较贵的。&lt;/p>
&lt;p>那么有没有比较便宜的选择呢？&lt;/p>
&lt;p>我咨询了一下某资深的各种电脑设备折腾家，他告诉我他家里就有一台NAS，他的解决方案是一台台式机，装centos，接一个raid5阵列，然后各种系统(win/mac/linux/ios)都用samba去访问储存资源。这一番话让我醍醐灌顶，原来nas并不需要专用设备以及装专用系统，思路一打开，后面的解决方案就很容易确定了。&lt;/p>
&lt;p>我先整理了一下我的需求，需求决定实现，所以要先捋清楚，我大概有下面几个需求。&lt;/p>
&lt;ul>
&lt;li>存储。我有一些文件/图片/视频需要找个地方存起来，这是备份的需求，因为副本是每天都存在的，所以这是一个日常存储需求；&lt;/li>
&lt;li>从各个设备上看照片。没事我会翻一下照片，这是低频需求；&lt;/li>
&lt;li>看视频/电影。这个是低频需求，因为基本没啥时间看；&lt;/li>
&lt;li>走线/组网简单。我家里走线非常困难，所以NAS要支持无线传输;&lt;/li>
&lt;/ul>
&lt;p>所以综合看来，我的需求其实简单而且要求不高，那么我的NAS实现其实只要满足下面几个点就好了&lt;/p>
&lt;ul>
&lt;li>稳定。长期不关机，所以系统用linux最好，我有一台云服务器自从启动到现在就没有关机或者重启过，几年了，非常稳定；&lt;/li>
&lt;li>有samba就够，samba基本上支持所有主流的操作系统，而且搭建非常简单，省时省力;&lt;/li>
&lt;li>功耗低。因为要常年不关机，所以电费的支出应该越低越好；&lt;/li>
&lt;li>支持无线，不走线的方案才不是老婆见打的方案；&lt;/li>
&lt;/ul>
&lt;p>所以最后我选择的是低功耗机器+linux+samba的方案。&lt;/p>
&lt;h3 id="硬件篇">硬件篇&lt;/h3>
&lt;p>有了方案，那么就要选择合适的硬件了。&lt;/p>
&lt;p>折腾家向我推荐了一款机器，是个mini主机，用的是笔记本主板，带无线，没有风扇，全靠铝制机身散热，某宝看了报价，32G系统盘+4G内存+cpu赛扬N3150的配置大概是810块，尽管成本还是有点高，买来会给贫困的家庭雪上加霜，但想到3150的cpu功率只有4w，长期使用的话成本其实可控，而且没有风扇的噪音，咬牙买了吧。&lt;/p>
&lt;p>机器大概长这个样子的。&lt;/p>
&lt;p>正面面板4个USB3,2个USB2接口，双千兆网口，双HDMI接口，带无线网卡，小巧，跟家里的路由器差不多大，安静，毕竟没风扇，唯一的问题是机身整体散热，所以要放在通风的地方，不能藏起来让老婆不发现，但搭建低成本NAS本来就是一个挑战，挑战总是有代价的。&lt;/p>
&lt;p>再去某东买了块2.5寸的2T硬盘，500块，稳稳的塞进小主机里，这样总价1300块，硬件方面就准备完毕了。&lt;/p>
&lt;p>其实也考虑过带风扇的小机箱准系统解决方案，如果去某宝捡垃圾的话(就是买国外淘汰的洋垃圾)，联想准系统(只有机箱主板没有cpu内存硬盘)大概300多，加上cpu内存硬盘，可能总价1000之内是可以搞定的，不过捡垃圾毕竟有风险的，而且折腾起来也花时间，万一翻车点不亮就麻烦了，性价比太低，所以就没有考虑这个方案了。&lt;/p>
&lt;h3 id="软件篇">软件篇&lt;/h3>
&lt;p>下面就是装系统了，ubuntu，我所欲也，centos，亦我所欲也;二者不可得兼， 舍centos而取ubuntu掌者也。其实这两个大众化的分发版本随便装一个就好了，因为ubuntu的live ubs教程更多，所以我选择安装ubuntu的server版本，也就是没有UI界面的版本。&lt;/p>
&lt;h3 id="装机篇">装机篇&lt;/h3>
&lt;p>我从ubuntu官网下了个服务器版本的iso，然后通过教程一步一步做了个装系统的u盘，大概晚上10点半左右的时候开始安装server版本，大概11点就装完了。&lt;/p>
&lt;p>装完以后发现server版本并没有带无线网络的服务，所以需要上网去下载，然而我并不能查有线上网，所以死循环了，翻车了。&lt;/p>
&lt;p>没办法，只能下载个desktop版本，也就是有UI的版本装上，这个版本是自带无线网卡服务的，安装过程中无线网就配置好了。不过desktop版本安装非常慢，折腾好之后，安装ssh服务，然后禁用ui界面，重启进入纯server模式，搞完已经是12点半了，太累了，明天再战。&lt;/p>
&lt;p>第二天晚上花半小时装好samba，迫不及待的拷了一些文件测速，nas的写入速度大概是2m/s，比百度网盘快不了多少，分析了一下原因，可能是因为走的无线网络，丢包率高带宽有限，所以2m应该是极限速度了，完美翻车。&lt;/p>
&lt;p>### 调优篇&lt;/p>
&lt;p>2m的上传下载速度其实跟百度云是差不多了，不过按照其他人的说法，这个速度是有上升的空间的。&lt;/p>
&lt;p>首先能想到的就是组网方式的调优，要想办法把nas用有线连接到路由器上面去，这个基本很难，但可以挑战一下。&lt;/p>
&lt;p>翻出一条陈年的网线，战战兢兢的把路由器从弱电箱里搬出来放在桌子上，最后让nas跟它肩并肩，一根网线两相连，再来试试速度，果然4M/s，比之前提高了2倍。&lt;/p>
&lt;p>后面就是samba的配置调优，这个不急，有时候再搞，4m的速度已经超过了百度云，家用凑合吧，不过桌子上现在摆了2尊神器，我提醒自己一定要做好老婆的情绪管理。&lt;/p>
&lt;h3 id="外网访问篇">外网访问篇&lt;/h3>
&lt;p>出门在外如果想访问nas那怎么办呢？&lt;/p>
&lt;p>其实我的路由器是有NAT功能的，只要有公网ip就可以连接了，不过运营商基本把nat的端口给封完了，所以在路由器上配置基本就没有用了。&lt;/p>
&lt;p>同事告诉我一个神器，是某品牌的一个盒子，接上去就可以从外网打洞/vpn访问家里的网络了。&lt;/p>
&lt;p>花98买了一台，傻瓜式接入和配置，现在手机上直接vpn回家里，访问mas上的小文件基本上没啥问题了。&lt;/p>
&lt;p>不过这个盒子有自己的局限，只支持2台外网设备，外网下载速度最多才250k，每个月只有1g流量，也就是玩一下，保留了外网访问的能力而已。&lt;/p>
&lt;h3 id="总结">总结&lt;/h3>
&lt;p>这次低成本nas+外网访问的挑战算是告一段落了。&lt;/p>
&lt;p>总成本大概是1400元左右，花费了大概6个小时的时间。&lt;/p>
&lt;p>总之组网加各种配置是挺有意思的，但是装机啥的因为没有啥技术含量，就显得挺无聊了。&lt;/p>
&lt;p>简单总结一下，这套方案也就是能用够用，成本不算特别低，不过稳定性还不错，功耗也比较低，长期使用成本可控。&lt;/p>
&lt;p>下次看看再折腾点啥，来点更有意思的挑战吧。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1431887773042-803ed52bed26?w=300"
 data-srcset="https://images.unsplash.com/photo-1431887773042-803ed52bed26?w=300, https://images.unsplash.com/photo-1431887773042-803ed52bed26?w=300 1.5x, https://images.unsplash.com/photo-1431887773042-803ed52bed26?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1431887773042-803ed52bed26?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>推荐几个值得测试同学使用的免费开源软件</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%8E%A8%E8%8D%90%E5%87%A0%E4%B8%AA%E5%80%BC%E5%BE%97%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E4%BD%BF%E7%94%A8%E7%9A%84%E5%85%8D%E8%B4%B9%E5%BC%80%E6%BA%90%E8%BD%AF%E4%BB%B6/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%8E%A8%E8%8D%90%E5%87%A0%E4%B8%AA%E5%80%BC%E5%BE%97%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E4%BD%BF%E7%94%A8%E7%9A%84%E5%85%8D%E8%B4%B9%E5%BC%80%E6%BA%90%E8%BD%AF%E4%BB%B6/</guid><description>&lt;p>今天给大家推荐几个开源免费软件，这些软件可能会对大家的工作和生活带来一定的便利性。&lt;/p>
&lt;h3 id="截图软件flameshot">截图软件Flameshot&lt;/h3>
&lt;p>提bug的时候好的截图胜过千言万语。&lt;/p>
&lt;p>截图还在用qq/微信或者是系统自带的截图快捷键？没什么大问题，不过这款名为Flameshot的良心软件其实更胜一筹。&lt;/p>
&lt;p>Flameshot非常好用，看一下动图就明白了。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://github.com/flameshot-org/flameshot-org.github.io/blob/master/docs/media/animatedUsage.gif"
 data-srcset="https://github.com/flameshot-org/flameshot-org.github.io/blob/master/docs/media/animatedUsage.gif, https://github.com/flameshot-org/flameshot-org.github.io/blob/master/docs/media/animatedUsage.gif 1.5x, https://github.com/flameshot-org/flameshot-org.github.io/blob/master/docs/media/animatedUsage.gif 2x"
 data-sizes="auto"
 alt="https://github.com/flameshot-org/flameshot-org.github.io/blob/master/docs/media/animatedUsage.gif"
 title="https://github.com/flameshot-org/flameshot-org.github.io/blob/master/docs/media/animatedUsage.gif" />&lt;/p>
&lt;p>基本上qq微信自带的功能都有，关键是开源免费，除了界面有点像紫药水，基本上是没有槽点了。&lt;/p>
&lt;p>在windows上可以用flameshot来替换系统的print screen键，当然这款软件基本上是windows良心软件推荐榜的常客，大家应该不会陌生。&lt;/p>
&lt;p>然而Flameshot的0.9版本之后也加入了对mac的官方支持，这也让我的在mac上的截图体验提升了一个档次。说来也惭愧，之前mac上截图加标注我基本是用微信来完成的。&lt;/p>
&lt;p>相比于其他截图软件，flameshot的优势有&lt;/p>
&lt;ul>
&lt;li>支持windows/linux/mac&lt;/li>
&lt;li>支持丰富的快截图&lt;/li>
&lt;li>提供丰富的配置选项&lt;/li>
&lt;li>支持命令行启动及丰富的选项&lt;/li>
&lt;/ul>
&lt;p>所以对于专业截图而言，flameshot是一个很好的选择。&lt;/p>
&lt;h3 id="源码可视化软件sourcetrail">源码可视化软件Sourcetrail&lt;/h3>
&lt;p>读源码，特别是你不熟悉的源码往往是一种不太好的体验。&lt;/p>
&lt;p>Sourcetrail就是提升阅读源码体验的工具，它大概长这个样子&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://www.sourcetrail.com/assets/frontend/concept-e2621a44d7d8341761d1d8ec334b536a9d6f97ea28372c299ee38f1df81e9c1d.png"
 data-srcset="https://www.sourcetrail.com/assets/frontend/concept-e2621a44d7d8341761d1d8ec334b536a9d6f97ea28372c299ee38f1df81e9c1d.png, https://www.sourcetrail.com/assets/frontend/concept-e2621a44d7d8341761d1d8ec334b536a9d6f97ea28372c299ee38f1df81e9c1d.png 1.5x, https://www.sourcetrail.com/assets/frontend/concept-e2621a44d7d8341761d1d8ec334b536a9d6f97ea28372c299ee38f1df81e9c1d.png 2x"
 data-sizes="auto"
 alt="https://www.sourcetrail.com/assets/frontend/concept-e2621a44d7d8341761d1d8ec334b536a9d6f97ea28372c299ee38f1df81e9c1d.png"
 title="https://www.sourcetrail.com/assets/frontend/concept-e2621a44d7d8341761d1d8ec334b536a9d6f97ea28372c299ee38f1df81e9c1d.png" />&lt;/p>
&lt;p>整个界面分为&lt;/p>
&lt;ul>
&lt;li>源码区&lt;/li>
&lt;li>图形化区域&lt;/li>
&lt;li>搜索区&lt;/li>
&lt;/ul>
&lt;p>该软件可以分析源码并生成调用关系图，可以使我们在读源码的时候可以比较清晰的抓住代码的主干以及快速找到变量或者函数的定义和引用，提升源码阅读的效率。&lt;/p>
&lt;p>sourcetrail的核心特性有&lt;/p>
&lt;ul>
&lt;li>生成辅助图，可以大致看一下调用关系&lt;/li>
&lt;li>支持c/c++/java/python&lt;/li>
&lt;li>开源免费&lt;/li>
&lt;li>支持一些主流的编辑器，比如atom&lt;/li>
&lt;/ul>
&lt;p>对于一些复杂的开源项目，借助这个工具还是能有不错的阅读体验的。&lt;/p>
&lt;p>当然，读源码的核心还是在一行一行读代码，图只是辅助工具，这个工具只能让你在源码间跳来跳去的效率有提升，并不能化腐朽为神奇，让你理解你本不知道的东西。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://www.sourcetrail.com/assets/frontend/step-by-step/3-graph-dbc55d668ea753c990c5b54191143f479c8778844ef38d5628c3737217ae3764.png"
 data-srcset="https://www.sourcetrail.com/assets/frontend/step-by-step/3-graph-dbc55d668ea753c990c5b54191143f479c8778844ef38d5628c3737217ae3764.png, https://www.sourcetrail.com/assets/frontend/step-by-step/3-graph-dbc55d668ea753c990c5b54191143f479c8778844ef38d5628c3737217ae3764.png 1.5x, https://www.sourcetrail.com/assets/frontend/step-by-step/3-graph-dbc55d668ea753c990c5b54191143f479c8778844ef38d5628c3737217ae3764.png 2x"
 data-sizes="auto"
 alt="https://www.sourcetrail.com/assets/frontend/step-by-step/3-graph-dbc55d668ea753c990c5b54191143f479c8778844ef38d5628c3737217ae3764.png"
 title="https://www.sourcetrail.com/assets/frontend/step-by-step/3-graph-dbc55d668ea753c990c5b54191143f479c8778844ef38d5628c3737217ae3764.png" />&lt;/p>
&lt;h3 id="背单词工具anki">背单词工具anki&lt;/h3>
&lt;p>因为工作关系，经常需要背一些单词，之前试过很多的背单词软件总难以坚持，最终都是草草了事，从下载到放弃。&lt;/p>
&lt;p>anki是我使用比较多的背单词工具，它的设计理念其实很简单，就是flash card 单词卡，通过多轮的复习，从而让我们战胜遗忘曲线，达到记忆的目的。&lt;/p>
&lt;p>anki跟主流的背单词工具最大的不同是：anki的单词卡需要自己创建(当然你也可以导入别人整理好的卡片，不过别人的卡片不一定适合你)，这是需要投入极大的精力的。&lt;/p>
&lt;p>如果创建卡片是输入而背单词是输出的话，那么显然anki的输入门槛是很高的，这也是很多人放弃的最主要原因。&lt;/p>
&lt;p>anki基本上支持全平台，我一般使用anki的电脑端来创建单词卡片，然后在手机上通过anki客户端来进行复习。&lt;/p>
&lt;p>anki的android版本是免费的，ios版本收费。&lt;/p>
&lt;p>anki的使用教程太多了，这里就不展开了，不过就我个人的使用情况来看，如果想坚持记忆下去，那么是有一些技巧是值得了解的。&lt;/p>
&lt;ul>
&lt;li>在电脑端创建卡片以提升效率，尽量不要花费太多时间去创建精良的卡片，毕竟人们总是喜欢做容易的事情&lt;/li>
&lt;li>每个卡片的内容尽量少，不要一张卡片满满的干货，这样复习一张卡片需要很长时间，复习时很有挫败感，容易让人放弃&lt;/li>
&lt;li>卡片可以多一点，内容精简一些，一分钟刷n张卡片的快感会让你欲罢不能&lt;/li>
&lt;li>碎片时间去刷，我手机上没有今日头条之类的资讯app，所以零碎时间可以拿去刷单词，还是那句话，时间总是可以挤出来的&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p></description></item><item><title>微软内部资料告诉你:如何成为优秀的软件测试工程师(1)</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%BE%AE%E8%BD%AF%E5%86%85%E9%83%A8%E8%B5%84%E6%96%99%E5%91%8A%E8%AF%89%E4%BD%A0%E5%A6%82%E4%BD%95%E6%88%90%E4%B8%BA%E4%BC%98%E7%A7%80%E7%9A%84%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E5%B7%A5%E7%A8%8B%E5%B8%881/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%BE%AE%E8%BD%AF%E5%86%85%E9%83%A8%E8%B5%84%E6%96%99%E5%91%8A%E8%AF%89%E4%BD%A0%E5%A6%82%E4%BD%95%E6%88%90%E4%B8%BA%E4%BC%98%E7%A7%80%E7%9A%84%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E5%B7%A5%E7%A8%8B%E5%B8%881/</guid><description>&lt;p>坐我隔壁的同事之前在美国微软工作多年，这天他递给我一本打印的册子，应该是微软的内部资料，封面上写着：What makes a great software engineer? 如何成为优秀的软件工程师。想到测试工程师也是软件开发的一部分，这些经验应该是相通的，于是就翻了翻，看看有什么是值得借鉴的地方。&lt;/p>
&lt;h3 id="持续提升">持续提升&lt;/h3>
&lt;p>持续提升是增加自我竞争力的最有效的方式。随着年龄的增长，我们的知识和技能应该也是逐渐增长的。&lt;/p>
&lt;p>之前前端技术发展很快，新技术和概念层出不穷，当时就有人感叹，技术太多，学不动了。后面学不动了成了一个梗，大体是用来指代不愿意持续提升的技术人员。&lt;/p>
&lt;p>如果持续想在技术路线上精进，那么学不动了这种心态是很危险的；其实就算以后你走的管理路线，持续学习也是必要的，新的思路技术以及理念层出不穷，哪怕细节没时间了解，那么大体的概念也是需要了解的。&lt;/p>
&lt;p>自我提升应该是一种习惯，每天花一点时间，日积月累进步就会非常可观了。&lt;/p>
&lt;p>那么什么会阻碍你自我提升呢？&lt;/p>
&lt;ul>
&lt;li>心理上的拒绝。希望待在舒适区，不愿意主动改变；&lt;/li>
&lt;li>实在是太忙了。曾经看过一个纪录片，说的是香港的富豪体验3天左右的最底层清洁工的生活。富豪在开始体验之前还很乐观，觉得凭借自己的商业头脑，应该可以想出办法改变命运，但最终富豪一天就放弃了，因为清早就起床，然后不停不息的忙着生存糊口，根本没有多余的精力去考虑其他的事情了。对于很多人来说，活着就已经让大家竭尽全力了。&lt;/li>
&lt;/ul>
&lt;p>老外特别喜欢谈论工作与家庭的平衡，在中国情况可能不太一样，我们可能需要平衡：工作，学习，以及家庭。&lt;/p>
&lt;h3 id="open-minded">open-minded&lt;/h3>
&lt;p>开放的心态。&lt;/p>
&lt;p>对于新鲜的信息不排斥，不拘泥于陈见，拥抱变化。&lt;/p>
&lt;h3 id="执行力不纸上谈兵">执行力，不纸上谈兵&lt;/h3>
&lt;p>有一些同学说的多做的少，比如专门喜欢讨论技术方案，但缺不真正动手去做。&lt;/p>
&lt;p>对于测试同学来说，这种情况相对比较少，做业务测试的时候往往开发都差不多完成了，对着现有的功能去测基本不会出现纸上谈兵的情况。不过也许有些情况下在做自动化测试和性能测试的时候我们会把大部分时间花费在调研和预研阶段，从而出现执行力不足的情况，这是需要去避免的。&lt;/p>
&lt;h3 id="self-reliant">self-reliant&lt;/h3>
&lt;p>独立自主的完成任务，必要的沟通其实没有问题，但可以独立解决的问题和克服的困难还是要多靠自己。&lt;/p>
&lt;h3 id="self-reflecting">Self-reflecting&lt;/h3>
&lt;p>自省。&lt;/p>
&lt;p>多反思才会多进步。&lt;/p>
&lt;h3 id="坚持">坚持&lt;/h3>
&lt;p>我们经常会遇到难题，这些难题只有坚持不懈才能去解决，而解决这些难题的过程其实就是提升，这也是在工作中提升的关键。&lt;/p>
&lt;h3 id="好奇心">好奇心&lt;/h3>
&lt;p>好奇心会让你尽可能多的了解信息，从而为你以后的判断和工作积累足够的数据量。&lt;/p>
&lt;h3 id="匠人精神">匠人精神&lt;/h3>
&lt;p>对自己的产品感到骄傲，并且乐于磨练自己的心境和技能。&lt;/p>
&lt;h3 id="desires-to-turn-ideas-in-to-reality">Desires to turn ideas in to reality&lt;/h3>
&lt;p>渴望将想法变成现实，并在这一过程中感到享受。&lt;/p>
&lt;h3 id="willing-to-go-into-unknown">Willing to go into unknown&lt;/h3>
&lt;p>愿意步入未知，敢于冒风险去全新的领域接受挑战。&lt;/p>
&lt;h3 id="热情">热情&lt;/h3>
&lt;p>对工作有热情才会带来高效和生产力。&lt;/p>
&lt;h3 id="专注">专注&lt;/h3>
&lt;p>专注会带来意想不到的收获。&lt;/p>
&lt;p>测试同学应该不需要专注在点来点去上，我们应该专注于质量管理，盲点识别和精通业务。&lt;/p>
&lt;h3 id="高效">高效&lt;/h3>
&lt;p>效率越高，你就越有额外的时间来提升自己。&lt;/p>
&lt;h3 id="与组织目标对齐">与组织目标对齐&lt;/h3>
&lt;p>这个很好理解，比如我个人兴趣是做自动化，但是团队的目标是先把产品上线再说，那么开始还是以功能测试为主，等以后条件成熟了，团队的目标变成了维护稳定的产品时再做自动化也不迟。&lt;/p>
&lt;h3 id="数据驱动">数据驱动&lt;/h3>
&lt;p>数据驱动包含两点，首先是定指标，然后是看懂这些指标。&lt;/p>
&lt;p>对于测试同学来说一些质量数据的量化和解读都是非常有意义的，甚至可能直接影响到晋升等活动。&lt;/p>
&lt;p>如果你在工作中完全没有用到数据，那么是时候开始接触这个概念了。&lt;/p>
&lt;p>今天就暂时分享到这里，后面还有很多点，来日方长，以后娓娓道来。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=300"
 data-srcset="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=300, https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=300 1.5x, https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>我的2019</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%88%91%E7%9A%842019/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%88%91%E7%9A%842019/</guid><description>&lt;p>2019的关键字应该是忙吧。&lt;/p>
&lt;p>今年比较忙，从年初的项目从0到1上线，到年中的一些波折，以及下半年的各种大促活动，忙是主旋律。&lt;/p>
&lt;p>忙着招人，从去年年底到今年，大概应该参与了100多场面试了吧，一场面试平均1.5小时，总体看来花费的时间还是很可观的。&lt;/p>
&lt;p>忙着稳定业务，业务是要大踏步往前走的。没有业务就没有生存的空间，精力主要是投在这里了。&lt;/p>
&lt;p>忙着解决问题，问题总是突如其来又猝不及防，慢慢来，办法总会有的。&lt;/p>
&lt;p>忙着拿新的业务，业务多一点，生存的空间也许就大一点。&lt;/p>
&lt;p>忙于工作就难免疏于思考。年底了，是时候来总结一下。&lt;/p>
&lt;h3 id="well">well&lt;/h3>
&lt;p>这一年做的好的地方不多。大概有下面一些吧。&lt;/p>
&lt;ul>
&lt;li>坚持分享。基本上每周都有一篇公众号推文，水平良莠不齐，有阅读数不超过800的硬核技术文，也碰巧出过爆文，嗯，如果大家积极评论，我还是很开心的；&lt;/li>
&lt;li>持续学习。年纪大了才发现要学的地方非常多，继续查缺补漏，由于精力有限，不能再像年轻时那样面面俱到，只能抓住一个点尽可能的深入了；&lt;/li>
&lt;li>团队成长。今年的部门的服务稳定性和高性能都有不错的进步，尽力而为，希望明年做的更好；&lt;/li>
&lt;li>业务稳定。几个业务基本上都跑通顺了，而且有余力去承接更多挑战；&lt;/li>
&lt;/ul>
&lt;h3 id="less">less&lt;/h3>
&lt;p>做的不足的地方太多了。&lt;/p>
&lt;ul>
&lt;li>给测试同学的成长空间不够。今年测试团队主要聚焦在业务上了，但其他方面的成长显得不是很够，明年要给大家创造更好的环境才行；&lt;/li>
&lt;li>一些领域缺乏管理。精力有限，有些地方的管理确实没有跟上；&lt;/li>
&lt;li>技术精进不够。今年的技术成长是不明显的，需要检讨；&lt;/li>
&lt;li>质量意识没有传导下去。有时候是自己干着急，这样不行；&lt;/li>
&lt;li>待在舒适区。没有做更多有挑战的事情，在舒适区温水煮青蛙，这样不好；&lt;/li>
&lt;/ul>
&lt;h3 id="建议">建议&lt;/h3>
&lt;p>作为一个很老很老的测试人，在这里顺便给大家一些不成熟的建议吧。&lt;/p>
&lt;ul>
&lt;li>持续成长。前几天看了一篇文章，上面说到某年纪偏大的测试同学在公司倒闭之后没办法找到工作，仔细品读了一下，文章的主人公并没有持续进步，因此年纪大没有成为优势，反而成了劣势，行业竞争很激烈，继续成长是立身之本了；&lt;/li>
&lt;li>寻求挑战。多做一些有挑战的事情，这无非是另一种成长的方式了；&lt;/li>
&lt;li>不要焦虑。很多文章不经意间贩卖焦虑，看看就好，焦虑并不能解决问题，只会带来脱发的困扰。你去贩卖你的星辰大海，我自内心春暖花开；&lt;/li>
&lt;li>不要过分的忙。太忙了连焦虑的时间都没有，才是最需要焦虑的事情。对大部分测试同学来讲，过分忙碌很有可能意味着没有时间进步；&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1503122703469-3dbbe39d0d1c?w=300"
 data-srcset="https://images.unsplash.com/photo-1503122703469-3dbbe39d0d1c?w=300, https://images.unsplash.com/photo-1503122703469-3dbbe39d0d1c?w=300 1.5x, https://images.unsplash.com/photo-1503122703469-3dbbe39d0d1c?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1503122703469-3dbbe39d0d1c?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>希望这份大厂测试面试心经来的不算晚</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%B8%8C%E6%9C%9B%E8%BF%99%E4%BB%BD%E5%A4%A7%E5%8E%82%E6%B5%8B%E8%AF%95%E9%9D%A2%E8%AF%95%E5%BF%83%E7%BB%8F%E6%9D%A5%E7%9A%84%E4%B8%8D%E7%AE%97%E6%99%9A/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%B8%8C%E6%9C%9B%E8%BF%99%E4%BB%BD%E5%A4%A7%E5%8E%82%E6%B5%8B%E8%AF%95%E9%9D%A2%E8%AF%95%E5%BF%83%E7%BB%8F%E6%9D%A5%E7%9A%84%E4%B8%8D%E7%AE%97%E6%99%9A/</guid><description>&lt;p>最近一直的面试，所以感触会比较多一点。&lt;/p>
&lt;p>回想这些年，面了几个大厂，基本上顺利拿到了offer，其中有经验也有教训，在这里给大家分享一下。&lt;/p>
&lt;h3 id="鹅厂">鹅厂&lt;/h3>
&lt;p>鹅厂应该是我第一个拿到offer的大厂。&lt;/p>
&lt;p>那时候应该是2009或者是2010年左右，一晃十年了。当时我的情况是211本科相关专业毕业，三年工作经验。不过工作经验不是很亮眼，加入过一个现在很有名气但是当年却没什么认知度公司，不过基本上对后面的面试过程没有任何帮助。&lt;/p>
&lt;p>面试的岗位是测试开发工程师，不过那时候的测开基本上的工作是写自动化测试用例，跟现在做工具或平台开发的测试开发工程师还是有差距的，要求不如现在的专业测开那么严格。&lt;/p>
&lt;p>一面是技术面，问了啥不太记得了。不过两个面试官的外形却让我感到新奇，一位带着耳钉，另一位是男生长头发扎了个辫子，鹅厂开放的文化可见一斑，后来这两位成了我不错的朋友，至今还有联系。&lt;/p>
&lt;p>依稀记得当时长发哥问了我一个问题：做自动化测试时页面上的元素如何进行管理会更加高效？我的答案是使用页面对象(page object)的方式，那时候page object其实才刚兴起，用的人很少，用qtp的我其实也没用过，只不过当时在国外的qtp论坛上看到过有人对page object进行过讨论和分析，不小心记了下来，面试的时候就蒙混过关了。后来长发哥告诉我就因为这个回答他对我的评价很高，觉得技术不错，可以通过。不过我当时只是纸上谈兵而已，并没有真正落地过po，现在想来确实是很惭愧。&lt;/p>
&lt;p>二面是组长面，问了个问题，大概是问服务部署在深圳，如何确保在新疆和西藏的用户也能稳定快速的访问。说实话确实不知道，不过也稀里糊涂的过了。&lt;/p>
&lt;p>三面是跨部门面试，应该是测试通道的面试。三面里又分为两轮。第一轮问了个开放性问题，给你一个一次性杯子，你应该怎么测试？不记得是怎么回答的了，反正应该答的不好，面试官连连摇头。第二轮是通道会长面试，问了啥完全没印象了，不过应该是挂了。&lt;/p>
&lt;p>接下来是四面。后来我才知道因为是第三面测开通道挂了，所以临时将我放到测试通道去做三面。测试通道面试了一轮，是通道老大面的，问了我很多技术细节，我完全答不上来，但是我一直强调我可能现在不会，但我可以学，我觉得我肯定能学会的。当时面试官的眼神是悲天悯人的，反正自我感觉不好，但是一不小心又过了。&lt;/p>
&lt;p>五面是部门经理面，完全不记得问了啥，只记得问的问题角度刁钻，但又十分合理，让人难以招架。&lt;/p>
&lt;p>所以，鹅厂一共面了5轮，见到了7名面试官，面的问题难度比较大，特别是在技术通道那边问的非常详细，没有做过的建议直接承认，没必要强行回答。多年以后看来，我当年可以面试通过完全是运气好，硬实力还是差了一些。&lt;/p>
&lt;p>不过现在据说鹅厂的面试已经没有跨部门通道面试了，要求可能会稍微低一点点。&lt;/p>
&lt;p>最终拿到offer，定级T2.3。&lt;/p>
&lt;p>经验&lt;/p>
&lt;ul>
&lt;li>平时的技术积累可能在面试时发挥非常关键的作用&lt;/li>
&lt;li>拥有不错教育的背景在面试大厂时可能会带来不错的运气&lt;/li>
&lt;li>对测试来说，初级到中级这个阶段技术的广度其实很重要&lt;/li>
&lt;li>表现出良好的潜力或者勤奋好学的精神可能会打动面试官&lt;/li>
&lt;/ul>
&lt;p>教训&lt;/p>
&lt;ul>
&lt;li>技术要扎实，有实力才能随机应变&lt;/li>
&lt;li>测试开发要以开发的标准来要求自己&lt;/li>
&lt;/ul>
&lt;h3 id="动物园厂">动物园厂&lt;/h3>
&lt;p>动物园厂的面试基本上都是电话沟通的。具体发生时期可能在2016-2017年左右，岗位应该是测试开发专家。&lt;/p>
&lt;p>第一面是电话面，聊了一下之前做过的东西，比如测试平台的开发，效率提升工具的开发，基本上是问之前的经验，因为这块我做的比较多，里面的细节基本都清楚，所以答的比较自如。期间还探讨了关于测试覆盖率的问题，比如增量覆盖率，代码覆盖率，行覆盖率和分支覆盖率之类，最后讨论了一下圈复杂度对单元测试复杂度的影响，整体的过程不像是面试，像是在交流。&lt;/p>
&lt;p>二面是半夜，大概十点半以后，也是电话面试，对方可能是团队的负责人，基本上聊了一下对于效率提升的看法，然后了解了一下后面要负责的具体工作，持续了半个小时，基本上是交流的状态。&lt;/p>
&lt;p>因为记忆已经模糊了，所以细节没有记起来太多。&lt;/p>
&lt;p>总结：&lt;/p>
&lt;ul>
&lt;li>动物园的电话面试一面聊了很多细节，比如之前做过什么，怎么做的之类，面试官有相同的经验，所以基本上靠忽悠是行不通的；&lt;/li>
&lt;li>动物园的电话二面基本上属于在一面基础上进一步确定候选人的工作经历，与团队的匹配程度，不会再去讨论具体的细节问题；&lt;/li>
&lt;/ul>
&lt;p>最终拿到offer，定级p7+。&lt;/p>
&lt;p>经验&lt;/p>
&lt;ul>
&lt;li>大厂有时候的需求特别明确，如果能力与岗位要求匹配的话，整个面试流程会很轻松&lt;/li>
&lt;/ul>
&lt;p>教训&lt;/p>
&lt;ul>
&lt;li>保持谦逊&lt;/li>
&lt;li>自己的需求最好跟用人单位直接沟通，不要通过猎头，猎头的信息总是脱敏过的，毕竟利益不同&lt;/li>
&lt;/ul>
&lt;h3 id="绿厂">绿厂&lt;/h3>
&lt;p>绿厂的面试是现场面，应该是下午的时候去的，进去之前要做安全检查，当时很惊讶，毕竟除了菊花厂基本上没听说过会做安全检查的。&lt;/p>
&lt;p>一面开始聊了一会之前的工作经验，面试官似乎对我无所适从，后来又拉了应该是他领导过来一起聊了一下，基本上技术层面的东西涉及的比较少，或者是因为他们涉及到的基于安卓的底层测试我没做过，所以就没有仔细问了。&lt;/p>
&lt;p>二面应该是部门的测试负责人。主要是跟我介绍了一下绿厂的情况和遇到的问题，然后带我去食堂吃了个晚饭，晚饭挺便宜的，味道也在线。&lt;/p>
&lt;p>三面是hr。hr问了很多问题，细节不记得了，主要是考察稳定性，比如有没有小孩，是不是在本地定居之类的。然后就是非常严肃的告诉我，绿厂的工作强度非常大，比如需要加班，周末有时候也很忙之类的，问我能不能接受。抱着收集offer的态度，我很肯定的回答了接受，hr面就顺利通过了。&lt;/p>
&lt;p>四面是部门长面试，有2个人，一个可能是部门的技术专家，另一个是部门长。其中技术专家问我能不能尽可能详细的列出linux的性能参数，我应该是白板上密密麻麻的写满了从cpu到内存到磁盘io以及网络的性能指标，并描述了指标的含义和具体的异常场景，当时就感到两位的眼神中充满了惊奇和肯定，这一面顺利通过。&lt;/p>
&lt;p>不出意外拿到了offer，定级不记得了，应该比较高。&lt;/p>
&lt;p>经验&lt;/p>
&lt;ul>
&lt;li>如果面试的时候遇到了自己拿手的领域，可以尽情的开始你的表演&lt;/li>
&lt;li>如果面试时间持续的比较长，也许有机会蹭一顿饭&lt;/li>
&lt;li>绿厂的工作强度比较大，我面试从下午一直到晚上10点，走的时候办公室里还高朋满座&lt;/li>
&lt;/ul>
&lt;h3 id="菊花厂">菊花厂&lt;/h3>
&lt;p>大概是在2008年我就参加过菊花厂的面试，当时的岗位是测试工程师。&lt;/p>
&lt;p>当时是在某个园区举行的专场。&lt;/p>
&lt;p>一面在食堂做题，做完题以后现场等结果。&lt;/p>
&lt;p>通过一面以后在食堂二面，不记得问了啥，大概意思是我们这里很忙，你确定可以接受吗？自然回答说接受。&lt;/p>
&lt;p>然后就是叫号，叫到号的从食堂带走，分批进行群面。群面在工作区的会议室进行，进去前所有东西都要清空，手机也被严肃认真的保安暂时保管。&lt;/p>
&lt;p>群面应该有3个面试官，可能是西装革履又可能是穿着比较复古，总之对他们的衣着印象深刻。&lt;/p>
&lt;p>群面是各种岗位一起面试，在一起面的有市场销售有开发和测试，但是开发和测试的人很少很少，可能就1个测试和1个开发。可以明显感到销售的同学轻松自在谈笑风生，开发的小哥一脸嫌弃，而我应该是比较紧张，正襟危坐，战战兢兢。&lt;/p>
&lt;p>群面的过程大概是先介绍自己，然后说自己的优点和不足的地方，等大家都介绍完以后面试官就开始带节奏，随便指定一人做靶子，再明示其他人群启而攻之。最后每个人都被轮一遍，群面胜利结束。也许当场就选出了群面的胜利者继续后面的流程，淘汰者黯然离开，细节记不太清楚了，流程大致如此。&lt;/p>
&lt;p>这次面试耗时一整天，从早到晚，没有通过，不知道是为什么，反正也只是去见识见识，所以也不放在心上，只是群面的感受让人觉得奇怪，为什么一群人周末的大好时光不做点有意义的事情，反而聚在一起相濡以翔呢？&lt;/p>
&lt;p>果然几年以后当我第二次面菊花厂时，群面的环节消失了。&lt;/p>
&lt;p>一面的面试官是测试专家，问了一些测试思路和测试工具的问题，似乎没有细节，但是很广很杂，不是特别好回答。&lt;/p>
&lt;p>二面是部门老大，不记得聊了什么了。&lt;/p>
&lt;p>总之大概2个多小时就搞定了，变化的部分是没有了群面，不变的部分是依然在食堂。&lt;/p>
&lt;p>顺利拿到offer，应该是专家级。&lt;/p>
&lt;p>写到这里忽然想起在这之前也拿到过一个菊花厂的offer，不过定级就没这么高，所以印象就模糊了。&lt;/p>
&lt;p>因此菊花厂的总战绩是3战2胜1负，面试不难，但整体的流程很长。&lt;/p>
&lt;p>经验&lt;/p>
&lt;ul>
&lt;li>菊花厂的面试相对灵活，但整体流程很长&lt;/li>
&lt;li>菊花厂对身体要求很高，如果有半年的空档期，简历很可能是无法通过的，因为用人方可能会认为你休假半年去治病或者休养&lt;/li>
&lt;/ul>
&lt;h3 id="bd厂">BD厂&lt;/h3>
&lt;p>BD厂面了2次，第一次挂了，第2次通过。&lt;/p></description></item><item><title>想换工作简历怎么写面试要注意什么</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%83%B3%E6%8D%A2%E5%B7%A5%E4%BD%9C%E7%AE%80%E5%8E%86%E6%80%8E%E4%B9%88%E5%86%99%E9%9D%A2%E8%AF%95%E8%A6%81%E6%B3%A8%E6%84%8F%E4%BB%80%E4%B9%88/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%83%B3%E6%8D%A2%E5%B7%A5%E4%BD%9C%E7%AE%80%E5%8E%86%E6%80%8E%E4%B9%88%E5%86%99%E9%9D%A2%E8%AF%95%E8%A6%81%E6%B3%A8%E6%84%8F%E4%BB%80%E4%B9%88/</guid><description>&lt;p>这两天在学院群里，有同学问了一个非常有代表性的问题。&lt;/p>
&lt;p>&lt;strong>当前做的是功能，想跳槽做性能、自动化。简历，面试，都需要注意什么？？？&lt;/strong>&lt;/p>
&lt;p>首先需要说明的是性能和自动化目前在一些公司是测试人员的标配技能了，去找这类的专项测试工作可能放出来的职位不会很多，可选择性没有那么强。所以我们可以这样来看这个问题，就是当前做的是纯功能(手工)测试，想跳槽做一些挑战(xin shui)高的工作，可能涉及到性能和自动化之类的，面试和简历需要注意些什么？&lt;/p>
&lt;h3 id="简历篇">简历篇&lt;/h3>
&lt;p>除非你是刚毕业不久，或者工作经验少于一年，那么如果你面试的岗位是有自动化和性能的要求的话，最好写上相应的内容。&lt;/p>
&lt;p>为什么呢？&lt;/p>
&lt;p>因为第一个看你简历的人是hr，大部分的hr筛选简历的标准都是有章可循的，比如&lt;/p>
&lt;ul>
&lt;li>
&lt;p>教育背景。教育背景好的话，那么经验欠缺一些也是没问题的，毕竟好的教育背景在hr看来是值得去培养的，好的教育背景等于较好的潜力&lt;/p>
&lt;/li>
&lt;li>
&lt;p>技能关键字。比如jd里面要求了python/性能/自动化之类的，那么hr会优先去匹配这些关键字&lt;/p>
&lt;/li>
&lt;li>
&lt;p>名企背景。这个大家都懂，名企背景是个很好的背书。因为名企招聘的要求本身就不低，有名企背景的人就证明他的起点可靠度会更好&lt;/p>
&lt;/li>
&lt;li>
&lt;p>项目经验。比如招大数据的测试，hr会看你是不是做过大数据相关的项目。我就内推过一个同学然后被hr拒掉的，因为有技能关键字，但是项目里体现不出来技能关键字，这样就被判断为不合适了&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>所以，总结一下，简历可以这样写了。&lt;/p>
&lt;ul>
&lt;li>教育背景好可以强调一下，比如学校名称后面加个211，985之类的，前提是，实事求是，不要弄虚作假&lt;/li>
&lt;li>技能关键字跟着jd走&lt;/li>
&lt;li>项目经验跟技能关键字最好能对应上&lt;/li>
&lt;/ul>
&lt;p>当然了，这个是个人观点，仅供参考。&lt;/p>
&lt;h3 id="面试篇">面试篇&lt;/h3>
&lt;p>面经到处都是，我这里专注一种情况，也就是&lt;strong>没有在项目里做过自动化和性能的情况下，如何在面试时候让人觉得你可以胜任此类的工作?&lt;/strong>&lt;/p>
&lt;p>首先我不是教你弄虚作假，面试官都是很有经验的，弄虚作假没有意义。我这里只是抛出一些问题让大家提前思考，这样面试时候也可以坦诚的聊一下，把自己提前思考的答案跟面试官交流一下，说不定能有共鸣。&lt;/p>
&lt;p>首先考虑细节，比如&lt;/p>
&lt;ul>
&lt;li>你们的接口测试里面有没有做鉴权？鉴权的细节能不能说明一下呢？&lt;/li>
&lt;li>你们的接口是说明协议的呀？能说明一个这个协议么？&lt;/li>
&lt;/ul>
&lt;p>很多情况下不知道细节等于没有做过。比如如果你回答，我们有鉴权呀，鉴权就是调用开发的接口呀，细节我也不清楚，那么面试官可能认为你技术深度不够或者是没有做过。&lt;/p>
&lt;p>细节是最难的，因为你的任何技能关键字都有被问到细节的可能。而且可能你的弱项是面试官的强项，然后被强行拖入面试官熟悉的领域，按在地上摩擦。&lt;/p>
&lt;p>然后就是场景了。比如&lt;/p>
&lt;ul>
&lt;li>你们在什么样的场景下做自动化测试呀？&lt;/li>
&lt;li>你们的接口测试是怎么样的执行策略呀？&lt;/li>
&lt;li>你们性能测试的场景是什么样的呀？&lt;/li>
&lt;/ul>
&lt;p>自动化测试的场景其实很多，比如定期的回归，线上用户侧监控之类的，都是自动化的场景。而有一些场景是不合适的，比如快速迭代的新业务就不是非常适合，你的答案最好逻辑上能自洽，不然很容易被面试官挑战。&lt;/p>
&lt;p>接口测试执行策略可以看出你的测试工程化的思维。比如接口测试的执行频率，执行环境，测试环境的规划，测试数据的规划，这些我在之前的文章也多多少少涉及到一些，大家可以参考一下。&lt;/p>
&lt;p>总之，你的性能/自动化/接口等测试一定是有场景的，可以落地的，否则很容易被一直挑战。&lt;/p>
&lt;p>流程也需要考虑。&lt;/p>
&lt;ul>
&lt;li>你们自动化测试的流程是？&lt;/li>
&lt;li>你们接口测试的流程是？&lt;/li>
&lt;li>你们性能测试的流程是？&lt;/li>
&lt;/ul>
&lt;p>这里的流程又关系到用例的编写思路，回归策略等。需要注意的是，性能测试一般是功能测试结束之后，这点不要弄错了。&lt;/p>
&lt;p>所以，总结一下，如果你没做过性能/自动化/接口等专项测试，你又想跟面试官来电，那么你需要考虑&lt;/p>
&lt;ul>
&lt;li>
&lt;p>将场景代入现在的项目。哪怕你没有真的做的，你也可以想象一下如果是自己来做，你该怎么做。自己的项目里哪些地方可以用到专项，用的时候会遇到什么困难等等，注意逻辑自洽&lt;/p>
&lt;/li>
&lt;li>
&lt;p>脑补流程。你的专项测试流程是怎么样的，什么时候介入，什么时候结束，结束的时候有什么产出等等&lt;/p>
&lt;/li>
&lt;li>
&lt;p>技术扎实。尽量在有广度的前提下，深入一些细节，最好是你技术关键字的一些细节。比如selenium的原理，appium原理，webdriver协议之类的&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>上面就是我的一些不成熟的建议，还请各位不吝斧正。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1536649986370-e623f6c7c1e1?w=300"
 data-srcset="https://images.unsplash.com/photo-1536649986370-e623f6c7c1e1?w=300, https://images.unsplash.com/photo-1536649986370-e623f6c7c1e1?w=300 1.5x, https://images.unsplash.com/photo-1536649986370-e623f6c7c1e1?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1536649986370-e623f6c7c1e1?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>一起读测试论文(1)--web自动化测试工具</title><link>https://itest2025.pages.dev/tutorials/47-000-%E4%B8%80%E8%B5%B7%E8%AF%BB%E6%B5%8B%E8%AF%95%E8%AE%BA%E6%96%871--web%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E4%B8%80%E8%B5%B7%E8%AF%BB%E6%B5%8B%E8%AF%95%E8%AE%BA%E6%96%871--web%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7/</guid><description>&lt;p>最近看到了一篇2014年的论文，在google scholar上面排名比较靠前，随便浏览了一下，内容非常的平易近人，可以给大家分享一下。&lt;/p>
&lt;p>在介绍部分，文章说道，软件测试是软件研发流程中的重要一环，占到整体时间周期的40%-70%，软件测试的目的是&lt;/p>
&lt;ul>
&lt;li>确定软件符合需求&lt;/li>
&lt;li>准确实现了特性&lt;/li>
&lt;li>满足金主的预期和需求&lt;/li>
&lt;/ul>
&lt;p>总之一句话，软件测试很重要。&lt;/p>
&lt;p>下面文章又介绍了测试的类型&lt;/p>
&lt;ul>
&lt;li>静态测试和动态测试&lt;/li>
&lt;li>box approach方法，应该是灰盒测试&lt;/li>
&lt;li>手工和自动化测试&lt;/li>
&lt;/ul>
&lt;p>下面是手工和自动化测试的比较&lt;/p>
&lt;ul>
&lt;li>执行速度上：手工慢，自动化快&lt;/li>
&lt;li>人力资源投入上：手工要投人测，自动化不需要&lt;/li>
&lt;li>隐藏信息上：自动化可以拿到隐藏信息，手工不行，这条我也不是很理解&lt;/li>
&lt;li>可靠性上：自动化测试每次执行的结果都很精确，手工测试同样用例每次执行结果可能不一样&lt;/li>
&lt;/ul>
&lt;h3 id="测试工具的进化史">测试工具的进化史&lt;/h3>
&lt;p>这是比较有意思的部分了。 下面的文字属于机翻，可能语义上没那么准确。&lt;/p>
&lt;p>软件测试其实并不是什么新鲜事，在40年代用于测试软件的程序员中，他们不仅是测试人员，也是开发调试人员 在整个六十年代，有关测试，例如IFIPS会议的议事录，几乎假设程序员已经测试了他们所使用的软件。 随着更大，更复杂的系统的出现，专门的软件测试人员开始流行。 第一次测试软件会议于1972年在教堂山组织 会议记录表明 测试的学科不同于编程。 技术的自动化使我们可以共享信息，几位研究人员使用了Web自动化 研究工作中的测试工具。研究人员还增强了一些工具，以获得更好的性能和结果。这些工具可以独立应用，也可以组合使用，来解决软件测试中的挑战。 在这里，我们讨论 使用以下工具完成网络自动化测试的工作。&lt;/p>
&lt;p>Leott等提出了关于测试的工业案例研究学习环境中的自动化和测试套件维护的内容管理系统。 在此作者提出调整工作，得出基于ID的方法 定位比Xpath更好的网页元素方法。 作者工作的目的是了解哪个Selenium WebDriver方法适合于定位Web页面元素，减少了所需的维护工作 将测试用例重新调整为新版本。 Leott等还提出了另一项关于工业的报告 进行案例研究以调查潜在利益页面对象模式的改进，提高selenium webDriver测试用例的可维护性。 论文比较了两个等效的测试套件。其中一个是使用页面对象模式，另一个并则没有。结果表明使用PO对象的对照组可维护性胜出。&lt;/p>
&lt;p>Cheluvaraju等提出了一种新颖的方法，调查文件之间的关系 通过应用高级SNA共同致力于社交网络分析。 在本文中，他们对修订版本的历史进行了实证分析。 众所周知的开源Web应用程序测试系统， selenium和结果参数，例如提取交叉语言更改依赖性，更改传播，影响 分析报告。这段原文我也看不懂，机翻的也是一头雾水。&lt;/p>
&lt;p>Wong等提出了一种采矿的方法，给定的Selenium IDE测试套件中的可执行规范。 那里的方法通过测试套件的数量进行评估现实世界。 那里的工作还展示了 模型挖掘和模型的两个相反过程,基于一个框架的测试生成。 Nagowah等通过分析现有的工具，提出了一种自动化的设计的测试工具Kishanium， Kishanium工具是一种创新工具，改进了记录和回放方法。 工具管理套装 测试数据，并且即使存在 是用户界面中的更改数量。 工具提供其他功能，例如数据生成器，spylink, 快照。&lt;/p>
&lt;p>Wang等引入了新的自动化框架 由selenium和Jmeter集成。 该框架大量复用了测试步骤和测试数据，因而很容易跨应用迁移，支持多浏览器和操作系统，大大提升了自动用例的扩展性和重用性。&lt;/p>
&lt;p>这部分其实给我们介绍了一些研究人员在自动化框架上的探索实践，可以补充一下我们的技术视野。&lt;/p>
&lt;p>最后一部分就是各种自动化测试工具的对比了，很多工具因为年份久远，现在市面上基本上都见不到了，只剩下selenium QTP等老牌工具依然不忘初心，持久坚守。&lt;/p>
&lt;p>所以大家可以看出来，对于自动化框架的探索，这些年其实并没有特别突破性的技术诞生，很多6年前论文中提到的东西，我们还在孜孜不倦的反复实现。&lt;/p>
&lt;p>不过技术的洪流总是滚滚向前的，在AI时代即将到来的今天，自动化工具和框架也许会迎来井喷也说不定，我们继续努力，持续学习。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1504217051514-96afa06398be?w=300"
 data-srcset="https://images.unsplash.com/photo-1504217051514-96afa06398be?w=300, https://images.unsplash.com/photo-1504217051514-96afa06398be?w=300 1.5x, https://images.unsplash.com/photo-1504217051514-96afa06398be?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1504217051514-96afa06398be?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>一起读测试论文(2)--基于selenium+testNG的测试框架</title><link>https://itest2025.pages.dev/tutorials/47-000-%E4%B8%80%E8%B5%B7%E8%AF%BB%E6%B5%8B%E8%AF%95%E8%AE%BA%E6%96%872--%E5%9F%BA%E4%BA%8Eseleniumtestng%E7%9A%84%E6%B5%8B%E8%AF%95%E6%A1%86%E6%9E%B6/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E4%B8%80%E8%B5%B7%E8%AF%BB%E6%B5%8B%E8%AF%95%E8%AE%BA%E6%96%872--%E5%9F%BA%E4%BA%8Eseleniumtestng%E7%9A%84%E6%B5%8B%E8%AF%95%E6%A1%86%E6%9E%B6/</guid><description>&lt;p>今天给大家带来的论文发表于2015年，全文的主旨是在描述如何使用selenium + testNG来实现一个稳定高效的web自动化测试框架。&lt;/p>
&lt;p>文章开篇还是祖传的测试论文三件套&lt;/p>
&lt;ul>
&lt;li>为什么要做测试&lt;/li>
&lt;li>什么是web自动化测试&lt;/li>
&lt;li>用什么工具做web自动化测试&lt;/li>
&lt;/ul>
&lt;p>这里就不展开了。&lt;/p>
&lt;p>后面直接上了一张模块图，并对每个模块进行了详细的说明。&lt;/p>
&lt;h3 id="object-repository">Object Repository&lt;/h3>
&lt;p>对象库。好吧，你说你没有对象&amp;hellip;&lt;/p>
&lt;p>selenium支持多种定位业务元素的方式，不过如果页面频繁变化的话，用selenium原生的地方方式就会带来一个维护成本偏高的问题。&lt;/p>
&lt;p>于是有人就提出了对象库的概念，把所有的元素定位都集中在一个地方管理，我最早是在08年左右在一个叫做QPT的自动化测试工具中了解到这个概念的，如今12年过去了，这种方式依然行之有效。&lt;/p>
&lt;h3 id="input-file">Input file&lt;/h3>
&lt;p>在web系统中，用户经常需要输入一些信息，比如登录时候的用户名和密码。这些输入就可以放在input file里维护，这样每次输入相同内容的时候就可以直接从文件里读取了。不过要注意的是，这里仅维护一些必填项，一些可选项我们可以用随机值的方式去代替。&lt;/p>
&lt;h3 id="utility-section">Utility Section&lt;/h3>
&lt;p>工具库，可以分成下面几种。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>User Actions File：selenium提供了一些基本的元素操作方式，比如点击，但是另外一些操作，比如选择select box等的复杂操作其实并没有提供(原文大概是这个意思，不过selenium后面的版本确实提供了多种多样的操作行为工具，比如action chains以及select的操作等，可能当年文章写作时selenium是缺乏该能力的)，可以将这些操作封装起来，后面调用的时候就可以多次复用了。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Utility file： 这个文件封装了一些常用功能，比如登录登出。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Screenshot Generation：实现了用例错误时自动截图的功能。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>具体截图过程如下&lt;/p>
&lt;ul>
&lt;li>创建文件夹&lt;/li>
&lt;li>从testNG拿执行结果&lt;/li>
&lt;li>判断执行结果&lt;/li>
&lt;li>如果执行失败则自动截图&lt;/li>
&lt;li>截图用执行时间来命名&lt;/li>
&lt;li>保存截图&lt;/li>
&lt;/ul>
&lt;h3 id="test-suite">Test suite&lt;/h3>
&lt;p>testNG提供。&lt;/p>
&lt;h3 id="customization-of-test-report">Customization of test report&lt;/h3>
&lt;p>自定义测试报告。基本上就是用的testNG提供的html report。&lt;/p>
&lt;h3 id="email-customized-report-to-respective-person">Email customized report to respective person&lt;/h3>
&lt;p>发邮件通知相关人员。使用 Mail.jar来实现。&lt;/p>
&lt;h3 id="结果对比">结果对比&lt;/h3>
&lt;p>文中最后给出了该框架prowork Framework对比传统方式的优势，基本上是全面碾压。&lt;/p>
&lt;h3 id="总结">总结&lt;/h3>
&lt;p>可以看出框架整体的结构是非常简单的，核心思想就是尽量复用TestNG的功能，然后封装一些工具函数，增加框架的可维护性。&lt;/p>
&lt;p>如果大家遇到一些技术瓶颈或是想了解最新的一些测试思潮，偶然读一些论文还是很有帮助的。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1445768593937-05a3f7832b68?w=300"
 data-srcset="https://images.unsplash.com/photo-1445768593937-05a3f7832b68?w=300, https://images.unsplash.com/photo-1445768593937-05a3f7832b68?w=300 1.5x, https://images.unsplash.com/photo-1445768593937-05a3f7832b68?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1445768593937-05a3f7832b68?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>一站式接口管理及测试工具yapi介绍</title><link>https://itest2025.pages.dev/tutorials/47-000-%E4%B8%80%E7%AB%99%E5%BC%8F%E6%8E%A5%E5%8F%A3%E7%AE%A1%E7%90%86%E5%8F%8A%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7yapi%E4%BB%8B%E7%BB%8D/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E4%B8%80%E7%AB%99%E5%BC%8F%E6%8E%A5%E5%8F%A3%E7%AE%A1%E7%90%86%E5%8F%8A%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7yapi%E4%BB%8B%E7%BB%8D/</guid><description>&lt;p>我们部门正在使用yapi做接口文档的管理，较之之前纯手工写接口注释的方式确实方便了不少。&lt;/p>
&lt;h3 id="功能介绍">功能介绍&lt;/h3>
&lt;p>稍微看了一下，发现yapi除了做接口文档的可视化管理之外，还有不少的功能。&lt;/p>
&lt;p>按照官方说法，YApi 是一个可本地部署的、打通前后端及QA的、可视化的接口管理平台。&lt;/p>
&lt;p>YApi 是高效、易用、功能强大的 api 管理平台，旨在为开发、产品、测试人员提供更优雅的接口管理服务。可以帮助开发者轻松创建、发布、维护 API，YApi 还为用户提供了优秀的交互体验，开发人员只需利用平台提供的接口数据写入工具以及简单的点击操作就可以实现接口的管理。&lt;/p>
&lt;ul>
&lt;li>基于 Json5 和 Mockjs 定义接口返回数据的结构和文档，效率提升多倍&lt;/li>
&lt;li>扁平化权限设计，即保证了大型企业级项目的管理，又保证了易用性&lt;/li>
&lt;li>类似 postman 的接口调试&lt;/li>
&lt;li>自动化测试, 支持对 Response 断言&lt;/li>
&lt;li>MockServer 除支持普通的随机 mock 外，还增加了 Mock 期望功能，根据设置的请求过滤规则，返回期望数据&lt;/li>
&lt;li>支持 postman, har, swagger 数据导入&lt;/li>
&lt;li>免费开源，内网部署，信息再也不怕泄露了&lt;/li>
&lt;/ul>
&lt;p>亮点是支持类似于postman的接口调试方式，这对测试同学会比较友好；另外还支持自动化测试，支持response的断言。&lt;/p>
&lt;h3 id="自动化测试">自动化测试&lt;/h3>
&lt;p>那么yapi如何做自动化测试的呢？&lt;/p>
&lt;p>yapi定义了包含测试集、Pre-Script 、Test-Script 三方面。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>测试集: 在平时的开发过程中，经常遇到的一个问题是每次调试接口都需要重新填写参数，YApi测试集能够保存之前填写的参数，方便下次的调试。每个的请求参数还可以通过前面已请求的接口数据读取，或填写mock随机字符串，通过设置断言脚本验证返回数据的正确性。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Pre-Script:Pre-Script 包括请求参数处理脚本和响应数据处理脚本两部分。通过自定义 js 脚本方式改变请求的参数和返回的 response 数据。他的使用场景如下： (1)接口请求参数需要加密及返回 response 解密;(2)接口请求参数需要添加计算 token&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Test-Script (测试脚本): 通过自定义脚本断言接口参数或返回 response 数据，在接口用例页面点击 Test 编辑。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>具体示例：&lt;/p>
&lt;pre tabindex="0">&lt;code>assert.equal(body.errcode, 0)
assert.equal(body.data.group_name, &amp;#39;testGroup&amp;#39;)
assert.equal(status, 200)
&lt;/code>&lt;/pre>&lt;p>总的来看跟postman支持的测试能力差不多。&lt;/p>
&lt;h3 id="插件">插件&lt;/h3>
&lt;p>yapi支持如下的一些插件&lt;/p></description></item><item><title>疫情过后测试人员对面的机遇和挑战</title><link>https://itest2025.pages.dev/tutorials/47-000-%E7%96%AB%E6%83%85%E8%BF%87%E5%90%8E%E6%B5%8B%E8%AF%95%E4%BA%BA%E5%91%98%E5%AF%B9%E9%9D%A2%E7%9A%84%E6%9C%BA%E9%81%87%E5%92%8C%E6%8C%91%E6%88%98/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E7%96%AB%E6%83%85%E8%BF%87%E5%90%8E%E6%B5%8B%E8%AF%95%E4%BA%BA%E5%91%98%E5%AF%B9%E9%9D%A2%E7%9A%84%E6%9C%BA%E9%81%87%E5%92%8C%E6%8C%91%E6%88%98/</guid><description>&lt;p>最近在某视频网站看到有人讨论疫情之后有潜力爆发的一些行业，深以为然，结合自己对测试行业的浅薄理解，这里也分析一下疫情之后测试同学会面对的机遇和挑战。&lt;/p>
&lt;p>可以比较确定的是5g 行业由于时机和国家政策的强力支持，将迎来爆发期。5g 行业整体产业链较长，所以会提供相当多的就业机会，毕竟有开发的地方就有测试，相爱相杀，喜迎福报。另外5g 的出现将催生一批新的行业，比如4g 带来的全民短视频现象，另外一些现有的产品也会产生新的形态，新产业的诞生和老行业的升级都是机遇。&lt;/p>
&lt;p>宅家产业在疫情期间得到了一波流量红利，比如线上教育，在线幼教，在线带娃，线上会议等。这些产品形态在疫情结束后也应该会有迅猛的发展，毕竟如果证明效果拔群的话，以后线上的相应的行为是会减少的，特别是在线教育，前景是值得期待的。测试同学在找工作的时候可以考虑相应的细分市场和产品。这些产品将是以资本追捧的对象，换句话说就是可能不差钱，对应的待遇也有想象的空间。&lt;/p>
&lt;p>送货到家，比如送菜送药等细分市场也在疫情期间野蛮生产，这种小而美的小店模式应该是疫情之后的重点发展方向。这种更紧密的线上线下结合产品对测试同学来说是有不少的进场机会的。这些产品往往意味着五脏俱全的客户端和庞大的上下游供应链后端系统，应该能提供不少岗位需求。&lt;/p>
&lt;p>上面讲的是行业需求，下面我们不妨看看疫情过后对测试同学自身的要求是否会发生变化。&lt;/p>
&lt;p>协作工作的使用能力。远程办公让人们意识到协作工具可以有效的降低大家的沟通成本，而测试很多时候都会充当润滑剂和主动沟通者的角色，因此更好的使用协作工具应该是顺理成章的必然要求。这些协作工具的使用包括但不限于：提让人秒懂的bug；提的bug可以带上自动化的重复步骤等等。总之从流程管理工具，到缺陷管理工具再到知识沉淀工具，从会用到用的精妙，是一个不算强人所难的要求。&lt;/p>
&lt;p>流程的线上化。疫情过后流程的线上化，特别是测试流程的线上化可能会是大家所关注的点。因为线上化意味着更加精确的介入和控制，以及更加完善记录和总结，这会降低沟通成本，把流程的参与人员拉到同一个维度去进行思考和对话，进一步降低沟通效率。测试流程的电子化建设也会给测试同学带来新的挑战。&lt;/p>
&lt;p>资源的线上共享。在疫情期间我们遇到一个问题，测试机在公司，而我们在家中办公，鞭长莫及。而且测试机现在挂在人身上，共享和远程获取都不是很方便，疫情放大了这个痛点，结束之后云测平台等各种个性化的解决方案可能会迎来新的春天。&lt;/p>
&lt;p>有带测试玩的CI/CD。不管你人在哪里，ci/cd总在那里。之前有些公司的ci/cd其实是没有太多测试元素的，疫情期间测试远程导致测试效率降低之后，带有测试元素的ci/cd可能会是人们思考的方向。比如加入更多的自动化测试，加入门槛用例，加入适量的回归用例，这种ci/cd才能经得起远程和疫情的考验。&lt;/p>
&lt;p>更好的沟通能力。如何不说话就把问题描述清楚，这是一门艺术，对于大部分行业都会适用。&lt;/p>
&lt;p>代码能力。疫情过后远程资源的使用应该会越来越多，使用代码进行远程资源的调用和管理将是测试同学的必备技能了吧。&lt;/p>
&lt;p>暂时想到这么多，尚待补充的地方欢迎讨论。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1502786129293-79981df4e689?w=300"
 data-srcset="https://images.unsplash.com/photo-1502786129293-79981df4e689?w=300, https://images.unsplash.com/photo-1502786129293-79981df4e689?w=300 1.5x, https://images.unsplash.com/photo-1502786129293-79981df4e689?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1502786129293-79981df4e689?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>用ipad做笔记是什么样的一种体验</title><link>https://itest2025.pages.dev/tutorials/47-000-%E7%94%A8ipad%E5%81%9A%E7%AC%94%E8%AE%B0%E6%98%AF%E4%BB%80%E4%B9%88%E6%A0%B7%E7%9A%84%E4%B8%80%E7%A7%8D%E4%BD%93%E9%AA%8C/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E7%94%A8ipad%E5%81%9A%E7%AC%94%E8%AE%B0%E6%98%AF%E4%BB%80%E4%B9%88%E6%A0%B7%E7%9A%84%E4%B8%80%E7%A7%8D%E4%BD%93%E9%AA%8C/</guid><description>&lt;p>今天分享的题目很知乎体，那就是用ipad做笔记是什么样的一种体验？&lt;/p>
&lt;p>事情是这样的了，之前我在pdd上面蹲到了一张优惠券，差不多1900左右入了一个ipad mini5的乞丐版。A12处理器，64G的配置用来爱奇艺也应该够了吧。&lt;/p>
&lt;p>因为新版的ipad支持手写笔，之前经常在本子上写写画画，不过各种本子整理起来其实蛮麻烦的，于是就考虑入一只手写笔拿ipad做笔记。&lt;/p>
&lt;p>那么问题就来了，入什么笔比较好呢？&lt;/p>
&lt;p>首选肯定是官方的ipencil，不过一代的苹果笔要500多，算下来基本上就是ipad机身价的25%，这年头钱还是很难赚的，加上如果之后新鲜了一阵就送去吃灰，500多的试错成本还是比较高的。&lt;/p>
&lt;p>于是就在京东上选了个100多第三方笔，各种优惠券叠加以及京豆抵扣，大概100块就搞定了，试错成本直线下降，以后就算不想用了出掉也亏不了多少，所以就它了。&lt;/p>
&lt;h3 id="第三方笔的感受">第三方笔的感受&lt;/h3>
&lt;p>首先我没用过苹果的官方笔，所以没办法做对比，但我入的高仿笔整体来说&lt;/p>
&lt;ul>
&lt;li>写起来很流畅，也很跟手，基本上是指哪打哪，作为一只做笔记的笔，那是绰绰有余的；&lt;/li>
&lt;li>待机能力感人，typec的充电口，充一次电能用很久，具体多久没算过，反正一直有电的状态；&lt;/li>
&lt;li>typec的充电口，好评；&lt;/li>
&lt;li>点触一下笔头就开机，我一般是拿笔头戳脸开机，灵敏还能提神；&lt;/li>
&lt;li>防误触似乎做的不是特别好，有时候手放上去就直接zoom in了，肯跟官方的会好很多&lt;/li>
&lt;li>能磁吸，不过ipad mini5不支持吸附，没啥用；&lt;/li>
&lt;/ul>
&lt;p>总的来说满意，考虑到价格因素，妥妥的80分，少给10分是祖传的防止骄傲措施。&lt;/p>
&lt;h3 id="笔记软件">笔记软件&lt;/h3>
&lt;p>ios自带的备忘录功能是支持手写笔的，不过据说比不上更专业的good note和notability，所以就二选一好了。&lt;/p>
&lt;p>最终选了notability，其实没啥偏好和具体比较，就是随机选的。&lt;/p>
&lt;h3 id="记笔记">记笔记&lt;/h3>
&lt;p>笔记软件上手还是有一些学习成本的，跟传统的提笔就记比起来，笔记软件的选择很多&lt;/p>
&lt;ul>
&lt;li>可以调钢笔，画笔之类的，还可以选择颜色和笔尖的大小，可以配置的项目很多，选择多就意味着记笔记之前就要想一想，有时候想好了却忘了该记录什么了，双刃剑吧&lt;/li>
&lt;li>可以选择画布和背景之类，我直接设置了一个默认值，省的每次都去选&lt;/li>
&lt;li>有记录模式和浏览模式，不过记录模式下用手指滑来滑去其实就是浏览模式，所以按默认来就好&lt;/li>
&lt;/ul>
&lt;p>记录笔记的方式可选性也有&lt;/p>
&lt;ul>
&lt;li>可以在pdf/ppt上画来画去，不过先要导入文件，试过一次就放弃&lt;/li>
&lt;li>直接空白的纸上写，我一般用这个&lt;/li>
&lt;/ul>
&lt;h3 id="效率">效率&lt;/h3>
&lt;p>港真，我打字速度比较快，用笔写字不仅相对较慢而且丑，在记录一些纯文本的信息的时候，写字是的确不如敲键盘那么灵便的。&lt;/p>
&lt;p>但是写写画画确实有他特殊的优势。&lt;/p>
&lt;p>比如，画流程图。在电脑上画流程图其实并不是特别高效的事情，首先需要打开专门的画图软件，然后各种拖拽，键盘鼠标的操作一个都不能少。但是手写就不一样了，各种形状想怎么画就怎么画，流程图的布局以及标注都非常的灵活， 架构图也是同理，这给了我们极大的创作和发挥空间。&lt;/p>
&lt;p>另外在文档上进行标注和高亮用笔来做其实是相当自然的，有一种回到小时候读书时的感觉，相较而言使用鼠标键盘就是另外一回事了。&lt;/p>
&lt;p>因此效率主要看场景，在一些需要创作空间的场景，用笔来做确实比较高效。&lt;/p>
&lt;h3 id="其他">其他&lt;/h3>
&lt;p>ipad mini的屏幕尺寸比较小，其实用笔来各种涂鸦的画限制还是有一些的，而全尺寸甚至是大尺寸的ipad以及ipad pro应该是更好的选择。&lt;/p>
&lt;p>不过考虑到便携性，比如ipad mini在地铁上拿出来其实不算突兀，而10寸以上的ipad在地铁上发挥空间就有限了。&lt;/p>
&lt;h3 id="总之">总之&lt;/h3>
&lt;p>ipad上做笔记是有一定的实用性的，不怕写错而且修改起来相当容易，有笔记需求的同学可以试试。&lt;/p>
&lt;p>最后这是我的统计学笔记的截图，献丑献丑。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1502790671504-542ad42d5189?w=300"
 data-srcset="https://images.unsplash.com/photo-1502790671504-542ad42d5189?w=300, https://images.unsplash.com/photo-1502790671504-542ad42d5189?w=300 1.5x, https://images.unsplash.com/photo-1502790671504-542ad42d5189?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1502790671504-542ad42d5189?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>有人财务自由了，他竟然说要自动化</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%9C%89%E4%BA%BA%E8%B4%A2%E5%8A%A1%E8%87%AA%E7%94%B1%E4%BA%86%E4%BB%96%E7%AB%9F%E7%84%B6%E8%AF%B4%E8%A6%81%E8%87%AA%E5%8A%A8%E5%8C%96/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%9C%89%E4%BA%BA%E8%B4%A2%E5%8A%A1%E8%87%AA%E7%94%B1%E4%BA%86%E4%BB%96%E7%AB%9F%E7%84%B6%E8%AF%B4%E8%A6%81%E8%87%AA%E5%8A%A8%E5%8C%96/</guid><description>&lt;p>前不久看到一篇文章，大意是有个35岁的程序员实现了财务自由，然后选择退休。&lt;/p>
&lt;p>稍微仔细看了一下，这个名为史蒂夫/阿德科克的程序员其实并不是真正意义上的财务自由，而只是财务独立，毕竟他退休的时候活期账户上只有百万美元的存款，更准确的意义上，他实现了财务独立。&lt;/p>
&lt;p>他在一篇文章中提及了他认为每个人都应该掌握和坚守的6条财务守则。&lt;/p>
&lt;ul>
&lt;li>第一，把财务自由当作首要目标&lt;/li>
&lt;li>第二，积极扩展提升个人收入&lt;/li>
&lt;li>第三，投资可以增值的资产&lt;/li>
&lt;li>第四，凡事尽可能实现自动化&lt;/li>
&lt;li>第五，清楚了解自己金钱的去向&lt;/li>
&lt;li>第六，不买不需要的东西&lt;/li>
&lt;/ul>
&lt;p>这里面第1和第2没啥好说的，第5和第6是最难的，毕竟双十一要到了，尾款人大概率会买不需要的东西。&lt;/p>
&lt;p>最值得说道的是第4点，如果这点是由一个亿万富翁说出来，我肯定认为他只是在吹牛而已，不过这话从一个程序员嘴里说出来，那么我们就要好好思考了。&lt;/p>
&lt;p>为什么要尽可能的实现自动化？&lt;/p>
&lt;p>个人认为可能有以下几个原因&lt;/p>
&lt;h4 id="节约时间">节约时间&lt;/h4>
&lt;p>重复的工作从长期看来是最浪费时间的，比如每周从一些表格里拷贝一些数据手工进行汇总，手工统计bug缺陷率之类的，这些重复性的工作并不能让你变得更加优秀，相反只会浪费你的生命。时间就是金钱是老生常谈了，对于大部分的打工人来说，我们是靠出卖自己的自由时间来换得报酬的，那么把重复的事情自动化起来，我们就可以把这部分出卖的时间节约出来变成自己的时间，这样单位时间的收入其实就变高了，等于变相加薪，仔细思考以下还是划算的。&lt;/p>
&lt;h4 id="提高效率">提高效率&lt;/h4>
&lt;p>提高效率的过程是有挑战的，在提效的过程中我们获得的锻炼往往是非常巨大的，鸡汤一点提升效率可以让我们成就更好的自己。&lt;/p>
&lt;h4 id="获得收入规划化的可能">获得收入规划化的可能&lt;/h4>
&lt;p>记得在李笑来的一本书上看到过，说是有钱人总是在请别人来替自己工作，从而获得不需要自己亲自动手就可以自动赚钱的能力。这句话在某种程度上是对的，因为很多产业我们都是通过人力的规划化来进行收入的提升，比如之前海底捞的疯狂开店就是个明显的例子。不过在软件领域，规划化的边际成本相对是比较低的，比如把一个服务十万人的应用扩容成服务二十万人的服务往往只需要增加几台服务器就可以了，成本相对精准可控。实现自动化其实就是实现软件化，既然是软件，那么规模化的成本其实相对就还好了，这样如果你的自动化能力可以给你带来收入，那么你就潜在的拥有了收入规模化的可能。&lt;/p>
&lt;h4 id="自动化让生活更美好">自动化让生活更美好&lt;/h4>
&lt;p>当我们不需要从事一些重复费神的工作时，生活自然就会美好一些了吧。&lt;/p>
&lt;p>整体看来，我认为这位功成身退程序员的的建议是相当中肯的，对我触动很大，所以我在思考这样一件事情。&lt;/p>
&lt;h3 id="怎么让我的生活更加的自动化">怎么让我的生活更加的自动化&lt;/h3>
&lt;p>自动化往往带来智能化，比如现在一些智能家居产品其实就是这样的逻辑，折腾智能家居意味着硬件的投入，不一定划得来，所以优先级可以放低一些。&lt;/p>
&lt;p>下面就是纯软件层面的自动化的实践了，因为打工人一天大部分时间都在工作，所以可以从工作开始。&lt;/p>
&lt;ul>
&lt;li>我写了个自动在测试教程网发布文章的脚本，这样一旦我的代码库里有新的文章提交(是的，我的文章我都用代码库进行管理)就可以自动的发布到测试教程网了(&lt;a href="https://www.testclass.net" target="_blank" rel="noopener noreffer ">www.testclass.net&lt;/a>)&lt;/li>
&lt;li>我曾经一上午发布了n篇知乎专栏的内容，触发了知乎的限频逻辑；手动发表文章很心累，而且对我本人没有任何成长，所以我准备写个脚本自动化的去发表知乎专栏以及博客园文章的更新&lt;/li>
&lt;li>自动跟踪线上的bug，一旦有新的线上问题就给我发提醒，这样提高了跟进线上问题的效率；&lt;/li>
&lt;li>自动对工作进度进行检查，提升工作效率；&lt;/li>
&lt;li>自动扫描github的热门项目，有我自定义感兴趣的内容就推送给我，试了一下，不如github自带的explore好用&amp;hellip;&lt;/li>
&lt;li>自动抢电商平台的优惠券&lt;/li>
&lt;li>应该还有更多&amp;hellip;&amp;hellip;&lt;/li>
&lt;/ul>
&lt;p>我甚至专门维护了一个自动化idea的列表，有新的想法就写上去，然后抽时间实现。&lt;/p>
&lt;p>我还在油管关注了一些知名的博主，这些博主不定期更新一些关于python的视频，这些视频里很大一部分就是如何用python实现一些稀奇古怪的自动化idea，比如一旦某美女模特发了新推就第一时间自动点赞之类的,有些灵感是可以从里面获取的。&lt;/p>
&lt;p>期待后面可以实现更多有意思的自动化想法。&lt;/p>
&lt;h3 id="总而言之">总而言之&lt;/h3>
&lt;p>尽管努力自动化不能使我们一步到位的实现财务独立，但节约下来的时间和精力可以让我们有余地更多的去计划如何扩大收入和减少支出，当你的收入远远大于支出的时候，财务独立也许就触手可及了。&lt;/p>
&lt;p>梦想还是要有的，万一哪天实现了呢？&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1547234935-80c7145ec969?w=300"
 data-srcset="https://images.unsplash.com/photo-1547234935-80c7145ec969?w=300, https://images.unsplash.com/photo-1547234935-80c7145ec969?w=300 1.5x, https://images.unsplash.com/photo-1547234935-80c7145ec969?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1547234935-80c7145ec969?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>又是绩效评估时，如何合理的评估测试同学的绩效?</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%8F%88%E6%98%AF%E7%BB%A9%E6%95%88%E8%AF%84%E4%BC%B0%E6%97%B6%E5%A6%82%E4%BD%95%E5%90%88%E7%90%86%E7%9A%84%E8%AF%84%E4%BC%B0%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E7%9A%84%E7%BB%A9%E6%95%88/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%8F%88%E6%98%AF%E7%BB%A9%E6%95%88%E8%AF%84%E4%BC%B0%E6%97%B6%E5%A6%82%E4%BD%95%E5%90%88%E7%90%86%E7%9A%84%E8%AF%84%E4%BC%B0%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E7%9A%84%E7%BB%A9%E6%95%88/</guid><description>&lt;p>又是绩效评估时，如何合理的评估测试同学的绩效&lt;/p>
&lt;p>这是我最近思考比较多的一个问题，也是很重要的一个问题，因为这关系到大家一年来辛辛苦苦工作的结果。&lt;/p>
&lt;p>在我看来，大部分测试同学都是很辛苦的，加班，给开发背锅这些事情都是常态，所以如果没有给大家一个非常客观的年终评定的话，不仅经济收益上会有影响，更有可能打击大家的积极性，从而对团队稳定性造成不好的影响。&lt;/p>
&lt;p>绩效评估如果不合理，那么大家可能会有这样的疑惑&lt;/p>
&lt;ul>
&lt;li>我明明工作很努力，为什么绩效这么差&lt;/li>
&lt;li>我觉得我的能力很强，为什么不给我涨薪&lt;/li>
&lt;li>某某某并不如我啊，为什么绩效比我好&lt;/li>
&lt;/ul>
&lt;p>其实测试的绩效比开发同学的绩效要难评估一些。毕竟开发大神大家很容易看得出来，贡献大的绩效好，相对比较容易做比较，但测试同学很多时候技能的区分程度不大，大家其实水平差不多，做的事情也差不多，也都差不多的努力和敬业，尽管很多时候是被动的，但功劳苦劳其实差不多。&lt;/p>
&lt;p>如何能够比较好的进行测试同学输出的评价呢？我思考了几个维度，希望可以跟大家讨论一下。&lt;/p>
&lt;h3 id="个人能力维度">个人能力维度&lt;/h3>
&lt;p>个人能力包括当前能力及成长。如果个人能力一直没有较大提升，那么可以认为该成员的成长速度可能一般，或者已经达到自己潜力的巅峰了，可以考虑让其承担一些更有挑战的工作之类。&lt;/p>
&lt;p>我觉得年终评价的时候我们可能更需要关注成长。主动成长和被动成长从结果上看其实是差不多的，但主动成长的人可能在成长的持续性方面会更好一点。&lt;/p>
&lt;p>关于测试同学的能力的评估我之前写过文章描述，这里再列一遍&lt;/p>
&lt;ul>
&lt;li>业务能力，理解业务和快速熟悉业务的能力&lt;/li>
&lt;li>文档能力，有时候写文档也很重要&lt;/li>
&lt;li>沟通能力，不言而喻&lt;/li>
&lt;li>和项目组其他成员打成一片的能力：这个是双刃剑，有时候这种能力强推动力强，有时候则会陷入过度的容忍&lt;/li>
&lt;li>技术能力，这里可以很细，就不展开了&lt;/li>
&lt;/ul>
&lt;h3 id="业务输出">业务输出&lt;/h3>
&lt;p>从结果导向上看，测试同学的输入是质量控制和保障，只要不出问题，没人想起你，那么你就是成功的，否则，如果你成了团队里最让人惦记的人，那么你的质量可能就没有太高。&lt;/p>
&lt;p>这里可以给出一些指标，我觉得最简单粗暴的指标就是线上问题的数量。这个指标比较片面，这是因为&lt;/p>
&lt;ul>
&lt;li>可能你在测试过程中发现了太多的问题，但是代码质量实在太差，导致问题一直没有办法根除，从而遗留到了线上，这种情况下，可能测试同学就是线上问题的背锅侠了&lt;/li>
&lt;li>如果代码质量好的话，那么测试同学在测试过程中可能不需要太费心，最后上线之后如果发现了问题，那就是运气不好，没有出事故的话，其实跟测试同学的努力关系也不是特别的大，这就是命了&lt;/li>
&lt;/ul>
&lt;p>既然这个指标问题那么多，那么我为什么还是推荐大家使用这个指标呢？这因为质量管理不一定是疯狂的点来点去，以自己的一己之力去避免缺陷的发生，而是要将项目组所有成员都拉到质量控制的大流程中去。&lt;/p>
&lt;p>举个例子，开发的提交质量太烂，那么能不能提升准入门槛，让他们自己多测一会，多思考一些事情再提交呢？能不能让这个锅大家背，而不是测试独自去承担？线上问题追责的时候，能不能谁写的代码谁承担主要责任？没测出来的最多算个从犯，而不算主犯？有锅大家背，如果开发被背锅的恐惧感支配，那么代码质量多少还是有提升的。&lt;/p>
&lt;p>所以这个结果我们是可以基本信赖的，哪怕这个指标有争议，但争议的过程引导我们去做的更好。&lt;/p>
&lt;p>另外我喜欢让测试同学站在产品的角度去向整个项目团队去讲解需求，假如你是产品经理，那么你应该怎么向我们表述你的需求？每次讲解的时候当场就可以收集到反馈，这就可以看出另一个指标：业务熟悉程度。&lt;/p>
&lt;p>让测试同学写系统或产品的使用说明书也能看到大家的业务熟悉程度，有时候写太麻烦了，所以我倾向让他们讲出来，这也能看出业务熟悉程度。&lt;/p>
&lt;p>有了上面一些维度之后，我们可能就能大致的评判大家的工作输出了吧。指标其实还有很多，但核心思想大概都是：看测试质量，看人员成长。&lt;/p>
&lt;p>最后，这只是我的个人浅见，仅供参考。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1494625927555-6ec4433b1571?w=300"
 data-srcset="https://images.unsplash.com/photo-1494625927555-6ec4433b1571?w=300, https://images.unsplash.com/photo-1494625927555-6ec4433b1571?w=300 1.5x, https://images.unsplash.com/photo-1494625927555-6ec4433b1571?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1494625927555-6ec4433b1571?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>在没有线上监控的情况下放肆裸奔</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%9C%A8%E6%B2%A1%E6%9C%89%E7%BA%BF%E4%B8%8A%E7%9B%91%E6%8E%A7%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%E6%94%BE%E8%82%86%E8%A3%B8%E5%A5%94/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%9C%A8%E6%B2%A1%E6%9C%89%E7%BA%BF%E4%B8%8A%E7%9B%91%E6%8E%A7%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%E6%94%BE%E8%82%86%E8%A3%B8%E5%A5%94/</guid><description>&lt;p>如果你的产品出现了一个线上问题，你会是怎么样的反应？&lt;/p>
&lt;p>也许会跟下面这张图一样。&lt;/p>
&lt;p>哇！有一个线上bug，好慌呀！！&lt;/p>
&lt;p>咦，问题似乎自动解决了？ 渐渐冷静。&lt;/p>
&lt;p>不对！！！ 这个问题竟然突然自己就好了？？？ 更慌了！！！&lt;/p>
&lt;p>很多测试同学应该有上面这样的心路历程。线上bug不经意间出现，却又突然消失无踪，这会让我们精神紧张，心里各种没底，寝食难安。&lt;/p>
&lt;p>这时候可能就需要做一些线上监控和告警了。&lt;/p>
&lt;p>其实我之前有分享过，监控可以分为3个层次。&lt;/p>
&lt;ul>
&lt;li>基础监控。线上机器的内存，cpu，硬盘，网卡等核心指标的监控和告警。&lt;/li>
&lt;li>服务监控。服务监控程度的监控，比如接口的调用成功率，相应时间，错误码分布等。&lt;/li>
&lt;li>业务监控。定义核心的业务指标，比如电商的核心指标就是订单数，对业务指标进行监控和告警，一旦业务指标有异常，立即告警。&lt;/li>
&lt;/ul>
&lt;p>基础监控和服务监控大家都比较好理解。这里稍微具体讲一下业务监控。&lt;/p>
&lt;p>以电商的核心业务指标订单为例，假设我们通过各种方式计算出在每天下午2点的时候，大概一小时会有1万单，那么如果哪天下午2点左右订单数掉到5000了，那么可能是下单链路上某个环节出问题了，就需要立即排查。&lt;/p>
&lt;p>另外业务监控也可以用自动化的方式辅助去做，这样监控的路径会更长一些，排查问题也能迅速一点。&lt;/p>
&lt;p>还是以下单为例，我们可以在线上用一个特殊用户不停的买一些特殊商品（当然了，有影子库和特殊策略就更好了），如果下单流程失败，另外数据又监控到订单数环比确实有异常，那么就可以根据自动化用例的报错迅速定位到问题。&lt;/p>
&lt;p>最近我们线上出了一次比较严重的事故，当然导致事故的核心原因是开发流程没有正确进行，不过没有线上监控而放肆裸奔也是求生欲不够强的表现，如果一些核心数据可以被监控和告警的话，我们可能在上线之后就能迅速定位到问题，而不会等到用户投诉再去处理了。&lt;/p>
&lt;p>我们在线上监控很多时候都是通过阈值去感知变化的离散程度的，合理的阈值会让告警更加精准。不过由于一些突发性的原因，这些阈值可能会在短时间被突破，但是过完一个时间周期之后自动恢复正常，在这种情况下，为了减少误报，我们可能不仅要报异常情况，还要报问题自动恢复的情况。&lt;/p>
&lt;p>关于监控工具，目前市面上有很多开源免费的监控工具，都非常好用，比如&lt;/p>
&lt;ul>
&lt;li>prometheus。普罗米修斯，github star超30k，部署简单，功能强大，小白入坑无脑选择的最佳推荐；&lt;/li>
&lt;li>open-falcon。小米开源的企业级监控平台，国内很多企业都在使用。高可用易扩展，可以分布式部署，自带dashboard，最关键的是有中文文档，英文拙计的同学可以试试；&lt;/li>
&lt;/ul>
&lt;p>2020年大家可以给自己定一个小目标，那就是生产环境的业务监控先跑起来，不要再放肆裸奔了吧。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1516108317508-6788f6a160e4?w=300"
 data-srcset="https://images.unsplash.com/photo-1516108317508-6788f6a160e4?w=300, https://images.unsplash.com/photo-1516108317508-6788f6a160e4?w=300 1.5x, https://images.unsplash.com/photo-1516108317508-6788f6a160e4?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1516108317508-6788f6a160e4?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>这几家大公司准备干掉测试了，我们应该何去何从</title><link>https://itest2025.pages.dev/tutorials/47-000-%E8%BF%99%E5%87%A0%E5%AE%B6%E5%A4%A7%E5%85%AC%E5%8F%B8%E5%87%86%E5%A4%87%E5%B9%B2%E6%8E%89%E6%B5%8B%E8%AF%95%E4%BA%86%E6%88%91%E4%BB%AC%E5%BA%94%E8%AF%A5%E4%BD%95%E5%8E%BB%E4%BD%95%E4%BB%8E/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E8%BF%99%E5%87%A0%E5%AE%B6%E5%A4%A7%E5%85%AC%E5%8F%B8%E5%87%86%E5%A4%87%E5%B9%B2%E6%8E%89%E6%B5%8B%E8%AF%95%E4%BA%86%E6%88%91%E4%BB%AC%E5%BA%94%E8%AF%A5%E4%BD%95%E5%8E%BB%E4%BD%95%E4%BB%8E/</guid><description>&lt;p>最近因为招聘，所以经常会跟一些比较优秀的大厂同学聊天，无意中得知了这样一些信息。&lt;/p>
&lt;p>腾讯的pcg已经在逐步干掉测试了，这是所谓的去测试化。&lt;/p>
&lt;p>这里的干掉指的是日常的测试工作交给外包去做，曾经的正式员工往效能提高的方向去转型，做一些研发效率度量，质量度量以及效能提升的工作。&lt;/p>
&lt;p>去测试化万口传，至今已觉不新鲜。&lt;/p>
&lt;p>最早听说这个词应该是在2016年左右，正好是5年前。当时我们公司来了一批微软的测试专家，从他们口中得知微软总部在去测试化，之前的测试人员转做测试工具或者效率工具开发，开发尽可能的多写测试用例，一些实在需要人工覆盖的场景可以交给外包去做，所以现在微软应该没有测试这个角色了。尽管在做出这个决定的初期，微软产品的整体质量似乎是出现了一些不可避免的下降现象，比如win10之前出过非常多的bug，但是微软后来迅速走出了困境，整体的产品质量有了一定的提升。&lt;/p>
&lt;p>不过仔细一想微软是有这样做的资本的。在操作系统领域，哪怕windows的质量有了一定程度的下滑，但是对于大部分人来说，要么是没有选择，只能默默忍受，要么就是选择不升级，停留在之前的稳定版本里。所以对于一个在市场上占主导地位的公司或者产品，没有了活下去的压力，去测试化可能是一个不错的选择。将质量保障的压力传导给开发，这是最行之有效提升代码质量的方法。我记得很久之前分享过，如果一个项目中开发很强，测试相对不强，那么这个项目的质量其实是可控的；相反开发能力很弱，但是测试很强，产品的长期质量我其实是看衰的。再看一些很流行的开源项目，这些项目中似乎只有开发，他们写用例，做code review，发布代码，然后开源项目的使用者其实就是测试，他们试用产品，提出问题，寻求解决方案或者直接贡献代码解决。因此微软的去测试化其实就是让开发多做测试，让用户当小白鼠，反正用户的选项不多，也不是很怕用户流失。&lt;/p>
&lt;p>后来在18年左右，又听说一家公司在做去测试化，那就是字节。&lt;/p>
&lt;p>当时跟字节的一个部门负责人交流的时候，他说他们很欣赏微软的理念，要对标微软去测试化。测试人员主要的职能有&lt;/p>
&lt;ul>
&lt;li>提升测试效能，让开发会写用例以及提供相应的工具让测试的效率可以提升&lt;/li>
&lt;li>测试管理，大体是做流程管理和推动，顺便管管外包和实习生，似乎字节有让实习生做测试的传统&lt;/li>
&lt;/ul>
&lt;p>字节和微软不一样，字节应该是一家非常焦虑的公司，偏平的架构和不成功便成仁的kpi导向，使得这家公司的策略可能会偏向激进，所以作出去测试化的策略是可以理解的。毕竟字节产生产品的速度和放弃产品的速度一样快，一个产品因为质量不行而被诟病其实问题比较好解决，要么放弃掉，要么重新做一个。&lt;/p>
&lt;p>到了今天腾讯的一些部门也坚定的站在去测试化这一阵营，综合分析起来其实是可以理解的。&lt;/p>
&lt;ul>
&lt;li>来了新的gm，推进自己的技术理念&lt;/li>
&lt;li>稳定的产品占据市场主导地位，质量下降带来的副作用在短期内是可以接受的&lt;/li>
&lt;li>产品开发的快，放弃的也快，跟字节类似，所以一旦有质量问题，要么重新来做，要么直接放弃&lt;/li>
&lt;li>腾讯老一代的开发基本上新陈代谢的差不多了，向这部分人灌输开发做测试的概念其实比较难；但对于新鲜血液来说，推一推总是有办法的&lt;/li>
&lt;/ul>
&lt;p>所以我们可以有理由相信，对于一些在行业内有一定垄断地位的大厂来说，去测试化应该是大势所趋。&lt;/p>
&lt;p>那么我们测试同学应该何去何从呢？&lt;/p>
&lt;ul>
&lt;li>转型为测试开发，专心打辅助，开发质量度量工具，测试效率提升工具以及其他各种工具，另外还要教开发写测试用例，这是测试左移，可能不需要背锅&lt;/li>
&lt;li>大厂不好混可以去二线厂，只要市场没有被巨头垄断，其他玩家必定重视质量和口碑，这里测试同学的机遇和挑战并存，可能需要背锅&lt;/li>
&lt;li>转型为测试管理，大厂还是要有人做流程管理，外包管理，质量管理，职位不多，但有需求&lt;/li>
&lt;li>转型为开发，说句实话，在相同的预期条件下，写业务逻辑很多时候比写工具要简单，不过转开发要趁早，因为对于开发来说，你之前的测试经验可能是一文不值的&lt;/li>
&lt;li>转产品，我认识好几个转产品的测试同学，还是同样的道理，转要趁早&lt;/li>
&lt;li>转行，换个行业和赛道，想象的空间可能更大&lt;/li>
&lt;/ul>
&lt;p>不知道大家有什么样的想法，欢迎在评论区留言讨论。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1516026672322-bc52d61a55d5?w=300"
 data-srcset="https://images.unsplash.com/photo-1516026672322-bc52d61a55d5?w=300, https://images.unsplash.com/photo-1516026672322-bc52d61a55d5?w=300 1.5x, https://images.unsplash.com/photo-1516026672322-bc52d61a55d5?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1516026672322-bc52d61a55d5?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>这也许是最硬核的自动化测试机器人</title><link>https://itest2025.pages.dev/tutorials/47-000-%E8%BF%99%E4%B9%9F%E8%AE%B8%E6%98%AF%E6%9C%80%E7%A1%AC%E6%A0%B8%E7%9A%84%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E6%9C%BA%E5%99%A8%E4%BA%BA/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E8%BF%99%E4%B9%9F%E8%AE%B8%E6%98%AF%E6%9C%80%E7%A1%AC%E6%A0%B8%E7%9A%84%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E6%9C%BA%E5%99%A8%E4%BA%BA/</guid><description>&lt;p>当你用chrome浏览网页的时候，你可能会经常遇到这样的一幕。&lt;/p>
&lt;p>没错，这就是没网络时候的默认的界面。&lt;/p>
&lt;p>不过有多少人知道在这里点一下空格键，你将会开启一个全新的游戏的世界。没错了，这里google放了一个小小的彩蛋，当没网络提示出现之后，按空格键将会启动一款名叫dino的网页小游戏。&lt;/p>
&lt;p>这款游戏玩起来非常简单，玩家扮演一只名为dino的小暴龙，dino每天的工作就是不断的向前跑(脑补BGM:向前跑 迎着冷眼和嘲笑，生命的广阔不历经磨难怎能感到&amp;hellip;..)，这一路艰难险阻，会突然出现各式各样的大小仙人掌等障碍物，玩家需要操控dino上蹿下跳来躲避这些未知的危险。游戏操作非常简单，只需要用到空格键或者向上的箭头键，节奏明快，很上头，一不小心就会玩很久。&lt;/p>
&lt;p>除了断网的时候可以跟dino小恐龙不期而遇之外，我们还可以在chrome浏览器里输入&lt;code>chrome://dino/&lt;/code>，这样就可以直接打开游戏了。&lt;/p>
&lt;p>这款彩蛋小游戏其实很多人都知道了，而且也有不少人手上把玩过一番，大家可以把自己的最高分留言在评论区里，比一比谁更无聊。说起冲击高分，最近我看到有个老外搞了套硬核的自动系统，号称可以独孤求败，把这款游戏玩到天荒地老。废话不多说，直接上视频。&lt;/p>
&lt;p>小朋友，你是不是有很多的问号？&lt;/p>
&lt;p>这个是怎么实现的呢？&lt;/p>
&lt;p>其实我也不知道。不过我猜也许这是通过树莓派+传感器实现的，具体原理可能是&lt;/p>
&lt;ul>
&lt;li>利用光感电阻和电容进行串联，实现测光的效果，可以设计成也是有光的时候是高电频，弱光的时候是低电频&lt;/li>
&lt;li>当光敏电阻识别到是弱光的时候，发送指令给机械臂，按下空格键，实现dino跳跃的效果&lt;/li>
&lt;/ul>
&lt;p>所以理想情况下你只要会设计电路，熟悉树莓派编程，外加上运气好，你就可以实现同样的效果了。&lt;/p>
&lt;p>是不是有点硬核？不过这套系统可能会存在这样的问题，就是在外部的光线情况变化了的情况下，比如晚上光源比较弱的时候，这套系统可能就没办法工作的很好了，因为那时候dino可能会不停的跳来跳去，变成一只飞翔的恐龙，降落的时候踩到仙人掌，那可就game over了。&lt;/p>
&lt;p>瑕不掩瑜，这个例子告诉我们，只要脑洞够大，我们日常工作生活中能用到自动化的地方其实会有很多。世界上不缺乏需求，缺的是发觉需求的能力以及实现需求的勇气。记得当初在宜家里看到过自动测试柜门的机械臂（大概是这个，记的不是很清楚了），就是让机械臂不停的去开关柜门，进行持续的磨损测试，这种测试只能机器去做了，这是自动化的典型应用场景。另外我也有过耳闻有团队使用树莓派加温度传感器去自动化测试手机温度的案例。&lt;/p>
&lt;p>dino玩到后面难度其实会增加的，恐龙移动的速度会随着分数的提高越来越快，这时候可能要通过调整光感电阻的位置来实现提前跳跃的功能，所以上面的装置应该并不是可以一帆风顺的直接跑下去的。另外第二关整体的背景会变成黑色，这对光感电阻也是很不友好的，那么有没有什么办法可以让dino一直跑下去跑到天荒地老呢？&lt;/p>
&lt;p>答案是有的，看下面的视频。&lt;/p>
&lt;p>在这个视频里，我其实就是做了3件事情&lt;/p>
&lt;ul>
&lt;li>把障碍物小仙人掌的y坐标改成0，这样小仙人掌就飞升了 &lt;code>Obstacle.types[0].yPos = 0&lt;/code>&lt;/li>
&lt;li>把障碍物大仙人掌的y坐标改成0，这样大仙人掌就飘走了 &lt;code>Obstacle.types[1].yPos = 0&lt;/code>&lt;/li>
&lt;li>把障碍物翼龙的各种坐标改成0，这样就飞龙在天了 &lt;code>Obstacle.types[2].yPos = [0, 0, 0]&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>这样一来所有的障碍物都成了热气球，dino就可以永远的奔跑下去了吧。&lt;/p>
&lt;p>说回测试，上面的例子在游戏测试中其实有可能会用到，这是一种简单的跑关的方式。&lt;/p>
&lt;p>在做游戏测试的时候，我们需要验证我们的关卡设计是不是符合预期的，关卡设计中的梗能不能被玩家get到，比如dino的后面关卡中的深色背景梗，这时候就需要我们有快捷的方式去把所有的关卡跑通，而上面把障碍物全部放风筝的做法就可以很好的让关卡一直跑下去，简单的人工介入之后就可以做基本的测试和检查了。另外在一些游戏里会有一些经典的bug或者秘籍，比如魂斗罗的上、上、下、下、左、右、左、右、B、A、B、A 30条命秘籍，这些也许是当初为了测试游戏时候为了大幅度降低游戏难度，从而减少跑关时间所留下的后门。这种后门其实在软件开发领域很常见，比如测试环境上的万能验证码后门。&lt;/p>
&lt;p>无论是硬核的树莓派周边解决方案，还是代码流的改运行时的方法，我们的初衷都是遇到问题，然后解决问题。&lt;/p>
&lt;p>使用自动化的方式去提升测试效率，解决测试工作中遇到的特定问题，这是大家都广泛认可的观点和方案。有时候自动化做不好，可能并不是工具的锅，而是大家也许没有把有限的精力和能力用在最合适的场景上吧。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1509565840034-3c385bbe6451?w=300"
 data-srcset="https://images.unsplash.com/photo-1509565840034-3c385bbe6451?w=300, https://images.unsplash.com/photo-1509565840034-3c385bbe6451?w=300 1.5x, https://images.unsplash.com/photo-1509565840034-3c385bbe6451?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1509565840034-3c385bbe6451?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>主力机从iphone换到android是一种什么体验?</title><link>https://itest2025.pages.dev/tutorials/47-000-%E4%B8%BB%E5%8A%9B%E6%9C%BA%E4%BB%8Eiphone%E6%8D%A2%E5%88%B0android%E6%98%AF%E4%B8%80%E7%A7%8D%E4%BB%80%E4%B9%88%E4%BD%93%E9%AA%8C/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E4%B8%BB%E5%8A%9B%E6%9C%BA%E4%BB%8Eiphone%E6%8D%A2%E5%88%B0android%E6%98%AF%E4%B8%80%E7%A7%8D%E4%BB%80%E4%B9%88%E4%BD%93%E9%AA%8C/</guid><description>&lt;p>我的主力机最近6年应该一直都是iphone。从之前iphone 5s到iphone se再到iphone 8，基本上ios设备都能很好的满足我的日常需求，直到我的icloud存储空间捉襟见肘以及我的ip8陷入深深的电量焦虑之后，我感到是时候换一部新手机了。&lt;/p>
&lt;p>坦诚的说，iphone 8是一部不错的手机，尽管已经2020年末了，但是ip8的反应速度还是让人基本满意的。不过ip8现在待机时间确实有些让人着急，加上非全面屏的设计看上去有些怀旧，另外不支持双卡，所以还是换一部好了。&lt;/p>
&lt;h3 id="继续换一部ios设备">继续换一部ios设备？&lt;/h3>
&lt;p>因为我使用苹果的生态很久了，icloud的各种同步，mac和ios设备的协同，以及ipad os设备跟ios的设备的无缝衔接，继续使用iphone应该是一件顺理成章的事情。&lt;/p>
&lt;p>正好这时候iphone 12发布了，支持5g，支持双卡，屏幕手感响应速度都有提升，那么我的下一台iphone就是iphone 12好了。&lt;/p>
&lt;p>不过128g 6000+的售价会让我原本不富裕的家庭雪上加霜，思索良久还是放弃了，毕竟十三香，再等等吧。&lt;/p>
&lt;p>这时候iphone se2进入了我的视野，128g的售价是2800左右，经济上还是可以承受的。不过考虑到iphone se2跟我的ip8长得一模一样，似乎换机对体验的提升并不是很大，还是不要考虑了。&lt;/p>
&lt;p>所以，最终我的决定买一台iphone 12给我老婆，这样我就可以用她的iphone xr了，曲线救国也是可以的。但是老婆大人对换手机没有任何兴趣，因此只能作罢了。&lt;/p>
&lt;h3 id="只能换安卓设备了">只能换安卓设备了&lt;/h3>
&lt;p>为了获得不一样的换机体验，我将目光放到了安卓阵营，现在安卓手机的流畅度基本上跟iphone差距没有那么明显了，而且安卓手机可选择的余地很大，尽管长的都差不多，但总有一款大致可以适合我。&lt;/p>
&lt;p>我的需求也很明确&lt;/p>
&lt;ul>
&lt;li>不要太大太重，现在中低端安卓机器基本都是200g左右，长期使用有健身的效果，手感其实是不如iphone的&lt;/li>
&lt;li>支持5g和双卡，这些都是标配了，闭着眼睛选就好了&lt;/li>
&lt;li>待机能力强一些，有很多安卓机支持65w甚至是100w的快充，基本可以做到续航不焦虑了&lt;/li>
&lt;li>屏幕大一点，这点其实可以不用过多考虑，我发现现在基本找不到小屏幕的机器了&lt;/li>
&lt;li>便宜一点，这点其实最重要&lt;/li>
&lt;/ul>
&lt;p>于是搜索了一段时间之后，我买了一台某品牌的 8+128g的手机，重量175克，算是相对轻一点的了，支持屏下指纹和65w快充，最关键的是只要1299，这个价钱就不要自行车了。&lt;/p>
&lt;h3 id="主力机的体验">主力机的体验&lt;/h3>
&lt;p>因为我不玩手机游戏，其实也想玩，但是之前ip8只有64g的空间，装应用都不够，更别说是装游戏了，所以买小存储的空间的手机可以帮你戒掉游戏，这不仅是我的体验，我另一个只买乞丐版手机的同事也有类似的心路历程，换了乞丐版iphone以后，直接从王者变成青铜。&lt;/p>
&lt;p>因为之前的手机的存储空间小，而微信又非常吃空间，所以我基本上不必要的app都不会装，而我常用的app都有android版本，尽管没有iphone那么优雅，不过用起来其实也差不多。&lt;/p>
&lt;p>另外由于手机支持双卡，现在出门就不需要带两台手机了，减少了很多负担。&lt;/p>
&lt;p>128g对我来说是相对奢侈的，之前iphone只敢用来扫码，不敢拍照，现在用android机器可以适当拍照了，不过千元机的拍照水平不敢恭维，画面还是比较容易失真的，所以大部分时间可能还是用来扫码。&lt;/p>
&lt;p>所以对于一个主力机只用到微信，邮件，浏览器(有浏览器端的站点坚决不装对应的app)以及一些视频应用的手机中度用户来说，iphone和android的体验差距其实没有那么明显。&lt;/p>
&lt;p>iphone更加优雅，安全，稳定，高效，就像是理想中的初恋情人，你想要的她都有，符合你对一台手机的几乎全部定义；而安卓则像是现任女友，优点很明显，但总有一些地方让你难以忍受。&lt;/p>
&lt;p>而从iphone换成android的体验就像是你一直在听经典的古典音乐,沉浸于那种美感那种韵律那种从容，忽然转为听流行音乐，有一些地方一开始你确实非常欣赏，但听了久了就有一些乏善可陈，流于表面。&lt;/p>
&lt;p>但总的来说，如果你一天大部分时间都是在办公室里度过，作为专业社畜和资深打工人来说，而手机只是在通勤的时候中度使用的话，用iphone或者是android差距其实是不大的。&lt;/p>
&lt;h3 id="得到和失去">得到和失去&lt;/h3>
&lt;p>从ios转向android，有得有失&lt;/p>
&lt;p>没有了ios，我将&lt;/p>
&lt;ul>
&lt;li>carplay不能用了，这点最让人遗憾&lt;/li>
&lt;li>ios/ipad os以及mac os之前无缝转换的生态体验没有了&lt;/li>
&lt;li>再见siri，别了捷径&lt;/li>
&lt;li>不能用ios原生的记事本和提醒了&lt;/li>
&lt;li>失去了icloud同步一切的能力&lt;/li>
&lt;li>失去了一款方便携带的小屏手机&lt;/li>
&lt;/ul>
&lt;p>得到的也有一些&lt;/p>
&lt;ul>
&lt;li>不用电量焦虑了&lt;/li>
&lt;li>不用容量焦虑了&lt;/li>
&lt;li>屏幕更大了&lt;/li>
&lt;/ul>
&lt;p>总之经过这次换机我发现，社畜用啥机器都差不多，只要便宜稳定就可以了。&lt;/p>
&lt;p>&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1489493512598-d08130f49bea?w=300"
 data-srcset="https://images.unsplash.com/photo-1489493512598-d08130f49bea?w=300, https://images.unsplash.com/photo-1489493512598-d08130f49bea?w=300 1.5x, https://images.unsplash.com/photo-1489493512598-d08130f49bea?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1489493512598-d08130f49bea?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>自动化测试元素定位最佳实践</title><link>https://itest2025.pages.dev/tutorials/47-000-%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E5%85%83%E7%B4%A0%E5%AE%9A%E4%BD%8D%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E5%85%83%E7%B4%A0%E5%AE%9A%E4%BD%8D%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/</guid><description>&lt;p>最近在翻阅cypress文档的时候发现一些关于自动化测试中元素定位的思考，觉得很有意思，这里跟大家分享一下。&lt;/p>
&lt;h3 id="核心概念">核心概念&lt;/h3>
&lt;p>其实元素定义的核心概念很简单，一些元素总有自己独一无二的一些特点，比如我们每个人都有身份证号，利用这种独特性对元素进行定位，从而进一步做后续操作。&lt;/p>
&lt;p>有道是君子有所为有所不为，一些在实践中被证明了是不合适的做法是最好不要去采用的，比如&lt;strong>不要使用有可能发生改变的属性对元素进行定位&lt;/strong>。&lt;/p>
&lt;p>如果你有能力修改前端代码，那么最佳实践就是:&lt;strong>加一个定位专用的属性，比如&lt;code>data-*&lt;/code>&lt;/strong>，这个属性跟js逻辑以及css样式都无关，这样就做到了定位属性与易变属性(dom/css selector/js selector)隔离。&lt;/p>
&lt;p>下面的一些做法是cypress不太推荐的，不过见仁见智，不推荐不代表完全不能这样做。&lt;/p>
&lt;ul>
&lt;li>不要用css属性定位，比如&lt;code>id,class,tag&lt;/code>&lt;/li>
&lt;li>不要用可能会发生变化的文本文字进行定位，比如按钮上的文字等&lt;/li>
&lt;/ul>
&lt;h3 id="没有对比就没有伤害">没有对比就没有伤害&lt;/h3>
&lt;p>cypress的最佳实践里给大家列举了一些例子进行对比，我们感受一下&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>选择器&lt;/th>
 &lt;th>推荐程度&lt;/th>
 &lt;th>备注&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;code>cy.get('button').click()&lt;/code>&lt;/td>
 &lt;td>永远不要这样做&lt;/td>
 &lt;td>最差的选择，没有任何上下文，太通用&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>cy.get('.btn.btn-large').click()&lt;/code>&lt;/td>
 &lt;td>永远不要这样做&lt;/td>
 &lt;td>很差，这些class很容易发生修改&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>cy.get('#main').click()&lt;/code>&lt;/td>
 &lt;td>不太好&lt;/td>
 &lt;td>还行，不过还是跟js和css选择器耦合在一起&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>cy.get('[name=submission]').click()	&lt;/code>&lt;/td>
 &lt;td>不太好&lt;/td>
 &lt;td>跟html的name属性耦合在了一起&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>cy.contains('Submit').click()&lt;/code>&lt;/td>
 &lt;td>见仁见智&lt;/td>
 &lt;td>好多了，但是仍然跟按钮文本耦合在了一起&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>cy.get('[data-cy=submit]').click()&lt;/code>&lt;/td>
 &lt;td>最佳选择&lt;/td>
 &lt;td>单独的属性，与css和js隔离&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h3 id="然而人生十不如意有八九">然而，人生十不如意有八九&lt;/h3>
&lt;p>上面的一些观点，原则上我是非常赞同的。&lt;/p>
&lt;p>但是呢，现实往往比理论更加立体，cypress的理念是对于被测项目的前端代码，你必须百分百有控制权，也就是说你需要是这个项目的前端开发人员。&lt;/p>
&lt;p>cypress就是为前端开发人员设计的，这样的要求自然是合情合理的。&lt;/p>
&lt;p>但很多情况是我们其实并没办法修改前端代码的，在这种艰苦的条件下，一些妥协是可以有的，比如&lt;/p>
&lt;ul>
&lt;li>可以用html的name属性定位，因为这个属性相对稳定&lt;/li>
&lt;li>可以用dom的id属性定位，因为改id的概率可能会比较低&lt;/li>
&lt;li>不要用基于dom层级关系的xpath或css定位，这里一般指的是在浏览器上直接拷贝出来的xpath和css选择器&lt;/li>
&lt;/ul>
&lt;p>总之最佳实践是有前提的，不需要一味的去迷信最佳实践,在我们的工作场景中找到最适合自己的最佳实践才是王道。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1473800447596-01729482b8eb?w=300"
 data-srcset="https://images.unsplash.com/photo-1473800447596-01729482b8eb?w=300, https://images.unsplash.com/photo-1473800447596-01729482b8eb?w=300 1.5x, https://images.unsplash.com/photo-1473800447596-01729482b8eb?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1473800447596-01729482b8eb?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>自我隔离期间疯狂上公开课是种什么体验</title><link>https://itest2025.pages.dev/tutorials/47-000-%E8%87%AA%E6%88%91%E9%9A%94%E7%A6%BB%E6%9C%9F%E9%97%B4%E7%96%AF%E7%8B%82%E4%B8%8A%E5%85%AC%E5%BC%80%E8%AF%BE%E6%98%AF%E7%A7%8D%E4%BB%80%E4%B9%88%E4%BD%93%E9%AA%8C/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E8%87%AA%E6%88%91%E9%9A%94%E7%A6%BB%E6%9C%9F%E9%97%B4%E7%96%AF%E7%8B%82%E4%B8%8A%E5%85%AC%E5%BC%80%E8%AF%BE%E6%98%AF%E7%A7%8D%E4%BB%80%E4%B9%88%E4%BD%93%E9%AA%8C/</guid><description>&lt;p>自我隔离期间除了网络偶尔会延迟飙升之外，少了日常2个小时的通勤时间还是令人极度舒适的。&lt;/p>
&lt;p>怎么把这2个小时利用起来呢？我觉得可以给大家多做一些分享。&lt;/p>
&lt;p>说做就做，于是便开始张罗周期性（高频次）的以公开课的形式给大家分享。&lt;/p>
&lt;p>每次分享一个点，不贪多，但求把问题说清楚，让大家能够理解掌握，在日常工作中能用起来，最不济面试的时候听到相关概念不至于露出窘迫而不失礼貌的微笑。&lt;/p>
&lt;p>准备公开课其实比较麻烦，首先是选题，这是要掉头发的。&lt;/p>
&lt;p>然后便是准备内容，为了不翻车，头发也会少一点。&lt;/p>
&lt;p>接下来还要不厌其烦的通知大家，手指头会有点累。&lt;/p>
&lt;p>最后要编辑视频，上传以及各种通知，也是有工作量的。&lt;/p>
&lt;p>作为对重复工作相对抵触的人来说，每次这么搞有点累，不如就在这里一次性说明清楚好了。&lt;/p>
&lt;p>我们基本都是在B站进行直播，我们的B站账号是测试圈TC，和微信公众号同名。&lt;/p>
&lt;p>点击文章最后的【阅读原文】就能到我们的B站主页，有B站账号的同学可以关注我们，没有账号的同学收藏一下就好了。&lt;/p>
&lt;p>公开课1群微信群已经满了，没有加过1群的同学可以加2群，下面是二维码。&lt;/p>
&lt;p>如果二维码失效，可以联系我们的报名妹子加入。下面是她的微信号。&lt;/p>
&lt;p>那么这么多天我们上了哪些公开课呢? 点击文章最后的【阅读原文】可以回看&lt;/p>
&lt;ul>
&lt;li>UI自动化实战：selenium最简项目实战: 用史上最简单的用例编写过程向大家展示了如何快速进行UI自动化测试&lt;/li>
&lt;li>学会就能涨工资？接口自动化测试王道==单元测试框架 + 自动化脚本：接口自动化测试其实并不难&lt;/li>
&lt;li>测试同学必知：测试用例的灵魂——断言：学会给用例注入灵魂&lt;/li>
&lt;li>测试小白也能理解的测试驱动开发实例： 写不完的用例，永远搞不懂的测试驱动开发&lt;/li>
&lt;li>测试同学的核心技能：python单元测试入门：练内功的入门级心法&lt;/li>
&lt;li>测试世界的核心原则——3A原则： 构筑你的测试世界观和职业格局&lt;/li>
&lt;li>只用python3+postman实现接口自动化功能测试用例：只用python核心库也能写接口自动化用例&lt;/li>
&lt;li>python+postman+requests+assert实现接口自动化测试用例：不用测试框架也能凑合写用例&lt;/li>
&lt;li>接口测试环境配置(python + requests)：环境搭建，从入门到放弃的起点&lt;/li>
&lt;li>如何预习python语言：我也忘了是讲啥的了&lt;/li>
&lt;li>乙醇的性能课程之siege性能测试实战：很多年前性能课的一节内容了&lt;/li>
&lt;/ul>
&lt;p>记得点击文章最后的【阅读原文】可以回看哦。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1506773090264-ac0b07293a64?w=300"
 data-srcset="https://images.unsplash.com/photo-1506773090264-ac0b07293a64?w=300, https://images.unsplash.com/photo-1506773090264-ac0b07293a64?w=300 1.5x, https://images.unsplash.com/photo-1506773090264-ac0b07293a64?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1506773090264-ac0b07293a64?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>最近，我把之前的一些测试技能相关视频转移到了B站</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%9C%80%E8%BF%91%E6%88%91%E6%8A%8A%E4%B9%8B%E5%89%8D%E7%9A%84%E4%B8%80%E4%BA%9B%E6%B5%8B%E8%AF%95%E6%8A%80%E8%83%BD%E7%9B%B8%E5%85%B3%E8%A7%86%E9%A2%91%E8%BD%AC%E7%A7%BB%E5%88%B0%E4%BA%86b%E7%AB%99/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%9C%80%E8%BF%91%E6%88%91%E6%8A%8A%E4%B9%8B%E5%89%8D%E7%9A%84%E4%B8%80%E4%BA%9B%E6%B5%8B%E8%AF%95%E6%8A%80%E8%83%BD%E7%9B%B8%E5%85%B3%E8%A7%86%E9%A2%91%E8%BD%AC%E7%A7%BB%E5%88%B0%E4%BA%86b%E7%AB%99/</guid><description>&lt;p>之前录过一些视频放在腾讯视频和腾讯课堂，最近正好发现有些视频过期了，于是顺手就转移到了b站。&lt;/p>
&lt;p>现在转移了下面一些内容，以后会逐步更新。&lt;/p>
&lt;h3 id="接口测试入门postman的简单使用">接口测试入门：postman的简单使用&lt;/h3>
&lt;p>这一系列视频的目的是帮助大家快速的掌握postman简单使用和稍微深度一点的功能。&lt;/p>
&lt;p>其实postman除了是调试工具以外，还可以很方便的帮我们进行一些日常的接口自动化功能，比如postman支持断言，有了断言就有测试的可能，jmeter也是同理。&lt;/p>
&lt;p>这一系列视频花费了不少的精力，有19期，内容也算循序渐进，希望对大家能有所帮助。&lt;/p>
&lt;h3 id="纯粹测试测试杂谈系列视频">纯粹测试：测试杂谈系列视频&lt;/h3>
&lt;p>这一系列视频是之前录制的测试技术杂谈视频，现在发现还是有一些干货的，可以帮助大家扩展一下技术视野。&lt;/p>
&lt;p>由于视频需要重新剪辑，需要花费大量时间，所以尽量每周更新一次。&lt;/p>
&lt;p>另外视频剪辑的技术我也是刚刚尝试，后面我会尽量提升质量，比如背景音乐我会尽量低调一点。&lt;/p>
&lt;h3 id="短小精悍的技术视频">短小精悍的技术视频&lt;/h3>
&lt;p>这是我全新制作的2到10分钟的技术专项小视频，可能就一个小点做快速分享，让大家在最短的时间掌握一些会者不难，难者不会的技能。&lt;/p>
&lt;p>上周录了一个jmeter的使用小技巧，那就是永远都不要用gui模式做性能测试，如果大家对这类视频反馈良好，我会不定期更新。&lt;/p>
&lt;p>现在就点击下面的阅读原文查看吧。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1470164971321-eb5ac2c35f2e?w=300"
 data-srcset="https://images.unsplash.com/photo-1470164971321-eb5ac2c35f2e?w=300, https://images.unsplash.com/photo-1470164971321-eb5ac2c35f2e?w=300 1.5x, https://images.unsplash.com/photo-1470164971321-eb5ac2c35f2e?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1470164971321-eb5ac2c35f2e?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>最中二的性能测试工具--vegeta</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%9C%80%E4%B8%AD%E4%BA%8C%E7%9A%84%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7--vegeta/</link><pubDate>Tue, 17 Jun 2025 17:29:15 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%9C%80%E4%B8%AD%E4%BA%8C%E7%9A%84%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7--vegeta/</guid><description>&lt;p>在github上翻到一个项目，名字叫vegeta，看到这个单词，你的第一反应是什么？&lt;/p>
&lt;p>说来惭愧，我的第一反应是这个单词很奇怪，并不认识。&lt;/p>
&lt;p>直到我往下翻，看到了这样一幅场景。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://camo.githubusercontent.com/faf9be097f4731212debdd24210c750b2dc276d0a17df19c6a8ac026427c09e9/687474703a2f2f666330392e64657669616e746172742e6e65742f667334392f692f323030392f3139382f632f632f73736a325f7665676574615f62795f7472756e6b7332342e6a7067"
 data-srcset="https://camo.githubusercontent.com/faf9be097f4731212debdd24210c750b2dc276d0a17df19c6a8ac026427c09e9/687474703a2f2f666330392e64657669616e746172742e6e65742f667334392f692f323030392f3139382f632f632f73736a325f7665676574615f62795f7472756e6b7332342e6a7067, https://camo.githubusercontent.com/faf9be097f4731212debdd24210c750b2dc276d0a17df19c6a8ac026427c09e9/687474703a2f2f666330392e64657669616e746172742e6e65742f667334392f692f323030392f3139382f632f632f73736a325f7665676574615f62795f7472756e6b7332342e6a7067 1.5x, https://camo.githubusercontent.com/faf9be097f4731212debdd24210c750b2dc276d0a17df19c6a8ac026427c09e9/687474703a2f2f666330392e64657669616e746172742e6e65742f667334392f692f323030392f3139382f632f632f73736a325f7665676574615f62795f7472756e6b7332342e6a7067 2x"
 data-sizes="auto"
 alt="https://camo.githubusercontent.com/faf9be097f4731212debdd24210c750b2dc276d0a17df19c6a8ac026427c09e9/687474703a2f2f666330392e64657669616e746172742e6e65742f667334392f692f323030392f3139382f632f632f73736a325f7665676574615f62795f7472756e6b7332342e6a7067"
 title="https://camo.githubusercontent.com/faf9be097f4731212debdd24210c750b2dc276d0a17df19c6a8ac026427c09e9/687474703a2f2f666330392e64657669616e746172742e6e65742f667334392f692f323030392f3139382f632f632f73736a325f7665676574615f62795f7472756e6b7332342e6a7067" />&lt;/p>
&lt;p>这&amp;hellip;&amp;hellip;这不是儿时的回忆，七龙珠里的天字第一号配角，贝吉塔么？&lt;/p>
&lt;p>贝吉塔，日本漫画及改编动画《龙珠》系列中的主要角色。是战斗民族赛亚人的王子，拥有极高的自尊心。过去贝吉塔行星被弗利萨毁灭后（不知情，一直以为是被陨石撞击而毁灭。）在弗利萨军团那儿做事。初登场时是个侵略地球的反派角色，后被孙悟空（赛亚人卡卡罗特）等人打败。弗利萨一战结束后听说悟空成为超级赛亚人，于是决定以超越悟空为目标，一直留在地球上努力修行。
多次和悟空保护地球。在人造人篇中学会了超级赛亚人变身，起初只是想着超越悟空才呆在地球，后来有了家人后慢慢的爱上了这颗星球，在与布欧一战中为了保护地球决定与布欧同归于尽。后复活为悟空制造元气弹争取时间，击败布欧后仍为了超越悟空而努力修行。&lt;/p>
&lt;p>贝吉塔（Vegeta）与其弟弟塔布尔（Table）的名字合二为一（英文名）就是Vegetable（蔬菜）&lt;/p>
&lt;p>上面的描述来自百度百科，所以贝吉塔在漫画中是一个出道即巅峰，登场超强，然后一直被悟空超越，并且打不过就加入你的角色。&lt;/p>
&lt;p>可能对于很多读者来说，七龙珠这个上古漫画其实是熟悉而又陌生的，名字都听过，但至于漫画主要讲了什么，大家可能并不清楚。不过对于我这种老古董来说，七龙珠就意味着童年闲暇时愉快的阅读时光以及无数次的练习冲击波以求有朝一日能拯救地球的中二幻想。&lt;/p>
&lt;p>怀着强烈的好奇心，我真心希望看看这个中二又复古的项目究竟是做什么的。&lt;/p>
&lt;p>经过几分钟的探索，我发现vegeta其实是一个用go实现的性能测试工具，江湖上各种性能工具可谓是灿若星河，那么vegeta凭什么可以获得16.3k的star呢？&lt;/p>
&lt;p>可能是因为名字，毕竟github上的中老年宅男还是非常多的。&lt;/p>
&lt;p>不过玩笑归玩笑，作为性能测试工具，vegeta有个很不错的特性，那就是可以默认以一定的qps对被测服务进行压测。&lt;/p>
&lt;h3 id="固定qps的使用场景">固定qps的使用场景&lt;/h3>
&lt;p>比如我们经常需要对某个微服务进行单实例的容量评估，我们希望某个服务A他能承受的最大QPS是1000，这时候我们就需要有一个工具能持续产生1000qps的负载进行一段时间的压测，这段时间里，我们可能通过监控系统的核心指标来判断系统的健康度和稳定性，vegeta看上去是可以满足这个场景下的压测需求的。&lt;/p>
&lt;h3 id="安装">安装&lt;/h3>
&lt;p>vegeta只支持linux以及mac系统，不支持windows。&lt;/p>
&lt;p>vegeta只是一个可执行文件，所以直接下载就好了，下载地址是：https://github.com/tsenart/vegeta/releases&lt;/p>
&lt;h3 id="简单的使用">简单的使用&lt;/h3>
&lt;p>通过命令行使用，命令如下&lt;/p>
&lt;pre tabindex="0">&lt;code>echo &amp;#34;GET http://localhost:8080/api/articles/&amp;#34; | ./vegeta attack -duration=10s| tee results.bin | ./vegeta report
&lt;/code>&lt;/pre>&lt;p>执行结果&lt;/p>
&lt;pre tabindex="0">&lt;code>Requests [total, rate, throughput] 500, 50.10, 50.10
Duration [total, attack, wait] 9.981s, 9.98s, 610.816µs
Latencies [min, mean, 50, 90, 95, 99, max] 310.733µs, 549.662µs, 522.345µs, 706.005µs, 814.544µs, 912.57µs, 3.088ms
Bytes In [total, mean] 16500, 33.00
Bytes Out [total, mean] 0, 0.00
Success [ratio] 100.00%
Status Codes [code:count] 200:500 
&lt;/code>&lt;/pre>&lt;p>看到这个结果我不禁陷入了深思，因为qps实在是太低了。&lt;/p></description></item><item><title>这样的面试你能通过吗</title><link>https://itest2025.pages.dev/tutorials/47-000-%E8%BF%99%E6%A0%B7%E7%9A%84%E9%9D%A2%E8%AF%95%E4%BD%A0%E8%83%BD%E9%80%9A%E8%BF%87%E5%90%97/</link><pubDate>Thu, 13 Jun 2019 11:49:49 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E8%BF%99%E6%A0%B7%E7%9A%84%E9%9D%A2%E8%AF%95%E4%BD%A0%E8%83%BD%E9%80%9A%E8%BF%87%E5%90%97/</guid><description>&lt;p>近两周我的面试非常多，大概一天一个。我是二面面试官，一面是技术面，有一定的难度。按道理来说二面的通过率应该比较高才对，不过最近的二面通过率可能不到50%，一面的通过率一般比较稳定保持在30%以下，所以两面全过的概率大概只有15%左右，可能更低。&lt;/p>
&lt;p>那么二面的通过率为什么那么低呢？我想举几个例子就可以说明了。&lt;/p>
&lt;p>二面我一般都会问一道用例设计题，大概是给你一袋盐，或者给你一件衣服，写出一些测试用例。&lt;/p>
&lt;p>我的心理预期是15个可执行的用例。&lt;/p>
&lt;p>有的候选人是这么回答的。&lt;/p>
&lt;p>假如是一袋盐，那么要看看装盐的袋子是不是会漏？&lt;/p>
&lt;p>这时候我一般会反问，那应该是要漏还是不要漏？很多候选人这时候会愣住，可能完全意识不到我为什么会这么问。&lt;/p>
&lt;p>我这么问是因为我有个怪癖，那就是我希望测试用例都是可以执行的。可以执行的意思是，你要告诉我你究竟是希望袋子漏还是不漏。如果你希望袋子是不漏的，那么袋子漏的时候测试用例就是不通过的，反之也成立。如果你告诉我看看袋子漏不漏，那么因为我是很笨的，我不知道如何去执行这个用例，因为我不知道袋子究竟是需要漏呢还是不能漏。&lt;/p>
&lt;p>与之类似的，在测试衣服的时候，有的候选人会回答要看衣服的尺码是不是合适。那么我会反问，对于L号，衣服多长是合适，多长又是不合适呢？这是因为合适不合适是没有执行标准的，对于一个身高不高的人——比如1米49家穷人丑的我——来说，L号是不合适的，太长了。而对于身材匀称的其他人来说，L应该是合适的。所以合不合适没法量化，加上又有模棱两可的&lt;strong>是不是&lt;/strong>这样的词语推波助澜，这种用例执行起来是相当困难的。&lt;/p>
&lt;p>所以写用例，要想可执行，首先的第一条原则是，不要包含一些似是而非的词语，比如是不是，要不要，有没有之类的。换句话说，就是用例里大概率要么包含是，要么包含不是这样的词。&lt;/p>
&lt;p>比如&lt;/p>
&lt;ul>
&lt;li>装盐的袋子不能（不是）漏&lt;/li>
&lt;li>衣服的颜色是红的&lt;/li>
&lt;li>衣服的材料是80%的棉，20%的涤纶&lt;/li>
&lt;/ul>
&lt;p>像这样的是或者不是的句型，我们可以称之为断言。&lt;/p>
&lt;p>上面是最基本的用例设计，主要考察的是思维的全面程度，以及设计用例的最基本要求——可以执行，没有歧义。另外我还喜欢根据候选人的经历去问一些稍微有技术深度的问题。&lt;/p>
&lt;p>如果有候选人有性能测试的经验，那么我会问他关于他被测系统的系统架构问题，架构图起码大致要能画出来。这是因为如果不了解系统的架构，那么测试环境搭建，测试策略的选择都会难以下手，测试的结果也比较难有可信度。&lt;/p>
&lt;p>如果候选人的简历上写有精通/熟悉mysql调优，那么我就会问为什么mysql用主键去查询会很快？mysql的主键和数据都是怎么存储的？能不能画一下mysql的B+树的大体结构？什么是联合索引？给你几个真实的例子，你能告诉我索引命中的情况不？这些问题其实做过mysql性能调优的同学应该大体都会，没做过的话可能就是强人锁男了。&lt;/p>
&lt;p>简历上写精通python的同学我大概率会让他在现场写一个生成器的例子，并介绍一下生成器的主要应用场景。写精通selenium测试的候选人我会随便开个网页，指定个元素让其当场定位。写精通appium的同学我会让其解释appium协议与webdriver协议最大的不同点。诸如此类，在兼顾考察广度的情况下顺便考察深度。&lt;/p>
&lt;p>看上去是不是很难？&lt;/p>
&lt;p>其实不然。基本上我不是很关注候选人技术深度题有没有答出来，如果是二面的话。大部分情况下，候选人无法通过面试的原因大抵都是用例设计能力不过关。要么设计的不够全面，要么就是基本没有可执行性。&lt;/p>
&lt;p>技术不好的话其实是可以教的，用例设计的不好那么入职以后可能还没等到好好教就出线上问题了。&lt;/p>
&lt;p>写好每一条用例，大概应该是很多测试同学厚积薄发的第一步吧。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1450101215322-bf5cd27642fc?w=300"
 data-srcset="https://images.unsplash.com/photo-1450101215322-bf5cd27642fc?w=300, https://images.unsplash.com/photo-1450101215322-bf5cd27642fc?w=300 1.5x, https://images.unsplash.com/photo-1450101215322-bf5cd27642fc?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1450101215322-bf5cd27642fc?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>还是少背锅吧--聊聊线上监控</title><link>https://itest2025.pages.dev/tutorials/47-000-%E8%BF%98%E6%98%AF%E5%B0%91%E8%83%8C%E9%94%85%E5%90%A7--%E8%81%8A%E8%81%8A%E7%BA%BF%E4%B8%8A%E7%9B%91%E6%8E%A7/</link><pubDate>Wed, 03 Apr 2019 02:10:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E8%BF%98%E6%98%AF%E5%B0%91%E8%83%8C%E9%94%85%E5%90%A7--%E8%81%8A%E8%81%8A%E7%BA%BF%E4%B8%8A%E7%9B%91%E6%8E%A7/</guid><description>&lt;p>之前应该有写文章探讨过测试左右移的问题。&lt;/p>
&lt;p>左移大致就是在设计的时候，写代码之前先把问题考虑清楚，尽量减少一些伪需求和自相矛盾的需求，要求测试同学有较大的业务能力。&lt;/p>
&lt;p>右移就是上线之后通过监控等手段去提前感知线上的问题，争取在大部分用户发现问题之前就感知到问题并且快速修复和发布，没有被用户抓住的问题其实影响范围是有限的，可以想办法消化掉。&lt;/p>
&lt;p>从软件测试的生命周期上看，大部分项目可能都会经历发布上线和线上运行/运营的阶段，从绩效层面上看，线上问题对绩效的影响是很大的，起码从感觉上来说是这样的。比如某测试同学工作兢兢业业勤勤恳恳，但是由于某天线上出了一个很严重的问题，造成了经济损失，通过回溯和复盘，发现该测试人员应该负主要责任，如果你是他的上级，你会怎么评估他的绩效呢？是采取人非圣贤孰能无过，知错能改善莫大焉的态度，还是因为严重的线上问题全盘否定他的付出呢？一般来说，你可能会采取比较中庸的做法，事故责任是要承担的，但瑕不掩瑜，还是会有值得肯定的地方。这时候往往就是把大锅分成一个一个的小锅，找人一起背。不过测试是甩锅链中比较弱势的一环，也是背锅链中首当其冲的一环，还是要有比较强的求生欲以及良好的心理素质才可以。&lt;/p>
&lt;p>把线上监控做完备是求生欲强的表现之一。&lt;/p>
&lt;p>简单起见，我们把线上监控分为3种类型，分别是业务级，服务级和硬件级的监控。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>业务级。业务级的监控需要大家去定义一些核心的业务指标，然后对指标进行监控，如果指标有异常那么争取迅速定位问题，将业务重新推上正轨。拿电商业务举例，核心指标可能是订单量，假如平时下午2点到3点左右的平均单量是1000，但今天只有100，那么应该是哪里出了问题，需要迅速去定位和排查。如果订单数直接掉到0，那么可能是订单服务不可用或者整站都挂掉了。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>服务级。比如订单服务一共有10个接口，那么每个接口的调用次数，成功率，返回速度等。服务级的指标可以分的很细，每个团队每种业务都有不同的服务级指标的着重点。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>硬件级。这个比较好理解。比如可以看到某台服务器的cpu内存网卡等指标。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="谁来做">谁来做&lt;/h3>
&lt;p>监控谁来做是个老生常谈的问题。一般来业务级监控需要测试+产品+运维的同学一起来做，运维可以主导，测试同学可以辅助验证或验收。服务级的监控可以由开发+运维+测试来做。硬件级可以由运维同学主导。&lt;/p>
&lt;h3 id="3层是不是都要做">3层是不是都要做&lt;/h3>
&lt;p>一般来说3层都做的话是比较好的。比如业务级监控发现了订单量异常，然后通过服务级监控发现订单服务的库存接口调用失败率很高，导致订单无法正常创建，最后通过硬件层监控发现库存服务的硬件服务器磁盘io异常，从而可以快速定位到问题，迅速修复。&lt;/p>
&lt;p>如果没有精力把3层都做全的话，可以先做业务级，至上而下把3层逐步建设好。因为业务级的监控往往非常直观，有锅自远方来可以一目了然，做好业务层监控可以提高一些存活率，不过如果想把线上问题的影响降到最低，另2层也是需要建设完备的。&lt;/p>
&lt;h3 id="并不是所有的问题都可以监控到">并不是所有的问题都可以监控到&lt;/h3>
&lt;p>有时候我们并不是所有的问题都可以监控到，或者有一些监控的指标由于跨部门，或调用第三方服务的关系，我们没办法拿到我们想要的核心指标或数据。这时候我们可能需要模拟线上用户的一些具体操作去感知问题。举个例子，目前订单系统支持微信支付和支付宝支付，默认情况下展示的是微信支付的链接。我们可以通过在线上真实下单的方式(自动化测试的手段)去调用微信支付接口，如果可以正常走完流程，那么微信支付应该是没有问题的，如果走不通流程，那么微信支付可能暂时不可用，我们可以迅速把默认支付方式切成支付宝，这样可能对订单量不会造成特别大的影响。&lt;/p>
&lt;h3 id="告警">告警&lt;/h3>
&lt;p>监控往往跟告警结合起来，比如我们可以设置高峰期每十分钟的订单量如果小于100就通知相关人员进行故障排查。告警往往需要非常精准，因为如果老是误报，那么大家可能会习惯性的忽略告警信息，导致告警形同虚设，那就是狼来了的故事了。&lt;/p>
&lt;p>综上希望对大家有所帮助，另外作者水平有限能力一般，有问题还请斧正。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1482938289607-e9573fc25ebb?w=300"
 data-srcset="https://images.unsplash.com/photo-1482938289607-e9573fc25ebb?w=300, https://images.unsplash.com/photo-1482938289607-e9573fc25ebb?w=300 1.5x, https://images.unsplash.com/photo-1482938289607-e9573fc25ebb?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1482938289607-e9573fc25ebb?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>如何提升测试水平</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%A6%82%E4%BD%95%E6%8F%90%E5%8D%87%E6%B5%8B%E8%AF%95%E6%B0%B4%E5%B9%B3/</link><pubDate>Sun, 06 Jan 2019 10:20:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%A6%82%E4%BD%95%E6%8F%90%E5%8D%87%E6%B5%8B%E8%AF%95%E6%B0%B4%E5%B9%B3/</guid><description>&lt;p>有同学在公众号留言问如何提升测试技能，这里抛砖引玉给一下个人不成熟的建议，大家见仁见智，欢迎讨论。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://ww1.sinaimg.cn/large/726a2979gy1fz1d2pfad2j20zk0nw49a.jpg"
 data-srcset="http://ww1.sinaimg.cn/large/726a2979gy1fz1d2pfad2j20zk0nw49a.jpg, http://ww1.sinaimg.cn/large/726a2979gy1fz1d2pfad2j20zk0nw49a.jpg 1.5x, http://ww1.sinaimg.cn/large/726a2979gy1fz1d2pfad2j20zk0nw49a.jpg 2x"
 data-sizes="auto"
 alt="http://ww1.sinaimg.cn/large/726a2979gy1fz1d2pfad2j20zk0nw49a.jpg"
 title="http://ww1.sinaimg.cn/large/726a2979gy1fz1d2pfad2j20zk0nw49a.jpg" />&lt;/p>
&lt;h3 id="熟悉业务">熟悉业务&lt;/h3>
&lt;p>让人称赞和放心的测试同学往往对业务是非常熟悉的，知道自己的业务在干啥，知道业务的商业逻辑和非商业逻辑，其实对于测试同学来说是蛮重要的。&lt;/p>
&lt;p>熟悉业务的方式有很多，一般来说刚接触到新项目/新产品的同学往往会先体验一下产品，把这个产品的功能先点一遍，就当作是熟悉业务了。这样做没什么不对，不过有点不够深入，不理解产品的设计逻辑。理解了产品的设计逻辑才能更好的贯通整个产品的各个模块，真正做到精通。&lt;/p>
&lt;p>在熟悉业务的时候，我们可以问自己下面的一些问题。&lt;/p>
&lt;ul>
&lt;li>用户想要什么？用户的原始需求是什么？有些产品可能用户是没有直接需求的，完全是通过产品去创造需求的，这样的产品原始需求可能会比较模糊，理解起来会有点难度。还有些产品是直接照搬或者高仿友商的，理解这些产品的原始需求可能就要深入理解竞品了。&lt;/li>
&lt;li>我们提供了什么功能？为什么？这是我们自己产品的逻辑了，用户的需求我们可以一步一步慢慢去满足，先实现哪些后实现哪些，这些逻辑我们也要搞明白。另外有时候实现用户的需求成本很高，因为成本的原因我们可能提供一些有损或者折中的方案，这种逻辑也是测试同学所需要了解的。&lt;/li>
&lt;li>赢利点在哪里？这个比较难，我们靠什么赚钱？这个老板会比较关心，但是测试同学最好也关心一下，毕竟赚钱的地方往往是最最严重的缺陷发生的地方。电商平台的支付如果出了问题，那么这个事故的严重程度大部分情况下是最高的。福兮祸之所倚，祸兮福之所伏。&lt;/li>
&lt;li>有没有运营数据？运营数据怎么样？运营数据反应了线上的真实情况，能帮助我们更好的理解用户的行为，从而改进用例的优先级以及设计更加直击痛点的用例。&lt;/li>
&lt;/ul>
&lt;h3 id="了解实现">了解实现&lt;/h3>
&lt;p>我们的系统是怎么样实现的？代码的逻辑是什么？代码出错以后的异常处理是怎么样的？这些问题我们最好能多少了解一点。&lt;/p>
&lt;p>如果大家对上面的问题感到棘手，那么可以思考另外几个问题，其实也是殊途同归。&lt;/p>
&lt;ul>
&lt;li>数据库每个库每张表是做什么的？每个表的每个字段是做什么用的？关联关系是什么？(如果是关系型数据库的话)&lt;/li>
&lt;li>系统有没有用到缓存？缓存里存些什么数据？这些数据会不会过期？过期策略是什么？&lt;/li>
&lt;li>有哪些定时任务在跑？为什么要跑定时/延时任务?&lt;/li>
&lt;/ul>
&lt;p>把上面一些问题弄明白了的话，在面试的时候也是有一定好处的。&lt;/p>
&lt;h3 id="了解架构">了解架构&lt;/h3>
&lt;p>一般来说我们需要了解逻辑架构和运维架构。比如逻辑架构里的一些微服务模块，每个微服务的功能是什么，怎么跟其他微服务交互的，完全从逻辑的角度去看。&lt;/p>
&lt;p>运维架构可能涉及的点会多一点，比如用户微服务部署了2个实例，负载均衡用的是xxx，如何动态扩容之类的。&lt;/p>
&lt;p>这些在面试的时候是很好的谈资，很容易加分。&lt;/p>
&lt;h3 id="掌握专项">掌握专项&lt;/h3>
&lt;p>功能测试的话开发也会测，产品也能测，看上去并不是什么特别专业的技能。&lt;/p>
&lt;p>专项的话呢，开发可能要学一下才能会，产品可能一时半会学不会，嗯，终于有了点领域独占的优势，是大家提升技能时可以重点考虑的部分。&lt;/p>
&lt;ul>
&lt;li>性能专项。服务器性能比较有技术含量的。&lt;/li>
&lt;li>移动端专项。移动端的性能稳定性等。&lt;/li>
&lt;li>自动化专项。ui自动化和接口自动化了。&lt;/li>
&lt;li>安全专项。我也不会，白话不出来。&lt;/li>
&lt;li>监控专项。各种监控也是很有意思的。&lt;/li>
&lt;/ul>
&lt;p>好了，以上就是我的一些非常不成熟的见解，有些应该是臆断，求同存异，希望对你能有所帮助。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1470770841072-f978cf4d019e?w=300"
 data-srcset="https://images.unsplash.com/photo-1470770841072-f978cf4d019e?w=300, https://images.unsplash.com/photo-1470770841072-f978cf4d019e?w=300 1.5x, https://images.unsplash.com/photo-1470770841072-f978cf4d019e?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1470770841072-f978cf4d019e?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>你是怎么样跑测试用例的呢</title><link>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%A0%E6%98%AF%E6%80%8E%E4%B9%88%E6%A0%B7%E8%B7%91%E6%B5%8B%E8%AF%95%E7%94%A8%E4%BE%8B%E7%9A%84%E5%91%A2/</link><pubDate>Tue, 01 Jan 2019 10:10:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%A0%E6%98%AF%E6%80%8E%E4%B9%88%E6%A0%B7%E8%B7%91%E6%B5%8B%E8%AF%95%E7%94%A8%E4%BE%8B%E7%9A%84%E5%91%A2/</guid><description>&lt;p>大家应该都有过写测试用例的经历。&lt;/p>
&lt;p>我的经历大概是这样的。&lt;/p>
&lt;p>十多年之前刚入行的时候是用excel写用例。大概就是往模版里填充一些必填字段，比如用例编号，名称，步骤，预期等等。那时候啥都不懂，预期里基本上是随心写，填的都是&amp;quot;应该正常执行&amp;quot;, &amp;ldquo;结果应该正确&amp;quot;之类的写了等于没写的话语，无非就把格子填满，显得很有工作量的样子。执行用例的时候基本上是看需求文档，自己写的用例也不看，测完了就无脑打勾，显得工作是按时按量完成了的。&lt;/p>
&lt;p>后来很多年用例管理也一直没有改善，无非就是excel换模版，然后用打勾的形式去表明工作已经完成。这是手工执行的方式。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://ww1.sinaimg.cn/large/726a2979gy1fyue5jsrr3j20zy0f9wf4.jpg"
 data-srcset="http://ww1.sinaimg.cn/large/726a2979gy1fyue5jsrr3j20zy0f9wf4.jpg, http://ww1.sinaimg.cn/large/726a2979gy1fyue5jsrr3j20zy0f9wf4.jpg 1.5x, http://ww1.sinaimg.cn/large/726a2979gy1fyue5jsrr3j20zy0f9wf4.jpg 2x"
 data-sizes="auto"
 alt="http://ww1.sinaimg.cn/large/726a2979gy1fyue5jsrr3j20zy0f9wf4.jpg"
 title="http://ww1.sinaimg.cn/large/726a2979gy1fyue5jsrr3j20zy0f9wf4.jpg" />&lt;/p>
&lt;p>也经历过很长一段时间用自动化的方式去运行用例的情况，这时候用例基本是代码，代码是经常要去更新的，以便增强稳定性和更新业务逻辑。这时候报告和日志比较重要，因为跑出问题之后需要通过报告和日志迅速去定位问题，提bug或者再人肉验证一下。&lt;/p>
&lt;p>再后来便是开发了一些测试用例的管理系统，自己用起来还行，无非就是把excel填格子的过程改成了从网页上填表单，但是推广的时候遇到了很大的阻力，毕竟大家还是习惯于用excel去管理，在写好了execl之后导入到系统里，整个系统除了执行的时候可以体现用例状态之外，其他的话意义不是很明显，而且很多时候，用例的执行状态并不是大家关注的重点，所以用例管理系统后来也没太多任用，荒废掉了。&lt;/p>
&lt;p>近些年很多同学用脑图的方式来管理测试用例，等于就是把需求换个维度整理了一番，变成了一个个的场景或者检查点，测试的时候可以对照着检查点来，比excel有不错的提升，可以推荐大家试一下。&lt;/p>
&lt;p>脑图其实是整理+记录的过程，很像是我们之前初高中时候老师写的板书，好发散，格式比填格子灵活。我建议可以不用在脑图里写预期结果，执行完成之后再补充也行。&lt;/p>
&lt;p>写脑图可以用场景导向，枚举大部分的异常场景可能会比较的有价值。&lt;/p>
&lt;p>如果写了用例但是测试的时候不去对照着看或者执行，那么写不写都无所谓了。真正有价值的用例可能是&lt;/p>
&lt;ul>
&lt;li>自己测试的时候会去对照着看或执行&lt;/li>
&lt;li>大家都能看懂&lt;/li>
&lt;li>保持跟最新的需求同步&lt;/li>
&lt;/ul>
&lt;p>最后给一张最近关注度比较高的个税脑图，这个图基本上算是非常全面的测试检查点了，大家可以参考一下。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://ww1.sinaimg.cn/large/726a2979gy1fyudscuvtgj20nr0zkjto.jpg"
 data-srcset="http://ww1.sinaimg.cn/large/726a2979gy1fyudscuvtgj20nr0zkjto.jpg, http://ww1.sinaimg.cn/large/726a2979gy1fyudscuvtgj20nr0zkjto.jpg 1.5x, http://ww1.sinaimg.cn/large/726a2979gy1fyudscuvtgj20nr0zkjto.jpg 2x"
 data-sizes="auto"
 alt="http://ww1.sinaimg.cn/large/726a2979gy1fyudscuvtgj20nr0zkjto.jpg"
 title="http://ww1.sinaimg.cn/large/726a2979gy1fyudscuvtgj20nr0zkjto.jpg" />&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1471978445661-ad6ec1f5ba50?w=300"
 data-srcset="https://images.unsplash.com/photo-1471978445661-ad6ec1f5ba50?w=300, https://images.unsplash.com/photo-1471978445661-ad6ec1f5ba50?w=300 1.5x, https://images.unsplash.com/photo-1471978445661-ad6ec1f5ba50?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1471978445661-ad6ec1f5ba50?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>自动化测试如何准备测试数据</title><link>https://itest2025.pages.dev/tutorials/47-000-%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E5%A6%82%E4%BD%95%E5%87%86%E5%A4%87%E6%B5%8B%E8%AF%95%E6%95%B0%E6%8D%AE/</link><pubDate>Thu, 22 Nov 2018 11:10:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E5%A6%82%E4%BD%95%E5%87%86%E5%A4%87%E6%B5%8B%E8%AF%95%E6%95%B0%E6%8D%AE/</guid><description>&lt;p>其实大部分类型的测试都需要去准备测试数据。&lt;/p>
&lt;ul>
&lt;li>手工测试：一些基础数据，比如配置数据等等是需要去准备的；&lt;/li>
&lt;li>自动化测试：基础需要准备，现有数据，动态运行时产生的数据是需要准备的；&lt;/li>
&lt;li>性能测试：跟自动化测试差不多；&lt;/li>
&lt;/ul>
&lt;p>这里就牵扯到了一些关于数据的概念了。&lt;/p>
&lt;h3 id="测试数据的分类">测试数据的分类&lt;/h3>
&lt;p>我们可以给测试数据分一些种类&lt;/p>
&lt;ul>
&lt;li>基础数据，比如一些内容管理系统会配置站点的标题，友情链接之类的基础配置数据&lt;/li>
&lt;li>存量数据，也就是现有数据。比如在测试一些电商站点的时候会提前插入一些商品信息，类目信息物流信息等&lt;/li>
&lt;li>动态数据，也可以叫做session数据。比如在测试电商站点的发布商品功能的时候，往往会去创建一些新的商品&lt;/li>
&lt;/ul>
&lt;p>我们可以想象到，基础数据其实可以比较容易的跟生产环境保持一致。测试环境的存量数据会比线上环境要少，测试环境的动态数据可能不会像线上环境那样真实。&lt;/p>
&lt;p>这里就需要讨论测试数据的量级和真实性的问题了。&lt;/p>
&lt;h3 id="测试数据的量级">测试数据的量级&lt;/h3>
&lt;p>大部分情况下，测试数据的量级是没有产生环境多的。所以测试数据可以是真实数据的子集。&lt;/p>
&lt;p>如果有类生产环境或预发布环境的话，可以尽量保持跟线上数据相当的量级。这样一些测试环境不好测出来的由于数据量导致的问题可以在预发布环境测出来。&lt;/p>
&lt;h3 id="测试数据的真实性">测试数据的真实性&lt;/h3>
&lt;p>我们测试环境的数据往往跟真实用户产生的数据是有差异的。比如测试论坛系统时，我们在帖子里的贴图可能往往就那么几张，尺寸也是恰到好处，而线上用户的贴图可能是五花八门，从而导致意想不到的问题。&lt;/p>
&lt;h3 id="如何准备基础和存量数据">如何准备基础和存量数据&lt;/h3>
&lt;p>基础和存量数据与线上环境越一致，测试中发现问题的概率可能就越高。一般来说，可以有下面的策略&lt;/p>
&lt;ul>
&lt;li>全量+脱敏策略。直接定期把线上的数据做脱敏，导入到测试环境。这里脱敏是必选，数据泄漏导致的问题严重程度往往比普通的线上bug要严重得多。&lt;/li>
&lt;li>定量+脱敏策略。只上一些线上数据，比如只在线上拉1000个商品，1000个用户信息，然后做脱敏。这里技术实现难度会比较高，毕竟要把关联表理顺。&lt;/li>
&lt;li>爬虫策略。如果是新项目/产品的话，线上没有存量数据可以导，那么可能要去友商那里爬一些数据，导到测环境做测试。比如做一个旅游站点，开始的时候是没有用户的游记的，这时候就要去类似站点爬一点来测试了。&lt;/li>
&lt;li>生成动态数据。如果线上没有数据，友商也没有的爬，那么就要人肉或者自动化的方式去产生一些数据了。系统简单的话可以用sql去跑，复杂点的话可能要调用接口或者用自动化的方式去生成。实在没辙的时候也可以手动去造一些数据。&lt;/li>
&lt;/ul>
&lt;h3 id="关于动态数据">关于动态数据&lt;/h3>
&lt;p>大家在做自动化或者接口测试后往往会大量的去产生动态数据。那么问题就来了。&lt;/p>
&lt;p>这些数据存在哪里？什么意思呢？如果我们需要用自动化的方式去创建一个商品，那么商品的信息，图片地址该放在哪里呢？其实这是个持久化的问题了。&lt;/p>
&lt;ul>
&lt;li>放文件里。文件格式有很多可以选的，比如xml/csv/json/yaml等。不过不推荐excel，毕竟是私有格式，没有太强的扩展性。而且excel一升级，你的解析代码和库也可能要跟着改一次，嗯，强烈不推荐了。&lt;/li>
&lt;li>放数据库里。爬一些商品的信息存到数据库里，然后读数据库也是很好的办法，还能熟悉一下sql的用法，面试经常问到，另外可以用数据库的事务机制来清理测试数据&lt;/li>
&lt;li>在代码里动态生成。比如动态随机生成用户的姓名啊性别和年龄之类的&lt;/li>
&lt;/ul>
&lt;p>数据生成之后就面临着一个清理的问题。清理问题实际上数据生命周期的问题，测试数据应该有下面一些生命周期吧&lt;/p>
&lt;ul>
&lt;li>短期数据。用例完了就删掉的数据，一般线上做性能测试的数据都是这样的短期数据&lt;/li>
&lt;li>长期数据。用例跑出来的数据放在那里也没事，可以一直存在。这种数据太多有时候会影响测试环境的性能&lt;/li>
&lt;/ul>
&lt;p>自动化测试跑出的数据建议做短期数据，跑出来想办法清掉，因为自动化跑的频率其实可以很高，每次都产生一堆数据的话数据的量级可能会在短期变得很大，对测试环境的性能造成影响。&lt;/p>
&lt;p>以上的一些看法是个人的浅显的粗鄙的看法，肯定有很多不成熟的地方，欢迎大家斧正。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1476610182048-b716b8518aae?w=300"
 data-srcset="https://images.unsplash.com/photo-1476610182048-b716b8518aae?w=300, https://images.unsplash.com/photo-1476610182048-b716b8518aae?w=300 1.5x, https://images.unsplash.com/photo-1476610182048-b716b8518aae?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1476610182048-b716b8518aae?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>如何测试安全漏洞</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%A6%82%E4%BD%95%E6%B5%8B%E8%AF%95%E5%AE%89%E5%85%A8%E6%BC%8F%E6%B4%9E/</link><pubDate>Thu, 15 Nov 2018 02:16:58 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%A6%82%E4%BD%95%E6%B5%8B%E8%AF%95%E5%AE%89%E5%85%A8%E6%BC%8F%E6%B4%9E/</guid><description>&lt;p>这是2002年FreeBSD系统的一个安全漏洞。&lt;/p>
&lt;p>当时一些开发人员意识到&lt;code>getpeername&lt;/code>库的某个实现可能会隐藏致命的安全漏洞。&lt;/p>
&lt;p>下面的代码简单的还原了漏洞的发生过程。&lt;/p>
&lt;pre tabindex="0">&lt;code>1 /*
2 * Illustration of code vulnerability similar to that found in
3 * FreeBSD’s implementation of getpeername()
4 */
5
6 /* Declaration of library function memcpy */
7 void *memcpy(void *dest, void *src, size_t n);
8
9 /* Kernel memory region holding user-accessible data */
10 #define KSIZE 1024
11 char kbuf[KSIZE];
12
13 /* Copy at most maxlen bytes from kernel region to user buffer */
14 int copy_from_kernel(void *user_dest, int maxlen) {
15 /* Byte count len is minimum of buffer size and maxlen */
16 int len = KSIZE &amp;lt; maxlen ? KSIZE : maxlen;
17 memcpy(user_dest, kbuf, len);
18 return len;
19 }
&lt;/code>&lt;/pre>&lt;p>&lt;code>int copy_from_kernel(void *user_dest, int maxlen)&lt;/code>方法的作用是将系统内核中的大小为maxlen的内存拷贝到用户内存里。在系统运行时，用户进程是没有权限访问系统内核的内存的，该方法等于是为用户进程开了个小后门，使得用户进程可以访问最大KSIZE大小的系统内核内存。由于系统内核内存中有很多运行时的敏感信息，所以该方法做了最大KSIZE大小内存的的限制，这是有道理的。但如果用户访问了任意大小的内核内存，那么系统敏感信息将会暴露，这将为不怀好意的攻击者提供足够多的入侵信息。&lt;/p></description></item><item><title>是时候为明年的面试做准备了</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%98%AF%E6%97%B6%E5%80%99%E4%B8%BA%E6%98%8E%E5%B9%B4%E7%9A%84%E9%9D%A2%E8%AF%95%E5%81%9A%E5%87%86%E5%A4%87%E4%BA%86/</link><pubDate>Sun, 11 Nov 2018 01:23:50 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%98%AF%E6%97%B6%E5%80%99%E4%B8%BA%E6%98%8E%E5%B9%B4%E7%9A%84%E9%9D%A2%E8%AF%95%E5%81%9A%E5%87%86%E5%A4%87%E4%BA%86/</guid><description>&lt;p>今年面试了不少人，也被面了很多次，多多少少有些经验是可以分享的。&lt;/p>
&lt;p>之前在某个微信群里说了一下最近的互联网公司测试同学的面试套路，结果被怼，说是面试造火箭，进去以后拧螺丝，在这里分享出来，希望大家不吝赐教，错误的地方还请多多斧正。&lt;/p>
&lt;p>总的来说，目前的面试更加的专业化，如果面试官的水平不错的话，面试的内容会非常有针对性，一些专业面霸的生存空间可能会进一步被压缩。&lt;/p>
&lt;p>从经验上看，下面这些套路都是差不多的&lt;/p>
&lt;h3 id="业务介绍">业务介绍&lt;/h3>
&lt;ul>
&lt;li>介绍一下你所在的业务。这里主要是考察对自己的业务是否熟悉，是不是能讲清楚自己在做什么，自己什么样的角色，负责怎样的业务。&lt;/li>
&lt;li>介绍一下你所在项目/产品的技术栈。对于一些前后端都有的项目来说，这个问题希望考察候选人是否了解开发在做些什么，用些什么样的技术等等。&lt;/li>
&lt;li>能不能画一下你所在项目/产品的架构图。这个问题难度比较大，特别是对于从事纯客户端测试的同学来说，毕竟前后端分离的情况下，客户端测试很难了解到后台的架构情况。对于测试后台的同学来说，如果只是做单纯的功能测试的话，那么架构图也是画不出来的。这个问题其实是在考察候选人的主动学习能力和测试的深度。因为如果不是主动去了解的话，恐怕开发同学是不会跟你说明架构情况的。另外，如果测试深度足够的话，比如很深入的测试中后台系统的话，那么大致的架构情况是会毕竟清楚的。更进一步，如果你搭建过被测系统的独立性能测试环境的话，那么架构基本上是会了然于胸的了。&lt;/li>
&lt;li>能不能说明一下你们目前系统/产品在架构上存在的问题。这个问题是接着上面的问题的开放性问题，主要考察候选人能不能从架构上预测到系统的问题，从而将测试工作前置，提前暴露或感知潜在的问题。对于高级别的测试同学来说，这个问题是需要提前思考答案的。&lt;/li>
&lt;/ul>
&lt;h3 id="逻辑题">逻辑题&lt;/h3>
&lt;p>对于校招和初级测试同学来说，逻辑题是经常会被考察到的。逻辑题主要的考察点是解决问题的思路是不是清楚，另外这个人是不是足够的聪明灵活，毕竟很多时候，跟聪明一点的人沟通起来也相对容易一点。&lt;/p>
&lt;p>逻辑题是有套路的，可以提前准备，另外就算没准备的话临场发挥也是来得及的。有时候不需要那么准确，只要思路大致能对上就可以了。&lt;/p>
&lt;h3 id="数据库题">数据库题&lt;/h3>
&lt;p>我在面试的时候被问到过数据库的知识，但偏底层和原理，对于初中级的测试同学来说，数据库主要是考察应用,比如考察一些联表查询，group by之类的题目。对于高级别的测试同学来说，可能会问到索引，调优以及数据库引擎和集群的知识。这些也是可以提前准备的，难度不是特别大，应该是大家都能拿分的题。&lt;/p>
&lt;h3 id="linux相关的题目">linux相关的题目&lt;/h3>
&lt;p>我曾经面试的时候被问过linux cpu的性能指标，要求是能想到多少就列出来多少。不过对于初中级的测试同学来说，linux操作系统可能重点考察的是使用和数据处理，比如我们这里就有一道面试题是关于如何通过linux命令从log里过滤出重要信息的。当然了，在微信群中讨论的时候，有些同学说这个实在是太简单了，过滤一下导出一下就可以了，我思考了很久，还是不清楚如何在线上不通过命令做这些操作的，当然，如果log接入了类似于Elasticsearch之类的系统的话，那么不用命令也是可以的了。&lt;/p>
&lt;h3 id="编程题">编程题&lt;/h3>
&lt;p>是的，你没看错，确实是编程题。好在测试方向的编程题都不是很难，基本上的考察点是简单的算法，对时间和空间复杂度的理解以及基本的编程技能。另外写代码也能看出一个人是不是聪明，这里我遇到过下面几种类型的考察。&lt;/p>
&lt;ul>
&lt;li>白板写算法。据说白板写可以很清楚的看出候选人的思路。&lt;/li>
&lt;li>上机写代码并调试成功。这样可以远程面试以及自动计算时间和空间复杂度。&lt;/li>
&lt;li>读代码找bug。读的是LRU的O(1)算法，其中有几行代码是有问题，需要找出来，其实还是有难度的。&lt;/li>
&lt;/ul>
&lt;h3 id="用例设计">用例设计&lt;/h3>
&lt;p>用例设计题是五花八门的了，这是基本功，我喜欢给一些类似于需求文档的片段让候选人根据文档写用例，总体难度不大，主要是考察阅读理解能力和用例设计能力。&lt;/p>
&lt;p>总的来说，上面这些题是我遇到的比较多的类型，当然因为我经历有限水平有限，这些面试经验可能不太适用，不过很多情况下，这些面试的题目还是很有针对性的，毕竟入职之后查数据库，过滤日志，写用例，写代码做一些自动化的效率提升，这些都是日常工作的一部分，面试的时候出现相应的题目，这些也是说得通的。&lt;/p>
&lt;p>综上，希望对你有所帮助。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1512847179643-f1794c3e0ac8?w=300"
 data-srcset="https://images.unsplash.com/photo-1512847179643-f1794c3e0ac8?w=300, https://images.unsplash.com/photo-1512847179643-f1794c3e0ac8?w=300 1.5x, https://images.unsplash.com/photo-1512847179643-f1794c3e0ac8?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1512847179643-f1794c3e0ac8?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>性能测试之前你可能需要弄明白这些事情</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E4%B9%8B%E5%89%8D%E4%BD%A0%E5%8F%AF%E8%83%BD%E9%9C%80%E8%A6%81%E5%BC%84%E6%98%8E%E7%99%BD%E8%BF%99%E4%BA%9B%E4%BA%8B%E6%83%85/</link><pubDate>Thu, 08 Nov 2018 01:23:50 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E4%B9%8B%E5%89%8D%E4%BD%A0%E5%8F%AF%E8%83%BD%E9%9C%80%E8%A6%81%E5%BC%84%E6%98%8E%E7%99%BD%E8%BF%99%E4%BA%9B%E4%BA%8B%E6%83%85/</guid><description>&lt;p>这应该是一个老生常谈的话题了。&lt;/p>
&lt;p>之前也分享过，在做性能测试之前，对大部分同学来说，最重要的问题就是搞清楚性能测试需求。&lt;/p>
&lt;p>一般来说，需求大概是下面这样子的。&lt;/p>
&lt;ul>
&lt;li>给我们的系统/产品做一下性能测试。这种需求太虚了，不细化的话基本上是没有可操作性的。&lt;/li>
&lt;li>测一下我们的最大在线人数。这种需求基本上是做容量，看一下项目/产品的最大容量是多少。&lt;/li>
&lt;li>线上有一个问题，但是我们找不到问题的原因，希望可以压测复现一下问题，以证实一些猜想。这种需求是重现线上问题，要求脚本能够尽可能准确的模拟真实业务。&lt;/li>
&lt;/ul>
&lt;p>关于如何做需求分析，之前应该有分析过，这里就不重复了。很多情况下，对于测试同学来说，搞清楚性能测试的目的和需求往往是非常困难的，除了经验之外，我们还需要跟开发同学有一些共同话题，了解开发同学是怎么想的，有哪些问题是需要注意的。不过这就需要我们对开发技术有一定的了解，不然很容易跟开发之间产生信息不对称，进而开发搞开发的，我们自己测自己的，没产生合力，最终的结果应该是很难让大部分人满意的。&lt;/p>
&lt;p>其实，除了需求，环境因素也非常重要。&lt;/p>
&lt;p>性能测试在哪个环境测，其实很有学问。&lt;/p>
&lt;p>一般来说，我们建议在跟线上环境几乎一致的独立性能测试环境去测。为什么呢？很大程度上是架构的关系。不同的架构对于测试结果的影响是巨大的。大部分情况下，我们的测试环境跟正式环境的差异还是相当明显的。测试环境可能就是单机，生产环境可能是集群，我们在单机上压出来的问题可能在集群上不会出现，另外集群上出现的问题我们在单机上可能也难以重现。&lt;/p>
&lt;p>最简单省事的做法就是在正式环境上压测，不过这要注意脏数据和错误恢复的问题。我们希望在正式环境上的压测不会影响真实用户的使用，不会修改真实用户的数据，并且压出问题之后系统可以迅速恢复。&lt;/p>
&lt;p>当然，大部分情况下，在正式环境做压测是&lt;strong>相当危险&lt;/strong>的。我们一般建议在跟生产环境几乎一致的环境上做性能测试。那么这个几乎一致是什么意思呢？&lt;/p>
&lt;ul>
&lt;li>架构基本一致，但可以缩容。比如线上的反向代理之后的负载均衡机器有10台，我们可能用2台就够了。&lt;/li>
&lt;li>数据量基本一致。线上有100万条数据，那么我们压测的时候也用100万条左右的数据量。&lt;/li>
&lt;li>数据脱敏。不要暴露用户的敏感信息。&lt;/li>
&lt;li>网络条件一致。线上的带宽是1G，那么压测的时候也用同样的带宽。&lt;/li>
&lt;/ul>
&lt;p>那么我们定义了独立的性能测试环境之后，这个环境谁来搭建和维护呢？&lt;/p>
&lt;p>我是建议测试同学自己搭建和维护。那么问题就来了，搭建测试环境的话，除了一些基本的运维操作(安装软件，修改配置)之外,我们还需要什么知识呢？&lt;/p>
&lt;p>我们需要理解系统的架构。&lt;/p>
&lt;p>我在面试的时候喜欢让候选人简单画一下他所测系统的架构图，另外当你在某公司进行技术晋级的时候，无论哪个技术通道，都会问所在产品的架构，可见理解架构是相当重要的。&lt;/p>
&lt;p>搭建测试环境可以让我们更好的去学习系统架构。我记得之前的公司新人来了之后都会给他几天的时间去搭建一套全新的开发或者测试环境，有时候是类生产环境，搭建环境的时候，比如我们需要安装redis，那么我们可以问开发同学，redis是做什么用的，用于什么业务场景或者用于解决什么业务问题。长此以往，我们的架构理解能力一定会有所提升。&lt;/p>
&lt;p>另外很多情况下，架构的演进是为了解决一些已知问题，或者是为了能够服务更多的用户，这种架构更替中的讨论和技术选型也很有蕴藏着性能测试的需求，到后门一通百通，很多事情都会得心应手了吧。&lt;/p>
&lt;p>最后，基础很重要，基础好的话一些概念理解起来可能会更加顺畅。比如链路层转发进行负载均衡的方式，如果你对链路层不理解，那么这个概念理解起来就会比较的困难了。&lt;/p>
&lt;p>文章很长，总而言之，大家在做性能测试之前，可能需要&lt;/p>
&lt;ul>
&lt;li>分析清楚性能需求&lt;/li>
&lt;li>理解系统架构&lt;/li>
&lt;li>搭建测试环境&lt;/li>
&lt;li>努力补充基础知识&lt;/li>
&lt;/ul>
&lt;p>这些是我的一些不成熟的见解，希望对大家有所帮助。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1431887773042-803ed52bed26?w=300"
 data-srcset="https://images.unsplash.com/photo-1431887773042-803ed52bed26?w=300, https://images.unsplash.com/photo-1431887773042-803ed52bed26?w=300 1.5x, https://images.unsplash.com/photo-1431887773042-803ed52bed26?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1431887773042-803ed52bed26?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>浅谈测试环境</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%85%E8%B0%88%E6%B5%8B%E8%AF%95%E7%8E%AF%E5%A2%83/</link><pubDate>Thu, 18 Oct 2018 06:20:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%85%E8%B0%88%E6%B5%8B%E8%AF%95%E7%8E%AF%E5%A2%83/</guid><description>&lt;p>除了在床上，我们一天中大概最多的时间就是在测试环境上战斗和工作了。&lt;/p>
&lt;p>最近在梳理测试环境和一些测试流程，在这里顺手记录一下，几年以后看过来，应该是会显得幼稚和贻笑大方的吧。&lt;/p>
&lt;h3 id="测试环境的责任边界">测试环境的责任边界&lt;/h3>
&lt;p>因为测试环境基本上是属于测试同学安身立命之本了，很多时候由于环境问题造成的漏测和事故是屡见不鲜的，因此测试环境的重要性不言而喻。&lt;/p>
&lt;p>那么测试环境应该谁来管理呢？&lt;/p>
&lt;p>目前看来比较好的方案是所有的测试环境都由测试同学管理，测试同学掌控发布策略，准入准出规则等等。&lt;/p>
&lt;p>另外有条件的话，建议测试同学可以自行搭建测试环境。尽管很难，不过值得一试，因为这种做有如下好处&lt;/p>
&lt;ul>
&lt;li>
&lt;p>全面了解系统的架构。搭建了环境之后，你可能对数据库，服务器软件，各种中间件和一系列的配置有了一定程度的感性认识。记得我们当年新人来了之后有条件的话都会让他们搭建一下开发或者测试环境，这是熟悉系统架构的快捷方式。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>了解数据源。很多时候数据源差异也会引起潜在问题。搭建测试环境的时候基本上会准备一些基础数据和小规模的业务数据，如果这些数据跟线上数据相似度高，比如有一定比例的脏数据，那么的话发现缺陷的概率相应的也会高一点把。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>学习开发技能。这点不用展开了吧。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>理解环境之前的差异。生产环境和测试环境之间或多或少都会有差异，这些差异其实有可能是缺陷的温床。如果我们能理解这些差异，针对这些差异做一些验证，比如线上环境有集群，而测试环境是单机，可以在集群上验证一下数据一致性的问题，这会使我们的测试用例更加的完善和高效。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>综上，还是建议测试环境测试同学负责，好处还是显而易见的。卧榻之侧，岂容他人鼾睡，不是么？&lt;/p>
&lt;h3 id="准入准出规则及流程">准入准出规则及流程&lt;/h3>
&lt;p>准入准出其实跟测试环境的分层有一定的关系。不过原则上，我们可以建议在准入之前做一下简单的冒烟测试，提升准入门槛。&lt;/p>
&lt;p>提升准入门槛有下面一些好处。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>给开发敲警钟。很多低级问题其实都是开发质量意识低下所导致的。当然质量意识跟能力是成正比的，能力强的开发往往质量意识比较好。提升准入门槛实际上就是让大部分平均水准的开发多花点心思在功能的质量上，毕竟他们才是质量保障的源头。开发慎重一些，胜过测试点到吐血。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>节约沟通成本。如果让质量很差的版本轻易的发布到测试环境，那么各种阻塞性的问题是会相当耗费沟通成本的，如果版本打回的话，大家都不开心，所以严格一点，你好我也好。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="测试环境分层">测试环境分层&lt;/h3>
&lt;p>有条件的话，建议可以给测试环境分层，层层隔离，每层承担不同的使命。一般来说，测试环境可以分为&lt;/p>
&lt;ul>
&lt;li>开发联调测试环境。开发协作进行测试和联调的环境。这个环境可以让开发随便玩，也可以作为下一层环境的准入测试环境。&lt;/li>
&lt;li>功能或模块测试环境。测试维护的某个功能或者模块的测试环境。可以直接部署分支代码。&lt;/li>
&lt;li>集成测试环境。所有的功能都合入该环境进行测试，就是一般意义上的测试环境。前两个环境没有其实可以接受，但这个环境是一定需要稳定和可控的。&lt;/li>
&lt;li>uat环境。可以从主干拉uat分支到该环境进行uat测试，缺陷解决后可以合回主干。&lt;/li>
&lt;li>类生产环境。与生产环境尽量一致。包括代码，软硬件以及数据高度一致。正式发布之前回归策略执行的地方。&lt;/li>
&lt;li>灰度环境。有条件可以有灰度环境，用来进行灰度策略的实施。&lt;/li>
&lt;li>独立的性能测试环境。这种环境可能是临时的，性能测试结束之后资源可以释放掉。&lt;/li>
&lt;/ul>
&lt;p>一般来说，测试环境的层级越多就代表着越多的角色会参与到测试活动中去，提前发现问题的概率相对会高一点点。&lt;/p>
&lt;h3 id="测试环境与自动化">测试环境与自动化&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>多层级的测试环境要求发布过程尽可能高度自动化。如果每次发布都很手工，都很痛苦，那么团队可能会选择维护尽可能少的测试环境来降低工作量，这显然不是我们想要的结果。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>稳定的测试环境可以进行周期性的自动化回归测试。比如可以在集成测试环境跑接口或ui的自动化。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="测试环境与测试及发布流程">测试环境与测试及发布流程&lt;/h3>
&lt;p>测试环境与测试及发布流程强相关，什么样的测试环境分层从客观上会影响整体的测试开发及发布流程。&lt;/p>
&lt;p>综上，每个团队不同，所采用的测试环境分层策略也不尽相同，另外作者的水平有限，上面内容仅供参考，欢迎斧正。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1501854140801-50d01698950b?w=300"
 data-srcset="https://images.unsplash.com/photo-1501854140801-50d01698950b?w=300, https://images.unsplash.com/photo-1501854140801-50d01698950b?w=300 1.5x, https://images.unsplash.com/photo-1501854140801-50d01698950b?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1501854140801-50d01698950b?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>使用验收标准来进行高效学习</title><link>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%BF%E7%94%A8%E9%AA%8C%E6%94%B6%E6%A0%87%E5%87%86%E6%9D%A5%E8%BF%9B%E8%A1%8C%E9%AB%98%E6%95%88%E5%AD%A6%E4%B9%A0/</link><pubDate>Wed, 10 Oct 2018 06:20:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%BF%E7%94%A8%E9%AA%8C%E6%94%B6%E6%A0%87%E5%87%86%E6%9D%A5%E8%BF%9B%E8%A1%8C%E9%AB%98%E6%95%88%E5%AD%A6%E4%B9%A0/</guid><description>&lt;p>相信大家对验收标准不是很陌生。&lt;/p>
&lt;p>我们在进行测试活动的时候一般会为我们的需求加上验收标准。比如某需求要求我们实现个缺陷管理系统，那么我们可能会为这个需求分解出若干个验证标准，如可以正确的创建缺陷并分配给开发人员之类的，验收标准可以作为我们测试用例的大纲，测试用例可以来围绕验收标准展开，关注正常和异常的多种情况，从而达到保障系统质量的目的。&lt;/p>
&lt;p>回到我们今天的主题——高效学习上来。&lt;/p>
&lt;p>最近我也在查缺补漏，补充自己的知识，完善一下总体的认知架构。在学习过程中我发现，如果只有学习目标的话，那么学习的效率可能是不够高，或者说是学习的过程是不够聚焦的。&lt;/p>
&lt;p>举个例子，比如你在学习python，你给自己定了一个小目标，半年内学会python。这个目标看起来是没有问题的，有开始和结束时间，也有着强烈的目的性。&lt;/p>
&lt;p>于是你开始学习，你去网上找到了学习资料，并且看完了语法，然后搭建了python开发环境，尽管在ide和编辑器上纠结了好久，尽管对命令行执行python命令从内心深处强烈的抵触，不够好歹你可以写个hello world，然后正确运行。后来应该做什么呢？如何在工作中将python运用起来呢？你没什么头绪。过了一段时间，你又鼓起勇气，重新捡起来python，但是语法和一切都是似曾相识，但hello world运行起来已经不是那么驾轻就熟了，然后又是不知道该如何继续，再搁浅，再捡起，无限循环。&lt;/p>
&lt;p>这是初学者学python的一般轨迹，相信不出意外再学习其他技能时也会陷入这样的困境。经过思考以后，我发现其实我们可以简单调整一下我们的学习方法，也许会对学习过程有一定的改进。&lt;/p>
&lt;p>我们分析一下上面的例子，再上例中，我们有目标，有过程，但是却缺少一个很重要的因素，那就是学习结果的度量，也就是我们在测试活动中所说的验收标准。没有验收标准的话我们就不知道自己的学习的结果是怎么样的。比如我学完了python语法，这是一个过程，我投入了时间，经历了这些过程，但是结果如何？我学会了python语法了么？我不知道，但我知道我真的花了很多时间，其间也非常努力，我对自己的努力很满意，至于结果，没学会可能是因为我不够聪明，或者不适合学习这个吧。&lt;/p>
&lt;p>真的是这样么？如果我们给学习python这个目标增加一些验收标准呢？比如最简单的验收标准：可以使用python连接数据库并自动插入一些测试数据。好了，现在我们的学习目标和验收标准是这样的了&lt;/p>
&lt;ul>
&lt;li>目标： 学会使用python&lt;/li>
&lt;li>验收标准：可以使用python连接数据库并自动插入一些测试数据&lt;/li>
&lt;/ul>
&lt;p>根据目标和验收标准，我们可以重新规划学习过程&lt;/p>
&lt;ul>
&lt;li>学习基本语法，先看熟，然后写一些小例子&lt;/li>
&lt;li>学习python连接数据库的方法&lt;/li>
&lt;li>学会python往数据库里插数据的方法&lt;/li>
&lt;li>学会自动生成测试数据的方法&lt;/li>
&lt;li>最后写一个脚本，完成最终功能&lt;/li>
&lt;/ul>
&lt;p>这样学习可能更有目的性，学习的效果也许会更好一些吧。&lt;/p>
&lt;p>我们再看其他一些例子，看看如何为自己设置验收标准。&lt;/p>
&lt;p>比如我要学会vuejs，那么&lt;/p>
&lt;ul>
&lt;li>目标：学会vuejs&lt;/li>
&lt;li>验收标准： 使用vuejs写1个简单的todo list&lt;/li>
&lt;li>过程分解
&lt;ul>
&lt;li>学习js语法&lt;/li>
&lt;li>学习html/css&lt;/li>
&lt;li>搭建vuejs开发环境&lt;/li>
&lt;li>了解vuejs原理&lt;/li>
&lt;li>学习vuejs的数据绑定&lt;/li>
&lt;li>学会使用vuejs进行页面的动态渲染&lt;/li>
&lt;li>学会使用vuejs处理相应用户输入&amp;hellip;&lt;/li>
&lt;li>&amp;hellip;&lt;/li>
&lt;li>&amp;hellip;&lt;/li>
&lt;li>最后写todo list，完成最终功能&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>其中上面的每个过程都可以给出更进一步的细分验收条件，比如学习html/css怎么样才算是学会呢？验收目标可以是写个简单的表单，看起来舒服就可以。&lt;/p>
&lt;p>另外在这么多年的教学过程中，我发现只给学员布置作业其实是不够的。&lt;/p>
&lt;p>作业可以看做是验收标准，但如果只是让同学们自己去做作业，而不去验收，或者说不去强制查看的话，那么很多人可能就因为各种原因不做作业了，没有作业的复习和巩固，很多需要大量练习的技能是很难掌握的。所以在最近的几期里，我们尝试在学院系统中为大家布置作业，然后老师批改作业，有了作业的加持，我发现一些同学的进步是非常明显的，这也验证了我的猜想，学习实际上是目标+过程+结果检查的过程。想想我们之前的学习经历，目标就是教学大纲，过程就是老师上课，结果检查和验证就是作业和考试。在我们工作之后，我们往往只注重前两点而忘记了结果的检查，这大概是导致我们自学效果不好的重要原因吧。&lt;/p>
&lt;p>综上，希望对你有所帮助。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1465188035480-cf3a60801ea5?w=300"
 data-srcset="https://images.unsplash.com/photo-1465188035480-cf3a60801ea5?w=300, https://images.unsplash.com/photo-1465188035480-cf3a60801ea5?w=300 1.5x, https://images.unsplash.com/photo-1465188035480-cf3a60801ea5?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1465188035480-cf3a60801ea5?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>如何学习重要的css属性</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%A6%82%E4%BD%95%E5%AD%A6%E4%B9%A0%E9%87%8D%E8%A6%81%E7%9A%84css%E5%B1%9E%E6%80%A7/</link><pubDate>Thu, 27 Sep 2018 06:20:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%A6%82%E4%BD%95%E5%AD%A6%E4%B9%A0%E9%87%8D%E8%A6%81%E7%9A%84css%E5%B1%9E%E6%80%A7/</guid><description>&lt;p>之前我写过一篇文章，大意是测试同学可以适当的学一学前端。前端技术里面，依赖相对较少的可能就是css了。&lt;/p>
&lt;p>那如何学习css呢？作为一个半吊子的css的使用者，我发现其实大家经常使用到的css属性其实是有限的，能不能有什么办法来统计一下哪些属性是重要且必须掌握的呢？所以就萌发了统计重要的css属性的想法。&lt;/p>
&lt;p>首先需要考虑的问题是，什么样的属性算是重要属性。一般来说，大家使用频率比较高的属性应该是重要且必须掌握的了。&lt;/p>
&lt;p>后来的问题就是，如何统计这些属性的使用频率呢？其实可以从分析流行的css框架中的属性做起。先选定一些css框架，下载对应的css文件，然后从文件里拿到所有的属性，统计其对应的出现次数，频繁出镜的属性可以认为是重要的了。&lt;/p>
&lt;p>有了思路，那就开始做吧。&lt;/p>
&lt;h3 id="下载css文件">下载css文件&lt;/h3>
&lt;p>我随便选择了一些css框架&lt;/p>
&lt;ul>
&lt;li>twitter-bootstrap&lt;/li>
&lt;li>bulma&lt;/li>
&lt;li>foundation&lt;/li>
&lt;li>materialize&lt;/li>
&lt;li>pure&lt;/li>
&lt;li>semantic-ui&lt;/li>
&lt;/ul>
&lt;p>上面这些框架没有个人喜好，就是根据github的star数随便选的。&lt;/p>
&lt;p>下载的话用脚本去做就好了，不需要手工搞。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># https://cdnjs.com/libraries/twitter-bootstrap&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">wget https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.css
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># https://cdnjs.com/libraries/bulma&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">wget https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.css
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># https://cdnjs.com/libraries/foundation&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">wget https://cdnjs.cloudflare.com/ajax/libs/foundation/6.4.3/css/foundation.css
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># https://cdnjs.com/libraries/materialize&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">wget https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.css
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># https://cdnjs.com/libraries/pure&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">wget https://cdnjs.cloudflare.com/ajax/libs/pure/1.0.0/pure.css
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># https://cdnjs.com/libraries/semantic-ui&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">wget https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.3.3/semantic.css
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="统计每个css属性出现的次数">统计每个css属性出现的次数&lt;/h3>
&lt;p>一般来说，css的语法是这样的&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-css" data-lang="css">&lt;span class="line">&lt;span class="cl">&lt;span class="p">.&lt;/span>&lt;span class="nc">kls&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">width&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">100&lt;/span>&lt;span class="kt">%&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>我们可以发现，一般来说，有&lt;code>;&lt;/code>出现的行就是css属性出现的行，所以第一步就是过滤出所有包含&lt;code>;&lt;/code>的行，那就用&lt;code>grep&lt;/code>吧。&lt;/p>
&lt;p>找到所有包含;号的行之后，我们还需要使用&lt;code>:&lt;/code>来切割该行，输出第1列，也就是属性名称列。这里用的是&lt;code>cut&lt;/code>。&lt;/p>
&lt;p>拿到属性名称之后，做一些梳理，比如去掉开头的空格之类的，再使用&lt;code>sort + uniq&lt;/code>，排序加去重。&lt;/p>
&lt;p>完整的shell命令如下&lt;/p>
&lt;pre tabindex="0">&lt;code>cat *.css | grep &amp;#39;;&amp;#39; | tr -d &amp;#39; &amp;#39; | cut -d &amp;#39;:&amp;#39; -f 1 | sort | grep -v &amp;#34;^-&amp;#34; | grep -v &amp;#34;^/&amp;#34;| grep -v &amp;#34;^\.&amp;#34;| grep -v &amp;#34;^\*&amp;#34;|grep -v &amp;#34;^@&amp;#34;| grep -v &amp;#34;^\s&amp;#34;|uniq -c | sort -r &amp;gt; all.txt
&lt;/code>&lt;/pre>&lt;p>这时候就拿到了临时输出文件all.txt&lt;/p></description></item><item><title>2018校招初感</title><link>https://itest2025.pages.dev/tutorials/47-000-2018%E6%A0%A1%E6%8B%9B%E5%88%9D%E6%84%9F/</link><pubDate>Thu, 20 Sep 2018 06:20:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-2018%E6%A0%A1%E6%8B%9B%E5%88%9D%E6%84%9F/</guid><description>&lt;p>今年在北京参加校园招聘，我负责测试开发岗位的二面。我们的面试流程是这样的。首先在线做题加视频面试，这是一面。一面通过后再现场面试，这是二面，也是我负责的部分。&lt;/p>
&lt;p>一面的题目有难度，估计很多社招的同学做起来都会感到棘手。按道理来说二面的时候我应该不再对候选人的技能能力进行考察了，但是由于是应届生，经验基本是不足的，二面的时候也没有可以深入去聊的过往背景和项目经验，因此还是以考察逻辑思维，编程思维和技术基础为主。&lt;/p>
&lt;p>我这里准备了一些题目，大概是几道编程题，难度最低的那种，考察基本语法和编程基础。几道测试相关的问题，比如测试流程和bug生命周期之类的，因为有些同学有测试实习的经验。还有一些用例设计题，考察用例设计时的知识广度。最后就是逻辑题，看看这个人逻辑思维如何。一天面了5-6个人吧，还是有些感触的。&lt;/p>
&lt;h3 id="候选人清一色都是硕士毕业">候选人清一色都是硕士毕业&lt;/h3>
&lt;p>没有本科生，问了一下hr，说是本科生投递的人数本来就少，而且优秀的本科生不是保研了就是出国了，只有硕士生在忙着找工作。&lt;/p>
&lt;p>所以以后潜在的竞争对手可能都是研究生的相关专业毕业了，我不禁瑟瑟发抖。&lt;/p>
&lt;h3 id="候选人的背景优秀">候选人的背景优秀&lt;/h3>
&lt;p>随便举例说明一下，大部分的候选人都是名校硕士，有各种证书奖学金科研成果加成。相比自己当年，不由得自惭形秽。&lt;/p>
&lt;h3 id="女生居多">女生居多&lt;/h3>
&lt;p>10个候选人里大概8个女生，占80%。稍微问了一下，大家的想法基本是一致的。就是开发可能太难太累了，但是测试开发呢，首先是测试，不会特别难搞，其次都有一定的开发任务，不会离技术太远。这个想法是可以理解的，不过万事开头难，一开始做测试的时候应该是困难和挑战大于成就感和乐趣，而开始做开发的话可能成就感会比较高，自己提高的速度可能会更快一些。&lt;/p>
&lt;h3 id="都有编程基础">都有编程基础&lt;/h3>
&lt;p>尽管有些题目写不出来，但是基本上能看出在实习期间都是写过代码的。一般这种情况下，只要逻辑题能过我就基本上给通过了。&lt;/p>
&lt;h3 id="linux和sql都有基础">linux和sql都有基础&lt;/h3>
&lt;p>基本都用过，还有不少可以写出比较复杂的bash命令来做log过滤，基础确实不错。&lt;/p>
&lt;h3 id="自我规划不足">自我规划不足&lt;/h3>
&lt;p>在问及最近一两年的规划的时候，大家基本上没有特别多的规划，给人的感觉是赶紧找个工作先做着，至于规划以后等熟悉了职位再说。&lt;/p>
&lt;p>还有不少同学不清楚测试岗位的具体情况，这样自然就没办法进行规划了。&lt;/p>
&lt;p>给人的感觉是大家把测试当成是难度较低的求职途径，至于今后的规划那就是另当别论了。&lt;/p>
&lt;p>综上，校招之后个人的压力继续增大，越来越多优秀的人才涌入测试行业，对行业的进步是好事，但对目前从业者的个人素质来说，是需要普遍提升的。&lt;/p>
&lt;p>路漫漫其修远兮，继续求索吧。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1469827160215-9d29e96e72f4?w=300"
 data-srcset="https://images.unsplash.com/photo-1469827160215-9d29e96e72f4?w=300, https://images.unsplash.com/photo-1469827160215-9d29e96e72f4?w=300 1.5x, https://images.unsplash.com/photo-1469827160215-9d29e96e72f4?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1469827160215-9d29e96e72f4?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>你是不是那个带不动的队友</title><link>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%A0%E6%98%AF%E4%B8%8D%E6%98%AF%E9%82%A3%E4%B8%AA%E5%B8%A6%E4%B8%8D%E5%8A%A8%E7%9A%84%E9%98%9F%E5%8F%8B/</link><pubDate>Thu, 06 Sep 2018 12:55:59 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%A0%E6%98%AF%E4%B8%8D%E6%98%AF%E9%82%A3%E4%B8%AA%E5%B8%A6%E4%B8%8D%E5%8A%A8%E7%9A%84%E9%98%9F%E5%8F%8B/</guid><description>&lt;p>刚在群里看到小伙伴们的讨论，有一位同学说招人招了好久没有找到合适的。稍微聊了一下，大概情况是这样的。&lt;/p>
&lt;p>最新项目紧张，自动化的测试用例需要给力的小伙伴帮忙一起写一下，之前花心思带了一位同学，那位同学学了一段时间之后离开了，工资涨了2k。现在想招个能直接上手做项目的，但是茫茫人海，遇到一个合适的人真的很难，面试时候遇到有不错潜力的，不过因为项目周期的原因也不可能给时间去慢慢学习上手，如今非常为难。&lt;/p>
&lt;p>了解了情况之后，我自己也相当有感触。目前所在的公司面试要求比较高，我推荐了一个自认为潜力还不错的同学来面试，结果直接被hr给婉拒了，理由是技术方面没有实际的项目经验，培养周期可能比较长，暂时不予考虑。&lt;/p>
&lt;p>还有一位候选人，背景很不错，经验也令人非常满意，但是技术方面可能缺乏磨练，最终一面技术面没有通过，面试官给的拒绝理由是技术能力不强，与公司对于资深测试人员的定位不符，所以还是想看看有没有综合能力更好的候选人。&lt;/p>
&lt;p>顺便又想到一件事情，最近有一位同学试用期评估的时候没有达到预期，原因是综合能力不足，自我成长速度比较慢，已经用心去带了，但是带不动，占用了团队其他成员(也是测试同学)的很多时间。比如脚本跑不通需要别人帮忙调试等等。&lt;/p>
&lt;p>总的来说，在某些团队，一般是小团队，对队友的时间容忍度不会特别高，一般希望招来的人能立即干活，减少培养的成本，尽快的有稳定输出。而大公司对毕业生的培养要相对耐心很多，某些公司会有导师制度，就是老带新，帮助新人融入环境，解决新人的各种问题。另外大公司的培训也比较立体，可能测试新人会直接从用例设计培训到linux，数据库，自动化测试等等，整个周期可能会有1到2个月，但大公司对背景的要求比较高，门槛高了成材率也相应会高，这些成本是公司可以承担的。&lt;/p>
&lt;p>如果用人企业承担不了培养的成本呢？&lt;/p>
&lt;p>自我成长其实很重要。自我成长的关键是自己希望自己可以变得更好。如果自己没有成长的意愿，那么外部的环境再好再优越，成长的速度也是有限的。&lt;/p>
&lt;p>就拿向我吐槽招人不顺，也就是文首露面的那位同学来说，他目前每天坚持学习2小时，晚上加班到11点，在车上也会看书，中午也要看书看半小时，还经常写博客，做知识总结和归纳。&lt;/p>
&lt;p>我个人觉得自己成长最快的那段时间(当然了，是被逼的)，每天压力很大，早上睡不着5点起来写代码，午休的时候也睡不着，别人睡觉我在轻轻的敲代码，晚上一般10点多到家，洗完澡倒头就睡，梦里都梦到敲代码做需求，毕竟那段时间，在团队其他成员看来，我也属于带不动的队友行列。&lt;/p>
&lt;p>大家换工作的话，其实可以站在招聘方去考虑一下问题。对于有工作经验的同学来说，用人单位一般希望你可以独当一面，马上干活稳定输出；对于一些没有太多经验的同学来说，企业可能会承担一定的培养成本，但是要求你迅速的成长，让人可以带的动。&lt;/p>
&lt;p>说了这么多，可能大家也比较好奇我们所谓的对候选人的技术水平要求到底是怎么样的，我稍微总结了一下，对于普通测试同学来说，我们这里要求&lt;/p>
&lt;ul>
&lt;li>首先测试技能，比如对需求的理解，测试用例设计等&lt;/li>
&lt;li>熟练使用linux，我记得有一道笔试题大概是如何从log里找出不重复的用户数量&lt;/li>
&lt;li>熟练进行性能测试，好像有一道笔试题考察了一些监控指令&lt;/li>
&lt;li>熟练使用一门编程语言，有一道笔试题考察了搜索的算法，关注时间复杂度&lt;/li>
&lt;li>熟练进行接口测试，入职后马上会有一些跟接口测试相关的小项目需要独立完成，大概是自己写mock server，写接口测试用例，自己进行压测，给出最大qps，做不出来貌似就要立即闪人了&lt;/li>
&lt;/ul>
&lt;p>其实有一些趋势是比较明显的，测试的薪资会越来越高，与此对应的，门槛也会越来越高。&lt;/p>
&lt;p>共勉。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1519120944692-1a8d8cfc107f?w=300"
 data-srcset="https://images.unsplash.com/photo-1519120944692-1a8d8cfc107f?w=300, https://images.unsplash.com/photo-1519120944692-1a8d8cfc107f?w=300 1.5x, https://images.unsplash.com/photo-1519120944692-1a8d8cfc107f?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1519120944692-1a8d8cfc107f?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>使用python实现测试工具(四)</title><link>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%BF%E7%94%A8python%E5%AE%9E%E7%8E%B0%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7%E5%9B%9B/</link><pubDate>Tue, 21 Aug 2018 06:55:32 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%BF%E7%94%A8python%E5%AE%9E%E7%8E%B0%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7%E5%9B%9B/</guid><description>&lt;p>本系列教程使用的python版本是&lt;strong>3.6.3&lt;/strong>。&lt;/p>
&lt;h3 id="背景">背景&lt;/h3>
&lt;p>这一节我们对unittest模块做一丁点的扩展，我们将实现动态运行用例的功能。&lt;/p>
&lt;p>测试用例如下，基本上是从python官方文档上摘取的。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">unittest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">TestStringMethods&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TestCase&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">test_upper&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;foo&amp;#39;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">upper&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="s1">&amp;#39;FOO&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">test_isupper&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertTrue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;FOO&amp;#39;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">isupper&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertFalse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Foo&amp;#39;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">isupper&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">test_split_important&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">s&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;hello world&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;hello&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;world&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># check that s.split fails when the separator is not a string&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">with&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertRaises&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="ne">TypeError&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">s&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行testcase下全部的用例">运行TestCase下全部的用例&lt;/h3>
&lt;p>这个需求是最常见的。根据官网的文档，代码实现如下&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># load all test methods from a TestCase class&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">common_suite&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TestLoader&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">loadTestsFromTestCase&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">TestStringMethods&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TextTestRunner&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">verbosity&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">common_suite&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>使用&lt;code>TestLoader&lt;/code>类中自带的&lt;code>loadTestsFromTestCase&lt;/code>方法创建&lt;code>TestSuite&lt;/code>运行既可。&lt;/p>
&lt;h3 id="运行testcase下的某些用例">运行TestCase下的某些用例&lt;/h3>
&lt;p>我们可以手动添加TestCase下的部分用例，然后一次执行。核心方法是使用&lt;code>addTest()&lt;/code>方法&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># add only 1 test method&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">one_case_suite&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TestSuite&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">one_case_suite&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">addTest&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">TestStringMethods&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;test_upper&amp;#39;&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TextTestRunner&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">verbosity&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">one_case_suite&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="给用例打标签只运行某些具有标签的用例">给用例打标签，只运行某些具有标签的用例&lt;/h3>
&lt;p>很多的测试框架都有类似的功能，我们可以用最简单的方式在unittest中实现类似功能。这里有一个小小的trick，就是我们通过命名测试用例的方式来实现打标签的功能。比如我们可以在测试方法名称后加上&lt;code>_important&lt;/code>表示这是重要的测试方法，需要在每天进行回归。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># only run test methods the name of which ends with important&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">only_run_important_suite&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TestSuite&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="k">case&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="n">method&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">method&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">dir&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">TestStringMethods&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="n">method&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">endswith&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;important&amp;#39;&lt;/span>&lt;span class="p">)]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">only_run_important_suite&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">addTest&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">TestStringMethods&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">case&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TextTestRunner&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">verbosity&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">only_run_important_suite&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这里的关键点是&lt;/p></description></item><item><title>使用python实现测试工具(五)</title><link>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%BF%E7%94%A8python%E5%AE%9E%E7%8E%B0%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7%E4%BA%94/</link><pubDate>Mon, 20 Aug 2018 06:55:32 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%BF%E7%94%A8python%E5%AE%9E%E7%8E%B0%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7%E4%BA%94/</guid><description>&lt;p>本系列教程使用的python版本是&lt;strong>3.6.3&lt;/strong>。&lt;/p>
&lt;h3 id="背景">背景&lt;/h3>
&lt;p>我们在进行测试的时候经常需要去生成一些测试数据，这就是所谓的造数据。&lt;/p>
&lt;p>生成随机的用户真实姓名是非常常见的需求，这一节我们看一下如何使用python的来实现这个功能。&lt;/p>
&lt;p>我们将实现随机生成英文名的功能。&lt;/p>
&lt;p>英文名的生成规则是&lt;code>first_name last_name&lt;/code>，也就是名在前，姓在后，中间空格分隔。&lt;/p>
&lt;h3 id="代码">代码&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">random&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">last&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Appleyard&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Bigmeat&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Bloominshine&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Boogerbottom&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Breedslovetrout&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Butterbaugh&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Clovenhoof&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Clutterbuck&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Cocktoasten&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Endicott&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Fewhairs&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Gooberdapple&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Goodensmith&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Goodpasture&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Guster&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Henderson&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Hooperbag&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Hoosenater&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Hootkins&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Jefferson&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Jenkins&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Jingley-Schmidt&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Johnson&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Kingfish&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Listenbee&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;M&amp;#39;Bembo&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;McFadden&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Moonshine&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Nettles&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Noseworthy&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Olivetti&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Outerbridge&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Overpeck&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Overturf&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Oxhandler&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Pealike&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Pennywhistle&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Peterson&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Pieplow&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Pinkerton&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Porkins&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Putney&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Quakenbush&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Rainwater&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Rosenthal&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Rubbins&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Sackrider&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Snuggleshine&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Splern&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Stevens&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Stroganoff&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Sugar-Gold&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Swackhamer&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Tippins&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Turnipseed&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Vinaigrette&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Walkingstick&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Wallbanger&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Weewax&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Weiners&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Whipkey&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Wigglesworth&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Wimplesnatch&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Winterkorn&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Woolysocks&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">first&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Baby Oil&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Bad News&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Big Burps&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;Bill &amp;#39;Beenie-Weenie&amp;#39;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Bob &amp;#39;Stinkbug&amp;#39;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Bowel Noises&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Boxelder&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;Bud &amp;#39;Lite&amp;#39;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Butterbean&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Buttermilk&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Buttocks&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Chad&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Chesterfield&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Chewy&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Chigger&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Cinnabuns&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Cleet&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Cornbread&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Crab Meat&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Crapps&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Dark Skies&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Dennis Clawhammer&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Dicman&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Elphonso&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Fancypants&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Figgs&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Foncy&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Gootsy&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Greasy Jim&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Huckleberry&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Huggy&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Ignatious&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Jimbo&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Joe &amp;#39;Pottin Soil&amp;#39;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Johnny&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Lemongrass&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Lil Debil&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Longbranch&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;&amp;#34;Lunch Money&amp;#34;&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Mergatroid&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;&amp;#34;Mr Peabody&amp;#34;&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Oil-Can&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Oinks&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Old Scratch&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Ovaltine&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Pennywhistle&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Pitchfork Ben&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Potato Bug&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Pushmeet&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Rock Candy&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Schlomo&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Scratchensniff&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Scut&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;Sid &amp;#39;The Squirts&amp;#39;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Skidmark&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Slaps&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Snakes&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Snoobs&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Snorki&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Soupcan Sam&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Spitzitout&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Squids&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Stinky&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Storyboard&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Sweet Tea&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;TeeTee&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Wheezy Joe&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;Winston &amp;#39;Jazz Hands&amp;#39;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Worms&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">random_full_name&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2"> &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">choice&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">first&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">choice&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">last&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">random_full_name&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="分析">分析&lt;/h3>
&lt;p>代码很简单，定义2个原组，就是小括号括起来的那个像列表的东西，分别是&lt;code>last&lt;/code>和&lt;code>first&lt;/code>。&lt;/p></description></item><item><title>当前测试人员应该具备的基本技能</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%BD%93%E5%89%8D%E6%B5%8B%E8%AF%95%E4%BA%BA%E5%91%98%E5%BA%94%E8%AF%A5%E5%85%B7%E5%A4%87%E7%9A%84%E5%9F%BA%E6%9C%AC%E6%8A%80%E8%83%BD/</link><pubDate>Fri, 10 Aug 2018 01:23:50 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%BD%93%E5%89%8D%E6%B5%8B%E8%AF%95%E4%BA%BA%E5%91%98%E5%BA%94%E8%AF%A5%E5%85%B7%E5%A4%87%E7%9A%84%E5%9F%BA%E6%9C%AC%E6%8A%80%E8%83%BD/</guid><description>&lt;p>最近发现一些测试岗位的薪资水平很高，然而与此形成鲜明对比的是，另一些测试岗位的回报却是少得可怜，两级分化特别严重。&lt;/p>
&lt;p>我一直有这样一个观点，除去各种软技能因素，你会的越多拿的就越多。&lt;/p>
&lt;p>那么当前测试同学应该具备哪些技能呢？我想大概应该有下面一些。&lt;/p>
&lt;h3 id="沟通能力">沟通能力&lt;/h3>
&lt;p>沟通能力我认为分为2种，一种是表达自己，另一种是聆听别人。&lt;/p>
&lt;p>表达自己的意思就是能让其他人知道你想做什么，在做什么，有什么困难，需要什么帮助；聆听别人就是你听得懂对方在做什么，要做什么，有什么困难之类。&lt;/p>
&lt;p>很多测试同学在表达自己方面能力很强，但是聆听别人方面却差强人意。经常沟通之后完全不知道开发或者项目要做什么。这应该是由于信息不对称造成的，开发和项目方面的事情大家不是很清楚，所以沟通的实话往往貌合神离，只能报以尴尬而不失礼貌的微笑。&lt;/p>
&lt;h3 id="阅读能力">阅读能力&lt;/h3>
&lt;p>这里特指阅读文档的能力。&lt;/p>
&lt;p>文档有很多种，我们最应该读懂的是需求文档。&lt;/p>
&lt;p>需求文档里可能有很多字，这时候我们需要一边读一边思考，哪些地方是合理的，哪些地方又是需要推敲的，比如根据手机壳自动变换软件主题颜色之类的需要，还是要多多讨论一下才比较好。&lt;/p>
&lt;p>需求文档里面很可能就一句话，比如我要实现一个跟淘宝一摸一样的网站，这时候上文描述的沟通能力就有用武之地了。我们需要把需求一点一点的挖出来，丰富和细化，最终还原为真实需求。个人经验看来，一句话的需求往往是在表达美好的愿望，只是冰山一角，实际要做的事情往往相当的繁复。&lt;/p>
&lt;h3 id="设计用例的能力">设计用例的能力&lt;/h3>
&lt;p>用例设计的方法大家应该耳熟能详了，起码每次面试之前都会背一遍。但是会了那么多方法，并不一定代表你就能编写合理有效的用例。&lt;/p>
&lt;p>其实我一直认为，我们所推崇的用例设计方式很多时候是很微观的，但我们设计的测试用例在大多数时候却是宏观的，两者之间似乎并不能令人信服的融会贯通。&lt;/p>
&lt;p>比如边界值法，在单元测试里边界值是很容易分类(等价类)和枚举的，但是在设计一个真正的手工测试用例的时候，我们往往很难做这种枚举，我们可能会有一个输入范围及其庞大的无效类，叫做异常情况。如何在异常情况中再次细分，选取有代表的性的输入或操作进行测试，往往相当有挑战，这就需要真正的理解需求，理解被测系统。&lt;/p>
&lt;p>所以很多时候，这种设计用例识别盲点的能力最终还是转化为，你对系统熟不熟，对业务熟不熟，知不知道用户在想些什么。&lt;/p>
&lt;h3 id="写文档的能力">写文档的能力&lt;/h3>
&lt;p>因为衡量测试输出的指标不是很多，所以有些时候我们要输出一些文档来表示我们确实在努力工作。比如&lt;/p>
&lt;ul>
&lt;li>测试计划&lt;/li>
&lt;li>测试用例&lt;/li>
&lt;li>测试报告&lt;/li>
&lt;/ul>
&lt;p>这些其实有很大的优化空间，毕竟在项目紧张的时候测试报告也就是一个结论一封邮件的事情。&lt;/p>
&lt;h3 id="一定的代码能力">一定的代码能力&lt;/h3>
&lt;p>测试重复性的工作很多，有一些重复性高的事情是可以用写代码的方式去快速搞定的。比如可以用写一些脚本逻辑加sql的方式快速生成一些测试数据之类的。有了代码能力之后，想象空间就会变大相对大一些。&lt;/p>
&lt;h3 id="执行用例能力">执行用例能力&lt;/h3>
&lt;p>手工执行用例也是一种能力，并不是测试用例写的好换谁执行都一样的。但是自动执行用例的能力也是当前的测试人员所需要掌握的。&lt;/p>
&lt;p>自动化的用例执行可以节约成本，提升执行效率，加速回归测试，不过需要找到投入和产出的平衡点。&lt;/p>
&lt;p>把一些回归用例用代码的方式实现并维护其实蛮有挑战的，毕竟学会写代码是需要一个过程的。&lt;/p>
&lt;h3 id="专项测试能力">专项测试能力&lt;/h3>
&lt;p>掌握一项专项测试能力，比如性能，app之类的，毕竟说不准什么时候项目就要求你这样做，能顶上去才有更好的发展空间。&lt;/p>
&lt;p>不知道大家觉得还有哪些能力是必备的，欢迎留言讨论。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1454982523318-4b6396f39d3a?w=300"
 data-srcset="https://images.unsplash.com/photo-1454982523318-4b6396f39d3a?w=300, https://images.unsplash.com/photo-1454982523318-4b6396f39d3a?w=300 1.5x, https://images.unsplash.com/photo-1454982523318-4b6396f39d3a?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1454982523318-4b6396f39d3a?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>你为什么会加班?</title><link>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%A0%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BC%9A%E5%8A%A0%E7%8F%AD/</link><pubDate>Fri, 10 Aug 2018 01:23:50 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%A0%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BC%9A%E5%8A%A0%E7%8F%AD/</guid><description>&lt;p>上周在群里跟一些同学聊了关于加班的问题，很有感触，在这里跟大家分享一下。&lt;/p>
&lt;p>每个公司都有自己的加班理由，有的很奇怪，有的看上去不可挑战，不过概括一下，原因大概有下面一些吧。&lt;/p>
&lt;h3 id="公司文化">公司文化&lt;/h3>
&lt;p>有些公司的加班是文化性质的，价值观性质的。比如大家都心照不宣的晚上一起吃饭，然后9点之后陆续离开。9点走可能是因为有班车，如果是晚上打车报销的话，也许会等到10点以后才下班。这些公司加班的时候往往有些同学是没有什么特别紧急的事情需要处理的，有的人可能会在玩手机打游戏，有的可能会在视频通话，总之很多人在加班的时候身材曹营心在汉，效率不高。&lt;/p>
&lt;p>这种就是反正你干啥都行，就是不到9点你不能走。&lt;/p>
&lt;h3 id="个别领导要求">个别领导要求&lt;/h3>
&lt;p>有些同学加班其实也没啥事情，只是因为主管要求，主管不走，自己也不能走。&lt;/p>
&lt;p>这种有点像是个别领导的个体行为，整个公司加班的情况不多，只有某些部门看似在加班，其实大家怨声载道，敢怒不敢言而已。&lt;/p>
&lt;p>这种一般是主管为了绩效强制加班，给大领导看，可能是个短期行为。&lt;/p>
&lt;h3 id="工作安排不合理">工作安排不合理&lt;/h3>
&lt;p>这种大概就是工作安排的不太合理，有时候不忙，有时候又突然很紧张，甚至立下军令状，几天一定要弄完，不然如何如何云云。如果是偶尔会这样，其实问题不大，但如果一直如此，也许整个团队的节奏需要调整一下，要么把工作量平均分配，不要某个时间段突然负载加倍，要么就是把开发节奏放慢，把交付时间拉长。&lt;/p>
&lt;h3 id="意想不到突如其来">意想不到，突如其来&lt;/h3>
&lt;p>这种是突然是插入一些任务，十万火急，然后简单粗暴的把压力传导下去，急急忙忙赶出一些东西，最终可能因为匆忙的关系，交付质量不高，或者产品反馈不好，导致大家身心疲惫，士气低下。&lt;/p>
&lt;p>不过也有这种不期而遇的事情在短时间内处理很好的情况，大家士气高涨，吃饭团建，当是历练。&lt;/p>
&lt;p>如果这种情况属于常态的话，那么团队的管理或定位方面大概就有问题了吧。&lt;/p>
&lt;h3 id="士气高涨奋勇拼搏">士气高涨，奋勇拼搏&lt;/h3>
&lt;p>还有一些公司士气很高，整个公司都在加班，大家很拼，很忙，但是乐在其中，非常有成就感。&lt;/p>
&lt;p>这种公司要么是管理水平很高，要么是创业公司，大家齐心协力，士气高涨，战斗力强，输出非常可靠可观。&lt;/p>
&lt;p>不知道你的公司是属于哪一种呢？欢迎留言讨论。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1496060169243-453fde45943b?w=300"
 data-srcset="https://images.unsplash.com/photo-1496060169243-453fde45943b?w=300, https://images.unsplash.com/photo-1496060169243-453fde45943b?w=300 1.5x, https://images.unsplash.com/photo-1496060169243-453fde45943b?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1496060169243-453fde45943b?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>使用python实现测试工具(三)</title><link>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%BF%E7%94%A8python%E5%AE%9E%E7%8E%B0%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7%E4%B8%89/</link><pubDate>Wed, 01 Aug 2018 06:55:32 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%BF%E7%94%A8python%E5%AE%9E%E7%8E%B0%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7%E4%B8%89/</guid><description>&lt;p>本系列教程使用的python版本是&lt;strong>3.6.3&lt;/strong>。&lt;/p>
&lt;h3 id="背景">背景&lt;/h3>
&lt;p>这一节我们实现一个简单的寻找页面上无效链接的工具。&lt;/p>
&lt;p>我们这样定义无效链接: http响应的返回状态码 &lt;strong>&amp;gt;=400&lt;/strong>的链接。 为什么？大家可以去搜索一下。&lt;/p>
&lt;p>该工具的作用是访问某个页面，然后找到页面上所有的链接，依次对这些链接进行访问，通过返回的状态码来确定该链接是不是无效链接。&lt;/p>
&lt;h3 id="工具设计">工具设计&lt;/h3>
&lt;p>我们设计一个命令行工具，给工具传1个参数，也就是该被测页面的url&lt;/p>
&lt;p>所以工具大概是这样用的: &lt;code>python dead_link.py www.example.com&lt;/code>&lt;/p>
&lt;h3 id="代码实现">代码实现&lt;/h3>
&lt;p>简单起见，我们会用到requests-html库。安装文档在&lt;a href="http://html.python-requests.org/" target="_blank" rel="noopener noreffer ">这里&lt;/a>。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">requests_html&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">HTMLSession&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">requests&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">sys&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">argv&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">urllib.parse&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">urlparse&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">urljoin&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">DEBUG&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">USAGE&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;&amp;#39;&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1">USAGE:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1">python dead_link.py www.itest.info
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1">&amp;#39;&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">argv&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">USAGE&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">script_name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">url&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">argv&lt;/span> 
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="n">url&lt;/span>&lt;span class="p">[:&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="s1">&amp;#39;http&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">url&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;http://&amp;#39;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">url&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">urlparse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="n">res&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">netloc&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;无法获取站点的domain信息&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">domain&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">res&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">netloc&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;站点domain: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">domain&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">session&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">HTMLSession&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">r&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">session&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">links&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">r&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">html&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;a&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">link&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">links&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="s1">&amp;#39;href&amp;#39;&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">link&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">attrs&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">href&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">link&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">attrs&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;href&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">continue&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">urlparse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">href&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">netloc&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">href&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">urljoin&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">href&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">url_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;内链&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">domain&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">href&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">url_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;内链&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">url_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;外链&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">requests&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">href&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status_code&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">400&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">url_type&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">href&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> 失败&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">url_type&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">href&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> 成功&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;出现异常&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="精讲">精讲&lt;/h3>
&lt;ul>
&lt;li>我们需要注意的是内链的情况，也就是有些链接是&lt;code>/xxx/yyy/zzz&lt;/code>的情况，这种情况下需要将域名或者ip补全再访问&lt;/li>
&lt;li>requests-html库的基本使用参考&lt;a href="http://html.python-requests.org/#tutorial-usage" target="_blank" rel="noopener noreffer ">这里&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="运行示例">运行示例&lt;/h3>
&lt;pre tabindex="0">&lt;code>python dead_link.py www.itest.info

站点domain: www.itest.info
内链 http://www.itest.info/ 成功
内链 http://www.itest.info/ 成功
内链 http://www.itest.info/newclass 成功
内链 http://www.itest.info 成功
内链 http://www.itest.info/courses/8 成功
内链 http://www.itest.info/courses/7 成功
内链 http://www.itest.info/courses/6 成功
内链 http://www.itest.info/courses/3 成功
内链 http://www.itest.info/courses/2 成功
内链 http://www.itest.info/faq 成功
内链 http://www.itest.info/videos 成功
外链 http://www.testclass.net 成功
外链 http://www.testpub.cn 成功
内链 http://www.itest.info/about 成功
内链 http://www.itest.info/courses/2 成功
内链 http://www.itest.info/courses/7 成功
内链 http://www.itest.info/courses/7 成功
内链 http://www.itest.info/courses/6 成功
内链 http://www.itest.info/courses/6 成功
内链 http://www.itest.info/courses/3 成功
内链 http://www.itest.info/courses/3 成功
内链 http://www.itest.info/courses/2 成功
内链 http://www.itest.info/courses/2 成功
内链 http://www.itest.info/about 成功
外链 http://www.cnblogs.com/fnng/ 成功
外链 http://www.cnblogs.com/nbkhic/ 成功
外链 http://testpub.cn/ 成功
外链 http://www.testclass.net/ 成功
内链 http://www.itest.info/about 成功
&lt;/code>&lt;/pre>&lt;h3 id="动手时间">动手时间&lt;/h3>
&lt;ul>
&lt;li>抄一遍代码，看自己能不能运行起来&lt;/li>
&lt;li>给这段代码每一行都加上注释，理解代码做了些什么&lt;/li>
&lt;li>试着将上面的脚本改为实现判断页面上是否有无效图片的工具&lt;/li>
&lt;/ul>
&lt;h3 id="扩展阅读">扩展阅读&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="http://www.testclass.net/2018/04/25/requests-html/" target="_blank" rel="noopener noreffer ">最新的爬虫工具REQUESTS-HTML&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="源码地址">源码地址&lt;/h3>
&lt;p>&lt;a href="https://github.com/easonhan007/simple_test_tools" target="_blank" rel="noopener noreffer ">github地址&lt;/a>&lt;/p></description></item><item><title>puppeteer:官方出品的chrome浏览器自动化测试工具</title><link>https://itest2025.pages.dev/tutorials/47-000-puppeteer%E5%AE%98%E6%96%B9%E5%87%BA%E5%93%81%E7%9A%84chrome%E6%B5%8F%E8%A7%88%E5%99%A8%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7/</link><pubDate>Thu, 26 Jul 2018 07:54:13 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-puppeteer%E5%AE%98%E6%96%B9%E5%87%BA%E5%93%81%E7%9A%84chrome%E6%B5%8F%E8%A7%88%E5%99%A8%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7/</guid><description>&lt;p>puppeteer发布应该有一段时间了，这两天正好基于该工具写了一些自动化解决方案，在这里抛砖引给大家介绍一下。&lt;/p>
&lt;p>官方描述：&lt;/p>
&lt;blockquote>
&lt;p>Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the DevTools Protocol. Puppeteer runs headless by default, but can be configured to run full (non-headless) Chrome or Chromium.&lt;/p>&lt;/blockquote>
&lt;p>简单来说，puppeteer的特点如下&lt;/p>
&lt;ul>
&lt;li>是node的库&lt;/li>
&lt;li>基于DevTools Protocol协议&lt;/li>
&lt;li>默认是无界面模式运行&lt;/li>
&lt;/ul>
&lt;h3 id="安装">安装&lt;/h3>
&lt;pre tabindex="0">&lt;code>npm i puppeteer
# or &amp;#34;yarn add puppeteer&amp;#34;
&lt;/code>&lt;/pre>&lt;h3 id="基本使用方式">基本使用方式&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">puppeteer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;puppeteer&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="kr">async&lt;/span> &lt;span class="p">()&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">browser&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kr">await&lt;/span> &lt;span class="nx">puppeteer&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">launch&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">page&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kr">await&lt;/span> &lt;span class="nx">browser&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">newPage&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">await&lt;/span> &lt;span class="nx">page&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="kr">goto&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;https://example.com&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">await&lt;/span> &lt;span class="nx">page&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">screenshot&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="nx">path&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;example.png&amp;#39;&lt;/span>&lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">await&lt;/span> &lt;span class="nx">browser&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">close&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">})();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上面代码的作用是打开一个页面，然后给这个页面截图，最后关闭浏览器。&lt;/p>
&lt;h3 id="想象空间">想象空间&lt;/h3>
&lt;ul>
&lt;li>可以做一些界面的自动化工作&lt;/li>
&lt;li>可以做爬虫&lt;/li>
&lt;li>可以在服务器上稳定运行，方便容器化&lt;/li>
&lt;/ul>
&lt;h3 id="更多例子">更多例子&lt;/h3>
&lt;p>将页面保存成pdf的例子&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">puppeteer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;puppeteer&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="kr">async&lt;/span> &lt;span class="p">()&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">browser&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kr">await&lt;/span> &lt;span class="nx">puppeteer&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">launch&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">page&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kr">await&lt;/span> &lt;span class="nx">browser&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">newPage&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">await&lt;/span> &lt;span class="nx">page&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="kr">goto&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;https://news.ycombinator.com&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="nx">waitUntil&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;networkidle2&amp;#39;&lt;/span>&lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">await&lt;/span> &lt;span class="nx">page&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">pdf&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="nx">path&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;hn.pdf&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">format&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;A4&amp;#39;&lt;/span>&lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">await&lt;/span> &lt;span class="nx">browser&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">close&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">})();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在页面上下文执行js的例子&lt;/p></description></item><item><title>使用“数据驱动测试”之前应该知道的</title><link>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%BF%E7%94%A8%E6%95%B0%E6%8D%AE%E9%A9%B1%E5%8A%A8%E6%B5%8B%E8%AF%95%E4%B9%8B%E5%89%8D%E5%BA%94%E8%AF%A5%E7%9F%A5%E9%81%93%E7%9A%84/</link><pubDate>Thu, 26 Jul 2018 07:54:13 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%BF%E7%94%A8%E6%95%B0%E6%8D%AE%E9%A9%B1%E5%8A%A8%E6%B5%8B%E8%AF%95%E4%B9%8B%E5%89%8D%E5%BA%94%E8%AF%A5%E7%9F%A5%E9%81%93%E7%9A%84/</guid><description>&lt;p>我曾经写过一篇博客《自动化测试&amp;mdash;被玩坏的数据驱动》讨论过数据驱动测试，当时主要是吐槽那些教大家读取txt、csv/excel、xml文件文章。“我教大家如何做数据驱动测试，来！我们先学习如何读取excel文件。。。”，然后，网上也有大量的文章来介绍如何用excel来管理测试数据的，甚至是测试报告展示的。&lt;/p>
&lt;p>读各种数据文件就是驱动测试？这样真的方便做测试么？&lt;/p>
&lt;h4 id="什么是数据驱动测试">什么是数据驱动测试？&lt;/h4>
&lt;blockquote>
&lt;p>从它的定义来看，就是数据的改变从而驱动自动化测试的执行，最终引起测试结果的改变。说的直白些，就是参数化的应用。&lt;/p>&lt;/blockquote>
&lt;h4 id="他们认为数据驱动什么样子">“他们”认为数据驱动什么样子？&lt;/h4>
&lt;p>这里以csv文件为例，大多文章也是选用的csv/excel文件。
&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/tc_tes_driver_1.png"
 data-srcset="http://img.testclass.net/tc_tes_driver_1.png, http://img.testclass.net/tc_tes_driver_1.png 1.5x, http://img.testclass.net/tc_tes_driver_1.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/tc_tes_driver_1.png"
 title="http://img.testclass.net/tc_tes_driver_1.png" />
参数、断言、结果都有了，大概就这样子吧？&lt;/p>
&lt;p>接下来需要将数据读取出来。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># coding=utf-8&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">csv&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">codecs&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">itertools&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">islice&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 读取本地 CSV 文件&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">csv&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">reader&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">codecs&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;user_info.csv&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;r&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;utf_8_sig&amp;#39;&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 用户存放用户数据&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">users&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 循环输出每一行信息&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">line&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">islice&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">users&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">line&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 打印&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">users&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>得到结果：&lt;/p>
&lt;pre tabindex="0">&lt;code>[[&amp;#39;&amp;#39;, &amp;#39;123&amp;#39;, &amp;#39;请输入帐号&amp;#39;, &amp;#39;&amp;#39;],
[&amp;#39;user&amp;#39;, &amp;#39;&amp;#39;, &amp;#39;请输入密码&amp;#39;, &amp;#39;&amp;#39;],
[&amp;#39;error&amp;#39;, &amp;#39;error&amp;#39;, &amp;#39;帐号或密码错误&amp;#39;,&amp;#39;&amp;#39;],
[&amp;#39;admin&amp;#39;, &amp;#39;admin123&amp;#39;, &amp;#39;admin你好&amp;#39;, &amp;#39;&amp;#39;],
[&amp;#39;guest&amp;#39;, &amp;#39;guest123&amp;#39;, &amp;#39;guest你好&amp;#39;, &amp;#39;&amp;#39;]]
&lt;/code>&lt;/pre>&lt;p>这里得到一个测试数据的二维数组。&lt;/p>
&lt;p>那么接下来要用这些数据做自动化测试了？被测试功能如下：
&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/tc_tes_driver_2.png"
 data-srcset="http://img.testclass.net/tc_tes_driver_2.png, http://img.testclass.net/tc_tes_driver_2.png 1.5x, http://img.testclass.net/tc_tes_driver_2.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/tc_tes_driver_2.png"
 title="http://img.testclass.net/tc_tes_driver_2.png" />&lt;/p></description></item><item><title>使用python实现测试工具(二)</title><link>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%BF%E7%94%A8python%E5%AE%9E%E7%8E%B0%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7%E4%BA%8C/</link><pubDate>Wed, 11 Jul 2018 06:55:32 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%BF%E7%94%A8python%E5%AE%9E%E7%8E%B0%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7%E4%BA%8C/</guid><description>&lt;p>本系列教程使用的python版本是&lt;strong>3.6.3&lt;/strong>。&lt;/p>
&lt;h3 id="背景">背景&lt;/h3>
&lt;p>这一节我们实现一个简单的ui测试工具。&lt;/p>
&lt;p>该工具的作用是访问某个页面，然后根据css选择器去定位页面上的元素，最后判断页面上元素的个数与我们的预期是否相符。&lt;/p>
&lt;p>举一个具体的例子，比如我们去访问&lt;a href="www.itest.info" rel="">www.itest.info&lt;/a>这个页面，我们需要判断页面上&lt;code>class = thumbnail-img&lt;/code>的元素存在，并且有4个。因为每一个元素代表一门课程，所以这个断言的意思是重定向科技主页上应该有4门主要课程。&lt;/p>
&lt;p>视频讲解在&lt;a href="https://ke.qq.com/webcourse/index.html#course_id=246722&amp;amp;term_id=100291046&amp;amp;taid=1567401070281666&amp;amp;vid=x1419ozo3qn" target="_blank" rel="noopener noreffer ">这里&lt;/a>。&lt;/p>
&lt;h3 id="工具设计">工具设计&lt;/h3>
&lt;p>我们设计一个命令行工具，给工具传3个参数。&lt;/p>
&lt;ul>
&lt;li>被访问页面的url&lt;/li>
&lt;li>页面上元素的css选择器&lt;/li>
&lt;li>预期的元素数量，页面上可以存在n个元素，如果传入0，则表示元素不存在，做反向断言&lt;/li>
&lt;/ul>
&lt;p>所以工具大概是这样用的: &lt;code>python script_name.py url css_selector length&lt;/code>&lt;/p>
&lt;h3 id="代码实现">代码实现&lt;/h3>
&lt;p>简单起见，我们会用到requests-html库。安装文档在&lt;a href="http://html.python-requests.org/" target="_blank" rel="noopener noreffer ">这里&lt;/a>。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">requests_html&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">HTMLSession&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">sys&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">argv&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">DEBUG&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">USAGE&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;&amp;#39;&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1">USAGE:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1">python html_assertion.py www.itest.info .thumbnail-img 4
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1">&amp;#39;&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">argv&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">USAGE&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">script_name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">url&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">css_selector&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">length&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">argv&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="n">url&lt;/span>&lt;span class="p">[:&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="s1">&amp;#39;http&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">url&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;http://&amp;#39;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">url&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">session&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">HTMLSession&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">r&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">session&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">elements&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">r&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">html&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">css_selector&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">debug&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">DEBUG&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;*&amp;#39;&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">100&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;css选择器: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">css_selector&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">, 共找到&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">elements&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">个元素&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">element&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">elements&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">element&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">html&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">element&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">attrs&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">elements&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">length&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;失败! 预期&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">length&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">个元素，实际存在&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">elements&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">个元素&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">debug&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;成功!&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">debug&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="精讲">精讲&lt;/h3>
&lt;ul>
&lt;li>用例失败之后使用&lt;code>exit(1)&lt;/code>表示异常退出，这样在使用jenkins运行的时候，用例失败jenkins的job结果也会相应失败&lt;/li>
&lt;li>requests-html库的基本使用参考&lt;a href="http://html.python-requests.org/#tutorial-usage" target="_blank" rel="noopener noreffer ">这里&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="运行示例">运行示例&lt;/h3>
&lt;pre tabindex="0">&lt;code># 失败情况
python html_assertion.py www.itest.info .thumbnail-img 1
失败! 预期1个元素，实际存在4个元素

****************************************************************************************************
css选择器: .thumbnail-img, 共找到4个元素

&amp;lt;div class=&amp;#34;thumbnail-img&amp;#34;&amp;gt;&amp;lt;div class=&amp;#34;overflow-hidden&amp;#34;&amp;gt;&amp;lt;img class=&amp;#34;img-responsive&amp;#34; src=&amp;#34;/uploads/course/image/7/mission_impossible_cut.jpg&amp;#34;/&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;a class=&amp;#34;btn-more hover-effect&amp;#34; href=&amp;#34;/courses/7&amp;#34;&amp;gt;更多&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;
{&amp;#39;class&amp;#39;: (&amp;#39;thumbnail-img&amp;#39;,)}

&amp;lt;div class=&amp;#34;thumbnail-img&amp;#34;&amp;gt;&amp;lt;div class=&amp;#34;overflow-hidden&amp;#34;&amp;gt;&amp;lt;img class=&amp;#34;img-responsive&amp;#34; src=&amp;#34;/uploads/course/image/6/120606ineam4nspdc6qdaw.jpg&amp;#34;/&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;a class=&amp;#34;btn-more hover-effect&amp;#34; href=&amp;#34;/courses/6&amp;#34;&amp;gt;更多&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;
{&amp;#39;class&amp;#39;: (&amp;#39;thumbnail-img&amp;#39;,)}

&amp;lt;div class=&amp;#34;thumbnail-img&amp;#34;&amp;gt;&amp;lt;div class=&amp;#34;overflow-hidden&amp;#34;&amp;gt;&amp;lt;img class=&amp;#34;img-responsive&amp;#34; src=&amp;#34;/uploads/course/image/3/12.jpg&amp;#34;/&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;a class=&amp;#34;btn-more hover-effect&amp;#34; href=&amp;#34;/courses/3&amp;#34;&amp;gt;更多&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;
{&amp;#39;class&amp;#39;: (&amp;#39;thumbnail-img&amp;#39;,)}

&amp;lt;div class=&amp;#34;thumbnail-img&amp;#34;&amp;gt;&amp;lt;div class=&amp;#34;overflow-hidden&amp;#34;&amp;gt;&amp;lt;img class=&amp;#34;img-responsive&amp;#34; src=&amp;#34;/uploads/course/image/2/13.jpg&amp;#34;/&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;a class=&amp;#34;btn-more hover-effect&amp;#34; href=&amp;#34;/courses/2&amp;#34;&amp;gt;更多&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;
{&amp;#39;class&amp;#39;: (&amp;#39;thumbnail-img&amp;#39;,)}

# 成功情况
python html_assertion.py www.itest.info .thumbnail-img 4
成功!

****************************************************************************************************
css选择器: .thumbnail-img, 共找到4个元素

&amp;lt;div class=&amp;#34;thumbnail-img&amp;#34;&amp;gt;&amp;lt;div class=&amp;#34;overflow-hidden&amp;#34;&amp;gt;&amp;lt;img class=&amp;#34;img-responsive&amp;#34; src=&amp;#34;/uploads/course/image/7/mission_impossible_cut.jpg&amp;#34;/&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;a class=&amp;#34;btn-more hover-effect&amp;#34; href=&amp;#34;/courses/7&amp;#34;&amp;gt;更多&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;
{&amp;#39;class&amp;#39;: (&amp;#39;thumbnail-img&amp;#39;,)}

&amp;lt;div class=&amp;#34;thumbnail-img&amp;#34;&amp;gt;&amp;lt;div class=&amp;#34;overflow-hidden&amp;#34;&amp;gt;&amp;lt;img class=&amp;#34;img-responsive&amp;#34; src=&amp;#34;/uploads/course/image/6/120606ineam4nspdc6qdaw.jpg&amp;#34;/&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;a class=&amp;#34;btn-more hover-effect&amp;#34; href=&amp;#34;/courses/6&amp;#34;&amp;gt;更多&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;
{&amp;#39;class&amp;#39;: (&amp;#39;thumbnail-img&amp;#39;,)}

&amp;lt;div class=&amp;#34;thumbnail-img&amp;#34;&amp;gt;&amp;lt;div class=&amp;#34;overflow-hidden&amp;#34;&amp;gt;&amp;lt;img class=&amp;#34;img-responsive&amp;#34; src=&amp;#34;/uploads/course/image/3/12.jpg&amp;#34;/&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;a class=&amp;#34;btn-more hover-effect&amp;#34; href=&amp;#34;/courses/3&amp;#34;&amp;gt;更多&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;
{&amp;#39;class&amp;#39;: (&amp;#39;thumbnail-img&amp;#39;,)}

&amp;lt;div class=&amp;#34;thumbnail-img&amp;#34;&amp;gt;&amp;lt;div class=&amp;#34;overflow-hidden&amp;#34;&amp;gt;&amp;lt;img class=&amp;#34;img-responsive&amp;#34; src=&amp;#34;/uploads/course/image/2/13.jpg&amp;#34;/&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;a class=&amp;#34;btn-more hover-effect&amp;#34; href=&amp;#34;/courses/2&amp;#34;&amp;gt;更多&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;
{&amp;#39;class&amp;#39;: (&amp;#39;thumbnail-img&amp;#39;,)}
&lt;/code>&lt;/pre>&lt;h3 id="动手时间">动手时间&lt;/h3>
&lt;ul>
&lt;li>抄一遍代码，看自己能不能运行起来&lt;/li>
&lt;li>给这段代码每一行都加上注释，理解代码做了些什么&lt;/li>
&lt;/ul>
&lt;h3 id="扩展阅读">扩展阅读&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="http://www.testclass.net/2018/04/25/requests-html/" target="_blank" rel="noopener noreffer ">最新的爬虫工具REQUESTS-HTML&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors" target="_blank" rel="noopener noreffer ">css选择器&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="源码地址">源码地址&lt;/h3>
&lt;p>&lt;a href="https://github.com/easonhan007/simple_test_tools" target="_blank" rel="noopener noreffer ">github地址&lt;/a>&lt;/p></description></item><item><title>使用python实现测试工具(一)</title><link>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%BF%E7%94%A8python%E5%AE%9E%E7%8E%B0%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7%E4%B8%80/</link><pubDate>Tue, 10 Jul 2018 06:55:32 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E4%BD%BF%E7%94%A8python%E5%AE%9E%E7%8E%B0%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7%E4%B8%80/</guid><description>&lt;p>本系列教程我们将使用python实现一些简单的测试工具，为了尽可能的简单，我们的工具以&lt;strong>命令行&lt;/strong>工具为主。&lt;/p>
&lt;p>本系列教程使用的python版本是&lt;strong>3.6.3&lt;/strong>。&lt;/p>
&lt;h3 id="背景">背景&lt;/h3>
&lt;p>这一节我们实现简单的命令行发送get请求的工具，使用方式如下：&lt;/p>
&lt;pre tabindex="0">&lt;code>python get.py www.v2ex.com/api/nodes/show.json\?name\=python
接口地址: http://www.v2ex.com/api/nodes/show.json?name=python

状态码: 200

Headers:
Date : Tue, 10 Jul 2018 07:06:12 GMT
Content-Type : application/json;charset=UTF-8
Transfer-Encoding : chunked
Connection : keep-alive
Vary : Accept-Encoding
X-Rate-Limit-Remaining : 119
Expires : Tue, 10 Jul 2018 08:03:49 GMT
Server : Galaxy/3.9.8.1
Etag : W/&amp;#34;76a33d25372411dc6fa4190a5cf9679caa0edc2a&amp;#34;
X-Rate-Limit-Reset : 1531209600
Cache-Control : max-age=3600
X-Rate-Limit-Limit : 120
Google : XY
Content-Encoding : gzip
Strict-Transport-Security : max-age=31536000
{
 &amp;#34;id&amp;#34; : 90,
 &amp;#34;name&amp;#34; : &amp;#34;python&amp;#34;,
 &amp;#34;url&amp;#34; : &amp;#34;https://www.v2ex.com/go/python&amp;#34;,
 &amp;#34;title&amp;#34; : &amp;#34;Python&amp;#34;,
 &amp;#34;title_alternative&amp;#34; : &amp;#34;Python&amp;#34;,
 &amp;#34;topics&amp;#34; : 9530,
 &amp;#34;stars&amp;#34; : 6601,

 &amp;#34;header&amp;#34; : &amp;#34;这里讨论各种 Python 语言编程话题，也包括 Django，Tornado 等框架的讨论。这里是一个能够帮助你解决实际问题的地方。&amp;#34;,


 &amp;#34;footer&amp;#34; : null,

 &amp;#34;created&amp;#34; : 1278683336,
 &amp;#34;avatar_mini&amp;#34; : &amp;#34;//cdn.v2ex.com/navatar/8613/985e/90_mini.png?m=1531131631&amp;#34;,
 &amp;#34;avatar_normal&amp;#34; : &amp;#34;//cdn.v2ex.com/navatar/8613/985e/90_normal.png?m=1531131631&amp;#34;,
 &amp;#34;avatar_large&amp;#34; : &amp;#34;//cdn.v2ex.com/navatar/8613/985e/90_large.png?m=1531131631&amp;#34;
}
&lt;/code>&lt;/pre>&lt;p>主要使用场景是快速访问http的api接口，查看状态码，响应头以及响应内容。&lt;/p></description></item><item><title>2018年年中网络直播课开课通知</title><link>https://itest2025.pages.dev/tutorials/47-000-2018%E5%B9%B4%E5%B9%B4%E4%B8%AD%E7%BD%91%E7%BB%9C%E7%9B%B4%E6%92%AD%E8%AF%BE%E5%BC%80%E8%AF%BE%E9%80%9A%E7%9F%A5/</link><pubDate>Mon, 09 Jul 2018 07:11:44 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-2018%E5%B9%B4%E5%B9%B4%E4%B8%AD%E7%BD%91%E7%BB%9C%E7%9B%B4%E6%92%AD%E8%AF%BE%E5%BC%80%E8%AF%BE%E9%80%9A%E7%9F%A5/</guid><description>&lt;p>夏天应该是充电的好时机。休息日的时候外面骄阳似火，不如在屋里一边吹冷气一边学习新技能吧。&lt;/p>
&lt;p>从目前的情况看来，自动化测试，接口自动化技术及性能测试技术已经成为了测试人员的必备技能。无论是从初级测试晋升到中高级测试，还是去换一份更加有前途的工作，这些技能已经成为了面试及日常工作中都需要掌握的核心竞争力。&lt;/p>
&lt;p>目前我们开设了这三门课程,均是&lt;strong>线上课程，歪歪语音直播授课，有互动有提问有解答&lt;/strong>。&lt;/p>
&lt;ul>
&lt;li>&lt;a href="http://www.itest.info/courses/7" target="_blank" rel="noopener noreffer ">性能测试入门到精通班&lt;/a>，学费2999，为期4到5个月，周六上午上课。&lt;/li>
&lt;li>&lt;a href="http://www.itest.info/courses/2" target="_blank" rel="noopener noreffer ">selenium自动化测试班(python语言)&lt;/a>，学费2999，为期4到5个月，周日下午上课。&lt;/li>
&lt;li>&lt;a href="http://www.itest.info/courses/6" target="_blank" rel="noopener noreffer ">接口自动化测试班(python语言)&lt;/a>，学费2999，为期4到5个月，周日上午上课。&lt;/li>
&lt;/ul>
&lt;p>有兴趣提升自己的同学请QQ联系12079456进行咨询报名吧。&lt;/p>
&lt;p>或者微信联系&lt;strong>重定向&lt;/strong>，二维码如下。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://wx4.sinaimg.cn/mw690/726a2979ly1ft3norn7s0j20by0bymxz.jpg"
 data-srcset="https://wx4.sinaimg.cn/mw690/726a2979ly1ft3norn7s0j20by0bymxz.jpg, https://wx4.sinaimg.cn/mw690/726a2979ly1ft3norn7s0j20by0bymxz.jpg 1.5x, https://wx4.sinaimg.cn/mw690/726a2979ly1ft3norn7s0j20by0bymxz.jpg 2x"
 data-sizes="auto"
 alt="https://wx4.sinaimg.cn/mw690/726a2979ly1ft3norn7s0j20by0bymxz.jpg"
 title="重定向科技二维码" />&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1529688124-e6c364d3285c?w=300"
 data-srcset="https://images.unsplash.com/photo-1529688124-e6c364d3285c?w=300, https://images.unsplash.com/photo-1529688124-e6c364d3285c?w=300 1.5x, https://images.unsplash.com/photo-1529688124-e6c364d3285c?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1529688124-e6c364d3285c?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>一步一步教你打造接口测试平台(2)</title><link>https://itest2025.pages.dev/tutorials/47-000-%E4%B8%80%E6%AD%A5%E4%B8%80%E6%AD%A5%E6%95%99%E4%BD%A0%E6%89%93%E9%80%A0%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B02/</link><pubDate>Thu, 21 Jun 2018 02:08:17 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E4%B8%80%E6%AD%A5%E4%B8%80%E6%AD%A5%E6%95%99%E4%BD%A0%E6%89%93%E9%80%A0%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B02/</guid><description>&lt;p>这一节我们实现下面两个功能&lt;/p>
&lt;ul>
&lt;li>自动判断服务器响应的状态码，如果状态码是4xx，5xx的话则认为请求失败&lt;/li>
&lt;li>增加断言功能，可以判断响应的json字符串里是否包含预期的字段&lt;/li>
&lt;/ul>
&lt;p>为了测试方便，我们先在main.py文件中增加2个测试的接口&lt;/p>
&lt;pre tabindex="0">&lt;code>@app.route(&amp;#39;/api&amp;#39;)
def api():
 return jsonify({&amp;#39;name&amp;#39;: &amp;#39;etf&amp;#39;, &amp;#39;version&amp;#39;: &amp;#39;0.01&amp;#39;})

@app.route(&amp;#39;/error&amp;#39;)
def error():
 codes = [404, 401, 403, 500]
 random.shuffle(codes)
 abort(codes[0])
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>/api接口返回json字符串&lt;code>{&amp;quot;name&amp;quot;: &amp;quot;etf&amp;quot;, &amp;quot;version&amp;quot;: &amp;quot;0.01&amp;quot;}&lt;/code>&lt;/li>
&lt;li>/error接口随机抛出401, 403, 404, 500错误中的1个&lt;/li>
&lt;/ul>
&lt;h3 id="实现状态码自动判断">实现状态码自动判断&lt;/h3>
&lt;p>再修改handle_get()方法&lt;/p>
&lt;pre tabindex="0">&lt;code>def handle_get():
 url = request.form[&amp;#39;url&amp;#39;]
 try:
 r = requests.get(url)
 except Exception as e:
 print(e)
 r = None

 resp = build_resp(r)

 return render_template(&amp;#39;home.html&amp;#39;, resp=resp)

def build_resp(r):
 resp = {&amp;#39;success&amp;#39;: False}
 if r is None:
 return resp

 if r.status_code &amp;lt; 400:
 resp[&amp;#39;success&amp;#39;] = True

 resp[&amp;#39;url&amp;#39;] = r.url
 resp[&amp;#39;text&amp;#39;] = r.text
 resp[&amp;#39;headers&amp;#39;] = r.headers
 resp[&amp;#39;status_code&amp;#39;] = r.status_code

 return resp
&lt;/code>&lt;/pre>&lt;p>这里我们新增了build_resp(r)方法，该方法的主要作用是判断请求响应的状态码，如果小于400就将请求成功状态设置为True。&lt;/p></description></item><item><title>一步一步教你打造接口测试平台(1)</title><link>https://itest2025.pages.dev/tutorials/47-000-%E4%B8%80%E6%AD%A5%E4%B8%80%E6%AD%A5%E6%95%99%E4%BD%A0%E6%89%93%E9%80%A0%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B01/</link><pubDate>Wed, 20 Jun 2018 02:08:17 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E4%B8%80%E6%AD%A5%E4%B8%80%E6%AD%A5%E6%95%99%E4%BD%A0%E6%89%93%E9%80%A0%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B01/</guid><description>&lt;p>发现很多同学对测试平台比较感兴趣，我们这一系列教程就围绕着测试平台的开发来展开。&lt;/p>
&lt;p>本系列教程中，我们将实现一个超级简单的接口测试平台，类似postman，只不过是web版，而不是客户端版本。&lt;/p>
&lt;p>这一节我们将实现在前端界面发送get请求并拿到响应的功能。等于是我们会实现1个调试get接口的平台小工具。&lt;/p>
&lt;p>实现之后的效果是这个样子的。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://github.com/easonhan007/ETF/blob/master/imgs/preview.gif?raw=true"
 data-srcset="https://github.com/easonhan007/ETF/blob/master/imgs/preview.gif?raw=true, https://github.com/easonhan007/ETF/blob/master/imgs/preview.gif?raw=true 1.5x, https://github.com/easonhan007/ETF/blob/master/imgs/preview.gif?raw=true 2x"
 data-sizes="auto"
 alt="https://github.com/easonhan007/ETF/blob/master/imgs/preview.gif?raw=true"
 title="预览" />&lt;/p>
&lt;h3 id="从哪里开始">从哪里开始&lt;/h3>
&lt;p>你可能需要下面的一些知识以便更好的理解教程&lt;/p>
&lt;ul>
&lt;li>python基础，能大致读懂代码就可以&lt;/li>
&lt;li>web服务器知识&lt;/li>
&lt;li>html知识，因为会涉及到提交表单&lt;/li>
&lt;li>最基本的css知识，涉及到几行css代码&lt;/li>
&lt;/ul>
&lt;p>如果你完全没有基础那也没关系，你可以一边学习教程一边学习遇到的新知识点，积少成多，坚持下去就有收获。&lt;/p>
&lt;h3 id="技术选型">技术选型&lt;/h3>
&lt;p>为了尽可能的简单，我们选择使用python来实现测试平台，毕竟python学习成本相对不高，另外python以后也应该是测试岗位的标配技能。&lt;/p>
&lt;p>我们的平台主要是web应用，所以我们选择&lt;a href="http://flask.pocoo.org/docs/1.0/quickstart/" target="_blank" rel="noopener noreffer ">flask&lt;/a>框架来快速实现功能。&lt;/p>
&lt;p>为了能让我们的前端页面稍微好看一点点，我们选择&lt;a href="http://getbootstrap.com/" target="_blank" rel="noopener noreffer ">bootstrap4&lt;/a>作为前端组件。&lt;/p>
&lt;p>为了能够更简单的处理http请求和响应，我们将使用&lt;a href="http://docs.python-requests.org/en/master/" target="_blank" rel="noopener noreffer ">requests&lt;/a>来简化请求处理过程。&lt;/p>
&lt;h3 id="安装依赖">安装依赖&lt;/h3>
&lt;p>对于初学者来说这一步应该是最难的，出错之后希望大家可以去搜索相关的解决方案，不要轻易放弃。&lt;/p>
&lt;p>首先安装python3。&lt;/p>
&lt;p>然后使用pip从命令行安装reqeusts和flask，命令如下&lt;/p>
&lt;pre tabindex="0">&lt;code>pip install requests

pip install Flask
&lt;/code>&lt;/pre>&lt;h3 id="实现ui">实现UI&lt;/h3>
&lt;p>我们先写个页面，也就是让我们的测试平台有个UI可以从浏览器中访问。&lt;/p>
&lt;p>创建文件&lt;code>main.py&lt;/code>，内容如下&lt;/p>
&lt;pre tabindex="0">&lt;code>from flask import Flask, render_template, request
import requests

app = Flask(__name__)

@app.route(&amp;#39;/&amp;#39;)
def home():
 return render_template(&amp;#39;home.html&amp;#39;, resp=None)
&lt;/code>&lt;/pre>&lt;p>在&lt;code>main.py&lt;/code>同级目录下创建&lt;code>templates&lt;/code>文件夹，在文件夹内创建文件&lt;code>home.html&lt;/code>，内容如下&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;lt;html lang=&amp;#34;zh&amp;#34;&amp;gt;
 &amp;lt;head&amp;gt;
 &amp;lt;!-- Required meta tags --&amp;gt;
 &amp;lt;meta charset=&amp;#34;utf-8&amp;#34;&amp;gt;
 &amp;lt;meta name=&amp;#34;viewport&amp;#34; content=&amp;#34;width=device-width, initial-scale=1, shrink-to-fit=no&amp;#34;&amp;gt;

 &amp;lt;!-- Bootstrap CSS --&amp;gt;
 &amp;lt;link rel=&amp;#34;stylesheet&amp;#34; href=&amp;#34;https://cdn.bootcss.com/bootstrap/4.0.0/css/bootstrap.min.css&amp;#34; integrity=&amp;#34;sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm&amp;#34; crossorigin=&amp;#34;anonymous&amp;#34;&amp;gt;
 &amp;lt;style media=&amp;#34;screen&amp;#34;&amp;gt;
 .main-title {
 margin-top: 2rem;
 margin-bottom: 1rem;
 }
 &amp;lt;/style&amp;gt;

 &amp;lt;title&amp;gt;ETF&amp;lt;/title&amp;gt;
 &amp;lt;/head&amp;gt;
 &amp;lt;body&amp;gt;
 &amp;lt;div class=&amp;#34;container&amp;#34;&amp;gt;
 &amp;lt;h3 class=&amp;#34;text text-center main-title&amp;#34;&amp;gt;ETF接口测试平台&amp;lt;/h3&amp;gt;
 &amp;lt;form action=&amp;#34;/handle_get&amp;#34; method=&amp;#34;post&amp;#34;&amp;gt;
 &amp;lt;div class=&amp;#34;form-group&amp;#34;&amp;gt;
 &amp;lt;input type=&amp;#34;text&amp;#34; name=&amp;#34;url&amp;#34; id=&amp;#34;url&amp;#34; placeholder=&amp;#34;请输入URL&amp;#34; class=&amp;#34;form-control&amp;#34; autofocus&amp;gt;
 &amp;lt;/div&amp;gt;
 &amp;lt;div class=&amp;#34;form-group&amp;#34;&amp;gt;
 &amp;lt;input type=&amp;#34;submit&amp;#34; name=&amp;#34;submit&amp;#34; value=&amp;#34;确定&amp;#34; class=&amp;#34;btn btn-primary&amp;#34;&amp;gt;
 &amp;lt;/div&amp;gt;
 &amp;lt;/form&amp;gt;
 &amp;lt;/div&amp;gt;

 &amp;lt;!-- Optional JavaScript --&amp;gt;
 &amp;lt;!-- jQuery first, then Popper.js, then Bootstrap JS --&amp;gt;
 &amp;lt;script src=&amp;#34;https://cdn.bootcss.com/jquery/3.2.1/jquery.slim.min.js&amp;#34; integrity=&amp;#34;sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN&amp;#34; crossorigin=&amp;#34;anonymous&amp;#34;&amp;gt;&amp;lt;/script&amp;gt;
 &amp;lt;script src=&amp;#34;https://cdn.bootcss.com/popper.js/1.12.9/umd/popper.min.js&amp;#34; integrity=&amp;#34;sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q&amp;#34; crossorigin=&amp;#34;anonymous&amp;#34;&amp;gt;&amp;lt;/script&amp;gt;
 &amp;lt;script src=&amp;#34;https://cdn.bootcss.com/bootstrap/4.0.0/js/bootstrap.min.js&amp;#34; integrity=&amp;#34;sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl&amp;#34; crossorigin=&amp;#34;anonymous&amp;#34;&amp;gt;&amp;lt;/script&amp;gt;
 &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code>&lt;/pre>&lt;p>上面的html代码直接拷贝就好，并没有什么技术含量。&lt;/p></description></item><item><title>加班到半夜时,你有没有留下过没有技术的泪水</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%8A%A0%E7%8F%AD%E5%88%B0%E5%8D%8A%E5%A4%9C%E6%97%B6%E4%BD%A0%E6%9C%89%E6%B2%A1%E6%9C%89%E7%95%99%E4%B8%8B%E8%BF%87%E6%B2%A1%E6%9C%89%E6%8A%80%E6%9C%AF%E7%9A%84%E6%B3%AA%E6%B0%B4/</link><pubDate>Tue, 29 May 2018 14:10:12 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%8A%A0%E7%8F%AD%E5%88%B0%E5%8D%8A%E5%A4%9C%E6%97%B6%E4%BD%A0%E6%9C%89%E6%B2%A1%E6%9C%89%E7%95%99%E4%B8%8B%E8%BF%87%E6%B2%A1%E6%9C%89%E6%8A%80%E6%9C%AF%E7%9A%84%E6%B3%AA%E6%B0%B4/</guid><description>&lt;p>最近我们因为一个问题需要加班到半夜。&lt;/p>
&lt;p>因为我们的主干代码里有一个严重的问题，需要紧急修复，这个bug发现的时间很精妙，在发布的前一天夜里。&lt;/p>
&lt;p>那一夜，基本上所有的需求都开发完成了，处于测试状态中，那么如何去修改这个严重的bug呢？开发说就在主干上改，改完以后测试同学顺便加班把其他需求都测完，我们提前一天在半夜强行发布。&lt;/p>
&lt;p>于是测试同学便需要加班到半夜，那天我不在，不知道他们有没有留下没有技术的泪水。&lt;/p>
&lt;p>其实紧急问题没有必要合在常规版本里强行发布。&lt;/p>
&lt;p>一般的做法是在当前生产的分支修复问题，然后把生产分支合回主干。&lt;/p>
&lt;p>但我们的情况没有这么幸运，我们直接在master分支上开发，生产的代码也是master的，这就导致了用单一主干去承载开发，测试和发布3种主要用途，风险很高。&lt;/p>
&lt;p>比如一旦生产有问题，那么就必须去回忆生产代码的具体版本，能够回忆出来的话就从那个版本拉一条分支出来修复问题并测试发布。然后再去master上把相同的代码再改一次，紧急发布分支就不合回master。&lt;/p>
&lt;p>要是回忆不起来版本号的话，那么就只能加班加点测试完master代码，直接发布主干，也就是我们上面发生的情况。&lt;/p>
&lt;p>其实代码管理也算是范质量管理里的一部分。如果团队规模比较小的话，我们可以采用下面的模型&lt;/p>
&lt;ul>
&lt;li>主干: 稳定的代码&lt;/li>
&lt;li>开发分支: 从主干拉出来，开发都提交都开发分支，发布之前将代码合回主干&lt;/li>
&lt;li>发布分支: 开发分支直接合到发布分支&lt;/li>
&lt;li>hotfix分支: 紧急bug修复，从发布分支拉，然后合回发布分支&lt;/li>
&lt;/ul>
&lt;p>配合一些持续集成或者工程化实践，稳定主干模式可以在短时间极大的提升项目质量(前提是当前项目的质量有极大的提升空间)。&lt;/p>
&lt;ul>
&lt;li>对主干进行daily build，每天定时自动化回归&lt;/li>
&lt;li>每次开发分支合入主干进行后进行自动化回归&lt;/li>
&lt;li>hotfix后对hotfix分支进行自动化回归&lt;/li>
&lt;/ul>
&lt;p>自动化用例的组成建议是&lt;/p>
&lt;ul>
&lt;li>40%左右的单元测试&lt;/li>
&lt;li>40%左右的接口测试&lt;/li>
&lt;li>20%左右的ui测试&lt;/li>
&lt;/ul>
&lt;p>建议用例运行时间不超过20分钟。&lt;/p>
&lt;p>回到上面的问题，如果是稳定主干的话，我们可以直接从线上的发布分支拉出hotfix分支，在该分支上进行紧急问题的修复，修复后进行自动化回归，没有问题的话就合到发布分支，发布到线上。最后将修改内容同步到开发分支即可。&lt;/p>
&lt;p>有了这样的代码管理模型，测试同学大概可以避免在夜深人静强上全量代码时留下没有技术的泪水吧。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1474433188271-d3f339f41911?w=300"
 data-srcset="https://images.unsplash.com/photo-1474433188271-d3f339f41911?w=300, https://images.unsplash.com/photo-1474433188271-d3f339f41911?w=300 1.5x, https://images.unsplash.com/photo-1474433188271-d3f339f41911?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1474433188271-d3f339f41911?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>如何使用jenkins自动部署java应用</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8jenkins%E8%87%AA%E5%8A%A8%E9%83%A8%E7%BD%B2java%E5%BA%94%E7%94%A8/</link><pubDate>Tue, 29 May 2018 13:28:39 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8jenkins%E8%87%AA%E5%8A%A8%E9%83%A8%E7%BD%B2java%E5%BA%94%E7%94%A8/</guid><description>&lt;p>其实事情的经过是这样的。&lt;/p>
&lt;p>最近在很短的时间内上线了一个小程序应用，在测试的过程中我们的开发同学很反感自己去测试环境的机器上更新部署java应用。&lt;/p>
&lt;p>为什么反感呢？因为之前的团队有运维，现在单独拉出来做微信小程序，运维的同学没有带过来，部署什么的都要自己手工搞，被惯坏了开发同学哪里咽得下这口气，使用拖字诀，测试环境更新基本看心情，有一些影响测试进度。&lt;/p>
&lt;p>那么就搞自动化部署好了，现在问题就来了，谁去搞？&lt;/p>
&lt;p>开发说应该运维去搞。&lt;/p>
&lt;p>运维说我不在项目组内心有余而力不足。&lt;/p>
&lt;p>测试说你们开发就搞一下，一劳永逸。&lt;/p>
&lt;p>开发说你们测试能不能自己搞，你行你上啊，你来搞给我们看看。&lt;/p>
&lt;p>测试说，那我们用jenkins去建立个简单的任务，这个任务5分钟轮询一次代码库，如果代码有更新就自动build出jar包并部署启动。你们看怎么样？&lt;/p>
&lt;p>开发说我们不管细节，你们随便怎么搞，只要能自动部署上去就好了。&lt;/p>
&lt;p>测试说那麻烦给一下代码库的权限吧。&lt;/p>
&lt;p>开发说自己找配置管理员申请吧。&lt;/p>
&lt;p>测试说那配置管理员能不能帮忙安装一下jenkins。&lt;/p>
&lt;p>开发说你行你上，自己搞定吧。&lt;/p>
&lt;p>大概就是这样，后来测试同学找到一直忙于打杂的我，我就花了点时间帮忙配置了一下。&lt;/p>
&lt;p>下面是我的大致的&amp;quot;作案过程&amp;quot;。&lt;/p>
&lt;p>首先申请在测试环境的机器上安装了jenkins，也就是说如果测试环境是127.0.0.2，那么就在这台机器上装jenkins，这样这台机器就成了master。&lt;/p>
&lt;p>使用下面的命令启动jenkins，因为我们希望jar包启动后常驻后台，而默认情况下jenkins会干掉job里所有的新启动的进程，所以我们必须关掉这个特性。参考&lt;a href="https://wiki.jenkins.io/display/JENKINS/ProcessTreeKiller" target="_blank" rel="noopener noreffer ">这里&lt;/a>&lt;/p>
&lt;pre tabindex="0">&lt;code>java -Dhudson.util.ProcessTree.disable=true -jar jenkins.war
&lt;/code>&lt;/pre>&lt;p>因为项目是用maven构建的，所以在安装jenkins的机器上安装maven，保证&lt;code>mvn&lt;/code>命令可以执行。&lt;/p>
&lt;p>在测试机器上安装git，因为我们需要使用git来拉取最新的代码。&lt;/p>
&lt;p>在测试机器上生成ssh公钥，加到代码管理平台的部署公钥上，这样做的目的是为了可以免密码直接使用git来拉取代码。&lt;/p>
&lt;p>使用git在测试机器上拉取最新代码。确保git没有问题。&lt;/p>
&lt;p>在测试机器上使用&lt;code>mvn install&lt;/code>来build jar包，确保build的过程是没有问题的。&lt;/p>
&lt;p>新建jenkins job，代码管理里填入git远程地址，配置5分钟轮询。&lt;/p>
&lt;p>在构建步骤里选择执行linux shell脚本，脚本大概是下面这个样子。&lt;/p>
&lt;pre tabindex="0">&lt;code>pwd

/usr/local/maven/bin/mvn install

# 找到jar包的pid，其实用awk更简单，我这里是为了使用sed而使用sed，不要学我
java_pid=`ps -C java -o command -o pid | grep jar_name | sed -r &amp;#34;s/java -jar jar_name.jar\s*//g&amp;#34;`

if [[ &amp;#34;$java_pid&amp;#34;==&amp;#34;&amp;#34; ]]; then
 echo &amp;#34;pid do not exists&amp;#34;
 echo $java_pid
else
 echo &amp;#34;kill&amp;#34;
 echo $java_pid
 kill -9 $java_pid
fi

cd target

nohup java -jar jar_name.jar &amp;lt;/dev/null &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 &amp;amp;
&lt;/code>&lt;/pre>&lt;p>嗯，差不多了，多调试几遍，fix一些小问题基本就可以了。&lt;/p></description></item><item><title>selenium是如何启动浏览器的</title><link>https://itest2025.pages.dev/tutorials/47-000-selenium%E6%98%AF%E5%A6%82%E4%BD%95%E5%90%AF%E5%8A%A8%E6%B5%8F%E8%A7%88%E5%99%A8%E7%9A%84/</link><pubDate>Thu, 17 May 2018 05:39:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-selenium%E6%98%AF%E5%A6%82%E4%BD%95%E5%90%AF%E5%8A%A8%E6%B5%8F%E8%A7%88%E5%99%A8%E7%9A%84/</guid><description>&lt;p>前几天有同学问到selenium是怎么样启动浏览器的(selenium启动浏览器的原理)，当时稍微讲解了一下，不过自我感觉不够具体，现在特地把启动原理通过代码和一系列操作给串联起来，希望可以帮助大家更好的理解。&lt;/p>
&lt;p>以chrome浏览器为例，selenium启动chrome浏览器的代码如下：&lt;/p>
&lt;p>&lt;a href="https://github.com/SeleniumHQ/selenium/blob/1a99e2161f8b777672f15fda9b329ee8e89af94a/py/selenium/webdriver/chrome/webdriver.py#L33" target="_blank" rel="noopener noreffer ">源码&lt;/a>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">executable_path&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;chromedriver&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">port&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">options&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">None&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">service_args&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">None&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">desired_capabilities&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">None&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">service_log_path&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">None&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chrome_options&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">None&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> Creates a new instance of the chrome driver.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> Starts the service and then creates new instance of chrome driver.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> :Args:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> - executable_path - path to the executable. If the default is used it assumes the executable is in the $PATH
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> - port - port you would like the service to run, if left as 0, a free port will be found.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> - desired_capabilities: Dictionary object with non-browser specific
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> capabilities only, such as &amp;#34;proxy&amp;#34; or &amp;#34;loggingPref&amp;#34;.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> - options: this takes an instance of ChromeOptions
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">chrome_options&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">warnings&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">warn&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;use options instead of chrome_options&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="ne">DeprecationWarning&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">options&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">chrome_options&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">options&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># desired_capabilities stays as passed in&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">desired_capabilities&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">desired_capabilities&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create_options&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to_capabilities&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">desired_capabilities&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">desired_capabilities&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">options&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to_capabilities&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">desired_capabilities&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">update&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">options&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to_capabilities&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">service&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Service&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">executable_path&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">port&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">port&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">service_args&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">service_args&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">log_path&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">service_log_path&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">service&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">start&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">RemoteWebDriver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">command_executor&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">ChromeRemoteConnection&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">remote_server_addr&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">service&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">service_url&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">desired_capabilities&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">desired_capabilities&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span> &lt;span class="ne">Exception&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">quit&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_is_remote&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>其中跟浏览器启动密切相关的是这几句&lt;/p></description></item><item><title>适合初学者的python实际例子</title><link>https://itest2025.pages.dev/tutorials/47-000-%E9%80%82%E5%90%88%E5%88%9D%E5%AD%A6%E8%80%85%E7%9A%84python%E5%AE%9E%E9%99%85%E4%BE%8B%E5%AD%90/</link><pubDate>Thu, 10 May 2018 12:55:59 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E9%80%82%E5%90%88%E5%88%9D%E5%AD%A6%E8%80%85%E7%9A%84python%E5%AE%9E%E9%99%85%E4%BE%8B%E5%AD%90/</guid><description>&lt;p>最近在github上发现了一个有意思的项目，很适合初学者学习python代码。&lt;/p>
&lt;p>学习一门语言刚开始的时候是很枯燥的，各种概念语法以及无聊的打印都会让人失去更进一步学习的动力。&lt;/p>
&lt;p>很多同学在学习了一段时间之后甚至会怀疑学习语言的用处，因为总是写不出东西，只会写一些简单的打印代码。&lt;/p>
&lt;p>这个叫做&lt;a href="https://github.com/geekcomputers/Python" target="_blank" rel="noopener noreffer ">geekcomputers/Python&lt;/a>的项目很好的回答了一个问题，就是学习python可以做什么。&lt;/p>
&lt;p>仔细观察里面的例子，我们可以发现写一些简单的python代码就可以做很多有意思的事情，比如&lt;/p>
&lt;ul>
&lt;li>批量修改文件的后缀名&lt;/li>
&lt;li>显示文件的一些信息&lt;/li>
&lt;li>测试某个文件夹是否存在，不存在就自动创建&lt;/li>
&lt;li>搜索所有目录下的log文件，并自动压缩归档&lt;/li>
&lt;li>把所有创建时间超过240天的文件移动到某个文件夹&lt;/li>
&lt;li>自动发twitter&lt;/li>
&lt;li>下载最新的漫画&lt;/li>
&lt;li>下载视频网站的视频&lt;/li>
&lt;li>&amp;hellip;&amp;hellip;&lt;/li>
&lt;/ul>
&lt;p>这些例子的代码都很简单，推荐大家这样学习&lt;/p>
&lt;ul>
&lt;li>首先照着这些代码敲一遍&lt;/li>
&lt;li>让代码可以正确运行&lt;/li>
&lt;li>为每一行代码写上注释&lt;/li>
&lt;li>只保留注释，去掉具体代码，看看自己能不能写出来&lt;/li>
&lt;/ul>
&lt;p>相信经过一段时间的努力，你应该可以熟练使用python去实现一些简单有趣的功能了。&lt;/p>
&lt;p>最后附上例子的链接。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;a href="https://github.com/geekcomputers/Python/blob/master/batch_file_rename.py" target="_blank" rel="noopener noreffer ">batch_file_rename.py&lt;/a> - This batch renames a group of files in a given directory, once you pass the current and the new extensions.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://github.com/geekcomputers/Python/blob/master/create_dir_if_not_there.py" target="_blank" rel="noopener noreffer ">create_dir_if_not_there.py&lt;/a> - Checks to see if a directory exists in the users home directory, if not then create it.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://github.com/geekcomputers/Python/blob/master/youtube-downloader%20fast.py" target="_blank" rel="noopener noreffer ">Fast Youtube Downloader&lt;/a> - Downloads youtube videos quickly with parallel threads using aria2c&lt;/p></description></item><item><title>最新的爬虫工具requests-html</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%9C%80%E6%96%B0%E7%9A%84%E7%88%AC%E8%99%AB%E5%B7%A5%E5%85%B7requests-html/</link><pubDate>Wed, 25 Apr 2018 08:17:27 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%9C%80%E6%96%B0%E7%9A%84%E7%88%AC%E8%99%AB%E5%B7%A5%E5%85%B7requests-html/</guid><description>&lt;p>使用Python开发的同学一定听说过Requsts库，它是一个用于发送HTTP请求的测试。如比我们用Python做基于HTTP协议的接口测试，那么一定会首选Requsts，因为它即简单又强大。现在作者Kenneth Reitz 又开发了requests-html 用于做爬虫。&lt;/p>
&lt;p>该项目从3月上线到现在已经7K+的star了！&lt;/p>
&lt;p>GiHub项目地址：&lt;/p>
&lt;p>&lt;a href="https://github.com/kennethreitz/requests-html" target="_blank" rel="noopener noreffer ">https://github.com/kennethreitz/requests-html&lt;/a>&lt;/p>
&lt;p>requests-html 是基于现有的框架 PyQuery、Requests、lxml、beautifulsoup4等库进行了二次封装，作者将Requests设计的简单强大的优点带到了该项目中。&lt;/p>
&lt;h3 id="安装">#安装：&lt;/h3>
&lt;pre tabindex="0">&lt;code>
&amp;gt; pip install requests-html
&lt;/code>&lt;/pre>&lt;h4 id="教程与使用">教程与使用：&lt;/h4>
&lt;p>使用GET请求 &lt;a href="https://python.org" target="_blank" rel="noopener noreffer ">https://python.org&lt;/a> 网站。&lt;/p>
&lt;br>
### ~~~~~~~~~~拜师学艺~~~~~~~~~~
&lt;p>先来看看requests的基本使用。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">requests_html&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">HTMLSession&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">session&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">HTMLSession&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">r&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">session&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;https://python.org/&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 获取页面上的所有链接。&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">all_links&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">r&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">html&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">links&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">all_links&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 获取页面上的所有链接，以绝对路径的方式。&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">all_absolute_links&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">r&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">html&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">absolute_links&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">all_absolute_links&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;br>
### ~~~~~~~~~~小试牛刀~~~~~~~~~~
&lt;p>作为一个IT技术人员，是不是要时时关心一下科技圈的新闻，上博客园新闻频道，抓取最新的推荐新闻。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">requests_html&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">HTMLSession&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">session&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">HTMLSession&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">r&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">session&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;https://news.cnblogs.com/n/recommend&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 通过CSS找到新闻标签&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">news&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">r&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">html&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">find&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;h2.news_entry &amp;gt; a&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">new&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">news&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">new&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 获得新闻标题&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">new&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">absolute_links&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 获得新闻链接&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>执行结果：&lt;/strong>&lt;/p>
&lt;pre tabindex="0">&lt;code>雷军：小米硬件综合净利率永远不超5％！
{&amp;#39;https://news.cnblogs.com/n/595156/&amp;#39;}
苦大仇深的“中国芯”，不妨学一学有趣的树莓派
{&amp;#39;https://news.cnblogs.com/n/595143/&amp;#39;}
我的快递，凭什么不能给我送到家！
{&amp;#39;https://news.cnblogs.com/n/595087/&amp;#39;}
倪光南回应方舟CPU失败论：企业失败不等于技术失败
{&amp;#39;https://news.cnblogs.com/n/595102/&amp;#39;}
清华大学突破纪录：首次实现25个量子接口间量子纠缠
{&amp;#39;https://news.cnblogs.com/n/595103/&amp;#39;}
定向免流量套餐用着爽，但背后的“坑”你可能不知道
{&amp;#39;https://news.cnblogs.com/n/595061/&amp;#39;}
你在微信群侃大山，有人却用微信群发大财
{&amp;#39;https://news.cnblogs.com/n/595059/&amp;#39;}
马云的三观
{&amp;#39;https://news.cnblogs.com/n/595047/&amp;#39;}
美国科技强大的全部秘密
{&amp;#39;https://news.cnblogs.com/n/595043/&amp;#39;}
盖茨看着听证会上的扎克伯格：满眼都是20年前的自己
{&amp;#39;https://news.cnblogs.com/n/595025/&amp;#39;}
史上最清晰癌细胞转移3D影像来袭
{&amp;#39;https://news.cnblogs.com/n/595019/&amp;#39;}
中兴员工：华为仅部分芯片自己设计 谁被美制裁都得死
{&amp;#39;https://news.cnblogs.com/n/594967/&amp;#39;}
作为曾经的华为员工，我想替中兴公司说两句公道话
{&amp;#39;https://news.cnblogs.com/n/594962/&amp;#39;}
匿名网友回评梁宁：方舟bug无数 贴钱给别人都未必用
{&amp;#39;https://news.cnblogs.com/n/594932/&amp;#39;}
一段关于国产芯片和操作系统的往事
{&amp;#39;https://news.cnblogs.com/n/594900/&amp;#39;}
芯片股总市值低于美国巨头 有公司靠政府补助盈利
{&amp;#39;https://news.cnblogs.com/n/594902/&amp;#39;}
被自家律师送上“枪口”的“二流”中兴
{&amp;#39;https://news.cnblogs.com/n/594859/&amp;#39;}
Google正在失去DeepMind？
{&amp;#39;https://news.cnblogs.com/n/594853/&amp;#39;}
&lt;/code>&lt;/pre>&lt;p>扩展：我们可以进一步将这里数据做持久化处理，设计出自己的“头条”。&lt;/p></description></item><item><title>性能测试场景，花5分钟了解一下?</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E5%9C%BA%E6%99%AF%E8%8A%B15%E5%88%86%E9%92%9F%E4%BA%86%E8%A7%A3%E4%B8%80%E4%B8%8B/</link><pubDate>Thu, 19 Apr 2018 08:17:27 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E5%9C%BA%E6%99%AF%E8%8A%B15%E5%88%86%E9%92%9F%E4%BA%86%E8%A7%A3%E4%B8%80%E4%B8%8B/</guid><description>&lt;p>小白学习性能测试的过程中，最普遍的一个问题就是没有办法弄清楚性能测试场景，这是因为，一般来说，小白收到的性能测试需求都是这样的&lt;/p>
&lt;ul>
&lt;li>把某某系统的性能测一下&lt;/li>
&lt;li>把这几个接口的性能测一下&lt;/li>
&lt;li>我们要对这个项目做性能测试，你来搞一下&lt;/li>
&lt;/ul>
&lt;p>这些需求往往让人无所适从。当然小白们也不会坐以待毙，他们会去各种渠道求助，但是遇到这样的需求，恐怕大多数人都会表示爱莫能助。&lt;/p>
&lt;p>今天我们就花5分钟的时间来了解一下性能测试的一种常见场景————重现线上问题。希望大家弄清楚了事情的始末之后能对性能测试场景有一定的感性认识。&lt;/p>
&lt;p>事情的经过是这样的：通过日志发现，用户在夜间2点到2点30分的时候， 访问某些页面的时候特别的慢，可能是出现了性能问题，这时候需要小白同学来重现一下性能问题，以便让开发可以更加有目的性的进行问题排查。&lt;/p>
&lt;p>小白同学大致可以这样做。&lt;/p>
&lt;p>首先确定哪些页面的性能可能出现了问题；这是确定测试范围。&lt;/p>
&lt;p>然后找相关人员，一般是运维或开发，了解一下在出现性能问题的段里，每个页面大概有多少用户进行了访问。这是确定压力负载。&lt;/p>
&lt;p>接着申请一套跟线上一致的测试环境，如果没有办法做到一摸一样，那么我们可以适当的降低规格，但是软硬件架构和一些定时任务等都需要跟线上保持一致。这是搞定测试环境。&lt;/p>
&lt;p>通过测试工具来实现性能测试脚本，来模拟发生性能测试的时间段内用户对系统的访问情况，并在测试环境上进行调试。这是完成测试脚本。&lt;/p>
&lt;p>最后通过给予一定量的负载，并在对应的时间段(2点到2点30分)进行压力测试，重现线上问题。这是测试执行。&lt;/p>
&lt;p>在本例中，系统2点到2点30分之间访问缓慢是因为线上定时任务在频繁的进行数据库操作，导致数据库读取缓慢，从而造成了性能问题，而小白在做测试执行时准确的重现了问题，开发经过排查，很顺利的定位到了问题根源，并解决了问题。&lt;/p>
&lt;p>最后的最后，小白输出测试报告，记录测试过程，并对结果进行建议，比如晚上的定时任务建议采用读写分离来提升数据库性能之类的。&lt;/p>
&lt;p>好了，这是出现问题并重现问题的过程，将这个任务的目的和过程调换一下位置，先自己想象一些测试场景，然后通过增加负载的方式去看看能不能发现问题，这是一般做先验性质的性能测试的过程。&lt;/p>
&lt;p>综上，希望对你有所帮助，有问题欢迎留言讨论。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1506333438925-a6203045b492?w=300"
 data-srcset="https://images.unsplash.com/photo-1506333438925-a6203045b492?w=300, https://images.unsplash.com/photo-1506333438925-a6203045b492?w=300 1.5x, https://images.unsplash.com/photo-1506333438925-a6203045b492?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1506333438925-a6203045b492?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>从高级测试到测试开发</title><link>https://itest2025.pages.dev/tutorials/47-000-%E4%BB%8E%E9%AB%98%E7%BA%A7%E6%B5%8B%E8%AF%95%E5%88%B0%E6%B5%8B%E8%AF%95%E5%BC%80%E5%8F%91/</link><pubDate>Mon, 09 Apr 2018 01:45:04 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E4%BB%8E%E9%AB%98%E7%BA%A7%E6%B5%8B%E8%AF%95%E5%88%B0%E6%B5%8B%E8%AF%95%E5%BC%80%E5%8F%91/</guid><description>&lt;p>最近加入了新的团队，角色发生较大的转变，在这里分享一下自己的感受。&lt;/p>
&lt;h3 id="测试的划分">测试的划分&lt;/h3>
&lt;p>如果我们把产品的生产看成一个流水线的话，那么测试就是流水线上的一个重要岗位，把控着产品的质量。&lt;/p>
&lt;p>当然，产品类型的不同，测试人员的能力不同，可做的事情也会有很大不同，比如是Web产品，那么我们会去做性能测试和Web UI自动化测试；比如是App产品，那么我们会去做专项测试和APP UI自动化测试，再比如是后端接口平台，那么我们会去做接口自动化测试。再比如游戏产品，测试方法和手段又不一样了。&lt;/p>
&lt;p>在此过程中，如果你是一名新手，只能测试UI功能，那么定位为测试工程师；如果你可负责一些复杂业务的测试，并且可以做一些自动化工作，那么定位为中级测试工程师；如果你有丰富的测试经验，综合的测试技术，以及深入到产品内部去做类白盒的测试能力，那么定位为高级测试工程师。（注：这里只是一般的划分，不代表任何公司）&lt;/p>
&lt;h3 id="高级测试">高级测试&lt;/h3>
&lt;p>接下来聊一聊我做高级测试时的工作。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/tc_level_test.png"
 data-srcset="http://img.testclass.net/tc_level_test.png, http://img.testclass.net/tc_level_test.png 1.5x, http://img.testclass.net/tc_level_test.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/tc_level_test.png"
 title="http://img.testclass.net/tc_level_test.png" />&lt;/p>
&lt;p>以我负责的接口平台为例，当开发完成接口开发后，我通过阅读接口代码逻辑的方式进行接口自动化用例的编写，过程中发的代码问题，反馈由开发修改；当我的用例编写完成，那么接口测试也基本搞定。当有新的接口更新时，我就可以重跑接口自动化用例来确保接口的质量，每次只需要对更新的接口编写测试用例。&lt;/p>
&lt;p>由于接口先测试，当产品提供可测界面时，问题就少很多了，只是界面样式和兼容性问题。整体上会在缩短整个测试时间。&lt;/p>
&lt;p>当然，产品测试过程中还会有一些零散的测试需求，可以快速的选取测试工具或编写测试脚本的方式来完成工作。&lt;/p>
&lt;p>这是一般高级测试工程师应该具备的能力。&lt;/p>
&lt;h3 id="测试开发">测试开发&lt;/h3>
&lt;p>接下来谈一谈测试开发，以及它在项目中的定位。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/tc_test_dev.png"
 data-srcset="http://img.testclass.net/tc_test_dev.png, http://img.testclass.net/tc_test_dev.png 1.5x, http://img.testclass.net/tc_test_dev.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/tc_test_dev.png"
 title="http://img.testclass.net/tc_test_dev.png" />&lt;/p>
&lt;p>以我目前所属的团队为例，初创阶段可能是没有测试人员的，随着产品的发展，为了提升产品的质量，另一方面也为了节约人力成本，所以会招一些功能测试人员承担产品的测试工作。开发人员完成功能开发后，由测试人员进行测试。&lt;/p>
&lt;p>当公司进一步发展之后，为了优化团队，提升效率，单纯的功能测试人员就会成为短板，但为了保持团队的运行，不可能把功能测试人员全部替换为高级测试。另一方面功能测试也需要伴随公司成长。另一种办法就是引入测试开发团队。&lt;strong>当然，大公司的测试开发与高级测试是并存的，测试开发只负责工具与平台的开发。&lt;/strong>&lt;/p>
&lt;p>（&lt;strong>注：&lt;/strong> 这里不讨论个体的情况，比如有一位能力很强的测试/Leader推动测试团队转型）&lt;/p>
&lt;p>测试开发不直接参于产品的测试工作。这其实也是与高级测试最大的不同之处。简单将测试开发工作总结为以下几个方面。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>协助开发编写单元测试（并不是所有开发都一定会写单元测试），规范开发输出（比如输出一定标准接口文档）。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>帮助功能测试人员提升技术能力，能够独立完成自动化测试工作。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>开发测试平台：比如，性能测试平台，帮助开发测试进行性能测试。开发接口测试平台，管理与维护接口平台，开发自动化测试平台，方便管理与维护自动化测试。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>挖掘测试需求，通过技术手段帮助测试团队提升测试效率。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>总结下来，就是测试的经验，开发的能力，干着服务于开发与测试的工作。&lt;/p>
&lt;p>最后，测试开发并不是高级测试的下一阶段，只职责不同而已。以上仅个人看法！&lt;/p>
&lt;br>
欢迎关注：__测试圈TC__ 公众号
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/34/BA1yLjNnQCI1yisIZGEi_2013-07-16_1922_IMG_9873.jpg?w=300"
 data-srcset="https://images.unsplash.com/34/BA1yLjNnQCI1yisIZGEi_2013-07-16_1922_IMG_9873.jpg?w=300, https://images.unsplash.com/34/BA1yLjNnQCI1yisIZGEi_2013-07-16_1922_IMG_9873.jpg?w=300 1.5x, https://images.unsplash.com/34/BA1yLjNnQCI1yisIZGEi_2013-07-16_1922_IMG_9873.jpg?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/34/BA1yLjNnQCI1yisIZGEi_2013-07-16_1922_IMG_9873.jpg?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>语言本身和代码规范哪个更重要？</title><link>https://itest2025.pages.dev/tutorials/47-000-%E8%AF%AD%E8%A8%80%E6%9C%AC%E8%BA%AB%E5%92%8C%E4%BB%A3%E7%A0%81%E8%A7%84%E8%8C%83%E5%93%AA%E4%B8%AA%E6%9B%B4%E9%87%8D%E8%A6%81/</link><pubDate>Fri, 30 Mar 2018 01:45:04 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E8%AF%AD%E8%A8%80%E6%9C%AC%E8%BA%AB%E5%92%8C%E4%BB%A3%E7%A0%81%E8%A7%84%E8%8C%83%E5%93%AA%E4%B8%AA%E6%9B%B4%E9%87%8D%E8%A6%81/</guid><description>&lt;p>这两天祖师爷 Martin Fowler的一番言论刷爆了海外朋友圈。&lt;/p>
&lt;blockquote>
&lt;p>I believe that the principles of good programming are more important than what language we code in. I&amp;rsquo;d rather work with well-written JavaScript than badly-written Smalltalk.&lt;/p>&lt;/blockquote>
&lt;p>大概的意思应该是好的编程原则比语言本身更重要。语言无高低，好的编程规范代码风格和代码结构应该比语言本身更重要。&lt;/p>
&lt;p>当然，老外的反应是五花八门的。&lt;/p>
&lt;p>有人认为语言很重要，比如你就很难举出写的不好的Smalltalk的例子。&lt;/p>
&lt;p>有人同意这个观点，好的编码风格确实比语言本身更加重要。&lt;/p>
&lt;p>也有人认为，在项目初期，在烂代码能够更快的将产品呈现给用户，有理有据。&lt;/p>
&lt;p>还有人认为好的语言有必要通过语言特性引导开发者编写出风格更好的代码，也有道理。&lt;/p>
&lt;p>你是怎么理解这句话的呢？你是否同意老马的言论呢？&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1512847179643-f1794c3e0ac8?w=300"
 data-srcset="https://images.unsplash.com/photo-1512847179643-f1794c3e0ac8?w=300, https://images.unsplash.com/photo-1512847179643-f1794c3e0ac8?w=300 1.5x, https://images.unsplash.com/photo-1512847179643-f1794c3e0ac8?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1512847179643-f1794c3e0ac8?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>小白学python时最容易犯的6个错误</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%B0%8F%E7%99%BD%E5%AD%A6python%E6%97%B6%E6%9C%80%E5%AE%B9%E6%98%93%E7%8A%AF%E7%9A%846%E4%B8%AA%E9%94%99%E8%AF%AF/</link><pubDate>Tue, 27 Mar 2018 02:46:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%B0%8F%E7%99%BD%E5%AD%A6python%E6%97%B6%E6%9C%80%E5%AE%B9%E6%98%93%E7%8A%AF%E7%9A%846%E4%B8%AA%E9%94%99%E8%AF%AF/</guid><description>&lt;p>最近又在跟之前的同学一起学习python，一起进步，发现很多测试同学在初学python的时候很容易犯一些错误，特意总结了一下。其实这些错误不仅是在学python时会碰到，在学习其他语言的时候也同样会碰到。&lt;/p>
&lt;h4 id="错误1-缩进">错误1: 缩进&lt;/h4>
&lt;p>python是强制缩进的语言，很多同学在初次接触python时可能会不习惯，缩进老是犯错。比如&lt;/p>
&lt;pre tabindex="0">&lt;code>
Python 2.7.12 (default, Sep 17 2016, 13:47:40)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.38)] on darwin
Type &amp;#34;help&amp;#34;, &amp;#34;copyright&amp;#34;, &amp;#34;credits&amp;#34; or &amp;#34;license&amp;#34; for more information.
&amp;gt;&amp;gt;&amp;gt; good = &amp;#34;ok&amp;#34;
 File &amp;#34;&amp;lt;stdin&amp;gt;&amp;#34;, line 1
 good = &amp;#34;ok&amp;#34;
 ^
IndentationError: unexpected indent
&lt;/code>&lt;/pre>&lt;p>这种错误一般会提示&lt;code>IndentationError&lt;/code>，最后根据错误所在行一般都能够很快的解决问题。&lt;/p>
&lt;h4 id="错误2-中英文符号">错误2: 中英文符号&lt;/h4>
&lt;p>很多初学者是分不清中英文符号的区别的，比如说&lt;code>:&lt;/code>这是英文的冒号，而&lt;code>：&lt;/code>这个冒号是中文的。乍一看长得差不多，但实际上确实不同的字符。比如&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt;&amp;gt;&amp;gt; x = 0
&amp;gt;&amp;gt;&amp;gt; if x == 1：
 File &amp;#34;&amp;lt;stdin&amp;gt;&amp;#34;, line 1
 if x == 1：
 ^
SyntaxError: invalid syntax
&lt;/code>&lt;/pre>&lt;p>上面的错误很明显，语法错误，冒号有问题。作为初学者，下面这些符号在输入的时候你可能需要警惕一些&lt;/p>
&lt;ul>
&lt;li>英文逗号&lt;/li>
&lt;li>英文冒号&lt;/li>
&lt;li>英文小括号&lt;/li>
&lt;li>英文中括号&lt;/li>
&lt;/ul>
&lt;p>符号不准确的情况下，一般python解释器会提示&lt;code>SyntaxError&lt;/code>，遇到这个错误不要怕，想办法解决就好。&lt;/p></description></item><item><title>接口自动化测试？平台VS框架</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%8E%A5%E5%8F%A3%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0vs%E6%A1%86%E6%9E%B6/</link><pubDate>Sun, 25 Mar 2018 14:11:20 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%8E%A5%E5%8F%A3%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E5%B9%B3%E5%8F%B0vs%E6%A1%86%E6%9E%B6/</guid><description>&lt;p>这几天准备接手一些接口的测试开发工作？在技术方案的选型上碰到了一些困惑，拿来和大家探讨。&lt;/p>
&lt;p>在我来新公司之前，团队已经开发出来了相对成熟的接口平台。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/tc_if_platform.png"
 data-srcset="http://img.testclass.net/tc_if_platform.png, http://img.testclass.net/tc_if_platform.png 1.5x, http://img.testclass.net/tc_if_platform.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/tc_if_platform.png"
 title="http://img.testclass.net/tc_if_platform.png" />&lt;/p>
&lt;p>注：以上截图自开源项目&lt;a href="https://github.com/HttpRunner/HttpRunnerManager" target="_blank" rel="noopener noreffer ">HttpRunnerManager&lt;/a> 。&lt;/p>
&lt;p>我们公司的平台要更加完善，可以自定义测试前置，测试后置，添加断言，自定义运行套件，执行SQL语句，定时任务，以及自动发邮件等。最主要的是不用写接口测试代码。&lt;/p>
&lt;p>我在上一家公司是基于单元测试框架写接口自动化测试的。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/tc_if_framework.png"
 data-srcset="http://img.testclass.net/tc_if_framework.png, http://img.testclass.net/tc_if_framework.png 1.5x, http://img.testclass.net/tc_if_framework.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/tc_if_framework.png"
 title="http://img.testclass.net/tc_if_framework.png" />&lt;/p>
&lt;p>注：以上截图取自《&lt;a href="https://item.jd.com/12164814.html" target="_blank" rel="noopener noreffer ">Web接口开发与自动化测试――基于Python语言&lt;/a>》书中项目&lt;a href="https://github.com/defnngj/pyrequest/" target="_blank" rel="noopener noreffer ">pyrequest&lt;/a> 。&lt;/p>
&lt;p>真正的项目要复杂得多，单元测试框架本身就帮我们做了很多事情，集成的参数化插件，极大的减少了用例的编写。可以方便的连接数数据库，初始化数据。同样可以实现HTML测试报告，自动发邮件，结合持续集成做定时任务。&lt;/p>
&lt;p>以下为某抽奖接口的10条测试用例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Python" data-lang="Python">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@parameterized.expand&lt;/span>&lt;span class="p">([&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;all_null&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">10021&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;无效ID&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;lid_mid_error&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;a&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;b&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">10021&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;无效ID&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;mid_error&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">90132&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">10609&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;会员不存在&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;lid_error&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">901&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">132&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">10601&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;活动不存在&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;activity_not_open&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">132&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">10604&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;活动未启用&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;activity_not_start&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">132&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">10605&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;活动未开始&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;activity_has_ended&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">132&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">10606&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;活动已结束&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;not_participate_in_activity&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">11&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">140&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">10612&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;用户没有加入活动&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;have_been_exhausted&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">11&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">132&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">10613&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;您的抽奖次数已用完!&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;is_prisoner&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">11&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">41&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">200&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;您没有中奖&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">test_random&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">lid&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">mid&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">status&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">message&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34; 随机抽奖接口失败用例 &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">MACRequests&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;lid&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">lid&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;mid&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">mid&lt;/span>&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;status&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">status&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;message&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">message&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>前面展示的各自的优势和特点。接下来说说各个的缺点。&lt;/p>
&lt;p>&lt;strong>测试平台的缺点：&lt;/strong>&lt;/p>
&lt;p>添加用例过程有点麻烦。对于一个熟练的测试开发来说，写代码的速度是高于在是高于在Web页面上点点点的。而且平台功能没有写代码灵活。&lt;/p>
&lt;p>&lt;strong>接口框架的缺点：&lt;/strong>&lt;/p>
&lt;p>必须要会写代码。接口测试用例是通过代码完成的，所以要求必须会写代码。框架看不去也没有平台高大上。&lt;/p>
&lt;p>其实，接口测试的难点并不在测试的编写上，而在数据的初始化上。假设有一个用户签到接口，第一次调用返回“签到成功”，第二次调用“已签到”；那我们在跑接口之前是不是要先修改数据状态为“未签到”。怎么构造数据就需要你对业务和表结构非常熟悉。脱离了这一个前提条件，不管是用平台还是框架你都写不出接口用例。如果想把用例设计更加全面可能还需要阅读接口代码的处理逻辑。&lt;/p>
&lt;p>&lt;strong>作为测试开发怎么考虑？&lt;/strong>&lt;/p>
&lt;p>如果做成接口平台，那么需要测试开发具备Web开发能力，主要工作是开发和维护接口平台。只需要教会测试人员使用平台创建接口用例即可。&lt;/p>
&lt;p>如果做成框架，开发工作量要小很多，只需要简单封装一些接口API，定制开发接口测试报告等。主要工作量是教会测试人员去写接口自动化代码。&lt;/p>
&lt;p>作为测试开发，我倾向于平台化，教会徒弟饿死师傅。而且平台也更好衡量测试开发工作。你们觉得呢？&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/uploads/1412026095116d2b0c90e/3bf33993?w=300"
 data-srcset="https://images.unsplash.com/uploads/1412026095116d2b0c90e/3bf33993?w=300, https://images.unsplash.com/uploads/1412026095116d2b0c90e/3bf33993?w=300 1.5x, https://images.unsplash.com/uploads/1412026095116d2b0c90e/3bf33993?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/uploads/1412026095116d2b0c90e/3bf33993?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>开班通知！>> Selenium自动化测试 &amp; 接口自动化测试开发</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%BC%80%E7%8F%AD%E9%80%9A%E7%9F%A5-selenium%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95-%E6%8E%A5%E5%8F%A3%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E5%BC%80%E5%8F%91/</link><pubDate>Sun, 25 Mar 2018 02:11:20 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%BC%80%E7%8F%AD%E9%80%9A%E7%9F%A5-selenium%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95-%E6%8E%A5%E5%8F%A3%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E5%BC%80%E5%8F%91/</guid><description>&lt;br>
&lt;h4 id="selenium自动化测试python班">Selenium自动化测试&amp;ndash;Python班&lt;/h4>
&lt;p>&lt;strong>课程特色：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>经历四年打磨经典课程Selenium自动化课程。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Python已经成为测试人员必备编程语言。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>我们除了注重自动化技术的传授，更注重开发思维的培养。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>appium自动化测试&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>&lt;a href="http://www.itest.info/courses/2" target="_blank" rel="noopener noreffer ">课程大纲&lt;/a>&lt;/p>
&lt;br>
&lt;h4 id="接口自动化测试开发python班">接口自动化测试开发&amp;ndash;Python班&lt;/h4>
&lt;p>&lt;strong>课程特色：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>测试开发/高级测试工程必备&lt;/p>
&lt;/li>
&lt;li>
&lt;p>基于Django框架全面介绍Web开技术&lt;/p>
&lt;/li>
&lt;li>
&lt;p>接口开发全过程 &amp;amp; 用例设计深入剖析&lt;/p>
&lt;/li>
&lt;li>
&lt;p>主流接口工具介绍&lt;/p>
&lt;/li>
&lt;li>
&lt;p>实战接口自动化测试框架开发&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>&lt;a href="http://www.itest.info/courses/6" target="_blank" rel="noopener noreffer ">课程大纲&lt;/a>&lt;/p>
&lt;br>
&lt;h4 id="讲师">讲师&lt;/h4>
&lt;p>虫师：测试开发工程师。&lt;/p>
&lt;p>乙醇：全栈高级工程师。&lt;/p>
&lt;h4 id="咨询qq12079456">咨询QQ：12079456&lt;/h4>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1523712999610-f77fbcfc3843?w=300"
 data-srcset="https://images.unsplash.com/photo-1523712999610-f77fbcfc3843?w=300, https://images.unsplash.com/photo-1523712999610-f77fbcfc3843?w=300 1.5x, https://images.unsplash.com/photo-1523712999610-f77fbcfc3843?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1523712999610-f77fbcfc3843?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>为什么你需要测试某个字段为空的场景</title><link>https://itest2025.pages.dev/tutorials/47-000-%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BD%A0%E9%9C%80%E8%A6%81%E6%B5%8B%E8%AF%95%E6%9F%90%E4%B8%AA%E5%AD%97%E6%AE%B5%E4%B8%BA%E7%A9%BA%E7%9A%84%E5%9C%BA%E6%99%AF/</link><pubDate>Sat, 17 Mar 2018 09:51:23 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BD%A0%E9%9C%80%E8%A6%81%E6%B5%8B%E8%AF%95%E6%9F%90%E4%B8%AA%E5%AD%97%E6%AE%B5%E4%B8%BA%E7%A9%BA%E7%9A%84%E5%9C%BA%E6%99%AF/</guid><description>&lt;p>在 “Null References: The Billion Dollar Mistake” 中，Tony Hoare，null 的发明者，曾经说到：&lt;/p>
&lt;blockquote>
&lt;p>I call it my billion-dollar mistake. At that time, I was designing the first comprehensive type system for references in an object-oriented language. My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn&amp;rsquo;t resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.&lt;/p></description></item><item><title>那些年我从入门到放弃的各种编程语言</title><link>https://itest2025.pages.dev/tutorials/47-000-%E9%82%A3%E4%BA%9B%E5%B9%B4%E6%88%91%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E6%94%BE%E5%BC%83%E7%9A%84%E5%90%84%E7%A7%8D%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/</link><pubDate>Thu, 15 Mar 2018 08:29:07 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E9%82%A3%E4%BA%9B%E5%B9%B4%E6%88%91%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E6%94%BE%E5%BC%83%E7%9A%84%E5%90%84%E7%A7%8D%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/</guid><description>&lt;p>大学时接触过pascal，但只是在作业本上写过代码，似乎考试也得了80分，但是却一行hello world都没有在真机上编译过，也不知道学了这门语言能做什么，老师也没说以后可以做什么，大家就是拿到学分，点到为止。&lt;/p>
&lt;p>毕业以后开始是做手工测试，没什么机会写代码，相反老是被写代码的人鄙视。&lt;/p>
&lt;p>后来右手鼠标手，肩膀基本报废，才感到天天点来点去的日子有点看不到头，不知道该怎么突破。现在想来，那时候其实是不知道测试以后的发展道路，没有目标，所以迷茫。&lt;/p>
&lt;p>穷则思变，那时候好不容易有机会接触了QTP，咬着牙学了vbs，QTP勉强能玩起来，搞了一套所谓的无人值守框架，其实就是定时晚上跑，跑出测试报告，客户也认可，算是有了一点点突破。&lt;/p>
&lt;p>由于以前负责LR的小姐姐回家生小孩去了，幸运的接触到了LR，用LR去搞了一些我当时不能理解的性能测试脚本，这是c语言从入门到放弃。&lt;/p>
&lt;p>但vbs并不是一门应用广泛的语言，于是从入门到放弃，开始乱学php，周六周日反正也没地方去，就在家里敲php代码，费了九牛二虎之力敲了个简单的blog系统，但由于基础太差，只能照着敲，自己写东西还是写不出来。&lt;/p>
&lt;p>凭借着一点点的php+mysql+简单代码基础，我找到了一份测试开发的工作。&lt;/p>
&lt;p>在工作里需要接触shell，于是shell从入门到放弃。&lt;/p>
&lt;p>需要接触ruby，用ruby实现watir的测试用例，于是ruby从入门到放弃。&lt;/p>
&lt;p>需要接触php，开始继续用php写一些后台功能。&lt;/p>
&lt;p>需要接触html+css+js，咬着牙学，闭着眼睛瞎写，每天不是在写代码，而是在制造bug，我就是移动的人肉bug生成器，也在生产上出现过严重问题，也曾经删掉过测试服务器(&lt;code>rm -rf / &lt;/code>)，好在命硬，没有背锅走人。&lt;/p>
&lt;p>应该是到了selenium的爆发的时候了吧，所以java从入门到放弃，为的是调用selenium RC以及最早版本的webdrier java binding。&lt;/p>
&lt;p>学python也是为了使用webdriver，python没正经学过，水平自然是在平均值以下，这是python 从入门到放弃。&lt;/p>
&lt;p>移动端app兴起了，java捡起来写android应用，突然发现java性价比确实很高，总能找到应用的点。&lt;/p>
&lt;p>学objective-c是为了写ios应用，正经学了，但是水平依旧很差，包括后来的swift，水平都一般，都是从入门到放弃。&lt;/p>
&lt;p>node的兴起以及前端的爆发使得我被迫去学习ES6以及很多前端框架，很花时间，但也算值得。&lt;/p>
&lt;p>docker的兴起使得我对go lang很感兴趣，于是从入门到放弃之。&lt;/p>
&lt;p>另外受ruby社区影响，我也去学习了rust和elixir，各有千秋，挺有意思。&lt;/p>
&lt;p>因为一些临时需求也折腾过lua了，erlang了,c#, solidity了之类的语言，应该还有其他的，想不起来了。&lt;/p>
&lt;p>总之，这些花去了我很多的时间，特别是刚开始的时候，需要下苦功夫去堆代码量，会了一些套路之后，其他语言从入门到放弃花的时间就会少一点了。&lt;/p>
&lt;p>对测试同学来说，有时间就推荐学一门编译性语言，一门脚本语言，没时间就直接折腾一门脚本语言，坚持写5000行代码，写完以后可能多多少少会有一些感觉。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1431631927486-6603c868ce5e?w=300"
 data-srcset="https://images.unsplash.com/photo-1431631927486-6603c868ce5e?w=300, https://images.unsplash.com/photo-1431631927486-6603c868ce5e?w=300 1.5x, https://images.unsplash.com/photo-1431631927486-6603c868ce5e?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1431631927486-6603c868ce5e?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>从爱奇艺招聘信息看当前测试开发的技能要求</title><link>https://itest2025.pages.dev/tutorials/47-000-%E4%BB%8E%E7%88%B1%E5%A5%87%E8%89%BA%E6%8B%9B%E8%81%98%E4%BF%A1%E6%81%AF%E7%9C%8B%E5%BD%93%E5%89%8D%E6%B5%8B%E8%AF%95%E5%BC%80%E5%8F%91%E7%9A%84%E6%8A%80%E8%83%BD%E8%A6%81%E6%B1%82/</link><pubDate>Mon, 12 Mar 2018 10:20:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E4%BB%8E%E7%88%B1%E5%A5%87%E8%89%BA%E6%8B%9B%E8%81%98%E4%BF%A1%E6%81%AF%E7%9C%8B%E5%BD%93%E5%89%8D%E6%B5%8B%E8%AF%95%E5%BC%80%E5%8F%91%E7%9A%84%E6%8A%80%E8%83%BD%E8%A6%81%E6%B1%82/</guid><description>&lt;p>很多同学问我测试开发究竟需要会哪些，或者说是测试开发究竟在做些什么？如果泛泛地说就显得很抽象，正好手上有朋友给的测试开发岗位招聘信息，结合jd给大家分解一下。&lt;/p>
&lt;blockquote>
&lt;p>测试开发工程师&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>职位诱惑：
12天带薪年假、有加班费、&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>工作内容：&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>1、负责本部门自动化平台的搭建，挖掘提升播放测试质量的工具需求，能独立完成工具架构和相关模块设计及编码；&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>2、负责部门相关产品终端的深度遍历测试的工具开发；&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>3、负责客户端app性能测试相关工作及相关性能测试工具的开发；&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>4、不断学习新的知识与工具，持续优化改进性能测试策略和测试方法，并及时落地，形成体系；&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>5、完成相关技术文档编写、报告输出、组织和参加相关的技术评审与培训；&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>任职资格：&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>1、本科或以上学历，计算机软件、电子、通讯相关专业优先；&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>2、精通移动客户端性能测试常见指标与测试方法，有安卓开发的app性能测试和分析经验优先；&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>3、熟练使用C++/C、Java、 Python等语言的一种或者多种；&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>4、有白盒测试开发经验优先；&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>5、具有较强的学习能力、沟通能力以及良好的团队协作精神，工作认真负责、积极思考、有耐心、严谨细致、不断创新，具备一定的抗压能力；&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>6、热爱新事物，具有主动学习与研究探索精神；&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>工作地址:&lt;/p>&lt;/blockquote>
&lt;blockquote>
&lt;p>深圳 - 南山区 - 科技园 - 高新科技园科技南四道创维半导体大厦东座&lt;/p>&lt;/blockquote>
&lt;h4 id="先看工作描述">先看工作描述&lt;/h4>
&lt;hr>
&lt;blockquote>
&lt;p>负责本部门自动化平台的搭建，挖掘提升播放测试质量的工具需求，能独立完成工具架构和相关模块设计及编码；
负责部门相关产品终端的深度遍历测试的工具开发；&lt;/p>&lt;/blockquote>
&lt;p>简单来说，第一点就是开发测试工具和平台。一些测试工具可以极大的提升测试的效率，比如测试数据的自动生成工具等。&lt;/p>
&lt;blockquote>
&lt;p>负责客户端app性能测试相关工作及相关性能测试工具的开发；&lt;/p>&lt;/blockquote>
&lt;p>第二点就是专项测试工具的开发，这里是app性能测试工具。&lt;/p>
&lt;p>第三点这个职位还有一定的性能专项的工作要求，要求会app的性能测试。&lt;/p>
&lt;blockquote>
&lt;p>不断学习新的知识与工具，持续优化改进性能测试策略和测试方法，并及时落地，形成体系；&lt;/p>&lt;/blockquote>
&lt;p>第四点，要求你持续学习持续进步，有一定的升值潜力。潜台词就是：你可以不是成品，但是你要表现出进步的潜力和空间。&lt;/p>
&lt;blockquote>
&lt;p>完成相关技术文档编写、报告输出、组织和参加相关的技术评审与培训；&lt;/p>&lt;/blockquote>
&lt;p>最后一点：知识沉淀与传播。不仅自己要技术精通业务能力强，还需要带动整个团队进步。&lt;/p>
&lt;p>从上面的分析我们可以知道，现在的测试开发已经不仅仅要求大家会写自动化用例（ui，接口，性能等）还需要大家有开发工具的能力，总的来说就是要求更高了，因为很多的专业开发人员都无法独立的开发出完整有用的测试工具。不过大家也不用过分担心，很多时候我们的工具都是内部使用的，这种内部工具的开发往往比通用的商用工具要容易不少。&lt;/p>
&lt;h4 id="再看看任职要求">再看看任职要求&lt;/h4>
&lt;hr>
&lt;blockquote>
&lt;p>本科或以上学历，计算机软件、电子、通讯相关专业优先；&lt;/p>&lt;/blockquote>
&lt;p>本科本科本科，计算机相关专业。重要的事情说3遍，现在主流大公司的最低门槛就是本科。非本科的同学可以考虑二线公司，一线公司的学历要求非常严格。&lt;/p>
&lt;blockquote>
&lt;p>熟练使用C++/C、Java、 Python等语言的一种或者多种；&lt;/p>&lt;/blockquote>
&lt;p>会一门主流语言。python学习成本最低，推荐一下。&lt;/p>
&lt;blockquote>
&lt;p>有白盒测试开发经验优先；&lt;/p>&lt;/blockquote>
&lt;p>会写单元测试。这一条的约束力不大，一般来说大家都不会写。&lt;/p></description></item><item><title>开课通知：Android测试开发--Java语言</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%BC%80%E8%AF%BE%E9%80%9A%E7%9F%A5android%E6%B5%8B%E8%AF%95%E5%BC%80%E5%8F%91--java%E8%AF%AD%E8%A8%80/</link><pubDate>Mon, 05 Mar 2018 10:20:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%BC%80%E8%AF%BE%E9%80%9A%E7%9F%A5android%E6%B5%8B%E8%AF%95%E5%BC%80%E5%8F%91--java%E8%AF%AD%E8%A8%80/</guid><description>&lt;br>
&lt;h4 id="android测试开发java语言">Android测试开发&amp;ndash;Java语言&lt;/h4>
&lt;hr>
&lt;p>&lt;strong>课程特色：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Android开发基础&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Android官方测试库（Espresso/UI Automator/Robolectric）&lt;/p>
&lt;/li>
&lt;li>
&lt;p>完整测试开发技术体系（Maven/Gradle/Git/Jenkins/docker）&lt;/p>
&lt;/li>
&lt;li>
&lt;p>单元测试框架（JUnit/TestNG）&lt;/p>
&lt;/li>
&lt;li>
&lt;p>appium从入门到应用&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>课程目标：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>整个课程基于Java语言，对Java下的技术体系有全面的认识。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>掌握一定的Android开发基础，对Android官方测试库有全面的认识。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>掌握appium自动化测试的应用，并自动化测试技术有深刻的理解。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>课程内容：&lt;/strong>&lt;/p>
&lt;p>&lt;a href="http://www.itest.info/courses/8" target="_blank" rel="noopener noreffer ">课程大纲&lt;/a>&lt;/p>
&lt;p>&lt;strong>开课时间：&lt;/strong>&lt;/p>
&lt;p>&lt;font color='red'>2018年03月10日&lt;/font>&lt;/p>
&lt;br>
&lt;h4 id="讲师">讲师&lt;/h4>
&lt;ul>
&lt;li>虫师：高级测试工程师&lt;/li>
&lt;/ul>
&lt;h4 id="咨询qq12079456">咨询QQ：12079456&lt;/h4>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1508923567004-3a6b8004f3d7?w=300"
 data-srcset="https://images.unsplash.com/photo-1508923567004-3a6b8004f3d7?w=300, https://images.unsplash.com/photo-1508923567004-3a6b8004f3d7?w=300 1.5x, https://images.unsplash.com/photo-1508923567004-3a6b8004f3d7?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1508923567004-3a6b8004f3d7?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>测试圈TC：又到一年换工作季</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E5%8F%88%E5%88%B0%E4%B8%80%E5%B9%B4%E6%8D%A2%E5%B7%A5%E4%BD%9C%E5%AD%A3/</link><pubDate>Mon, 05 Mar 2018 08:10:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E5%8F%88%E5%88%B0%E4%B8%80%E5%B9%B4%E6%8D%A2%E5%B7%A5%E4%BD%9C%E5%AD%A3/</guid><description>&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/tc_2018_jobs.png"
 data-srcset="http://img.testclass.net/tc_2018_jobs.png, http://img.testclass.net/tc_2018_jobs.png 1.5x, http://img.testclass.net/tc_2018_jobs.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/tc_2018_jobs.png"
 title="http://img.testclass.net/tc_2018_jobs.png" />&lt;/p>
&lt;p>又到一年换工作的季节，这里给同学一点建议！&lt;/p>
&lt;h4 id="不要频繁的跳槽">不要频繁的跳槽&lt;/h4>
&lt;p>如果你保持一年一跳的频率，或者更短，那么你可能需要慎重了。因为频繁的跳槽会给下家公司造成一种不稳定的感受。诚然，跳槽会成为薪资进阶的一种手段。比如你第一年的工资是5000，按照每年20%的加薪节奏加，这其实已经很高了，其实很多公司达不到这个幅度。&lt;/p>
&lt;p>5000 -&amp;gt; 6000 -&amp;gt; 7200 -&amp;gt; 8640。 至少需要四年才能达到8000+ ，但如果你工作满一到两年且具备扎实的测试基础，很可能通过跳槽就可以直接达到8k 或 1W。但是这种增长会随着年龄消减，比如你工作8年时达到30K，就很难通过跳槽达到50K。因为能提供50K职位并不多，另一方面综合能力的要求也会变得很高。参考金子塔模型，只有少数人站在塔顶。&lt;/p>
&lt;h4 id="不要妄图通过跳槽来提升技能">不要妄图通过跳槽来提升技能&lt;/h4>
&lt;p>我经常听到测试同学抱怨，现在的工作没有技术含量。希望通过跳槽来学到更多技术，如自动化测试、性能测试等。哪怕工资提升不多也可以接受。&lt;/p>
&lt;p>公司和学校是不一样的，公司招人是看你具备什么样的技能，可以帮助公司带来什么价值。这是公司招聘和支付薪水的标准。并且是创造环境帮助你成长的。反过来，当你成长了之后，是否会觉得当前薪水已经不匹配自己的技能，从而谋求更多高薪水？&lt;/p>
&lt;p>当然，好的公司会帮助员工一起成长。但最终也是为了自身的发展。&lt;/p>
&lt;p>&lt;strong>“大多数公司希望招聘到牛X的人来提升团队的能力，大多数人又希望加入牛X的团队来提高自己的技能。”&lt;/strong> 这是一个长期存在的矛盾。&lt;/p>
&lt;p>所以，我们要善于挖掘工作中的测试需求，并且通过勤奋好学习得解决需求的技能，把这些技能真正变成自己的能力。这样以才会有更优秀的团队邀请你加入。&lt;/p>
&lt;h4 id="不要只看薪水">不要只看“薪水”&lt;/h4>
&lt;p>当有多家公司满足了你的期望薪资之后，就不要把薪水作为权衡标准了。好的公司是可有助于你今后的发展的。我有一个朋友，当初在选择工作时，因为其中一家外包公司多给了几百块钱，而选择了外包，结果发现外包公司没有发展而选择跳槽，之后的几份工作也因为各种原因继续选择外包。几年过后，发现自己只熟悉一类系统的测试。简历上也没有擅长技术积累，跳槽的范围和薪水都受到了很大的局限。&lt;/p>
&lt;p>所以，要有长远的眼光去评估新的工作，这个行业是否有未来？是否是自己喜欢的业务？公司文化与发展。是否为下一次的跳槽提供更大的空间。&lt;/p>
&lt;h4 id="不要简历掺假">不要简历“掺假”&lt;/h4>
&lt;p>最后一条，我们可以适当对做过的一些项目进行美化，但最好不要罗列你熟悉的工具或技术。当然，这可能会影响到你的简历是否通过筛选。这也是前面我建议你要学好技术并尝试在工作中运用的原因。只有转化成自己的技能，才能从容应对各种细节问题。&lt;/p>
&lt;p>不要面试时回答：这个工具我只是搭建过环境。这就很尴尬了！从而给面试官造成不好印象。&lt;/p>
&lt;br>
以上个人一点建议，如果你正在找工作，预祝你找到自己称心的工作！
&lt;p>&lt;a href="https://mp.weixin.qq.com/s/ERUBHznouMfbotdpL7jLlg" target="_blank" rel="noopener noreffer ">阅读原文&lt;/a>&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1500817487388-039e623edc21?w=300"
 data-srcset="https://images.unsplash.com/photo-1500817487388-039e623edc21?w=300, https://images.unsplash.com/photo-1500817487388-039e623edc21?w=300 1.5x, https://images.unsplash.com/photo-1500817487388-039e623edc21?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1500817487388-039e623edc21?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>在得到之前先评估一下自己会失去什么吧</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%9C%A8%E5%BE%97%E5%88%B0%E4%B9%8B%E5%89%8D%E5%85%88%E8%AF%84%E4%BC%B0%E4%B8%80%E4%B8%8B%E8%87%AA%E5%B7%B1%E4%BC%9A%E5%A4%B1%E5%8E%BB%E4%BB%80%E4%B9%88%E5%90%A7/</link><pubDate>Wed, 31 Jan 2018 06:32:05 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%9C%A8%E5%BE%97%E5%88%B0%E4%B9%8B%E5%89%8D%E5%85%88%E8%AF%84%E4%BC%B0%E4%B8%80%E4%B8%8B%E8%87%AA%E5%B7%B1%E4%BC%9A%E5%A4%B1%E5%8E%BB%E4%BB%80%E4%B9%88%E5%90%A7/</guid><description>&lt;p>我其实是很喜欢罗振宇的得到app的，每天只要花很少的时间就可以学到一些很有用的知识，比如10分钟就可以学会如何跟大部分人达成共识。实话，这确实很吸引我。&lt;/p>
&lt;p>我时间有限，能花十分钟一边坐车一边学习，这种低投入高产出的满足感让我非常受用。&lt;/p>
&lt;p>不过这些碎片化的时间投入，除了带来自己很努力也很有收获的幻觉外，我好像确实也没有实质的提高。&lt;/p>
&lt;p>那么，是什么让我没有真正的得到？&lt;/p>
&lt;p>也许是因为不曾真正的失去些什么吧。&lt;/p>
&lt;p>当我们还是少年的时候，我们失去了大把的时间，把自己锁在学校中学习，早晚自习，各种考试，失去了玩游戏的时间，运动的时间，看电视的时间，最后得到了升学的机会，得到了智力的开发和启蒙。&lt;/p>
&lt;p>工作以后我们失去了去看看这个世界的机会，失去了在外面浪荡的时间，得到了一些薪水和每日通勤的疲惫。&lt;/p>
&lt;p>总的看来，得到必定伴随着失去，得到的越多，很可能对应失去的就越多。反之可能不一定，在方法不正确的情况下，或者在不对的时间地点，你失去的越多不见得可以得到越多。&lt;/p>
&lt;p>很多人跟我说，自己真的努力去学习了新的知识和技术，但总是学不会，这大概是因为失去的还不够多的缘故吧。&lt;/p>
&lt;p>天将降大任于斯人也，必先经过一连串的磨难，这些磨难代表了失去。&lt;/p>
&lt;p>在学习一些新的东西之前，我们可以先问问自己到底愿意失去些什么。是不是愿意失去休息的时间，失去看电视的时间，失去陪伴家人的时间。先知道自己可能会失去啥，然后舍弃那些可以丢弃的部分，这样可能才会真正的得到吧。&lt;/p>
&lt;p>比如，我愿意舍弃所有看视频的时间，来学习前端技术和测试技术。&lt;/p>
&lt;p>你呢？你愿意舍弃些啥，以便真正的得到？&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1495107334309-fcf20504a5ab?w=300"
 data-srcset="https://images.unsplash.com/photo-1495107334309-fcf20504a5ab?w=300, https://images.unsplash.com/photo-1495107334309-fcf20504a5ab?w=300 1.5x, https://images.unsplash.com/photo-1495107334309-fcf20504a5ab?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1495107334309-fcf20504a5ab?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>测试的一点思考</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E7%9A%84%E4%B8%80%E7%82%B9%E6%80%9D%E8%80%83/</link><pubDate>Mon, 29 Jan 2018 01:49:37 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E7%9A%84%E4%B8%80%E7%82%B9%E6%80%9D%E8%80%83/</guid><description>&lt;p>嗯！ 2018年了，这是我拥有“软件测试工程师”身份的第八个年头。&lt;/p>
&lt;p>以前吧！经常看到做了七、八测试的同学都叫自己是“测试老兵”，我倒不想称呼自己“老兵”。&lt;/p>
&lt;p>1、有倚老卖老的嫌疑，当然，这主要看接下来的观点，是否以“老子吃过的盐比你们这帮小兵吃的饭都多！”为格调。&lt;/p>
&lt;p>2、感叹自己真的老了，技术没多大精进，生活压力大，体力比不过小兵。&lt;/p>
&lt;p>3、软件测试已不在是刚刚起步的阶段，大把做了十年以上的同学，何以在此卖老？&lt;/p>
&lt;h4 id="我到底还算不算是测试">我到底还算不算是测试？&lt;/h4>
&lt;p>时至今日，我不知道自己还算不算是一名合格的测试，或者我到底还是不是一名测试。&lt;/p>
&lt;p>刚工作那个几年，我清楚的知道自己是一名测试，因为每天都在学习各种测试工具，与同行讨论测试方法与技巧，大量的时间在编写测试用例，执行测试用例，编写测试报告。这不就是一个测试的日常嘛！&lt;/p>
&lt;p>后来，我渐渐的不写测试报告了，测试用例也写得少了。开始关注（测试）开发技术，写自动化代码，写各种提高效率的脚本，写接口自动化测试用例。当然，软件的功能还是会测试的，不过，没有了测试用例辅助，全凭对产品需求的理解；对产品代码实现的分析，去发现bug。以便于满足用户的需求。&lt;/p>
&lt;p>再后来，我更关注新的技术，这些技术并不局限于“测试”，主流编程语言的发展，软件开发技术（Web框架、Android开发，TDD/BDD）、Git、持续集成、DevOps/TestOps、Docker的应用等。&lt;/p>
&lt;p>所以，我现在到底还算不是一名测试？&lt;/p>
&lt;p>（午夜我从梦中警醒，点上一支烟，陷入了深深的沉思&amp;hellip;..）注：此处，纯属为了装B效果。&lt;/p>
&lt;p>有人站出来说，我们测试应该回归初心，专心学习好测试基本方法，学习那些自动化到底能为公司带来多少价值。&lt;/p>
&lt;p>我突然又想到之前的一个同事，有一段时间SVN的服务器地址老是变，我抱怨了一句，刚前两天用过的一次，现在又要改了。那个同事说：“在这个互联网瞬息万变的时代，你能用一次就不错了。”&lt;/p>
&lt;p>哈哈！这当然是一句调侃，当是否映射了互联网行业的快速发展。当人工智能、自动驾驶、区块链这些技术普及的时候，如果你都不知道这些技术是什么，我不知道你的那些基本测试方法还能不能派上用场。&lt;/p>
&lt;p>对了，有同学还在考ISTQB认证么？&lt;/p>
&lt;p>小孩子的世界才有对错，大人的世界只有立场，你一旦确定了自己的立场，总能找到说服自己和别人的理由。&lt;/p>
&lt;p>（午夜我再次从梦中警醒，点上一支烟，陷入了深深的沉思&amp;hellip;..）注：此处，纯属为了装B×2。&lt;/p>
&lt;h4 id="做测试到xx岁就该转行了">做测试到xx岁就该转行了！&lt;/h4>
&lt;p>我也已经踏入30岁的门槛，那些说30岁就应该转行的同学，还真是未雨绸缪么、居安思危、积谷防饥、防患于未然、早为之所、有备无患、桑土绸缪、防患未然、防微杜渐、养儿防老&amp;hellip;. 反正就是很厉害了。&lt;/p>
&lt;p>不知道你抛出了这样的论调之后，有没有在30岁转职成功，晋升成功。。。不大了，我们再把观点改一就好了。“&lt;strong>做测试到35岁就该转行了！&lt;/strong>”，“&lt;strong>做测试到40岁就该转行了！&lt;/strong>”&amp;hellip; 又多了好多时间给你思考人生和转行的。音乐起：“来呀！快活呀！反正有大把时光。。。”&lt;/p>
&lt;p>我突然又想到了宫崎骏，他做了一辈子的动画，都在大把年纪了，一直嚷嚷都退休，可闲下来不知道干嘛，他说希望能在创作中离开这个世界。&lt;/p>
&lt;p>我又突然想起了成龙，也快一把年纪了，每个危险动作还是尽量自己上，他在采访中说，希望自己在某个危险动作中离开，这可能是最好的告别。&lt;/p>
&lt;p>人这一辈子，能把自己喜欢的事情当成事业，并通过这个事业成就自己，是一件多么幸福的时候的事。可太多人被世俗价值观绑架（当然包括我啦！）。你觉得30岁该转行了，如果这不是一个夕阳行业的话，说明你对目前从事的工作是不爱的。&lt;/p>
&lt;p>（抚摸~！可怜而又无奈的孩子。）&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1518098268026-4e89f1a2cd8e?w=300"
 data-srcset="https://images.unsplash.com/photo-1518098268026-4e89f1a2cd8e?w=300, https://images.unsplash.com/photo-1518098268026-4e89f1a2cd8e?w=300 1.5x, https://images.unsplash.com/photo-1518098268026-4e89f1a2cd8e?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1518098268026-4e89f1a2cd8e?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>不断演进的分层测试模型</title><link>https://itest2025.pages.dev/tutorials/47-000-%E4%B8%8D%E6%96%AD%E6%BC%94%E8%BF%9B%E7%9A%84%E5%88%86%E5%B1%82%E6%B5%8B%E8%AF%95%E6%A8%A1%E5%9E%8B/</link><pubDate>Thu, 25 Jan 2018 01:49:37 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E4%B8%8D%E6%96%AD%E6%BC%94%E8%BF%9B%E7%9A%84%E5%88%86%E5%B1%82%E6%B5%8B%E8%AF%95%E6%A8%A1%E5%9E%8B/</guid><description>&lt;p>分层测试的概念已经提出来多年了，至今已经不再新鲜，不过最近却发现分层测试的模型有了一些演进，在这里给大家分享一下。&lt;/p>
&lt;h3 id="三种模型">三种模型&lt;/h3>
&lt;p>分层测试把测试分层了3个层次，从下往上分别是: 单元测试，服务级的测试以及ui测试。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/level.png"
 data-srcset="http://img.testclass.net/level.png, http://img.testclass.net/level.png 1.5x, http://img.testclass.net/level.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/level.png"
 title="三种模型" />&lt;/p>
&lt;p>上图展示了3种不同的测试成熟度模型，分别是&lt;/p>
&lt;ul>
&lt;li>测试冰淇淋模型&lt;/li>
&lt;li>测试金字塔模型&lt;/li>
&lt;li>测试橄榄球模型&lt;/li>
&lt;/ul>
&lt;h3 id="测试冰淇淋模型">测试冰淇淋模型&lt;/h3>
&lt;p>这种模型的特点如下&lt;/p>
&lt;ul>
&lt;li>单元测试很少&lt;/li>
&lt;li>有一定的服务级的接口测试&lt;/li>
&lt;li>测试的重点放在通过ui去测试系统的功能上&lt;/li>
&lt;/ul>
&lt;p>由于单元测试和接口测试有限，在这种模型下，持续集成的实现难度很高。&lt;/p>
&lt;p>质量的重心放在ui上，就意味着系统必须充分开发完成并且正确部署之后才能进行测试，测试的开始时间相对就会较晚，面临着测试时间不充分的风险。&lt;/p>
&lt;p>自动化测试率有限，测试周期相对可能较长。&lt;/p>
&lt;p>ui测试较多，一些代码级的异常在ui测试时相对难以构造，有较高的测试不充分的风险。&lt;/p>
&lt;p>单元测试少就意味着代码改动的影响很难第一时间得到发现和评估，有可能出现改1个bug送几个bug的情况。&lt;/p>
&lt;p>大多数团队可能都符合这个模型。&lt;/p>
&lt;h3 id="测试金字塔模型">测试金字塔模型&lt;/h3>
&lt;p>对于单体应用来讲，测试金字塔模型是一个比较理想的模型，特点如下&lt;/p>
&lt;ul>
&lt;li>单元测试非常多&lt;/li>
&lt;li>接口级的测试相对少一点点&lt;/li>
&lt;li>ui级的测试最少，通常只是用户验证性的测试，可以用自动化测试去做&lt;/li>
&lt;/ul>
&lt;p>这种模型的好处不言而喻，不过由于该模型对开发人员的测试能力要求很高，而且质量控制基本成为开发的本职工作，所以在一些测试和开发完全分离的团队以及开发技能一般的团队，这种模式往往难以推广。不过一些著名的开源项目基本上都符合这个模型。&lt;/p>
&lt;h3 id="测试橄榄球模型">测试橄榄球模型&lt;/h3>
&lt;ul>
&lt;li>单元测试相对较少&lt;/li>
&lt;li>测试的重心放在接口级的测试上，并且提倡高度自动化&lt;/li>
&lt;li>ui级的测试可以较少&lt;/li>
&lt;/ul>
&lt;p>对于微服务模型的项目来说，服务之间沟通交流的方式一定是各种接口，所以接口是微服务模型项目和产品的核心。橄榄球模型正是抓住了这个重点，把测试的重心放在接口上。&lt;/p>
&lt;p>由于单元测试用例的开发需要额外的知识及技能，加上大家对单元测试的重要性理解也不太一致，所以这个模型弱化了单元测试的作用。&lt;/p>
&lt;p>ui测试由于开始的时间较晚以及实现和执行成本较高，所以这里也相对弱化。&lt;/p>
&lt;p>对于测试同学来说，橄榄球模型里我们可以承担大部分接口层的用例编写以及依赖服务接口的mock工作。&lt;/p>
&lt;p>另外微服务间的协作与信息对称对质量保障来说也是挑战，测试同学可以重点关注一下。&lt;/p>
&lt;p>最后，我说的基本上都是错的。每个团队有不同的质量要求和实践，没有标准，只有参考。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1520190282873-afe1285c9a2a?w=300"
 data-srcset="https://images.unsplash.com/photo-1520190282873-afe1285c9a2a?w=300, https://images.unsplash.com/photo-1520190282873-afe1285c9a2a?w=300 1.5x, https://images.unsplash.com/photo-1520190282873-afe1285c9a2a?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1520190282873-afe1285c9a2a?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>用Python来玩微信《跳一跳》分析</title><link>https://itest2025.pages.dev/tutorials/47-000-%E7%94%A8python%E6%9D%A5%E7%8E%A9%E5%BE%AE%E4%BF%A1%E8%B7%B3%E4%B8%80%E8%B7%B3%E5%88%86%E6%9E%90/</link><pubDate>Mon, 22 Jan 2018 01:10:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E7%94%A8python%E6%9D%A5%E7%8E%A9%E5%BE%AE%E4%BF%A1%E8%B7%B3%E4%B8%80%E8%B7%B3%E5%88%86%E6%9E%90/</guid><description>&lt;p>上周无意中发现的一个《跳一跳》辅助的开源程序；现在已经12k的Star了。&lt;/p>
&lt;p>&lt;a href="https://github.com/wangshub/wechat_jump_game" target="_blank" rel="noopener noreffer ">https://github.com/wangshub/wechat_jump_game&lt;/a>&lt;/p>
&lt;p>今天要就来简单分析一下它的实现原理。当然，目的肯学是学习啦！&lt;/p>
&lt;p>自动化的实现主要用到两个技术。&lt;/p>
&lt;h4 id="adb">ADB&lt;/h4>
&lt;hr>
&lt;p>官方网站：http://adbshell.com/&lt;/p>
&lt;p>Android Debug Bridge（ADB）是一种命令行工具，可以让PC与Android模拟器或连接的手机之间进行通信。&lt;/p>
&lt;p>做Android开发的同学都懂，我们在PC上开发App，需要通过“adb shell install ”命令安装到Android模拟器或连接的手机上运行。当然，Android自动化测试也离不开它。&lt;/p>
&lt;p>这里主要用它来截图，以便来计算跳跃的每个箱子之间的距离。还有最后执行对棋子的按压。&lt;/p>
&lt;p>通过数据线将手机与PC之间连接，开启USB调试功能。通过“adb devices”命令检查是否可以连接调试设备。&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt; adb devices
List of devices attached
d552be87 device
&lt;/code>&lt;/pre>&lt;p>打开微信，启动《跳一跳》小游戏，通过“adb shell screencap”命令截图。&lt;/p>
&lt;pre tabindex="0">&lt;code>D:\&amp;gt; adb shell screencap -p /sdcard/autojump.png
D:\&amp;gt; adb pull /sdcard/autojump.png
&lt;/code>&lt;/pre>&lt;p>“adb pull”命令将保存在手机里的截图拉取到PC当前目录。所以，我在D盘执行该命令，那么图片就会保存到D盘根目录。如下：&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/wechat_jump_img.png"
 data-srcset="http://img.testclass.net/wechat_jump_img.png, http://img.testclass.net/wechat_jump_img.png 1.5x, http://img.testclass.net/wechat_jump_img.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/wechat_jump_img.png"
 title="http://img.testclass.net/wechat_jump_img.png" />&lt;/p>
&lt;h4 id="python">python&lt;/h4>
&lt;hr>
&lt;p>首先，你需要有Python开发环境。&lt;/p>
&lt;p>其次，将项目用Git克隆（或直接下载）到本地。&lt;/p>
&lt;p>通过pip安装依赖库：&lt;/p>
&lt;blockquote>
&lt;p>pip install requirements.txt&lt;/p>&lt;/blockquote>
&lt;p>python部分分手动版和自动版，手动版会每次将截图展示在PC端，手动点击下一个跳跃的箱子，不需要考虑按压时间；所以，想跳哪里就点哪里。&lt;/p>
&lt;p>自动版就高级了，运行脚本后自动在手机上进行跳一跳游戏。接一来分析自动版实现（webchat_jump_auto.py）。作者在脚本里已经写得很清楚了。&lt;/p>
&lt;font color="blue">
__=== 思路 ===__
&lt;p>核心：每次落稳之后截图，根据截图算出棋子的坐标和下一个块顶面的中点坐标，根据两个点的距离乘以一个时间系数获得长按的时间。&lt;/p>
&lt;p>识别棋子：靠棋子的颜色来识别位置，通过截图发现最下面一行大概是一条直线，就从上往下一行一行遍历，比较颜色（颜色用了一个区间来比较）找到最下面的那一行的所有点，然后求个中点，求好之后再让 Y 轴坐标减小棋子底盘的一半高度从而得到中心点的坐标。&lt;/p>
&lt;p>识别棋盘：靠底色和方块的色差来做，从分数之下的位置开始，一行一行扫描，由于圆形的块最顶上是一条线，方形的上面大概是一个点，所以就用类似识别棋子的做法多识别了几个点求中点，这时候得到了块中点的 X 轴坐标，这时候假设现在棋子在当前块的中心，根据一个通过截图获取的固定的角度来推出中点的 Y 坐标。&lt;/p></description></item><item><title>再谈测试人员的核心竞争力</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%86%8D%E8%B0%88%E6%B5%8B%E8%AF%95%E4%BA%BA%E5%91%98%E7%9A%84%E6%A0%B8%E5%BF%83%E7%AB%9E%E4%BA%89%E5%8A%9B/</link><pubDate>Tue, 09 Jan 2018 10:10:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%86%8D%E8%B0%88%E6%B5%8B%E8%AF%95%E4%BA%BA%E5%91%98%E7%9A%84%E6%A0%B8%E5%BF%83%E7%AB%9E%E4%BA%89%E5%8A%9B/</guid><description>&lt;p>最近参加了公司组织的敏捷专场培训，与专家交流了一些测试相关的内容，这里分享一下关于测试人员核心竞争力的一些观点。&lt;/p>
&lt;p>我的观点是测试人员的核心竞争力在于提前发现参与研发过程中的其他人员所无法发现的问题。这里有2个关键字，分别是&lt;/p>
&lt;ul>
&lt;li>提前：问题发现的越早，解决的成本越低。如果1个需求在还未实现的时候就能发现需求的漏洞，那么这种问题的价值是最高的&lt;/li>
&lt;li>别人无法发现：所有人都能发现的问题，你发现了，那就证明你是可以被替代的。别人发现不了，而你可以发现，那么你就是无法被替代&lt;/li>
&lt;/ul>
&lt;p>专家的观点跟我类似，他认为测试同学的核心技能&lt;strong>不是执行用例&lt;/strong>，而是&lt;strong>识别盲点&lt;/strong>。&lt;/p>
&lt;p>测试同学应该要组织整个测试活动，并且识别出系统或者产品的盲点，让合适的人去进行合适的测试活动。比如告诉开发在做单元测试的时候注意哪些点，让测试开发的同学在做接口级的自动化测试的时候注意哪些异常的接口行为等。&lt;/p>
&lt;p>那么识别盲点的能力如何培养呢？我觉得可以从下面几个方面去主动提升这个能力。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>做最熟悉系统或产品的那个人。有同学可能觉得这应该是产品经理或BA的事情。其实产品经理们可能对系统或产品的正常行为比较清楚，对一些异常的行为可能关注度不够，测试同学是有能力做最熟悉产品和系统的那个人的，毕竟任何一个地方出问题首当其冲的就是测试同学；&lt;/p>
&lt;/li>
&lt;li>
&lt;p>经验。老司机们踩过的坑比较多，在一个领域浸淫的时间长了，试过许多错，自然就知道哪些地方出错的概率比较高，提前抛出问题，识别盲点，这大概就是是老司机测试之道吧；&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="关于全栈测试">关于全栈测试&lt;/h3>
&lt;p>目前测试人员的发展方向里出现了全栈测试的概念。&lt;/p>
&lt;p>这个概念具体代表什么，我其实不是很清楚，但职责范围可能会围绕着下面几个方面&lt;/p>
&lt;ul>
&lt;li>
&lt;p>测试左右移：我之前的文章里其实提过，测试可以把质量保障活动左移到需求分析阶段，把质量监控又移到线上阶段。左移要求业务熟练，右移要求运营敏感和技术提升&lt;/p>
&lt;/li>
&lt;li>
&lt;p>自动化执行测试能力：把测试的执行尽可能的分配给机器去做&lt;/p>
&lt;/li>
&lt;li>
&lt;p>识别盲点：核心能力不能丢&lt;/p>
&lt;/li>
&lt;li>
&lt;p>测试工程化：不同的测试策略需要不同的工程支持&lt;/p>
&lt;/li>
&lt;li>
&lt;p>专项测试能力：客户端，性能等专项测试，测试的广度跟精度都需要有&lt;/p>
&lt;/li>
&lt;li>
&lt;p>架构能力：能够识别出架构上的盲点，提前抛出问题，推动解决&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="总结">总结&lt;/h3>
&lt;p>测试的核心竞争力是识别盲点，业界对测试的期望越来越高，大概是出于项目或产品的实际需求以及节约人力成本提升测试效率的考虑。&lt;/p>
&lt;p>测试需要发现问题，但如果越早发现，价值越高。&lt;/p>
&lt;p>开发是可以做测试的，项目进度紧张的时候，其实开发可以顶上做测试，就是所谓的开发右移或者devops。然而开发资源紧张的时候，测试往往没办法左移去帮助开发，可以想到，当开发的质量意识提升，质量行为左右移之后，传统的测试岗位可能会减少。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1454982523318-4b6396f39d3a?w=300"
 data-srcset="https://images.unsplash.com/photo-1454982523318-4b6396f39d3a?w=300, https://images.unsplash.com/photo-1454982523318-4b6396f39d3a?w=300 1.5x, https://images.unsplash.com/photo-1454982523318-4b6396f39d3a?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1454982523318-4b6396f39d3a?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>DevOps/TestOps概念</title><link>https://itest2025.pages.dev/tutorials/47-000-devopstestops%E6%A6%82%E5%BF%B5/</link><pubDate>Mon, 08 Jan 2018 10:20:22 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-devopstestops%E6%A6%82%E5%BF%B5/</guid><description>&lt;p>天下大势分久必合合久必分，早期的软件开发只有软件工程师一人完成，为了提高效率逐渐实行分工模式：开发、测试、运维。不同角色担任不同的任务。分工越来越细之后带来了问题也越来越突出，那就是各角色之间的沟通成本越来越高。而全栈工程师、DevOps/TestOps相关职位和概念的提出，本质就是把不同的工作集中在一个人身上，或者让一个人涉及到更多方面的工作，从而来降低这种沟通成本。&lt;/p>
&lt;p>要想了解TestOps，必须要先了解DevOps。&lt;/p>
&lt;h3 id="devops-介绍">DevOps 介绍&lt;/h3>
&lt;hr>
&lt;p>wikipedia解释：DevOps是一种软件工程文化和实践，旨在统一软件开发(Dev)和软件运维(Ops)。DevOps运动的主要特点是在软件构建的所有步骤中极力提倡自动化和监控，从集成、测试、发布到部署和基础设施管理。DevOps的目标是缩短开发周期，增加部署频率，更可靠的发布，与业务目标紧密结合。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/tc_Devops.png"
 data-srcset="http://img.testclass.net/tc_Devops.png, http://img.testclass.net/tc_Devops.png 1.5x, http://img.testclass.net/tc_Devops.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/tc_Devops.png"
 title="http://img.testclass.net/tc_Devops.png" />&lt;/p>
&lt;p>Dev、QA、Ops的交汇处我们认为就是DevOps。实际上，DevOps就是把产品开发过程中各角色交汇处的活给干了，让各部门都专注于干他们自己的活儿。&lt;/p>
&lt;h4 id="devops与持续集成">DevOps与持续集成&lt;/h4>
&lt;p>DevOps是一个完整的面向IT运维的工作流，以IT自动化以及持续集成（CI）、持续部署（CD）为基础，来优化程式开发、测试、系统运维等所有环节。&lt;/p>
&lt;h4 id="devops-技术栈与工具链">DevOps 技术栈与工具链&lt;/h4>
&lt;p>只讲理论是非常空洞的，我们必须通过技术和工具将DevOps落地。这里整理了主流的工具，其中包括版本控制&amp;amp;协作开发工具、自动化构建和测试工具、持续集成&amp;amp;交付工具、部署工具、维护工具、监控，警告&amp;amp;分析工具等等，这里补充了一些国内的服务，可以让你更好的执行实施 DevOps 工作流。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>版本控制&amp;amp;协作开发：&lt;/strong> GitHub、GitLab、BitBucket、SubVersion、Coding、Gitee&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>自动化构建和测试：&lt;/strong> Apache Ant、Maven、Selenium、UnitTest、JUnit、JMeter、Gradle、PHPUnit&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>持续集成&amp;amp;交付：&lt;/strong> Jenkins、Capistrano、BuildBot、Fabric、Tinderbox、Travis CI、flow.ci Continuum、LuntBuild、CruiseControl、Integrity、Gump、Go&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>容器平台：&lt;/strong> Docker、Rocket、Ubuntu（LXC）、第三方厂商如（AWS/阿里云）&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>配置管理：&lt;/strong> Chef、Puppet、CFengine、Bash、Rudder、Powershell、RunDeck、Saltstack、Ansible&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>微服务平台：&lt;/strong> OpenShift、Cloud Foundry、Kubernetes、Mesosphere&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>服务开通：&lt;/strong> Puppet、Docker Swarm、Vagrant、Powershell、OpenStack Heat&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>日志管理：&lt;/strong> Logstash、CollectD、StatsD、ElasticSearch、Logstash&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>监控，警告&amp;amp;分析：&lt;/strong> Nagios、Ganglia、Sensu、zabbix、ICINGA、Graphite、Kibana&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>除了这种技术和工具外，在项目中制定出符合DevOps的工作流程是关键，但是，这个东西没有固定模板的，不同的项目、不同的团队和公司文化流程和可能有所不同，只要符合DevOps的理念和思想，你们需要走出一条自己的路。&lt;/p>
&lt;h3 id="testops-介绍">TestOps 介绍&lt;/h3>
&lt;hr>
&lt;p>TestOps主要目的是推动整个研发体系与发布体系更多在质量方面。可以这样理解DevOps是从研发推动配合运维和测试，而TestOps是从测试角度推动研发和运维。所以TestOps才是真正把测试落地到整个研发体系的关键岗位。&lt;/p>
&lt;p>关于TestOps定义：测试运维，测试角度推动研发、运维、持续测试到持续集成。&lt;/p>
&lt;p>新的趋势图：&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/tc_TestOps.gif"
 data-srcset="http://img.testclass.net/tc_TestOps.gif, http://img.testclass.net/tc_TestOps.gif 1.5x, http://img.testclass.net/tc_TestOps.gif 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/tc_TestOps.gif"
 title="http://img.testclass.net/tc_TestOps.gif" />&lt;/p>
&lt;p>测试与开发交叉的工作，通过测试驱动开发（TestDev）来进行。&lt;/p>
&lt;p>测试与运维交叉的工作，通过TestOps来完成。&lt;/p>
&lt;p>开发与运维交叉的工作，通过DevOps来完成。&lt;/p>
&lt;p>三个角色交叉的部分工作，由god来做吧！哈哈。&lt;/p>
&lt;h4 id="testops技能">TestOps技能&lt;/h4>
&lt;p>“TestOps”团队的本质是专注于提供所需的基础设施和平台所有级别的测试，从功能测试到集成测试，再到低级单元和API测试。&lt;/p>
&lt;p>Dev能力：Java、Python、PHP、Shell&lt;/p>
&lt;p>Ops能力：Jenkins、Docker、Maven、Ansible、Git、Linux&lt;/p>
&lt;p>Test能力：测试用例、测试方法、缺陷生命周期、单元测试、接口测试、Selenium&lt;/p></description></item><item><title>我是如何测试hello world的</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%88%91%E6%98%AF%E5%A6%82%E4%BD%95%E6%B5%8B%E8%AF%95hello-world%E7%9A%84/</link><pubDate>Mon, 08 Jan 2018 10:10:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%88%91%E6%98%AF%E5%A6%82%E4%BD%95%E6%B5%8B%E8%AF%95hello-world%E7%9A%84/</guid><description>&lt;p>回顾一下问题，对于下面这种简单的hello world代码，我们应该怎么测试呢？&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;hello world&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>下面是我的一些思路，抛砖引玉。&lt;/p>
&lt;p>&lt;strong>注意:下面的代码均在python2.7中运行通过，python3可能无法运行&lt;/strong>&lt;/p>
&lt;h3 id="重构代码测试输出">重构代码，测试输出&lt;/h3>
&lt;p>第一种方式很容易想到，上面的代码没有办法很好的进行测试是因为我们不太好去自动判断输出。&lt;/p>
&lt;p>如果能够拿到具体的输出，然后判断输出是否符合预期，这样测试就相对容易了。&lt;/p>
&lt;p>这里我们需要先假设&lt;code>print&lt;/code>方法是python的内置方法，是可以信任，不需要进行测试的，那么我们的测试点就变成了测试&lt;code>print&lt;/code>方法的入参是不是我们所期望的&lt;code>hello world&lt;/code>字符串。&lt;/p>
&lt;p>重构代码，达到我们的目的，并进行测试&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># test_hello_world.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">unittest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">return_hello_world&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s1">&amp;#39;hello world&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">return_hello_world&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">HelloWorldTest&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TestCase&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">test_return_hello_world&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;hello world&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">return_hello_world&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">main&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="拿到标准输出里的内容做断言">拿到标准输出里的内容做断言&lt;/h3>
&lt;p>其实&lt;code>print&lt;/code>是将参数中的内容打印到标准输出设备，我们只要知道标准输出设备究竟输出了什么内容就可以比较容易的对简单的hello world进行测试了。&lt;/p>
&lt;p>参考&lt;a href="https://stackoverflow.com/questions/16571150/how-to-capture-stdout-output-from-a-python-function-call" target="_blank" rel="noopener noreffer ">这个回答&lt;/a>，我们将实现调用&lt;code>print('hello world')&lt;/code>，然后拿到标准输出中的内容，再去判断标准输出中的内容是否是&lt;code>hello world&lt;/code>，代码如下&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># test_hello_world_1.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">unittest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">sys&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">cStringIO&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">StringIO&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># for python 3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># from io import StringIO&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Capturing&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">list&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__enter__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_stdout&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sys&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stdout&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sys&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stdout&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_stringio&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">StringIO&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="bp">self&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__exit__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">extend&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_stringio&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">getvalue&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">splitlines&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">del&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_stringio&lt;/span> &lt;span class="c1"># free up some memory&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sys&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stdout&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_stdout&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">TestHelloWorld1&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TestCase&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">test_hello_world&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">with&lt;/span> &lt;span class="n">Capturing&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">output&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;hello world&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;hello python&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;hello python 2.7&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;hello world&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">output&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;hello python&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">output&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertEqual&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;hello python 2.7&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">output&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">unittest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">main&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="使用pytest框架进行测试">使用pytest框架进行测试&lt;/h3>
&lt;p>pytest框架自带了捕获标准输出内容的特性，可以参考&lt;a href="https://docs.pytest.org/en/latest/capture.html" target="_blank" rel="noopener noreffer ">官方文档&lt;/a>&lt;/p></description></item><item><title>开课通知：性能测试从入门到精通班</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%BC%80%E8%AF%BE%E9%80%9A%E7%9F%A5%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E7%B2%BE%E9%80%9A%E7%8F%AD/</link><pubDate>Thu, 04 Jan 2018 10:20:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%BC%80%E8%AF%BE%E9%80%9A%E7%9F%A5%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E7%B2%BE%E9%80%9A%E7%8F%AD/</guid><description>&lt;br>
&lt;h4 id="性能测试从入门到精通班">性能测试从入门到精通班&lt;/h4>
&lt;hr>
&lt;p>&lt;strong>课程目标:&lt;/strong>&lt;/p>
&lt;p>性能专项测试培训，通过压力测试工具(jmeter/locust)/siege等了解性能测试的基本原理及性能测试流程。 学会目前主流的性能测试类型：web性能测试及接口性能测试。&lt;/p>
&lt;p>&lt;strong>我们能学到什么&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>学会使用主流性能测试工具：jmeter/locust/siege等&lt;/li>
&lt;li>学会使用linux及进行linux环境搭建和性能监控&lt;/li>
&lt;li>学会性能测试的流程和方法，能够自主进行性能测试&lt;/li>
&lt;li>学会性能测试的种种套路，比如测试场景分析，脚本编写，基准验证，测试报告及性能瓶颈的简单分析&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>课程内容：&lt;/strong>&lt;/p>
&lt;p>&lt;a href="http://www.itest.info/courses/7" target="_blank" rel="noopener noreffer ">课程大纲&lt;/a>&lt;/p>
&lt;p>&lt;strong>开课时间：&lt;/strong>&lt;/p>
&lt;p>&lt;font color='red'>2018年01月20日&lt;/font>&lt;/p>
&lt;br>
&lt;h4 id="讲师">讲师&lt;/h4>
&lt;ul>
&lt;li>
&lt;p>乙醇：测试开发架构师&lt;/p>
&lt;/li>
&lt;li>
&lt;p>虫师：高级测试开发工程师&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h4 id="咨询qq12079456">咨询QQ：12079456&lt;/h4>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1419064642531-e575728395f2?w=300"
 data-srcset="https://images.unsplash.com/photo-1419064642531-e575728395f2?w=300, https://images.unsplash.com/photo-1419064642531-e575728395f2?w=300 1.5x, https://images.unsplash.com/photo-1419064642531-e575728395f2?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1419064642531-e575728395f2?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>如何测试hello world</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%A6%82%E4%BD%95%E6%B5%8B%E8%AF%95hello-world/</link><pubDate>Wed, 03 Jan 2018 10:10:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%A6%82%E4%BD%95%E6%B5%8B%E8%AF%95hello-world/</guid><description>&lt;p>最近在跟敏捷专家聊到了单元测试的相关内容。&lt;/p>
&lt;p>我的问题主要集中在如何推广单元测试。&lt;/p>
&lt;p>我们发现在很多团队，开发人员并不是十分愿意去写单元测试，我认为主要的原因是学习写单元测试是有成本的，很多开发同学并不愿意投入时间去专心研究如何去写单元测试。&lt;/p>
&lt;p>敏捷教练的观点是单元测试很容易写，稍微学一学就会了，比如开发刚开始写hello world的时候就可以顺便写个单元测试用例去测试一下hello world。&lt;/p>
&lt;p>那么问题就来了，怎么去写单元测试用例去测试hello world呢？&lt;/p>
&lt;p>比如下面的python代码，怎么去测试呢?&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;hello world&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>欢迎讨论，欢迎留言。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1464039397811-476f652a343b?w=300"
 data-srcset="https://images.unsplash.com/photo-1464039397811-476f652a343b?w=300, https://images.unsplash.com/photo-1464039397811-476f652a343b?w=300 1.5x, https://images.unsplash.com/photo-1464039397811-476f652a343b?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1464039397811-476f652a343b?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>如何衡量测试人员的产出</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%A6%82%E4%BD%95%E8%A1%A1%E9%87%8F%E6%B5%8B%E8%AF%95%E4%BA%BA%E5%91%98%E7%9A%84%E4%BA%A7%E5%87%BA/</link><pubDate>Thu, 21 Dec 2017 10:20:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%A6%82%E4%BD%95%E8%A1%A1%E9%87%8F%E6%B5%8B%E8%AF%95%E4%BA%BA%E5%91%98%E7%9A%84%E4%BA%A7%E5%87%BA/</guid><description>&lt;p>我们在这几个月里将测试人员下放到了项目组，由项目经理统一管理，项目经理具有一定的考核建议权。&lt;/p>
&lt;p>实行一段时间之后我们发现在某些项目中，有些测试人员一直处于工作量不是很饱和的状态。由于人员的工作是由项目经理安排，而大部分项目经理是不太关注测试活动的，所以安排的工作难免流于形式，没办法充分调动起测试人员的工作积极性。这样就造成了在一些项目里，测试同学经常会某段时间没啥事情做，而版本快上线的时候又忙的焦头烂额，那时候项目经理又会找测试管理部门协调资源，希望能加大投入，准时交付。&lt;/p>
&lt;p>尽管我们发现了这个问题，也跟项目经理提议能不能把暂时闲置的测试人员调出来，学习其他项目的业务逻辑或者是支援别的项目，但这时候项目经理总会说，这个人很忙，不能兼顾其他的工作。&lt;/p>
&lt;p>下面问题就来了，怎么样度量一个测试人员忙碌与否？通过什么指标可以粗略的估算出测试人员的工作产出呢？如果测试人员的产出一直不高，要么就证明工作量不饱和，要么就是能力有问题，需要做技能提升或者是其他优化。&lt;/p>
&lt;p>哪些指标可以衡量测试人员的产出呢？&lt;/p>
&lt;h3 id="编写的用例数量">编写的用例数量&lt;/h3>
&lt;p>测试人员的日常工作基本上就是分析需求，编写用例，执行用例，追踪缺陷。&lt;/p>
&lt;p>编写测试用例的过程实际上加深了对需求的理解，整理了测试思路，找出需求中没有涉及到的地方，然后通过各种方式确定这些模糊的点。&lt;/p>
&lt;p>开发用代码去实现需求，测试同学则使用测试用例去分解需求，还原测试场景，了解需求的真实目的。&lt;/p>
&lt;p>我们是不是可以通过统计每个测试人员在单位时间内编写的用例数量来粗略估计测试的产出呢？应该是大致可以，不过有些需求描述的比较清晰，而有些需求就只有一句话，太多的内容需要去脑补，所以只看用例输出的效率未免不太客观，容易被挑战。&lt;/p>
&lt;p>另外用例编写规范的不一致也可能导致用例输入的效率有较大的差异。有些测试同学的用例基本上是测试点，没有断言信息，这样的用例写起来就比较快；有些人的用例则比较详尽，有测试数据，测试步骤及断言，这样的用例写起来就比较花时间。&lt;/p>
&lt;p>另外一些同学用excel来管理用例，各种拖拽加复制粘贴之后就能批量形成大量的用例，这些用例看起来都差不多，执行的时候能有多大的作用，实在是不好判断。&lt;/p>
&lt;p>如果只看测试用例的数量来判断工作量的话，那么也可能产生一些消极用例的情况。所谓消极的用例指的是测试同学编写很多无效的用例，这些用例看起来内容详尽，步骤及预期都显得挺有章法，但本质上是复制粘贴，只是为了增加用例数量，对具体的测试工作其实并没什么太大帮助。&lt;/p>
&lt;p>因此如何来保证用例的质量呢？如何尽可能多的去设计和输入有效用例，避免消极用例？评审是一个方法，用合适的方式去展示用例，让用例更容易看出端倪也是一个办法。&lt;/p>
&lt;h3 id="执行的用例数量">执行的用例数量&lt;/h3>
&lt;p>很多时候我们都是不看测试用例去执行的，所以执行了多少用例精确统计起来也很困难。很多情况下大家都是按照经验去估计，测的多一点就多估计一点，少一点执行的用例就少写几个，所以执行的用例量可以大致的看出工作量，当然也不排除有人虚报情况。&lt;/p>
&lt;h3 id="会议情况">会议情况&lt;/h3>
&lt;p>开会也是工作量。很多测试同学都会参与需求评审会，项目计划会，测试用例评审会等。如果一个测试同学不是在开会就是在去开会的路上，那么他在其他方面的产出自然会变少，这时候就需要想办法降低沟通成本了。&lt;/p>
&lt;h3 id="完成生命周期的bug数量">完成生命周期的bug数量&lt;/h3>
&lt;p>这些bug应该是有效的bug，也就是说跟开发达成一致的bug。由于bug是有生命周期的，所以只提bug而不去跟踪bug是不行的，因为bug的处理流程并没走完，相应的工作并没有结束。&lt;/p>
&lt;p>完成生命周期的bug数越多，大概可以认为工作量相对越大，但是也不排除有些项目质量其实不错，测不出来多少有效的bug的情况。&lt;/p>
&lt;hr>
&lt;p>从上面的分析可以看出来，这些指标都有一定的片面性，都只能反映出正常情况下的一些产出情况，仔细分析我们会发现，这些指标其实都不算特别合理。这些指标都有一些偏过程导向，如果从结果导向去分析测试同学的工作效果的话，交付后的遗留问题数或者线上bug数也是一些可以参考的指标。从结果导向上看，不管你测试同学做了些什么，投入了什么，只要项目质量没问题，那么大家做的都是对的，是合理的；否则做的越多，错的越多。&lt;/p>
&lt;p>考核测试同学的指标究竟应该是过程导向还是结果导向，其实有些微妙。可以用结果导向为主导，在结果相似的情况下看过程，这也许是一种比较中庸的做法吧。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1494935362342-566c6d6e75b5?w=300"
 data-srcset="https://images.unsplash.com/photo-1494935362342-566c6d6e75b5?w=300, https://images.unsplash.com/photo-1494935362342-566c6d6e75b5?w=300 1.5x, https://images.unsplash.com/photo-1494935362342-566c6d6e75b5?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1494935362342-566c6d6e75b5?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>HTTP协议基础</title><link>https://itest2025.pages.dev/tutorials/23-000-http%E5%8D%8F%E8%AE%AE%E5%9F%BA%E7%A1%80/</link><pubDate>Tue, 19 Dec 2017 14:55:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/23-000-http%E5%8D%8F%E8%AE%AE%E5%9F%BA%E7%A1%80/</guid><description>&lt;p>大多时候，我们使用抓包工具抓取和分析的为HTTP协议，所以，必须要了解HTTP协议。否则抓包工具无从学起。&lt;/p>
&lt;h3 id="http协议">HTTP协议&lt;/h3>
&lt;hr>
&lt;p>超文本传输协议（HTTP，HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。&lt;/p>
&lt;h3 id="特点">特点：&lt;/h3>
&lt;hr>
&lt;p>HTTP协议的主要特点可概括如下：&lt;/p>
&lt;p>1、&lt;strong>支持客户/服务器模式。&lt;/strong>
简单快速：客户向服务器请求服务时，只需传送请求方法和路径。请求方法常用的有GET、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单，使得HTTP服务器的程序规模小，因而通信速度很快。&lt;/p>
&lt;p>2.&lt;strong>灵活：&lt;/strong> HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。&lt;/p>
&lt;p>3.&lt;strong>无连接：&lt;/strong> 无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求，并收到客户的应答后，即断开连接。采用这种方式可以节省传输时间。&lt;/p>
&lt;p>4.&lt;strong>无状态：&lt;/strong> HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息，则它必须重传，这样可能导致每次连接传送的数据量增大。另一方面，在服务器不需要先前信息时它的应答就较快。&lt;/p>
&lt;h4 id="请求类型">请求类型：&lt;/h4>
&lt;hr>
&lt;p>HTTP请求类型：&lt;/p>
&lt;p>请求行以一个方法符号开头，以空格分开，后面跟着请求的URI和协议的版本，格式如下：Method Request-URI HTTP-Version CRLF, 其中 Method表示请求方法；Request-URI是一个统一资源标识符；HTTP-Version表示请求的HTTP协议版本；CRLF表示回车和换行（除了作为结尾的CRLF外，不允许出现单独的CR或LF字符）。&lt;/p>
&lt;p>请求方法（所有方法全为大写）有多种，各个方法的解释如下：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: left">请求方法&lt;/th>
 &lt;th style="text-align: left">说明&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: left">GET&lt;/td>
 &lt;td style="text-align: left">请求获取Request-URI所标识的资源&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">POST&lt;/td>
 &lt;td style="text-align: left">在Request-URI所标识的资源后附加新的数据&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">HEAD &lt;/td>
 &lt;td style="text-align: left">请求获取由Request-URI所标识的资源的响应消息报头&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">PUT  &lt;/td>
 &lt;td style="text-align: left">请求服务器存储一个资源，并用Request-URI作为其标识&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">DELETE&lt;/td>
 &lt;td style="text-align: left">请求服务器删除Request-URI所标识的资源&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">TRACE&lt;/td>
 &lt;td style="text-align: left">请求服务器回送收到的请求信息，主要用于测试或诊断&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">CONNECT&lt;/td>
 &lt;td style="text-align: left">保留将来使用&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: left">OPTIONS&lt;/td>
 &lt;td style="text-align: left">请求查询服务器的性能，或者查询与资源相关的选项和需求&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h4 id="响应状态码">响应状态码：&lt;/h4>
&lt;hr>
&lt;p>状态代码有三位数字组成，第一个数字定义了响应的类别，且有五种可能取值：&lt;/p>
&lt;ul>
&lt;li>1xx：指示信息&amp;ndash;表示请求已接收，继续处理&lt;/li>
&lt;li>2xx：成功&amp;ndash;表示请求已被成功接收、理解、接受&lt;/li>
&lt;li>3xx：重定向&amp;ndash;要完成请求必须进行更进一步的操作&lt;/li>
&lt;li>4xx：客户端错误&amp;ndash;请求有语法错误或请求无法实现&lt;/li>
&lt;li>5xx：服务器端错误&amp;ndash;服务器未能实现合法的请求&lt;/li>
&lt;/ul>
&lt;p>常见状态代码、状态说明：
200 OK      //客户端请求成功
400 Bad Request  //客户端请求有语法错误，不能被服务器所理解
401 Unauthorized //请求未经授权，这个状态代码必须和WWW-Authenticate报头域一起使用 
403 Forbidden  //服务器收到请求，但是拒绝提供服务
404 Not Found  //请求资源不存在，eg：输入了错误的URL
500 Internal Server Error //服务器发生不可预期的错误
503 Server Unavailable  //服务器当前不能处理客户端的请求，一段时间后可能恢复正常&lt;/p></description></item><item><title>测试圈TC：写给想辞职学习的你</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E5%86%99%E7%BB%99%E6%83%B3%E8%BE%9E%E8%81%8C%E5%AD%A6%E4%B9%A0%E7%9A%84%E4%BD%A0/</link><pubDate>Mon, 11 Dec 2017 10:20:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E5%86%99%E7%BB%99%E6%83%B3%E8%BE%9E%E8%81%8C%E5%AD%A6%E4%B9%A0%E7%9A%84%E4%BD%A0/</guid><description>&lt;p>大概在一个多月前，一位同学在QQ上问我辞职的问题：&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/tc_quit_after_sutdy_01.jpg"
 data-srcset="http://img.testclass.net/tc_quit_after_sutdy_01.jpg, http://img.testclass.net/tc_quit_after_sutdy_01.jpg 1.5x, http://img.testclass.net/tc_quit_after_sutdy_01.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/tc_quit_after_sutdy_01.jpg"
 title="http://img.testclass.net/tc_quit_after_sutdy_01.jpg" />&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/tc_quit_after_sutdy_02.jpg"
 data-srcset="http://img.testclass.net/tc_quit_after_sutdy_02.jpg, http://img.testclass.net/tc_quit_after_sutdy_02.jpg 1.5x, http://img.testclass.net/tc_quit_after_sutdy_02.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/tc_quit_after_sutdy_02.jpg"
 title="http://img.testclass.net/tc_quit_after_sutdy_02.jpg" />&lt;/p>
&lt;p>过程大该就是这个样子的，我们想辞职学习（不只是学习，只是没那么快进入下一份工作的一个空档期）无非就以下几个情况：&lt;/p>
&lt;ul>
&lt;li>工作很痛苦，被各种琐事缠身，没有提升空间，想辞职学习某一感兴趣的技术。&lt;/li>
&lt;li>作息不规律，加班太多，身体每下愈况，想辞职调整一下作息，锻炼一下身体，身体是革命的本钱嘛！&lt;/li>
&lt;li>做一些以前一直想做而没有时间去做的事情（比如，学弹琴、学英语、考驾照等）。&lt;/li>
&lt;li>世界那么大，我想去看看！&lt;/li>
&lt;li>&amp;hellip;&lt;/li>
&lt;/ul>
&lt;p>当我们在憧憬这些美好的事情的时候，又必须面临另一些问题。&lt;/p>
&lt;ul>
&lt;li>你的存款是否可以支撑你做以上事情，可以支撑多久？&lt;/li>
&lt;li>怎样有保证完成上述事情，你确定辞职后不会什么也不想做。如果不知道拖延证的威力，可以想想你十一、春节是规划自己假期的，结果是否如规划的那样完成了？&lt;/li>
&lt;li>怎么面对孤独？当周围的人都在上班的时候，学习也好，旅行也好都是你一个人。&lt;/li>
&lt;li>怎么找到新的动力？ 你今天不去上班，可能会失业；但是你今天不去健身（或学英语）并不会受任何影响。&lt;/li>
&lt;li>就算粮弹充足，如果只有支出没有收入，你是否会焦虑？&lt;/li>
&lt;li>&amp;hellip;&lt;/li>
&lt;/ul>
&lt;p>所以，你看！当你选择辞职，开始另一（小）段自己期待的生活时，可能要面临的问题也很多！&lt;/p>
&lt;p>结果是，上面那们同学告诉我他已经找到工作了，而现在离他上一份工作辞职才一个月多。而他原本的辞职学习计划是到明年。他给出的理由是，不会的东西太多，找一份工作边工作边学习，还有稳定的收入，这一点是我赞同的。&lt;/p>
&lt;p>我们学习的技术离不开工作的实践，只有经过工作实践的技术才能会真正理解，并转化成自己的技能。另外，脱离了工作的学习，也很容易迷失方向，我们是应该学习当前热门的技术的呢？还是应该学习自己感兴趣的技术？&lt;/p>
&lt;p>&lt;strong>所以，在没有强大内在和外在的时候，建议不要选择辞职学习。&lt;/strong>&lt;/p>
&lt;p>内在是指必须要有强大的自我学习能力，这其实由平时的习惯养成。如果你平时工作之余从来没有学习的动力和习惯的话，我建议你最好不要盲目自信。&lt;/p>
&lt;p>外在是指你是否有充足的粮草，最好有第二收入，而第二收入的能力也是靠工作之余发展而来的。我一位前同事，是做设计的，平时维护一个60万+的一个公众号，单靠接设计的私活和公众号软文年收入在7位数，这就是他第二收入能力。&lt;/p>
&lt;p>不过，在羡慕别人的时候，他经常透漏出的信息是时间不够用，上厕所还在想问题。单就每天推送高质量原创文章这一点，我是自愧不如的。他的SOHO状态并不是轻松。&lt;/p>
&lt;p>当我们想要处在一个进步阶段的时候（学习当然是进步阶段），一定是会很累的。如果你觉得最近很轻松，上班没什么事，下班陪孩子玩，晚上早早就休息，这一定不是你人生的上升阶段。虽然我们和马云有很大的财富差距，但有一点也许你会找到平衡，大家活得都很累，当你在挤地铁刷微薄的时候，也许他在私人飞机处理重要文件。当你晚上10点还在公司敲代码的时候，也许他晚上10点还在摄影棚拍电影或者录音棚录新歌（没办法，地球已经阻止不了马爸爸的才华了！2333）。&lt;/p>
&lt;p>再回到原话题，当你选择辞职学习的时候，到底地为了自己的进步？还是为了放松自我（睡觉+煲剧）？ 如果是前者的话，我想你缺的也许不是学习的时间，而是学习的动力。&lt;/p>
&lt;p>写给那些想辞职学习的同学。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1465311440653-ba9b1d9b0f5b?w=300"
 data-srcset="https://images.unsplash.com/photo-1465311440653-ba9b1d9b0f5b?w=300, https://images.unsplash.com/photo-1465311440653-ba9b1d9b0f5b?w=300 1.5x, https://images.unsplash.com/photo-1465311440653-ba9b1d9b0f5b?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1465311440653-ba9b1d9b0f5b?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>测试左移和测试右移</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%B7%A6%E7%A7%BB%E5%92%8C%E6%B5%8B%E8%AF%95%E5%8F%B3%E7%A7%BB/</link><pubDate>Mon, 11 Dec 2017 10:10:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%B7%A6%E7%A7%BB%E5%92%8C%E6%B5%8B%E8%AF%95%E5%8F%B3%E7%A7%BB/</guid><description>&lt;p>前几天看爬文的时候看到了这篇&lt;a href="https://blog.hiptest.net/2015/06/26/shift-left-and-shift-right-the-testing-swing/" target="_blank" rel="noopener noreffer ">《Shift left and shift right: the testing Swing》&lt;/a>，里面描述了一些测试左移和测试右移的思路和方法，觉得有一定的启发，可以分享一下。&lt;/p>
&lt;p>作者站在项目或者产研发负责人的角度阐述了自己团队在敏捷及devops中的测试实践，根据功能和产品所处的生命周期，描述了这样一些开发及测试实践&lt;/p>
&lt;ul>
&lt;li>
&lt;p>开发阶段&lt;/p>
&lt;/li>
&lt;li>
&lt;p>新功能： 我们应该做什么？&lt;/p>
&lt;/li>
&lt;li>
&lt;p>已有功能：如何自动化？&lt;/p>
&lt;/li>
&lt;li>
&lt;p>产品阶段&lt;/p>
&lt;/li>
&lt;li>
&lt;p>新功能：如何验证新功能所带来的用户价值&lt;/p>
&lt;/li>
&lt;li>
&lt;p>已有功能：性能及可用性监控&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h4 id="测试左移">测试左移&lt;/h4>
&lt;p>其中在开发新功能时候我们需要不断的问自己，我们实现的功能是什么？对需求做详尽的分析。作者认为bdd是一个很好的实践，用户或者客户去描述产品的行为，这种描述是有一定的规则或语法的，可以直接作为测试用例的描述，通过这些描述实现自动化的测试用例，那么我们的功能实现代码只需要通过这些测试用例就可以满足用户的需求了。&lt;/p>
&lt;p>这是测试左移的思想，本质是在一切开始之前先进行测试，测试对象是需求，越早的发现需求不合理的地方出问题的几率就越低。&lt;/p>
&lt;p>另外测试左移还可以是在开发阶段就进行测试，开发阶段可能产出只是代码，而不是完成的功能，这时候比较合适的测试是做持续集成的单元测试，通过代码覆盖率的方式找到未经测试的代码，尽可能的保证代码都被测试到。这些单元测试的用例可以在bdd时候通过用户或客户的用例描述来提炼。&lt;/p>
&lt;p>总之左移是在测试阶段到来之前，尽可能的抓紧开发前(需求分析)和开发中的时间做测试，提前发现问题，防微杜渐，避免积重难返。&lt;/p>
&lt;h4 id="测试右移">测试右移&lt;/h4>
&lt;p>左移是往测试之前的开发阶段移，右移是往发布之后移。也就是产品上线了之后也可以进行一些测试活动。当然在生产环境直接做测试是不推荐的，但是我们可以在生产环境做监控，监控线上性能和可用率，一旦线上发生任何问题，尽快反应，提前反应，给用户良好的体验。&lt;/p>
&lt;p>测试右移其实还可以理解为如果线上发生任何问题，我们有没有能力第一时间发现问题并解决问题，并保证线上数据的一致性或尽可能少的影响线上用户。&lt;/p>
&lt;p>很对时候，右移比左移更具有挑战性。&lt;/p>
&lt;h4 id="我们可以做什么">我们可以做什么&lt;/h4>
&lt;p>这里y有一些测试实践，是在不同的阶段可以去做的&lt;/p>
&lt;ul>
&lt;li>
&lt;p>开发阶段&lt;/p>
&lt;/li>
&lt;li>
&lt;p>新功能： 单元测试, BDD, 探索性测试&lt;/p>
&lt;/li>
&lt;li>
&lt;p>已有功能：自动化验证，性能测试，&lt;/p>
&lt;/li>
&lt;li>
&lt;p>产品阶段&lt;/p>
&lt;/li>
&lt;li>
&lt;p>新功能：可用性测试&lt;/p>
&lt;/li>
&lt;li>
&lt;p>已有功能：实时性能监控及用户反馈收集&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>其实我们不妨眼光放的更长远一点，软件测试实际上是软件质量控制，质量控制有很多实践，一些实践适合测试人员去做，另一些则可能不适合，比如线上性能监控，比如单元测试等。所以质量不只是测试团队的事情，而是整个项目或者产品团队需要重视的问题。一般来说，注重质量的团队产品或者交付质量往往好于不太重视质量的团队，或者把质量的指标压在测试人员头上的团队。&lt;/p>
&lt;p>质量无小事，质量也不是某几个人的事。好的质量是团队的荣耀，不好的质量也不应该是某几个测试人员的锅。&lt;/p>
&lt;p>最后，从质量管理的角度上看，好的质量管理者可能需要具备下面的一些素质&lt;/p>
&lt;ul>
&lt;li>把质量问题上升为整个研发团队或产品团队责任的能力&lt;/li>
&lt;li>能推动各种角色进行高效合理的测试实践的能力&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1448375240586-882707db888b?w=300"
 data-srcset="https://images.unsplash.com/photo-1448375240586-882707db888b?w=300, https://images.unsplash.com/photo-1448375240586-882707db888b?w=300 1.5x, https://images.unsplash.com/photo-1448375240586-882707db888b?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1448375240586-882707db888b?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>轻量级Selenium测试框架pyse</title><link>https://itest2025.pages.dev/tutorials/47-000-%E8%BD%BB%E9%87%8F%E7%BA%A7selenium%E6%B5%8B%E8%AF%95%E6%A1%86%E6%9E%B6pyse/</link><pubDate>Mon, 04 Dec 2017 10:10:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E8%BD%BB%E9%87%8F%E7%BA%A7selenium%E6%B5%8B%E8%AF%95%E6%A1%86%E6%9E%B6pyse/</guid><description>&lt;h4 id="前言">前言&lt;/h4>
&lt;hr>
&lt;p>在2015年的时候，我新进入了一家公司，刚去没什么工作安排，老大让我熟悉一下当前部门的产品，看有什么可以做自动化的产品，然后就试着做做。&lt;/p>
&lt;p>然后，我就开始对一个论坛产品下手，写了一个多月的UI自动化，近三百条测试用例，在此过程中，对Selenium开发有了更深一层的认识。顺手基于Selenium写了个框架 pyse。&lt;/p>
&lt;p>Pyse的命名分别取了“Python”和“Selenium”的前两个字母。现在看来这名字起得过于随意了，其实，它也只是我对Selenium二次开发的一点尝试。后来，我被分配去负责测试一个接口平台，论坛的自动化项目由于没人能接手，就丢一边了。这其中原因很多，Python +Selenium开发自动化测试有一定的门槛；测试任务比较重，没时间去接手自动化，还有，主动学习意愿不强，不是每个测试同学都对技术有追求的，对吧？！&lt;/p>
&lt;p>最近对pyse进行了一些重构，所以拿来分享一下。&lt;/p>
&lt;h4 id="为什么要对selenium进行封装和二次开发">为什么要对Selenium进行封装和二次开发？&lt;/h4>
&lt;hr>
&lt;p>对于原生的Selenium，我们用它来开发Web UI自动化测试，当你自动化测试用例写多了，就会发现，这TM就是一体力活，大部分时间就是拿个前端开发者工具（FireBug等）在尝试定位元素。比起手工测试毫无优越感好吧！&lt;/p>
&lt;p>当你的自动化测试用例达到一定规模的时候，逐渐就会意识原生Selenium的不好用。隐式等待不起作用，显式等待写起来太麻烦，sleep太耗时。&lt;/p>
&lt;p>单个用例运行好好的，放到一起运行，每次总有那么一两条用例“调皮”，运行不通过！&lt;/p>
&lt;p>还有每条用例都打开和关闭一次浏览器，严重拖慢用例的运行速度。&lt;/p>
&lt;p>还有&amp;hellip;.&lt;/p>
&lt;p>总之，遇到的各种问题，不是只会Selenium API就能解决的。接下来，你就要考虑对Selenium进行封装和二次开发了。&lt;/p>
&lt;h4 id="pyse特点">Pyse特点&lt;/h4>
&lt;hr>
&lt;p>项目地址：https://github.com/defnngj/pyse&lt;/p>
&lt;p>Pyse正是我为了解决前面的部分问题而设计的，它主要基于Selenium和unittest单元测试框架。&lt;/p>
&lt;ul>
&lt;li>支持多种定位方法（id\name\class\link_text\xpath\css）。&lt;/li>
&lt;li>本框架只是对selenium（webdriver）原生方法进行了简单的封装，精简为大约30个方法，这些方法基本能够胜任于我们的web自动化测试。&lt;/li>
&lt;li>以测试类为单位，自动打开和关闭浏览器，减少浏览器的打开/关闭次数，节省时间。&lt;/li>
&lt;li>自动生成/report/目录，以及HTML测试报告生成。&lt;/li>
&lt;li>针对Selenium的特点封装断言方法：assertTitle、assertUrl 和 assertText。&lt;/li>
&lt;/ul>
&lt;h4 id="安装">安装：&lt;/h4>
&lt;hr>
&lt;p>把整个项目克隆（下载）下来，进入pyse/目录，执行:&lt;/p>
&lt;blockquote>
&lt;p>python setup.py install&lt;/p>&lt;/blockquote>
&lt;h4 id="demo">Demo:&lt;/h4>
&lt;hr>
&lt;p>创建 test_case.py 文件。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Python" data-lang="Python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">pyse&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">BaiduTest&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pyse&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TestCase&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">test_baidu&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;&amp;#39;&amp;#39; baidu search key : pyse &amp;#39;&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;https://www.baidu.com&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">clear&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;id=&amp;gt;kw&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">type&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;id=&amp;gt;kw&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;pyse&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">click&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;css=&amp;gt;#su&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assertTitle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;pyse&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">runner&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pyse&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TestRunner&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">runner&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>1、首先导入 pyse库。
2、创建BaiduTest类继承 pyse的TestCase类。
3、创建test_baidu()测试方法（用例）。
4、接下来就是通过self.driver（默认使用 Chrome浏览器）来做百度搜索的操作；最后，使用assertTitle() 来断言浏览器标题是否包含“pyse”。
5、调用pyse的TestRunner() 类，通过它提供的 run() 方法来运行测试。&lt;/p>
&lt;p>&lt;strong>注意&lt;/strong>：这里的测试用例文件（test_case.py）和测试方法（test_baidu()）必须以“test”开头&lt;/p></description></item><item><title>如何尽可能避免漏测</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%A6%82%E4%BD%95%E5%B0%BD%E5%8F%AF%E8%83%BD%E9%81%BF%E5%85%8D%E6%BC%8F%E6%B5%8B/</link><pubDate>Wed, 29 Nov 2017 10:10:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%A6%82%E4%BD%95%E5%B0%BD%E5%8F%AF%E8%83%BD%E9%81%BF%E5%85%8D%E6%BC%8F%E6%B5%8B/</guid><description>&lt;p>在总结线上问题的时候，我们发现大部分的线上问题是由于功能漏测所导致的。原本应该测试的流程没有测到，或者是根本没有考虑到一些情况，这些都会产生漏测。&lt;/p>
&lt;p>在大部分的产品中，漏测是难以避免的，只要不出大问题，漏测的危害会被人为的粉饰和缩小，但是在某些跟货币或货币等价物打交道的行业，漏测往往意味着经济损失，一次漏测可能会影响一群人的职业生涯，万万马虎不得。&lt;/p>
&lt;p>下面描述的方法可能对降低漏测有所帮助。&lt;/p>
&lt;h3 id="完全理解需求">完全理解需求&lt;/h3>
&lt;p>站在业务和用户的角度去理解需求。尽量发现需求中不合理的地方或者是对用户来说讲不通的地方，给需求瘦身，让需求更加清晰简明。需求越明确，验证点也就越明确，用例设计起来难度也会降低。&lt;/p>
&lt;h3 id="尽可能了解现有业务">尽可能了解现有业务&lt;/h3>
&lt;p>如果是新接受一个产品或项目，尽可能的了解现有系统的逻辑和业务也可以降低漏测风险。&lt;/p>
&lt;p>现有系统中总是或多或少有一些坑，由于某些复杂或者不可描述的原因，这些坑不会有人告诉你。举一个我朋友的例子，他在做开发的时候因为偷懒，某些异常就直接捕获而不做相应的逻辑处理，在一些特殊条件下，这会造成数据丢失或者不一致的问题，但他认为这些问题发生的概率非常低，所以他谁也没告诉，天知地知你不知我知。像这种坑，一般来说要么测试同学自己试出来，要么跟开发关系好，让他善意的提醒某些异常场景。当然，前者可能更加靠谱一点点。&lt;/p>
&lt;h3 id="考虑环境差异">考虑环境差异&lt;/h3>
&lt;p>因为环境问题而翻车也是大概率事件。某些问题明明测试环境测出来是没问题的，但是在生产环境就各种问题，有经验的测试同学应该都遇到过。一般的解决思路是准备一个准生产环境，尽量跟线上环境保持一致，比如软硬件一致，数据量一致等，在准生产环境做最后一轮的回归。&lt;/p>
&lt;h3 id="提升用例质量">提升用例质量&lt;/h3>
&lt;p>一些用例看起来测了很多东西，但是场景实际上覆盖是不完全的。怎么判断场景覆盖是否全面的，常规做法是用例评审，邀请相关责任人做评审，发现用例中考虑不全面的地方，然后改进。因为用例评审会占用项目时间，所以在项目紧急的时候往往会被砍掉，又或者评审一般流于形式，这样到后来各方参与者的热情不高，直接变成了流程性的东西，没办法提出一些有建设性的建议，所以评审在某些时候的效果是一般的。&lt;/p>
&lt;p>去年曾经听到过用代码覆盖率去衡量用例质量的案例，今年在测试沙龙上也听到了类似的分享。既然场景都是由代码实现的，那么如果用例覆盖的场景够全的话，覆盖率相应就会更高。具体可以这样操作，对于增量代码，先把用例用手工和自动化的方式去运行用例，然后跑出代码覆盖率，如果增量代码中有代码没有覆盖到，那么就可能证明测试用例考虑的场景不全，需要改进。&lt;/p>
&lt;p>代码覆盖率并不能证明代码质量的高低，但是可以让我们知道哪些代码没有被测试到。没有被测试到，就改进用例，试着去覆盖。&lt;/p>
&lt;p>但是有些代码中的异常很难从黑盒端构造，对于这些情况，白盒用例可能更加适合。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1516690553959-71a414d6b9b6?w=300"
 data-srcset="https://images.unsplash.com/photo-1516690553959-71a414d6b9b6?w=300, https://images.unsplash.com/photo-1516690553959-71a414d6b9b6?w=300 1.5x, https://images.unsplash.com/photo-1516690553959-71a414d6b9b6?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1516690553959-71a414d6b9b6?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>测试圈TC：你求推荐的文章或者书籍，视频都在这里了!</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E4%BD%A0%E6%B1%82%E6%8E%A8%E8%8D%90%E7%9A%84%E6%96%87%E7%AB%A0%E6%88%96%E8%80%85%E4%B9%A6%E7%B1%8D%E8%A7%86%E9%A2%91%E9%83%BD%E5%9C%A8%E8%BF%99%E9%87%8C%E4%BA%86/</link><pubDate>Mon, 27 Nov 2017 02:10:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E4%BD%A0%E6%B1%82%E6%8E%A8%E8%8D%90%E7%9A%84%E6%96%87%E7%AB%A0%E6%88%96%E8%80%85%E4%B9%A6%E7%B1%8D%E8%A7%86%E9%A2%91%E9%83%BD%E5%9C%A8%E8%BF%99%E9%87%8C%E4%BA%86/</guid><description>&lt;h5 id="问题">问题：&lt;/h5>
&lt;p>找到一份软件测试的工作，但是没有系统学习过软件测试，求推荐快速上手的文章或者书籍，视频？&lt;/p>
&lt;br>
&lt;h5 id="回答">回答：&lt;/h5>
&lt;p>这其实是一个技术敏感度的问题。但更多的时候是懒！！！因为问别人要比自己找答案轻松啊！&lt;/p>
&lt;br>
&lt;p>&lt;strong>我经常会被问到：&lt;/strong>&lt;/p>
&lt;font color='blue'>
&lt;p>请问测试入门应该看什么书（教程，视频或文章）？&lt;/p>
&lt;p>请求我要学性能测试应该看什么书（教程，视频或文章）？&lt;/p>
&lt;p>请问学自动化测试应该看什么书（教程，视频或文章）？&lt;/p>
&lt;/font>
&lt;br>
&lt;p>还拿自己当“好”学生呢？不耻下问，不会就问，看我多虚心，多努力！&lt;/p>
&lt;p>你们经理分给你一个项目去测试，请问你是不是也要问应该看什么书（教程，视频或文章）？&lt;/p>
&lt;p>难道不是应该看项目文档和注册一个账号，看看项目有哪些功能，并进一步了解这些项目功能是干嘛用的，不同功能之间的关联条件？有不明白赶紧去问同事！&lt;/p>
&lt;p>&lt;strong>抱歉！这个回答我不是针对谁，我是针对在坐的每一位提这类问题的测试同学。&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>先来看看什么是技术敏感度？&lt;/li>
&lt;/ul>
&lt;p>我们可能都会遇到过，特别看读书的人，他们读的书很多你听都没听说过，他们是怎么知道这些书的？因为大多数时候他们是通过阅读一本书的时候，书中提到了另一本书；读者顺着这样的线就读很多自己感兴趣，又可能比较偏门的书。&lt;/p>
&lt;p>这也是为什么，学得越多，就发现自己不懂的越多。&lt;/p>
&lt;p>学技术也一样，从来没见哪些大牛说，我目前会xx、xx和xx，请问想成为大神，接下来应该看书（教程，视频或文章）？或者一个大牛去问大神，你说将来什么技术会火？我去学学！这一定不是大牛，最多就一水牛。因为他们都有一套自己的学习方法，和感知新技术的能力。&lt;/p>
&lt;ul>
&lt;li>那我应该去哪儿获取这些新技术呢？&lt;/li>
&lt;/ul>
&lt;p>这途径就多了去了，可能是关注某些大牛的博客、微博、知呼、公众号；或者是关注某些技术社区；或者是在查找解决一个问题时留意到一个新技术。&lt;/p>
&lt;p>总之，自己寻多去找答案（百度、google），不要到处求推荐，求指点。&lt;/p>
&lt;ul>
&lt;li>那我应该怎么学习新技术？&lt;/li>
&lt;/ul>
&lt;p>这就因人而异了，理论上看官方文档是学习新技术的最佳途径！但是，很多技术是有前提条件的，比如，我要学Android单元测试，那我得先学JUnit单元测试框架，要学单元测试框架得先会Java语言。你看！如果我的目标是学会Android单元测试，一下子该学哪些东西，先学什么后学什么马上就清楚了。你是怎么知道这些前提条件的？百度的呗。难道像你一样跑来问看应该什么书（教程，视频或文章）？有你这在线等答案的时间，我都练了两个demo了。&lt;/p>
&lt;p>所以，你不是懒！你给我一个睡服我的理由。&lt;/p>
&lt;p>对了！ 楼主不是做app测试的嘛，接下来不应该去整理一份 app测试方法和测试要点的文档出来。还问什么没“系统”学过测试，还要“快速”入门。能快速熟悉当前业务、做好当前工作不是当前最重要的么？&lt;/p>
&lt;p>我知道在这种提问下面，一定有好心人前来“列清单”。可笑的是他列的清单可能自己都不一定读完过。只是从别人那里听来的，然后，再转送给你！ 反正大家都说好就真的好了。更可笑的是你以为你得到清单，就有了学习的动力和目标？不见得！也许这些列的书（教程，视频或文章）你也许压根不会去读。&lt;/p>
&lt;p>因为，读了一半读不下去了呀！或者感觉对自己的工作没什么帮助啊！或者压根就不是自己想学的内容啊！&lt;/p>
&lt;p>好吧！就算你可以认真的读下去就没问题了么？学习的过程中仍然会碰到不懂地方，那你是不是又要另开一个问题：请问 xxx 看不懂，应该看什么书（教程，视频或文章）？&lt;/p>
&lt;p>&lt;a href="https://www.zhihu.com/question/68341783/answer/263868369" target="_blank" rel="noopener noreffer ">阅读原文&lt;/a>&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1504893524553-b855bce32c67?w=300"
 data-srcset="https://images.unsplash.com/photo-1504893524553-b855bce32c67?w=300, https://images.unsplash.com/photo-1504893524553-b855bce32c67?w=300 1.5x, https://images.unsplash.com/photo-1504893524553-b855bce32c67?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1504893524553-b855bce32c67?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>测试圈TC：双11期间，我选择了这5本书!</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E5%8F%8C11%E6%9C%9F%E9%97%B4%E6%88%91%E9%80%89%E6%8B%A9%E4%BA%86%E8%BF%995%E6%9C%AC%E4%B9%A6/</link><pubDate>Mon, 20 Nov 2017 11:10:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E5%8F%8C11%E6%9C%9F%E9%97%B4%E6%88%91%E9%80%89%E6%8B%A9%E4%BA%86%E8%BF%995%E6%9C%AC%E4%B9%A6/</guid><description>&lt;p>好吧！我只是借着双11的余热，骗你进来的。这年头起一个正经严肃认真的标题已经没人愿意点开阅读了。&lt;/p>
&lt;p>（同事问你在用手机看什么？居然哭了，自己点开的文章含着泪也要看完&amp;hellip;.）&lt;/p>
&lt;p>事情是这样的，双11前出版社编辑告诉我，作为优秀作者可以到他们的出版社网站上挑选5本自己喜欢的书，免费赠送！&lt;/p>
&lt;p>现在我们的时间越来越碎片化，很难有整块的时间去阅读一本书。尤其是技术书，在阅读的过程中还操作上面的例子或代码；我其实更喜欢以需求为驱动去学新的技术，比如，我要用Flask开发一个网站，以此为需求驱动我查找相关资料进行学习。&lt;/p>
&lt;p>当然，好书还是值得我们花时间去学习的，什么算好的技术书呢？我认为：由浅入深、通俗易懂的介绍清楚一个技术。能做到这一点，在我看来就是一本好书。我去年阅读的《Test-Driven Development with Python》，以及今年阅读的《第一行代码 Android》，这两本在我看来就是好书。&lt;/p>
&lt;p>言归正传，接下来介绍一下我选的这几本书，由于是大概的翻阅了一下书中的内容，再加上个人的水平和阅读喜好不同，无法做到客观中立第三方，只能分享一点我的个人看法。&lt;/p>
&lt;p>《第一季Kotlin崛起：次世代Android开发》&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/kotlin_book.png"
 data-srcset="http://img.testclass.net/kotlin_book.png, http://img.testclass.net/kotlin_book.png 1.5x, http://img.testclass.net/kotlin_book.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/kotlin_book.png"
 title="http://img.testclass.net/kotlin_book.png" />&lt;/p>
&lt;p>这是我选择的第一本书，第一次听说Kotlin编程语言的时候还是在今年“Google I/O 2017开发者大会”的时候，因为这家伙在此之前从来没在编程语言排行榜上出现过，也没听说身边的公司或团队在使用。我们都知道Google 一直受制于人Oracle对Java的把持，为Android选择新的开发语言也在情理之中。&lt;/p>
&lt;p>惊讶的是短短半年就问世了好几本关于Kotlin 中文书，《第一季Kotlin崛起：次世代Android开发》就是其中之一。&lt;/p>
&lt;p>全书分三部分，第一部分Kotlin基础，和大多书编程入门书一样从“hello world”开始，很适合零编程的小白；第二部分面向对象；前两部分学习可以会对Kotlin语法有一个整体了解。第三部分介绍Android开发，基本把Android开发中的核心部分都做介绍到了，最后两章是实战例子。&lt;/p>
&lt;p>Kotlin的整体语法要比Java简化不少，但要以此做为卖点的话，Python就只能在旁边呵呵了！一个语言能否发展起来，主要是看它的扩展库/框架是否足够丰富和优秀。显然这一点Kotlin和Java差距巨大。但是，如果你是一名Android开发或测试开发的话，有必要学习一下！毕竟有Google加持。&lt;/p>
&lt;p>《Android移动性能实战》&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/android_per_book.png"
 data-srcset="http://img.testclass.net/android_per_book.png, http://img.testclass.net/android_per_book.png 1.5x, http://img.testclass.net/android_per_book.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/android_per_book.png"
 title="http://img.testclass.net/android_per_book.png" />&lt;/p>
&lt;p>这是我选择的第二本书，相比较Android自动化测试来说，大家似乎对Android性能方面关注的较少。其实，制约Android应用体验的一个很大的问题就是性能，启动速度、卡顿、耗电等，优化好APP的性能对于APP用户体验也非常重要。&lt;/p>
&lt;p>腾讯的测试团队太牛B了，如果你是个纯小白，且不懂Android开发，就不要买了，因为书中会直接贴小一段代码，告诉你在他们有的某款APP的某个场景下会有问题。&lt;/p>
&lt;p>这一点，我在《腾讯android自动化测试实战》一书中已经领略过了，前面还在讲appium的API，后面就直接贴一段他家某款APP的自动化代码。没头没尾的那种，可操作性太差，我们最多也只能看看他们写的代码的风格。&lt;/p>
&lt;p>不过，我觉得他们家团队出的书很适合做公司内部分享，因为大家都是在一个level上，而且都彼此熟悉相关的产品，我贴一段代码一分析，大家自然就收获良多，有技术有经验。我突然有一个大胆的猜测，这书确实是内部团队PPT的提炼。因为本身就是团队合著的。&lt;/p>
&lt;p>《京东系统质量保障技术实战》&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/jd_test_book.png"
 data-srcset="http://img.testclass.net/jd_test_book.png, http://img.testclass.net/jd_test_book.png 1.5x, http://img.testclass.net/jd_test_book.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/jd_test_book.png"
 title="http://img.testclass.net/jd_test_book.png" />&lt;/p>
&lt;p>除了BAT外，京东是国内第四大互联网公司，我很好奇他们的测试团队所应用的技术。&lt;/p>
&lt;p>这是我挑选的唯一一本正儿八经给测试人员看的书。整本书由京东“测试和质量部”所著。打开书发现是内容彩色的，纸张很好。&lt;/p>
&lt;p>整本书展示他们部门的技术体系，整本来看是Java流的，就是测试开发相关工作主要由Java语言完成；如果你想了解京东的测试是如何做测试的，会用到哪些技术和工具，那么值得一读。但如果想就着这本书就把这些技术和工具学会，不可能。&lt;/p>
&lt;p>对了，书有一章介绍Web安全，值得一读，有比较详细的概念和例子，很适合像我这种安全测试小白。&lt;/p>
&lt;p>《Jenkins权威指南》&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/jenkins_book.png"
 data-srcset="http://img.testclass.net/jenkins_book.png, http://img.testclass.net/jenkins_book.png 1.5x, http://img.testclass.net/jenkins_book.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/jenkins_book.png"
 title="http://img.testclass.net/jenkins_book.png" />&lt;/p>
&lt;p>Jenkins持续集成基本上已经成为了开发团队的标配，不管是开发、测试、还是运维都会用到。&lt;/p>
&lt;p>这本是中文翻译版，是2016年10月出版，如果你不想在网上找各种零碎的Jenkins教程的话，本书很适合你。&lt;/p>
&lt;p>不过，书中的内容有些过时，虽然书中没指明Jenkins的版本，但有提到Java版本用的是“最新的”Java 6，但是前不久Java9正式版推出。另外，我前几天在装 Jenkins 2.73.3 版本时发现和旧的版本有不小的差别，安装和使用都比以前复杂了许多。&lt;/p></description></item><item><title>测试圈TC：“测试开发”需要哪些技能？用数据说话！</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E6%B5%8B%E8%AF%95%E5%BC%80%E5%8F%91%E9%9C%80%E8%A6%81%E5%93%AA%E4%BA%9B%E6%8A%80%E8%83%BD%E7%94%A8%E6%95%B0%E6%8D%AE%E8%AF%B4%E8%AF%9D/</link><pubDate>Mon, 13 Nov 2017 02:10:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E6%B5%8B%E8%AF%95%E5%BC%80%E5%8F%91%E9%9C%80%E8%A6%81%E5%93%AA%E4%BA%9B%E6%8A%80%E8%83%BD%E7%94%A8%E6%95%B0%E6%8D%AE%E8%AF%B4%E8%AF%9D/</guid><description>&lt;p>有同学经常留言求指点，或者技术工具和技术太多，不知道学什么！那么我们用数据说话，看看招聘网站上对“测试开发”岗位都有哪些要求。&lt;/p>
&lt;p>周末的时候我写了个简单的爬虫，登录某互联网招聘网站，搜索“测试开发”关键字，然后，把每一条招聘信息上的内容爬取下来，做简单关键字的频率分析。&lt;/p>
&lt;p>&lt;strong>注：&lt;/strong> 每页显示15条招聘，共26页，大概390条招聘信息。&lt;/p>
&lt;h4 id="编程语言">编程语言&lt;/h4>
&lt;hr>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/tc_programming_01.jpg"
 data-srcset="http://img.testclass.net/tc_programming_01.jpg, http://img.testclass.net/tc_programming_01.jpg 1.5x, http://img.testclass.net/tc_programming_01.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/tc_programming_01.jpg"
 title="http://img.testclass.net/tc_programming_01.jpg" />
&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/tc_programming_02.jpg"
 data-srcset="http://img.testclass.net/tc_programming_02.jpg, http://img.testclass.net/tc_programming_02.jpg 1.5x, http://img.testclass.net/tc_programming_02.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/tc_programming_02.jpg"
 title="http://img.testclass.net/tc_programming_02.jpg" />
Java 排名第一，占绝对优势，因为有大量的项目基于Java开发，在这样的团队中，当然也要求测试开发能懂得Java语言了。Python出现的频率也很高，主要是它简单易学，有着非常丰富的测试库，符合测试人员的属性；我的建议是两个语言都要学，如果你编程能力比较弱的话可以从Python入门，如果你的项目以Java开发为主，建议从Java入手。&lt;/p>
&lt;p>注明：这里统计的“C语言”实际为“C/C++”这个关键词，因为云图生成不了这个关键词，所以改为“C语言”。&lt;/p>
&lt;p>Android和iOS两大平台不属于编程语言，我这里也归到了编程语言列表。出现的频率也很高，所以，测试开发也必须懂得移动平的测试技术（单元测试，接口/UI自动化等）。&lt;/p>
&lt;h4 id="测试工具">测试工具&lt;/h4>
&lt;hr>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/tc_test_tools_01.jpg"
 data-srcset="http://img.testclass.net/tc_test_tools_01.jpg, http://img.testclass.net/tc_test_tools_01.jpg 1.5x, http://img.testclass.net/tc_test_tools_01.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/tc_test_tools_01.jpg"
 title="http://img.testclass.net/tc_test_tools_01.jpg" />
&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/tc_test_tools_02.jpg"
 data-srcset="http://img.testclass.net/tc_test_tools_02.jpg, http://img.testclass.net/tc_test_tools_02.jpg 1.5x, http://img.testclass.net/tc_test_tools_02.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/tc_test_tools_02.jpg"
 title="http://img.testclass.net/tc_test_tools_02.jpg" />
JMeter 出现这么高的频率略为意外，仔细一起也正确，不管是性能还是自动化，开源工具的出现频率都占有绝对的优势。JMeter在性能测试和接口测试方面都非常优秀。&lt;/p>
&lt;p>Selenium和appium 是一定要学的两个自动化工具，前者针对Web UI ，后者针对 app UI。&lt;/p>
&lt;p>持续集成已经成为现在项目团队的标配了，所以一定要懂。&lt;/p>
&lt;p>单元测试框架Junit/TestNG/unittest也一定要会用，它是做自动化测试的基础。&lt;/p>
&lt;p>另外，Docker 技术也可以关注一下！&lt;/p>
&lt;h4 id="测试类型">测试类型&lt;/h4>
&lt;hr>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/tc_test_type_01.jpg"
 data-srcset="http://img.testclass.net/tc_test_type_01.jpg, http://img.testclass.net/tc_test_type_01.jpg 1.5x, http://img.testclass.net/tc_test_type_01.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/tc_test_type_01.jpg"
 title="http://img.testclass.net/tc_test_type_01.jpg" />
&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/tc_test_type_02.jpg"
 data-srcset="http://img.testclass.net/tc_test_type_02.jpg, http://img.testclass.net/tc_test_type_02.jpg 1.5x, http://img.testclass.net/tc_test_type_02.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/tc_test_type_02.jpg"
 title="http://img.testclass.net/tc_test_type_02.jpg" />
从测试类型可以看出，测试开发要求最多的，或者做得最多的还是“自动化测试”。“软件开发”和“开发经验”出现频率也很高，说明测试开发对“开发”能力要求接近开发人员水平。&lt;/p></description></item><item><title>0.写在前面</title><link>https://itest2025.pages.dev/tutorials/28-000-0%E5%86%99%E5%9C%A8%E5%89%8D%E9%9D%A2/</link><pubDate>Tue, 07 Nov 2017 08:17:22 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/28-000-0%E5%86%99%E5%9C%A8%E5%89%8D%E9%9D%A2/</guid><description>&lt;p>这是为测试同学编写的学习python的一系列教程。&lt;/p>
&lt;p>教程的主旨如下&lt;/p>
&lt;ul>
&lt;li>不要写废话: 尽可能用最简练的篇幅把事情说清楚&lt;/li>
&lt;li>多练多看: 读者应该把教程中代码敲一遍；教程里的示例代码，读者要想办法自己看懂&lt;/li>
&lt;li>尽量使用测试同学可以理解的概念&lt;/li>
&lt;/ul>
&lt;h3 id="python版本">python版本&lt;/h3>
&lt;p>我们使用&lt;strong>python3.6&lt;/strong>以上的版本。&lt;/p>
&lt;h3 id="编辑器">编辑器&lt;/h3>
&lt;p>推荐读者使用&lt;a href="" rel="">vscode&lt;/a>，vscode应该可以在windows及macos上运行。&lt;/p>
&lt;h3 id="命令行工具">命令行工具&lt;/h3>
&lt;p>我们的代码都是通过在命令行中使用&lt;code>python&lt;/code>命令的方式去运行的。&lt;/p>
&lt;ul>
&lt;li>macos可以用自带的terminal工具&lt;/li>
&lt;li>windows系统使用自带的cmd命令行工具和powershell工具就可以了&lt;/li>
&lt;/ul>
&lt;h3 id="学习方法">学习方法&lt;/h3>
&lt;ul>
&lt;li>先把所有代码都敲一遍&lt;/li>
&lt;li>确保你敲的代码都能正确运行&lt;/li>
&lt;li>修改代码，让代码报错，不能运行&lt;/li>
&lt;li>查看报错信息，弄明白代码为什么不能运行&lt;/li>
&lt;li>尽可能多的阅读教程里的示例代码，弄清楚代码是如何工作和实现需求的&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1517059224940-d4af9eec41b7?w=300"
 data-srcset="https://images.unsplash.com/photo-1517059224940-d4af9eec41b7?w=300, https://images.unsplash.com/photo-1517059224940-d4af9eec41b7?w=300 1.5x, https://images.unsplash.com/photo-1517059224940-d4af9eec41b7?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1517059224940-d4af9eec41b7?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>《IntelliJ-IDEA-Tutorial》教程发布</title><link>https://itest2025.pages.dev/tutorials/47-000-intellij-idea-tutorial%E6%95%99%E7%A8%8B%E5%8F%91%E5%B8%83/</link><pubDate>Mon, 06 Nov 2017 10:10:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-intellij-idea-tutorial%E6%95%99%E7%A8%8B%E5%8F%91%E5%B8%83/</guid><description>&lt;h4 id="本站开始学习intellij-idea-tutorial">本站开始学习&lt;a href="https://itest2025.pages.dev/idea/" rel="">《IntelliJ-IDEA-Tutorial》&lt;/a>!&lt;/h4>
&lt;hr>
&lt;p>&lt;a href="http://www.testclass.net" target="_blank" rel="noopener noreffer ">测试教程网&lt;/a> 对教程的编写有着很高的要求，一定要简单通俗易懂，而且不过时。所以，目前所有的测试教程都是由 虫师 和 乙醇 空余时间亲手编写。&lt;/p>
&lt;p>测试人员需要具备开发技能已经成为了不挣的事实，而且会越来越重要。我前两天爬了一下 “测试开发” 的招聘要求， Java 和 Python 是出现频率最高的两个编程语言。学习编程语言掌握一款强大的 IDE 是开发的基础。&lt;/p>
&lt;p>而 JetBrains 家的 IDE 基本上已经一统了各家主流编程语言的江湖。&lt;/p>
&lt;ul>
&lt;li>IntelliJ IDEA - 已经成为 Java 语言的主流编辑器。&lt;/li>
&lt;li>PHPStorm - PHP 集成开发工具。&lt;/li>
&lt;li>PyCharm - 智能 Python 集成开发工具。&lt;/li>
&lt;li>RubyMine - 是一个为Ruby 和Rails开发者准备的IDE。&lt;/li>
&lt;li>WebStorm - 智能HTML/CSS/JS开发工具。&lt;/li>
&lt;/ul>
&lt;p>包括 Android Studio 也是基于 IntelliJ IDEA 开发的。&lt;/p>
&lt;p>在偶然的机会看到了 &lt;a href="http://www.youmeek.com/" target="_blank" rel="noopener noreffer ">judasn&lt;/a> 同学编写《&lt;a href="https://github.com/judasn/IntelliJ-IDEA-Tutorial" target="_blank" rel="noopener noreffer ">IntelliJ-IDEA-Tutorial&lt;/a>》 教程，通俗易懂地全面介绍了 IntelliJ-IDEA 工具的使用。于是联系了他本人 ，经过他的允许将 《IntelliJ-IDEA-Tutorial》部分内容转载过来。在里这对他表示感谢！&lt;/p>
&lt;p>虽然是主要介绍 IntelliJ IDEA 的，但 JetBrains 家的 IDE 的界面和配置都大同小异！&lt;/p></description></item><item><title>测试圈TC：做你自己的大牛</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E5%81%9A%E4%BD%A0%E8%87%AA%E5%B7%B1%E7%9A%84%E5%A4%A7%E7%89%9B/</link><pubDate>Mon, 06 Nov 2017 01:10:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E5%81%9A%E4%BD%A0%E8%87%AA%E5%B7%B1%E7%9A%84%E5%A4%A7%E7%89%9B/</guid><description>&lt;h4 id="做你自己的大牛致每一位技术人员">《做你自己的大牛》&amp;mdash;致每一位技术人员&lt;/h4>
&lt;p>我有个习惯，从来不叫教自动化技术的帮人为“学生”，而是叫“同学”。学生的话表示我跟他们不是同一个level的，而同学的话表示咱们都是一个level的。当然，这不是纯粹套近乎，也不是我故意放低姿态，而是，有很多问题我并不比他们强。&lt;/p>
&lt;p>比如，前几天我就被鄙视了，原因是最近出不去，有一个同学问我怎么才能出去，我说我这几天也出不去，后来，那位同学不知哪里习得奇技淫巧出去了，我说，那你帮我下载个新版的selenium-sever吧！下完，我说再帮我下个最新的chromedriver 吧！他就不耐烦了。结果就是我就被鄙视了呗！&lt;/p>
&lt;p>我加了几个Selenium群，偶尔想起来了，会在里面冒个泡，马上会有人跳出来说，虫师，我是你的“粉丝”，我一般会骂回去“粉你妹去！”。你有问题我们交流问题，我有时间就鸟你，没时间（实际上是不会）就不鸟你！休想拿“粉丝”来绑架我，再说，我也不是靠脸吃饭的。&lt;/p>
&lt;p>我想这主要和我们从小受到的教育有关吧！当你学习成绩不好的时候，父母就会拿你和隔壁老王家的孩子比，当你学习成绩还不错的时候，父母就会说：“怎么没考满分？”“就这点成绩，尾巴不要翘的老高了！”，所以，我们骨子里是谦卑的，或者还有那么一点点自卑。总觉得做得不好，不如别人！&lt;/p>
&lt;p>前几天，看了陈皓（酷壳博主，上一期的文章也有介绍）的视频参访，其实，在我看来，不管从年龄和技术上，咱和人家都差得远着呢！他有一句话，给我印象很深，大概是被恭维，像他这么有天赋写代码的人少有，他说我也不认为自己写代码特别有天分。这是在故意谦虚么？我不觉得；难道你们想用一个“天分”来抹杀一个人的所有努力？&lt;/p>
&lt;p>他的技术实力背后是多少个日日夜夜坐在电脑面前换来的！天份固然重要，更重要的是兴趣与坚持。我不知道你们的晚上都用来干嘛了？从我2012来到深圳这个城市，差不多就保持了晚上（周一到周五）学习的习惯。所以，我是很讨厌加班的。你一个餐补才几个钱？我需要时间为自己加班，难道你希望看到我靠明年的那点加薪来提升自己的收入？那何时才能追赶上深圳的房价？&lt;/p>
&lt;p>我最近关注了一个公众号，他的每篇文章下面总有一个小“迷妹”留言：大牛，虽然我也不懂你在说什么，但是我会努力的。给你打赏几块钱，虽然，我挣的也不多！我心想，这人完了，这和追星有什么区别。如果有人在我们的公众号下这么留言，我一定会骂回去！当然，我们也不需要打赏，你留着这点钱多买两本技术书看看吧！&lt;/p>
&lt;p>我刚做测试时就觉得自己挺牛X的，看那些个测试大牛，觉得你丫不就是比我多干两年嘛。当我到了你这个工龄，也许比你更牛X，当然，背后是不断的学习更多的技术。虽然，后来发现身边有许多人确实比我聪明有天分！可是，那又怎样，还不是被我的坚持甩在了身后。所以，粉那些个技术大牛对自己并没有多大帮助。&lt;/p>
&lt;p>你需要做自己的大牛！&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1431631927486-6603c868ce5e?w=300"
 data-srcset="https://images.unsplash.com/photo-1431631927486-6603c868ce5e?w=300, https://images.unsplash.com/photo-1431631927486-6603c868ce5e?w=300 1.5x, https://images.unsplash.com/photo-1431631927486-6603c868ce5e?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1431631927486-6603c868ce5e?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>测试圈TC：工程师的成长与坚持</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E5%B7%A5%E7%A8%8B%E5%B8%88%E7%9A%84%E6%88%90%E9%95%BF%E4%B8%8E%E5%9D%9A%E6%8C%81/</link><pubDate>Mon, 30 Oct 2017 02:50:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E5%B7%A5%E7%A8%8B%E5%B8%88%E7%9A%84%E6%88%90%E9%95%BF%E4%B8%8E%E5%9D%9A%E6%8C%81/</guid><description>&lt;br>
前天晚上抽空听了一下 infoQ 的《极客的时间都去哪儿了？》在线视频，分享者（或者叫受访者）之一是陈皓（coolshell.cn 酷壳博主），相信你们多少都应该听说过这位大牛，他98年大学毕业，有二十多年的工作经验，增任职亚马逊和阿里巴巴，目前创业，主要帮助企业提升系统性能，仍然贴近技术人员。所以，他的部分回答值得给年轻的工程师参考。
&lt;p>&amp;mdash;-以下主要观点来采访视频&amp;mdash;-&lt;/p>
&lt;p>关于成长&lt;/p>
&lt;p>毕业到 30 岁是一个非常重要的学习期，主要精力应该放在学习上面，解决工作自由的问题，就是你可以有更多的工作机会可以选择。&lt;/p>
&lt;p>30岁到40多岁是这个社会的中流砥柱，所以，在这在阶段应该培养自己做决定的能力，做技术决定的能力，做Leader的能力。&lt;/p>
&lt;p>在选择工作时应该把关注点放在“成长”上，成长并一定是获得更高的title，而是让自己眼界更开阔的，让自己拥有更多可能性的。如果你不确定自己的选择是否更好的“成长”，那么可以思考一下当前的工作是否正在增加你的核心竞争力，是否在将来失业或跳槽时帮助你找到一份更好的工作。&lt;/p>
&lt;p>不要把注意力放城市的空气、房价、户口这些上面，因为有些问题并不是我们能改变的（环境），有些问题会随着我们的成长变得不再是问题（房价和户口）。&lt;/p>
&lt;p>关于坚持&lt;/p>
&lt;p>我们常常听到论调是程序员过了30或35岁就不再适合做技术，需要转行。那么有没有什么标准和迹象来表明我们是否适合做技术。&lt;/p>
&lt;p>陈皓也不认为自己是技术天赋很高的人，他说以前看两本书，一本《算法导论》，另一本是《TCP/IP协议》，每次看不了几页就睡着了，不过，后来看下来后，是收获的喜悦。你们也可以试着读一下，如果觉得晦涩难懂或无聊说明，你可能没有那么喜欢技术。如果是满满的获得收获之后的喜悦，说明真的喜欢技术。喜欢就一直做，不要太在意年龄的界限。&lt;/p>
&lt;p>最后，关于遗憾；陈皓觉得唯一的遗憾是年轻的时候没有把数学学得更好，如果可以重来，会更努力的学好数学。&lt;/p>
&lt;p>&amp;mdash;-以下我的看法&amp;mdash;-&lt;/p>
&lt;p>我们听了那么多道理和经验的分享，却依然走了许弯路，并且依然会遇到迷茫的时候。我这里也给出自己两个建议。&lt;/p>
&lt;p>从兴趣出发，我没见到过哪个人不喜欢一件事情还可以把它做得很好的。所以，在做选择的时候多从自己的兴趣出发。当然，兴趣也是可以培养的，比如，你把自己的技术和经验分享给别人的同时，会收到赞扬和成就感，从而也会推动你继续学习，慢慢的就会变成你所热爱和坚持的事情。&lt;/p>
&lt;p>跳出现在看现在，当你不知道现在做的事是否有意义，你可以跳出当前，假设，如果是5年或10年后的你来看现在做的事就会清楚是否有意义了。换句话说，假设你5年后想成为某公司架构师，那么当前这个选择是否对你成为架构师有帮助。&lt;/p>
&lt;p>&amp;mdash;-题外话&amp;mdash;-&lt;/p>
&lt;p>我知道陈皓是在2012年，因为他写了一篇《我们需要专职的QA吗？》，文章吐槽他遇到不专业的QA，并认为开发做好测试是分内的事，所以并不需要QA。遭到了测试圈的回击，比如另个一位测试大牛段念《对‘我们需要专职QA吗？’的回应》。当时刚入行做测试，愤青情绪高涨的我，也写了一篇博客回击《我们需要测试！》。哈哈！&lt;/p>
&lt;p>&lt;a href="https://mp.weixin.qq.com/s/xYN8RatLZGUiZJYdBStNsQ" target="_blank" rel="noopener noreffer ">原文链接&lt;/a>&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1431887773042-803ed52bed26?w=300"
 data-srcset="https://images.unsplash.com/photo-1431887773042-803ed52bed26?w=300, https://images.unsplash.com/photo-1431887773042-803ed52bed26?w=300 1.5x, https://images.unsplash.com/photo-1431887773042-803ed52bed26?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1431887773042-803ed52bed26?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>测试圈TC：编程与写作</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E7%BC%96%E7%A8%8B%E4%B8%8E%E5%86%99%E4%BD%9C/</link><pubDate>Mon, 23 Oct 2017 02:10:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E7%BC%96%E7%A8%8B%E4%B8%8E%E5%86%99%E4%BD%9C/</guid><description>&lt;br>
![](http://img.testclass.net/coding_and_writing.jpg)
&lt;p>作为一个略懂编程和略会文章的测试，突然想聊一聊这个话题，因为这两件在我的日常中很多时候是一件事。比如，我在写一篇技术分享的文章，其中就包括了写作，如何将技术描述清楚，中间再穿插一些代码。&lt;/p>
&lt;h4 id="写作">写作&lt;/h4>
&lt;p>写作难么？我认为不那么简单，虽然，我们每天都进行着大量的碎片化阅读（微信、知乎、头条&amp;hellip;），但如果让你对某个事件发表一下有深度的看法，或者在知乎上写一篇高质量的回答，这其实是有难度的，不是识字就能做到的。&lt;/p>
&lt;p>阅读更多是获取信息和观点；而写作是抛出信息和观点。写作是慢思考，一个模糊的想法转化成最终的文章期间会在大脑和指尖反复斟酌。&lt;/p>
&lt;p>写作有什么好处？它可提高语言组织能力，加强对问题认识的全面性和深度，比如，要求你明天给大家分享一个技术，准备PPT的过程（姑且也可以把它看写作吧！）其实就是对这个技术会面性和深度的再次挖掘。那么第二天的演讲一定会从容不迫。如果不经过“写作的思考”，就算这个技术你天天在用，真的要在分享的时候也会难免会有所纰漏。&lt;/p>
&lt;p>我觉得写作的另一个好处是提高人的情商，写作本身是对人对事的思考过程，善于思考的人做人做事一般会三思而行，会更稳重。&lt;/p>
&lt;h4 id="编程">编程&lt;/h4>
&lt;p>编程相于写作，我们感觉要更难一些。这主要是因为我们平时接触文字的时间要远远大于代码。但它们仍然有很多相似之处。&lt;/p>
&lt;p>比如都是看不会的，虽然这段文字很优美，但你不一定能写出这么优美的句字；虽然这段代码你能看懂，但你不一定能写出这段代码所实现的功能。所以，都需要长期的“写”训练。好吧！我们一般对编程叫“敲”代码，但是“敲”字比较机械化，别忘了带上脑子。&lt;/p>
&lt;p>它们有时候可以表达同样的意思：&lt;/p>
&lt;p>“如果我跟马云一样有钱，我就去周游世界！不然，我就继续工作。”&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">poorPeople&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">me&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">poorPeople&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">wealthPeople&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">maDad&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">wealthPeople&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">meMoney&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">me&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">money&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">maDadMoney&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">maDad&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">money&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">meMoney&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">==&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">maDadMoney&lt;/span>&lt;span class="p">){&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">me&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">goSeeWorld&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="k">else&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">me&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">work&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>看，看用编程一样可以表达我们的意思。&lt;/p>
&lt;h4 id="不同">不同&lt;/h4>
&lt;p>当然，编程与写作也有很多不一样的点，比如上面的代码，你会明显看出更加严谨。如果写作是一个感性的女孩，那么编程就是一个不懂情趣的直男，女孩说：“你都不关心我了，你一定是不爱我了！”。男孩默默写了个公示：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">love&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;care&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>女孩又说：“你都不回我信息，你一定是不爱我了！”，男孩不得不修改变量love的值：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">String&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">love&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;return info&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&amp;hellip;..&lt;/p></description></item><item><title>常见问题</title><link>https://itest2025.pages.dev/tutorials/24-000-%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98/</link><pubDate>Mon, 16 Oct 2017 12:59:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/24-000-%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98/</guid><description>&lt;h3 id="什么是firefox的profileprofile有什么用">什么是firefox的profile，profile有什么用？&lt;/h3>
&lt;hr>
&lt;p>&lt;a href="https://support.mozilla.org/en-US/kb/profiles-where-firefox-stores-user-data?redirectlocale=en-US&amp;amp;redirectslug=Profiles" target="_blank" rel="noopener noreffer ">官方解释&lt;/a>。&lt;/p>
&lt;p>简单来说，profile保存了&lt;/p>
&lt;ul>
&lt;li>书签&lt;/li>
&lt;li>记住的password&lt;/li>
&lt;li>其他信息，比如cookie&lt;/li>
&lt;/ul>
&lt;p>webidrver启动浏览器的时候会产生临时的profile，这也是为什么每次浏览器启动以后我们都要重新登录系统的原因，profile重置了，登录态也就没保存下来了。&lt;/p>
&lt;p>我们在使用selenium做测试的时候可以指定使用1个已经存在的profile，从而实现一段时间的免登录功能。&lt;/p>
&lt;p>&lt;a href="https://support.mozilla.org/en-US/kb/profiles-where-firefox-stores-user-data?redirectlocale=en-US&amp;amp;redirectslug=Profiles#w_how-do-i-find-my-profile" target="_blank" rel="noopener noreffer ">如何找到firefox的profile文件&lt;/a>&lt;/p>
&lt;h4 id="如何在selenium中指定使用已存在的profile">如何在selenium中指定使用已存在的profile&lt;/h4>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 传入profile所在的绝对路径&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">profile&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">webdriver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">FirefoxProfile&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;/home/jmunsch/.mozilla/firefox/yxjwk1py.default&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">webdriver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Firefox&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">profile&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="chrome-headless-模式">Chrome headless 模式&lt;/h3>
&lt;hr>
&lt;p>我们在通过Selenium运行自动化测试时，必须要启动浏览器，浏览器的启动与关闭必然会影响执行效率，而且还会干扰你做其它事情（本机运行的话）。&lt;/p>
&lt;p>那能不能把自动化测试的运行放在后台？当然可以！&lt;/p>
&lt;ul>
&lt;li>
&lt;p>htmlunit 项目可以模拟浏览器运行，是一个没有界面的浏览器，运行速度快。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>PhantomJS 是一个基于webkit的JavaScript API。它使用QtWebKit作为它核心浏览器的功能，使用webkit来编译解释执行JavaScript代码。任何你可以在基于webkit浏览器做的事情，它都能做到。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Chrome-headless 模式，Google 自己出的无头浏览器模式。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>htmlunit&lt;/strong> 在Selenium 下面，我都没跑通过一个 baidu 的 demo, 因为它不打开 UI 界面，所以，你也不知道它后台是如何渲染页面的。 弃之！&lt;/p>
&lt;p>&lt;strong>PhantomJS&lt;/strong> 非常不错，因为是使用的 QtWebKit 浏览器内核渲染页面，基本可以和真正浏览器保持一致。&lt;/p>
&lt;p>&lt;strong>Chrome-headless 模式&lt;/strong>， Google 针对 Chrome 浏览器新增加的一种模式，可以让你不打开UI界面的情况下使用 Chrome 浏览器，所以运行效果与 Chrome 保持完美一致。PhantomJS作者说，你这么搞我失业了啊！&lt;/p>
&lt;h4 id="用法">用法&lt;/h4>
&lt;p>Python Selenium 用法:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">webdriver&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">selenium.webdriver.chrome.options&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Options&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">chrome_options&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Options&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">chrome_options&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add_argument&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;--headless&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">driver&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">webdriver&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Chrome&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">chrome_options&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">chrome_options&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Java Selenium用法:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Java" data-lang="Java">&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.WebDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.chrome.ChromeDriver&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kn">import&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nn">org.openqa.selenium.chrome.ChromeOptions&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">class&lt;/span> &lt;span class="nc">WebTest&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">public&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">static&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kt">void&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">throws&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">InterruptedException&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">ChromeOptions&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">chromeOptions&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ChromeOptions&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">chromeOptions&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">addArguments&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;--headless&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">WebDriver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">driver&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ChromeDriver&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">chromeOptions&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">...&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原始封面&lt;/p></description></item><item><title>测试圈TC：Python测试框架最全资源汇总</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tcpython%E6%B5%8B%E8%AF%95%E6%A1%86%E6%9E%B6%E6%9C%80%E5%85%A8%E8%B5%84%E6%BA%90%E6%B1%87%E6%80%BB/</link><pubDate>Mon, 16 Oct 2017 02:10:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tcpython%E6%B5%8B%E8%AF%95%E6%A1%86%E6%9E%B6%E6%9C%80%E5%85%A8%E8%B5%84%E6%BA%90%E6%B1%87%E6%80%BB/</guid><description>&lt;br>
&lt;h3 id="收藏清单python测试框架最全资源汇总">收藏清单：Python测试框架最全资源汇总&lt;/h3>
&lt;br>
&lt;h4 id="xunit-frameworks-单元测试框架">xUnit frameworks 单元测试框架]()&lt;/h4>
&lt;hr>
&lt;p>&lt;strong>frameworks 框架&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;a href="https://docs.python.org/library/unittest.html" target="_blank" rel="noopener noreffer ">unittest&lt;/a> - python自带的单元测试库，开箱即用&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://pypi.python.org/pypi/unittest2" target="_blank" rel="noopener noreffer ">unittest2&lt;/a> - 加强版的单元测试框架，适用于Python 2.7以及后续版本&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="http://pytest.org/" target="_blank" rel="noopener noreffer ">pytest&lt;/a> - 成熟且功能强大的单元测试框架&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="http://plugincompat.herokuapp.com/" target="_blank" rel="noopener noreffer ">plugincompat&lt;/a> - pytest的执行及兼容性插件&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://nose.readthedocs.org/en/latest/" target="_blank" rel="noopener noreffer ">nosetests&lt;/a> - 让python测试更容易一点&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://github.com/slash-testing/slash" target="_blank" rel="noopener noreffer ">slash&lt;/a> - python实现的单元测试框架&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>extensions 扩展&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;a href="https://pythonhosted.org/proboscis/" target="_blank" rel="noopener noreffer ">proboscis&lt;/a> - 仿TestNG扩展了unittest模块以及Nose的功能&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://github.com/wgnet/grail" target="_blank" rel="noopener noreffer ">grail&lt;/a> - 可以让你一步一步编写测试用例的库&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://github.com/Yelp/Testify/" target="_blank" rel="noopener noreffer ">testify&lt;/a> - 单元测试框架，提供了加强型fixture，用例切割并行运行，testrunner高亮及详尽的log和report功能&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://github.com/Yelp/Testify/" target="_blank" rel="noopener noreffer ">trial&lt;/a> - unittest模块的扩展，提供了命令行的testrunner工具以及代码覆盖率的整合，跟nose差不多&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://launchpad.net/subunit" target="_blank" rel="noopener noreffer ">subunit&lt;/a> - 提供了unittest在另一个进程执行用例并汇总测试数据的能力&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://launchpad.net/testresources" target="_blank" rel="noopener noreffer ">testresources&lt;/a> - 提供了多用例间管理测试数据的机制，兼容unittest&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://launchpad.net/testtools" target="_blank" rel="noopener noreffer ">testtools&lt;/a> - 为Twisted和Bazaar提供的unittest扩展&lt;/p></description></item><item><title>测试圈TC：测试人员的两级分化</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E6%B5%8B%E8%AF%95%E4%BA%BA%E5%91%98%E7%9A%84%E4%B8%A4%E7%BA%A7%E5%88%86%E5%8C%96/</link><pubDate>Mon, 09 Oct 2017 03:50:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E6%B5%8B%E8%AF%95%E4%BA%BA%E5%91%98%E7%9A%84%E4%B8%A4%E7%BA%A7%E5%88%86%E5%8C%96/</guid><description>&lt;br>
&lt;p>&lt;font color='red'>“软件测试已死”&lt;/font> 的论调早几年就听到有人说，因为当时软件测试普通技术含量低，大多数以功能测试为主，所以，对于已经做了几年功能测试的人来说，看不到未来的方向。&lt;/p>
&lt;p>我当时的看法是：&lt;/p>
&lt;p>测试人员这个工种可能会消失，但“测试行为”肯定不会消失。因为任何产品的质量肯定需要通过测试来保证。这个测试的行为就算是通过机器或程序来做，总要有人去控制机器或有人去写测试程序吧！作为测试人员，想要不被淘汰，做那个写测试程序的人就好了嘛！&lt;/p>
&lt;p>几年时间过去了，软件测试这个岗位不但没有消失，而且发展的越来越好了，每年都有大批的新人加入，测试的地位也有很大的提升。&lt;/p>
&lt;p>但是，我要抛出的一个观点是，&lt;strong>测试人员逐渐进入了两极分化的阶段&lt;/strong>，如果你看过51testing发布的《2016中国软件测试现状调查报告》，我之前也有一篇文章做过简单的分析，大多数测试人员的月薪都停留在5k&lt;del>15k，但是你看国内一线互联网的软件测试相关岗位的招聘月薪30k&lt;/del> 40K 的很多。这就是我说的两极分化，跟现在的国民收入很像。&lt;/p>
&lt;p>那么，有同学说了，你说的30k~40k是行业里工作很多年的，我才刚入行没两年，真的只是工作年限不够长么？在IT行业里很少有大器晚成的牛人，牛的人一路的经历都很牛，比如，我们经常看到某某 13岁开始编程，18岁创建第一家公司等等的新闻，感觉他们的人生像开了挂一样。&lt;/p>
&lt;p>我随便的招聘网站上搜索一下薪资比较高（30k~40k）的招聘要求：&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/tc_zhaopin_1.jpg"
 data-srcset="http://img.testclass.net/tc_zhaopin_1.jpg, http://img.testclass.net/tc_zhaopin_1.jpg 1.5x, http://img.testclass.net/tc_zhaopin_1.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/tc_zhaopin_1.jpg"
 title="http://img.testclass.net/tc_zhaopin_1.jpg" />&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/tc_zhaopin_2.jpg"
 data-srcset="http://img.testclass.net/tc_zhaopin_2.jpg, http://img.testclass.net/tc_zhaopin_2.jpg 1.5x, http://img.testclass.net/tc_zhaopin_2.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/tc_zhaopin_2.jpg"
 title="http://img.testclass.net/tc_zhaopin_2.jpg" />&lt;/p>
&lt;p>不知道你有没有看到自己与招聘要求的差距？&lt;/p>
&lt;p>这里很醒目的字眼是应该是“主流编程语言”（Java/Python/PHP）、“开发”和“自动化”了吧！在我们开的测试课里大量穿插了一些开发技能，个别同学不理解，经常会说：“我又不做开发”，“多讲讲测试工具就好了”。&lt;/p>
&lt;p>&lt;strong>那么问题来说，公司为什么要懂开发的测试岗位？&lt;/strong>&lt;/p>
&lt;p>我觉得一个比较重要的原因和当前的开发模式有关。现在大多数互联网产品的迭代速度很快，每周或每天一个版本，跟本不给测试人员留有充足的测试时间。你还想按照传统的模式等功能都开发完了再来测试不现实。那只能让测试人员更早的介入了，如何介入？当然是去测试单元或接口了。&lt;/p>
&lt;p>另一方面，编程能力也是提高测试效率的重要因素。举个简单的例子，你通过手工测试可能要两天时间还容易出错，我写个测试脚本分分钟出结果。所以“自动化”要求在测试工作才会这么普及和重要。&lt;/p>
&lt;p>&lt;strong>这个招聘要求真的很难么？&lt;/strong>&lt;/p>
&lt;p>这个就因人而异了，对于测试小白来说确实门槛挺高的，尤其不是计算机相关专业跨行过来的同学。对于具有一定编程能力和做过一些自动化的同学，其实也没那么难。你可能缺少的是实践经验和开发能力的深度。&lt;/p>
&lt;p>在我看来，开发并不难，我们并不需要深入研究算法，测试也并不难，更多的是一个测试思维的培养，因为同时具备开发和测试能力的人并不多。所以，造成了市场的缺口。那只能通过高薪来吸引人才了。&lt;/p>
&lt;p>&lt;strong>抓住分化的机遇&lt;/strong>&lt;/p>
&lt;p>这其实就相当于在改革开放的时候，怎样成为先富那部分人，三十年前，有的人爸妈出来做点小生意，也许现在已经身价过亿了。有的人爸妈觉得老老实实在家种地有饭吃，也许现在还是农民。&lt;/p>
&lt;p>测试也一样，觉得“开发技能”对测试很重要的同学，现在也许已经跨过鸿沟拿到了高薪。我们之前采访过一位美女测试，工作两年月薪接近两万，未来30K~40K对她来说只是一个时间问题。&lt;/p>
&lt;p>“开发不用学”的同学依然会觉得，这个测试工具挺方便的，满足需求就好了。再过几年后也许依然会处在测试的底层，每次看到行业平均工资的时候，只能自我调侃一句，“唉！又拖了行业的后退！”。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1470164971321-eb5ac2c35f2e?w=300"
 data-srcset="https://images.unsplash.com/photo-1470164971321-eb5ac2c35f2e?w=300, https://images.unsplash.com/photo-1470164971321-eb5ac2c35f2e?w=300 1.5x, https://images.unsplash.com/photo-1470164971321-eb5ac2c35f2e?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1470164971321-eb5ac2c35f2e?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>测试圈TC：如何写出测不出bug的测试用例</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E5%A6%82%E4%BD%95%E5%86%99%E5%87%BA%E6%B5%8B%E4%B8%8D%E5%87%BAbug%E7%9A%84%E6%B5%8B%E8%AF%95%E7%94%A8%E4%BE%8B/</link><pubDate>Mon, 09 Oct 2017 02:50:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E5%A6%82%E4%BD%95%E5%86%99%E5%87%BA%E6%B5%8B%E4%B8%8D%E5%87%BAbug%E7%9A%84%E6%B5%8B%E8%AF%95%E7%94%A8%E4%BE%8B/</guid><description>&lt;br>
&lt;p>我们写测试用例的目的是为了能够整理思路，把要测试的地方列出来，做为知识的积淀，用例可以交给其他测试人员执行，或者是跟需求提出者进行讨论，对用例进行补充和修改。&lt;/p>
&lt;p>理论上用例写的越多，越容易发现bug。但是，本文我们将讨论如何写出发现不了bug的测试用例。&lt;/p>
&lt;p>&lt;strong>不看需求&lt;/strong>&lt;/p>
&lt;p>要想写出测不出bug的用例，最关键的一点就是不看需求或者随便看看需求。&lt;/p>
&lt;p>需求文档是个磨人的小妖精，要么是写的看不懂，要么写的太简单。这玩意很多时候我们是看不懂的，看不懂的话，嗯，那么就脑补咯，用例写的又快又好，执行的时候肯定发现不了bug。&lt;/p>
&lt;p>&lt;strong>只看需求&lt;/strong>&lt;/p>
&lt;p>我们的测试用例只涵盖需求中描述的部分，其他需求里面没有提到的部分坚决不写。测不出问题不是用例的错，都是需求的锅。&lt;/p>
&lt;p>&lt;strong>只写正常的逻辑&lt;/strong>&lt;/p>
&lt;p>永远只关注业务的正常流程和逻辑，把测试用例写成用户说明书，这样看起来内容会很多很详尽，但是根据这个用例，不管你怎么测你都测不出来问题，厉害吧。&lt;/p>
&lt;p>&lt;strong>拷贝粘贴&lt;/strong>&lt;/p>
&lt;p>一般大家都用excel写用例，这时候相似的用例是可以使用拷贝粘贴的方式去搞的，改几个字就是个新用例了，很聪明不是？这样的用例交到执行人员手里，因为长得差不多，执行的时候很容易被忽视造成场景漏侧，遗漏了就自然发现不到bug了，不是么？&lt;/p>
&lt;p>&lt;strong>只可意会&lt;/strong>&lt;/p>
&lt;p>把每一条用例都写得只可意会不可言传。这样的用例自己写过3天之后都会忘了写得时候到底是怎么想的，通过这种用例去找bug，只能靠运气。&lt;/p>
&lt;p>&lt;strong>没有断言&lt;/strong>&lt;/p>
&lt;p>只描述方法和步骤，不写断言，或者把断言写的很暧昧，有一种朦胧美，让人觉得看起来很有道理，但是执行的时候一脸懵逼，比如&lt;/p>
&lt;ul>
&lt;li>应该登录成功&lt;/li>
&lt;li>应该保存成功&lt;/li>
&lt;li>应该跳转到正确的页面&lt;/li>
&lt;li>应该有错误提示&lt;/li>
&lt;/ul>
&lt;p>只要掌握了上面的方法，勤加练习，相信大家很快就能练成撰写测不出bug测试用例的绝技。目前江湖上此等绝技风行一时，人人争相敬仰之。&lt;/p>
&lt;p>最后 &lt;strong>以上我说的都是反话&lt;/strong>&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1489493512598-d08130f49bea?w=300"
 data-srcset="https://images.unsplash.com/photo-1489493512598-d08130f49bea?w=300, https://images.unsplash.com/photo-1489493512598-d08130f49bea?w=300 1.5x, https://images.unsplash.com/photo-1489493512598-d08130f49bea?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1489493512598-d08130f49bea?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>测试教程网：祝各位测试同学国庆&amp;中秋快乐！</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E6%95%99%E7%A8%8B%E7%BD%91%E7%A5%9D%E5%90%84%E4%BD%8D%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E5%9B%BD%E5%BA%86%E4%B8%AD%E7%A7%8B%E5%BF%AB%E4%B9%90/</link><pubDate>Thu, 28 Sep 2017 06:20:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E6%95%99%E7%A8%8B%E7%BD%91%E7%A5%9D%E5%90%84%E4%BD%8D%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E5%9B%BD%E5%BA%86%E4%B8%AD%E7%A7%8B%E5%BF%AB%E4%B9%90/</guid><description>&lt;br>
&lt;p>&lt;strong>各位测试同学：&lt;/strong>&lt;/p>
&lt;p>大家好！&lt;a href="http://www.testclass.net/" target="_blank" rel="noopener noreffer ">&lt;strong>测试教程网&lt;/strong>&lt;/a> 建站三个多月以来上传的大量的 &lt;strong>测试基础教程&lt;/strong> 。我们希望给你们提供一个专业的测试学习平台。让你不再漫无目的找各种测试技术和工具的资料。我们没有专业的团队，也没有到处的爬取别人的资料做搬运工，这里几乎是虫师和乙醇的全部原创。&lt;/p>
&lt;p>除了技术之外，我们希望做一个有温度的测试网站，所以，我们的首页每周都会更新一些 &lt;strong>公众号文章&lt;/strong> 和 一些 &lt;strong>免费公开课&lt;/strong> 信息。我还特意为节日重新设计的网站logo（水平有限，一人身兼数职 ^_^ !）。&lt;/p>
&lt;p>我们会继续更新更多的优秀的测试教程，也会不定期的组织更多免费的公开课。同时你觉得这个网站不错的话也欢迎推荐给更多的测试小伙伴。&lt;/p>
&lt;p>最后，&lt;strong>祝&lt;/strong>: 各种测试同学 国庆节快乐！中秋节快乐！ 长期加班的同学辛苦了。可以趁这个节日休息一下！节后再战。&lt;/p>
&lt;p>测试教程网（虫师）&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1489493512598-d08130f49bea?w=300"
 data-srcset="https://images.unsplash.com/photo-1489493512598-d08130f49bea?w=300, https://images.unsplash.com/photo-1489493512598-d08130f49bea?w=300 1.5x, https://images.unsplash.com/photo-1489493512598-d08130f49bea?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1489493512598-d08130f49bea?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>测试圈TC：《2017测试行业状况调查报告》</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc2017%E6%B5%8B%E8%AF%95%E8%A1%8C%E4%B8%9A%E7%8A%B6%E5%86%B5%E8%B0%83%E6%9F%A5%E6%8A%A5%E5%91%8A/</link><pubDate>Mon, 25 Sep 2017 06:20:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc2017%E6%B5%8B%E8%AF%95%E8%A1%8C%E4%B8%9A%E7%8A%B6%E5%86%B5%E8%B0%83%E6%9F%A5%E6%8A%A5%E5%91%8A/</guid><description>&lt;br>
&lt;p>当这一份报告由QAIntelligence 的调查结果。报告的名称叫《State of Testing report|2017》&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/state-of-testing-cover2017.png"
 data-srcset="http://img.testclass.net/state-of-testing-cover2017.png, http://img.testclass.net/state-of-testing-cover2017.png 1.5x, http://img.testclass.net/state-of-testing-cover2017.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/state-of-testing-cover2017.png"
 title="http://img.testclass.net/state-of-testing-cover2017.png" />&lt;/p>
&lt;h4 id="什么是state-of-testing-">什么是State of Testing ?&lt;/h4>
&lt;hr>
&lt;p>State of Testing 是最大的年度调查，该调查旨在确定测试社区所面临的现有特征、实践和挑战，希望能够阐明并激发对改进的富有成效的讨论。这是QA Intelligence博客的倡议，并与测试人员合作。&lt;/p>
&lt;p>这篇报告在全球范围内与全球测试界共享，这在一定程度上要归功于我们的合作博主、媒体合作者、在线“word of mouth”和声誉。&lt;/p>
&lt;p>每一年，参与者的数量都在增加，最终的报告会更有价值，这是测试趋势、挑战和特征的最终反映。&lt;/p>
&lt;p>过去的调查报告甚至被翻译成几种语言，并在全球范围内共享，进一步扩大了本报告对我们所有QA部门的影响。&lt;/p>
&lt;p>注：参与本次调查的大概有1600位软件测试从业人员，比去年多了50%。&lt;/p>
&lt;p>想阅读报告分析，点击&lt;a href="http://mp.weixin.qq.com/s/qInA3IwFku9CPdZwTKlzqg" target="_blank" rel="noopener noreffer ">这里&lt;/a>.&lt;/p>
&lt;p>发布报告原网站，点击&lt;a href="http://qablog.practitest.com/state-of-testing/" target="_blank" rel="noopener noreffer ">这里&lt;/a>&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1500673922987-e212871fec22?w=300"
 data-srcset="https://images.unsplash.com/photo-1500673922987-e212871fec22?w=300, https://images.unsplash.com/photo-1500673922987-e212871fec22?w=300 1.5x, https://images.unsplash.com/photo-1500673922987-e212871fec22?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1500673922987-e212871fec22?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>测试圈TC：软件测试人员必备知识工具清单</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E4%BA%BA%E5%91%98%E5%BF%85%E5%A4%87%E7%9F%A5%E8%AF%86%E5%B7%A5%E5%85%B7%E6%B8%85%E5%8D%95/</link><pubDate>Mon, 25 Sep 2017 06:20:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95%E4%BA%BA%E5%91%98%E5%BF%85%E5%A4%87%E7%9F%A5%E8%AF%86%E5%B7%A5%E5%85%B7%E6%B8%85%E5%8D%95/</guid><description>&lt;br>
&lt;h4 id="收藏清单软件测试人员必备知识工具清单">收藏清单：软件测试人员必备知识工具清单&lt;/h4>
&lt;hr>
&lt;br>
__测试工具__
&lt;p>&lt;a href="http://beefproject.com/" target="_blank" rel="noopener noreffer ">BeEF&lt;/a>： 测试xss的&lt;/p>
&lt;p>&lt;a href="https://github.com/zaproxy/zaproxy" target="_blank" rel="noopener noreffer ">OWASP ZAP&lt;/a>：代理，可以实时查看和修改报文&lt;/p>
&lt;p>&lt;a href="https://chrome.google.com/webstore/detail/cookie-inspector/jgbbilmfbammlbbhmmgaagdkbkepnijn" target="_blank" rel="noopener noreffer ">Cookie Inspector&lt;/a>：让cookie操作和编辑更加简单&lt;/p>
&lt;p>&lt;a href="https://www.baremetalsoft.com/baretail/" target="_blank" rel="noopener noreffer ">BareTail&lt;/a>：在windows上使用linux tail命令&lt;/p>
&lt;p>&lt;a href="https://chrome.google.com/webstore/detail/full-page-screen-capture/fdpohaocaechififmbbbbbknoalclacl" target="_blank" rel="noopener noreffer ">Full Page Screenshot&lt;/a>：整页截屏，专治各种滚动条&lt;/p>
&lt;p>&lt;a href="https://chrome.google.com/webstore/detail/form-filler/bnjjngeaknajbdcgpfkgnonkmififhfo" target="_blank" rel="noopener noreffer ">Form Filler&lt;/a>：自动填写表单，强烈推荐&lt;/p>
&lt;p>&lt;a href="https://chrome.google.com/webstore/detail/bug-magnet/efhedldbjahpgjcneebmbolkalbhckfi" target="_blank" rel="noopener noreffer ">Bug Magnet&lt;/a>：根据字段类型自动建议特殊输入&lt;/p>
&lt;p>&lt;a href="https://chrome.google.com/webstore/detail/check-all/hcajloodonmplhncgandpgjgagckkdhn" target="_blank" rel="noopener noreffer ">Check All&lt;/a>：全选插件&lt;/p>
&lt;p>&lt;a href="http://yslow.org/" target="_blank" rel="noopener noreffer ">Yslow&lt;/a>：前端页面性能测试&lt;/p>
&lt;br>
__测试教程__
&lt;p>&lt;a href="http://www.testclass.net/" target="_blank" rel="noopener noreffer ">测试教程网&lt;/a>：涵盖了大部分测试工具的使用以及测试入门进阶的必备教程，强烈推荐&lt;/p>
&lt;br>
__书籍__
&lt;p>&lt;a href="https://www.amazon.co.uk/d/Books/Dont-Make-Me-Think-Usability/0321965515/" target="_blank" rel="noopener noreffer ">Don&amp;rsquo;t Make Me Think: A Common Sense Approach to Web Usability&lt;/a>：关于用户体验的必读书籍，有中文版&lt;/p>
&lt;p>&lt;a href="https://www.amazon.co.uk/UI-Communication-Intuitive-Interfaces-Effective/dp/0123969808" target="_blank" rel="noopener noreffer ">UI is Communication&lt;/a>：UI及用户体验测试可以读一下&lt;/p>
&lt;p>&lt;a href="https://www.amazon.co.uk/Thinking-Fast-Slow-Daniel-Kahneman/dp/0141033576" target="_blank" rel="noopener noreffer ">Thinking, Fast and Slow&lt;/a>：我们是如何做决定的，有中文版，UI及用户体验测试推荐阅读&lt;/p>
&lt;br>
__在线训练（主要是代码能力训练）__
&lt;p>&lt;a href="https://github.com/karlhorky/learn-to-program" target="_blank" rel="noopener noreffer ">Learn to Code&lt;/a>：如何开始写代码&lt;/p></description></item><item><title>测试圈TC：测试同学难道要写一辈子Hello World?</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E9%9A%BE%E9%81%93%E8%A6%81%E5%86%99%E4%B8%80%E8%BE%88%E5%AD%90hello-world/</link><pubDate>Mon, 18 Sep 2017 03:10:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E6%B5%8B%E8%AF%95%E5%90%8C%E5%AD%A6%E9%9A%BE%E9%81%93%E8%A6%81%E5%86%99%E4%B8%80%E8%BE%88%E5%AD%90hello-world/</guid><description>&lt;br>
![](http://img.testclass.net/tc_py_hello_worldd.png)
&lt;p>最近我们在测试团队内推行自动化用例责任制，大致的意思是：我们安排培训资源，提供技术支持和一对一辅导，要求每一个自主选择了自动化和接口测试发展通道的同学必须让自己负责的项目自动化用例覆盖率有所提升。&lt;/p>
&lt;p>后来我们组织了很多次的培训，开始人很多，逐渐的大家都没有参与的兴趣了，来的人越来越少。在工作群里问一下原因，无非就是下面几个方面&lt;/p>
&lt;ul>
&lt;li>项目太忙了。我了解到有些项目确实很忙，但是绝大多数项目是没有那么大的强度的&lt;/li>
&lt;li>基础太差，到后面听不懂了。这个我相信&lt;/li>
&lt;li>能听懂，但是不知道怎么在项目里用起来。我也相信，但是你从来没请教过别人这方面的问题&lt;/li>
&lt;/ul>
&lt;p>这时候有一位同学在群里跳出来了，说了一句让我印象很深刻的话：&lt;/p>
&lt;pre>&lt;code>大家不要找借口了，我觉得让我们学习和写用例是为了我们好，难道你们真想一辈子都只会写hello world吗？
&lt;/code>&lt;/pre>
&lt;p>后来这个天被他聊死了，因为大部分人连hello world都不会写。也许这个才是关键。&lt;/p>
&lt;p>万事开头难，我记得我刚开始写自动化用例的时候也是各种报错，不是环境没有弄好，就是报了一大堆的英文错误，密密麻麻的一串，不知道从哪里看好。那时候也不会提问，问一些各种没有上下文的问题，搞的别人也没办法帮我。后来在各种孤立无援的情况下求助于搜索引擎，反正什么地方不懂的我就去搜索，无非就是获取帮助的方式没那么直接，解决问题慢一点，但至少可以迂回前进，比原地踏步要好。&lt;/p>
&lt;p>后来我发现，如果你一辈子都只会写hello world，也许就意味着：要么你没有前进的方向，要么你不会自主学习。&lt;/p>
&lt;p>从目前的情况下，测试同学估计也需要写一些比hello world高级的东西了，无论是从质量控制的角度还是工程化的角度。年轻人有潜力，下班以后可以少农药几局，也许突破瓶颈了你的格局和以后的发展方向都不一样了，年纪稍微大一点的同学更要努力一些，随着年龄的增长，你会发现，也许你会从事一些更高层面，比如管理团队培养团队的工作，当你把某个自动化测试任务分配给其他同学的时候，你也许会受到他的挑战：这个我不会，你行你上啊？这时候，你应该静静的看着他，意味深长的来一句：“可以，如果你不会，我可以教你，我们一起来。”&lt;/p>
&lt;p>~深藏功与名!&lt;/p>
&lt;p>&lt;a href="http://mp.weixin.qq.com/s?__biz=MzIxMTg4NDg0MA==&amp;amp;mid=2247483812&amp;amp;idx=1&amp;amp;sn=f86076f838e984517f9242e5bd03d626&amp;amp;chksm=974fcfe3a03846f59c51316570cd238b8c0026cb9d3a8cb8fa097e975e76805e1e9285245dff&amp;amp;scene=0#rd" target="_blank" rel="noopener noreffer ">原文链接&lt;/a>&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1483728642387-6c3bdd6c93e5?w=300"
 data-srcset="https://images.unsplash.com/photo-1483728642387-6c3bdd6c93e5?w=300, https://images.unsplash.com/photo-1483728642387-6c3bdd6c93e5?w=300 1.5x, https://images.unsplash.com/photo-1483728642387-6c3bdd6c93e5?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1483728642387-6c3bdd6c93e5?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>测试圈TC：创业公司 VS 大公司</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E5%88%9B%E4%B8%9A%E5%85%AC%E5%8F%B8-vs-%E5%A4%A7%E5%85%AC%E5%8F%B8/</link><pubDate>Mon, 11 Sep 2017 02:10:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E5%88%9B%E4%B8%9A%E5%85%AC%E5%8F%B8-vs-%E5%A4%A7%E5%85%AC%E5%8F%B8/</guid><description>&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/tc_small_big_company_select.jpg"
 data-srcset="http://img.testclass.net/tc_small_big_company_select.jpg, http://img.testclass.net/tc_small_big_company_select.jpg 1.5x, http://img.testclass.net/tc_small_big_company_select.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/tc_small_big_company_select.jpg"
 title="http://img.testclass.net/tc_small_big_company_select.jpg" />&lt;/p>
&lt;p>这是前两天晚上一个同学问我的问题，我当时简单回答了一个自己的看法，后来想了想其实可以更详细的聊聊这个话题，这也是大多数人找工作时都会面临的选择。&lt;/p>
&lt;p>一谈到创业公司，我们往往想到一个公式：&lt;/p>
&lt;p>&lt;strong>创业公司 = 更多的机会！&lt;/strong>&lt;/p>
&lt;p>万一公司扩大规模，我进公司早，我不就成管理了，过不了三五年就走上人生巅峰，迎娶白富美（高富帅）了！&lt;/p>
&lt;p>万一公司上市了，我不是马上身价过亿了，王健林的小目标，一不小心就被我实现了！&lt;/p>
&lt;p>这几年瞬间发展成互联网巨头的公司确实不少，小米、美团、滴滴等都是近几年才成立，并在短短几年就发展成互联网大公司了。&lt;/p>
&lt;p>但是，获得巨大成功的公司毕竟在少数。想选择一个创业公司发家致富，我感觉跟中彩票差不多，下图就是我目前办公地方的创业公司。深圳这样的公司多了去了。&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/tc_small_company.jpg"
 data-srcset="http://img.testclass.net/tc_small_company.jpg, http://img.testclass.net/tc_small_company.jpg 1.5x, http://img.testclass.net/tc_small_company.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/tc_small_company.jpg"
 title="http://img.testclass.net/tc_small_company.jpg" />&lt;/p>
&lt;p>就算真成功了为什么会分你一杯羹呢？不应该是在BAT工作多年加入的核心员工/管理者么？因为主要是靠他们为公司贡献了自己的技能和管理经验的啊！&lt;/p>
&lt;p>可是，我可以有更多的机会学习管理能力呀！嗯，这确实是个不错的理由。不过，我们技术专业出身的人真的擅长去揣摩领导的心思和下属的想法么？或者，你是真心喜欢管理的么？我想大多人主要在意是的title！不过，IT行业都比较扁平化和开放了，而且管理职称和技术职称是两个不同通道；并不像政府部门，官大一级压死人。&lt;/p>
&lt;p>你想学管理可以，但要问问自己的内心，是否真的喜欢管理，还有自己的性格是否适合管理。&lt;/p>
&lt;p>另外，创业公司也会有一些普遍的短板，无偿加班多，福利跟不上，管理混乱。&lt;/p>
&lt;p>那么创业公司是不是不能去了？不是啊！我觉得看两点，公司产品的市场，如果是一个细分领域的产品，那么注定做不大；另外一个看趋势；当前大数据、人工智能、VR/AR、互联网金融&amp;hellip;都很热门，更早接触到这些前沿的产品和技术，将来肯定不会被淘汰。&lt;/p>
&lt;p>黑了半天创业公司，再来说说大公司！&lt;/p>
&lt;p>一提到大公司，我们往往想到的公式是：&lt;/p>
&lt;p>&lt;strong>大公司 = 螺丝钉！&lt;/strong>&lt;/p>
&lt;p>&lt;font color=#DC143C>我的观点是，趁年轻多去大公司看看。&lt;/font>&lt;/p>
&lt;p>大公司可以让你接触到：更大的项目和更厉害的人。&lt;/p>
&lt;p>更大的项目必然需要更多的人去做，在这个过程中，你可以接触到更规范的流程，或者更前沿的协作方法。更大的项目也会暴露出更多的技术问题（如性能），你从中也能学到更多的技术。&lt;/p>
&lt;p>更厉害的人可以影响你思考问题的方式，举个我自己的例子，半年前在被调到珠海的时候，很多同事都有车，一次出去聚餐坐同事的车，闲聊，我就问他住哪里，他说了一个离公司很多的地方，我说公司附近的房子租金也不贵啊，干嘛住那么远。他说：开车40多分钟就到公司了，房子买在那里了。&lt;/p>
&lt;p>我的思维是，那地方坐公交车太远了，不租，典型穷人思维。他的思维是开车不算远，可以考虑在这个买房。&lt;/p>
&lt;p>当然，这只是个例子，跟厉害的人一起工作久了，你的很多想法都趋同于他们的思维；慢慢的，自己也会变成厉害的人。&lt;/p>
&lt;p>当然，大公司也有一些普遍问题，只能触及到点，晋升困难，办公室政治会比较验证。不过，我仍然觉得有机会应该去大公司看看！&lt;/p>
&lt;p>最后，往往出去创业或成功的都是大公司走出来的。他们得到的技术、经验和人脉是小公司不具备的。&lt;/p>
&lt;hr>
&lt;p>&lt;font color=#DC143C>另外，前几天看前同事在他的公众号里说，妹子找男朋友，不要看他上班时候怎么样子，而是看他下班之后在做什么？他下班之后的样子，就是他未来的样子。这句话我越体会越觉得有道理！&lt;/font>&lt;/p>
&lt;p>（这里脑补一个画面，妹子们读到这段时，一脚把身边的正在玩某5V5对战游戏的的老公踹到了床下！对方一脸懵B，大写问号？&amp;hellip;..哈哈哈！！！）&lt;/p>
&lt;p>同理，你要想成为大牛，那就去看看大牛下班之后在做什么！&lt;/p>
&lt;p>&amp;mdash;-以上仅个人看法！&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1419064642531-e575728395f2?w=300"
 data-srcset="https://images.unsplash.com/photo-1419064642531-e575728395f2?w=300, https://images.unsplash.com/photo-1419064642531-e575728395f2?w=300 1.5x, https://images.unsplash.com/photo-1419064642531-e575728395f2?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1419064642531-e575728395f2?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>测试圈TC：接口测试需要验证数据库么？</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95%E9%9C%80%E8%A6%81%E9%AA%8C%E8%AF%81%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B9%88/</link><pubDate>Mon, 11 Sep 2017 02:10:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95%E9%9C%80%E8%A6%81%E9%AA%8C%E8%AF%81%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B9%88/</guid><description>&lt;p>&lt;strong>问题：&lt;/strong>&lt;/p>
&lt;p>&lt;font color=#000093>有的接口会返回很多数据，有的接口可能就返回一个状态码及success之类的消息，这些需要验证数据库么？现在在写一个测试框架，配置接口参数和预期返回值，生成xml文件管理用例，用一个比较方法对预期和返回作比较，不需要根据每个接口写脚本，现在的疑惑只之比较返回值，并不清楚接口是否真的成功了，比如删除之类的接口，返回说成功了，但数据是否真的删除了？如果要验证数据库，感觉得为每个用例写脚本去验证了，这就和初衷不符（只写个比较函数，比较返回的所有值，不需要为每个接口单独验证）&lt;/font>&lt;/p>
&lt;p>&lt;strong>回答：&lt;/strong>&lt;/p>
&lt;p>不少同学在做自动化时都会问要不要验证数据库？我的答案是不要！&lt;/p>
&lt;p>根据分层自动化测试的概念。&lt;/p>
&lt;p>UI层自动化模拟的是用户操作，假设我是一个普通的用户，在你家的系统上购买了一件商品，我怎么知道有没有购买成功？难道要去查你家系统的“已购买表”？没权限，就算有权限我也不会！那我怎么验证？很简单啊！系统不是有“已购买” 商品列表嘛！点开“已购买”菜单看就可以了！（如果没有这功能，那说明你的系统设计有问题。用户体验不好，差评！！）&lt;/p>
&lt;p>接口自动化模拟的是开发的代码操作，A开发写的接口给B开发去调用，A系统的接口给B系统去调用，假设我是一个开发，我调用了微信的接口去做获取用户头像，有个用户获取不到，来！微信团队，你让我查查你们的数据库呗！微信肯定不答应。（数据库不是你想查，想查就给你查！）&lt;/p>
&lt;p>那接口返回了“success”，但没有把数据添加/删除成功怎么办？从我两年接口自动化的经验来说，这中情况基本非常少见，因为开发在写代码的时候，返回“success”的前提条件肯定是基于操作成功的。（开发写代码的时候肯定会自已运行一下啊！怎么会运行都不运行，哪儿来的自信！）&lt;/p>
&lt;p>你们的开发就是粗心怎么办？我是这么做的，开发提交了新的接口，我会边读接口代码边设计接口用例（如果接口逻辑看不懂接口数据可能就构造不出来，接口用例自然也不会写。），代码有问题就直接告诉开发改了，在这个过程中，我是会查数据库的。一旦接口用例写好之后，后面再回归去跑的时候就不管了，当然，每条接口用例里面肯定不会加查询数据库的动作。&lt;/p>
&lt;p>在特殊情况下，我调用了一个删除数据的接口，有没有真的删除一条数据，我可以调用查询数据的接口啊！查不出来刚才删除的数据，不就证明刚才的删除接口操作是ok的了。&lt;/p>
&lt;p>大多数测试问这个问题就是把自己当测试了，在做手工测试的时候就是这么查数据库的呀！典型的站在测试的思维上想问题。我做UI自动化的时候，我就是普通的用户；我做接口测试的时候我就是开发。只不过，我会比普通用户和开发更细致更全面的“使用”系统所提供的功能而已。但“使用姿势”和他们是一样的！&lt;/p>
&lt;p>—、— 希望能帮到你！&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1493246507139-91e8fad9978e?w=300"
 data-srcset="https://images.unsplash.com/photo-1493246507139-91e8fad9978e?w=300, https://images.unsplash.com/photo-1493246507139-91e8fad9978e?w=300 1.5x, https://images.unsplash.com/photo-1493246507139-91e8fad9978e?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1493246507139-91e8fad9978e?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>测试圈TC：写给一直在背锅的你</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E5%86%99%E7%BB%99%E4%B8%80%E7%9B%B4%E5%9C%A8%E8%83%8C%E9%94%85%E7%9A%84%E4%BD%A0/</link><pubDate>Tue, 29 Aug 2017 11:10:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E5%86%99%E7%BB%99%E4%B8%80%E7%9B%B4%E5%9C%A8%E8%83%8C%E9%94%85%E7%9A%84%E4%BD%A0/</guid><description>&lt;br>
![](http://img.testclass.net/circle_back_pot_man.jpg)
&lt;p>你是一个测试人员，早出晚归，一身疲惫。你对项目的质量负责。&lt;/p>
&lt;p>但每次上线或交付以后，你总是觉得心里没底，成天惴惴不安。不出问题就好，出了问题，是你没测出来，锅是你的，可以选择忍辱偷生，或是走人。&lt;/p>
&lt;p>在大多数时候，大家背地你称呼你为：背锅侠。&lt;/p>
&lt;p>很多时候项目是这样一个循环。&lt;/p>
&lt;p>需求评审，测试只需要带耳朵去可以了，你说什么不重要，你人在就行，这就表示流程的要求达到了。这时候你跟道具没有区别。&lt;/p>
&lt;p>开发在憋大招实现需求的时候，你在努力的脑补测试用例。很多时候你可能意识到了，这样做的效果不好，但你还是需要接着做下去，毕竟，这是你的工作。&lt;/p>
&lt;p>终于等到开发写完了需求，他们会告诉你，来吧，我们做完了，开始测试吧。项目经理会来告诉你，由于需求变更和其他乱七八糟的事情，开发进度有点延后，没办法，测试时间需要压缩，你只能接受，别无他法。&lt;/p>
&lt;p>你开始拼命加班，希望多测一点，bug少一点。&lt;/p>
&lt;p>你开始白天催促开发改bug，等待开发下班提测，你主要的工作时间是晚上，你守着空荡荡的办公室，点来点去。&lt;/p>
&lt;p>你好不容易赶上了项目进度，按时发出了测试报告，但是在你心里，你觉得总有什么东西是你放不下的，哪天正式环境真出问题了，你反而会长舒一口气，默默收拾东西，找下一个背锅的地方。&lt;/p>
&lt;p>很久以后，你回忆起年轻时的背锅之旅，你可能会觉得，也许有什么办法可以解决这些问题。&lt;/p>
&lt;p>&lt;strong>测试左移&lt;/strong>&lt;/p>
&lt;p>为什么开发在憋大招写实现需求的时候测试不能介入？尽可能早的测试，也许能带来一定的质量改进效果。&lt;/p>
&lt;p>持续集成，每次代码提交或者定期(一般是1天)就对主干代码进行编译和测试，这样开发的整个工程就有了质量的控制和监控，问题可以尽可能早的发现，解决问题的成本也相应会降低。&lt;/p>
&lt;p>持续集成并不能消除Bug，而是让它们非常容易发现和改正。&amp;ndash; Martin Fowler&lt;/p>
&lt;p>定期的频繁的集成和测试会让开发人员在编写代码和提交代码的时候多一点的责任感，多用点心。开发一认真，bug都害怕。&lt;/p>
&lt;p>其实你会发现，所有的流程管理，项目质量回溯等工作，其实其最后的目的都是一个：开发啊，你就长点心吧。&lt;/p>
&lt;p>项目的质量很大程度上取决于开发人员的能力和态度。测试同学越努力，开发同学就越警惕，项目或产品的质量可能相对会更好一点。&lt;/p>
&lt;p>&lt;strong>测试右移&lt;/strong>&lt;/p>
&lt;p>在跟生产环境一致的环境上进行测试，可能会发现一些在测试环境无法发现的问题。&lt;/p>
&lt;p>在生产环境进行监控和告警，一旦发现问题，第一时间找出问题并快速上线解决，这种亡羊补牢，让线上问题的影响减小到对少，并保证数据的一致性和完整性，这其实也是质量控制的一环。&lt;/p>
&lt;p>把测试的左移和右移做好，也许对一直在背锅的你会有一些正面的效果。&lt;/p>
&lt;p>不要做背锅侠，也不要做甩锅狂魔，有问题就正视他，解决他，少一点阴阳怪气和怨天尤人，想办法把事情做好才是正道。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1490791539531-102a1e0beb7b?w=300"
 data-srcset="https://images.unsplash.com/photo-1490791539531-102a1e0beb7b?w=300, https://images.unsplash.com/photo-1490791539531-102a1e0beb7b?w=300 1.5x, https://images.unsplash.com/photo-1490791539531-102a1e0beb7b?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1490791539531-102a1e0beb7b?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>选读：Selenium的发展史</title><link>https://itest2025.pages.dev/tutorials/24-000-%E9%80%89%E8%AF%BBselenium%E7%9A%84%E5%8F%91%E5%B1%95%E5%8F%B2/</link><pubDate>Fri, 25 Aug 2017 02:20:11 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/24-000-%E9%80%89%E8%AF%BBselenium%E7%9A%84%E5%8F%91%E5%B1%95%E5%8F%B2/</guid><description>&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/selenium-logo.png"
 data-srcset="http://img.testclass.net/selenium-logo.png, http://img.testclass.net/selenium-logo.png 1.5x, http://img.testclass.net/selenium-logo.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/selenium-logo.png"
 title="http://img.testclass.net/selenium-logo.png" />&lt;/p>
&lt;p>Jason Huggins在2004年发起了Selenium项目，当时身处ThoughtWorks的他，为了不想让自己的时间浪费在无聊的重复性工作中，幸运的是，所有被测试的浏览器都支持Javascript。Jason和他所在的团队采用Javascript编写一种测试工具来验证浏览器页面的行为；这个JavaScript类库就是Selenium core，同时也是seleniumRC、Selenium IDE的核心组件。Selenium由此诞生。&lt;/p>
&lt;p>关于Selenium的命名比较有意思，当时QTP mercury是主流的商业自化工具，是化学元素汞（俗称水银），而Selenium是开源自动化工具，是化学元素硒，硒可以对抗汞。&lt;/p>
&lt;h3 id="selenium-10">Selenium 1.0&lt;/h3>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/selenium_1.jpg"
 data-srcset="http://img.testclass.net/selenium_1.jpg, http://img.testclass.net/selenium_1.jpg 1.5x, http://img.testclass.net/selenium_1.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/selenium_1.jpg"
 title="http://img.testclass.net/selenium_1.jpg" />&lt;/p>
&lt;p>用简单的公式：&lt;/p>
&lt;pre tabindex="0">&lt;code>Selenium 1.0 = Selenium IDE + Selenium Grid + Selenium RC
&lt;/code>&lt;/pre>&lt;p>&lt;strong>Selenium IDE&lt;/strong>&lt;/p>
&lt;p>Selenium IDE是嵌入到Firefox浏览器中的一个插件，实现简单的浏览器操作的录制与回放功能。&lt;/p>
&lt;p>&lt;strong>Selenium Grid&lt;/strong>&lt;/p>
&lt;p>Selenium Grid是一种自动化的测试辅助工具，Grid通过利用现有的计算机基础设施，能加快Web-App的功能测试。利用Grid可以很方便地实现在多台机器上和异构环境中运行测试用例。&lt;/p>
&lt;p>&lt;strong>Selenium RC&lt;/strong>&lt;/p>
&lt;p>Selenium RC（Remote Control）是Selenium家族的核心部分。Selenium RC 支持多种不同语言编写的自动化测试脚本，通过Selenium RC的服务器作为代理服务器去访问应用，从而达到测试的目的。&lt;/p>
&lt;p>Selenium RC分为Client Libraries和Selenium Server。Client Libraries库主要用于编写测试脚本，用来控制Selenium Server的库。Selenium Server负责控制浏览器行为。&lt;/p>
&lt;p>所以，我们在学习Selenium1.0的时候，核心应该是学习RC，它的工作原理是这样的：&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/selenium_RC.jpg"
 data-srcset="http://img.testclass.net/selenium_RC.jpg, http://img.testclass.net/selenium_RC.jpg 1.5x, http://img.testclass.net/selenium_RC.jpg 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/selenium_RC.jpg"
 title="http://img.testclass.net/selenium_RC.jpg" />&lt;/p></description></item><item><title>JMeter官方文档--翻译计划</title><link>https://itest2025.pages.dev/tutorials/47-000-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A3--%E7%BF%BB%E8%AF%91%E8%AE%A1%E5%88%92/</link><pubDate>Thu, 24 Aug 2017 11:10:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-jmeter%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A3--%E7%BF%BB%E8%AF%91%E8%AE%A1%E5%88%92/</guid><description>&lt;br>
由 __性能测试进阶群__ （328717832） 发起。
&lt;p>目的是通过翻译的方式，提高对JMeter开源性能测试工具的认识。另外，提高对英文档的阅读理解功能。&lt;/p>
&lt;p>JMeter官方文档地址：&lt;/p>
&lt;p>&lt;a href="http://jmeter.apache.org/usermanual/index.html" target="_blank" rel="noopener noreffer ">http://jmeter.apache.org/usermanual/index.html&lt;/a>&lt;/p>
&lt;p>如果你想参与翻译工具，请点击 &lt;a href="http://www.testpub.cn/t/151" target="_blank" rel="noopener noreffer ">这里&lt;/a>&lt;/p>
&lt;p>已经翻译完成的章节，请点击&lt;a href="https://itest2025.pages.dev/jmeter/" rel="">JMeter教程&lt;/a>&lt;/p>
&lt;p>在此感谢参与翻译工作的小伙伴。&lt;strong>把想法转化为行动真的很难！&lt;/strong>&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1446488547543-78c11468449a?w=300"
 data-srcset="https://images.unsplash.com/photo-1446488547543-78c11468449a?w=300, https://images.unsplash.com/photo-1446488547543-78c11468449a?w=300 1.5x, https://images.unsplash.com/photo-1446488547543-78c11468449a?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1446488547543-78c11468449a?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>测试圈TC：bug的一生</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tcbug%E7%9A%84%E4%B8%80%E7%94%9F/</link><pubDate>Tue, 22 Aug 2017 11:10:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tcbug%E7%9A%84%E4%B8%80%E7%94%9F/</guid><description>&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="http://img.testclass.net/find_bug.png"
 data-srcset="http://img.testclass.net/find_bug.png, http://img.testclass.net/find_bug.png 1.5x, http://img.testclass.net/find_bug.png 2x"
 data-sizes="auto"
 alt="http://img.testclass.net/find_bug.png"
 title="http://img.testclass.net/find_bug.png" />&lt;/p>
&lt;p>以下是来自三个bug来自述他们的一生&amp;hellip;&lt;/p>
&lt;p>大家好！我叫A，我是一个bug，我出生一个粗心的程序员之手，在我被制造出来时候，程序员看了两眼，扭头走了，我这才幸免生存下来。在之后的一段日子里，我的左邻右舍经常被叫去分配一些任务，唯独我，程序员每次都成功的避开了我，所以，我整天无所事实的混日子度过。&lt;/p>
&lt;p>有一天，我被交到了测试人员手上，这个家伙也不知道我的存在，因为它根本看不到我。哈哈！他总是站在门外乱喊乱叫来分配任务，这样搞得我的左邻右舍很不满意，因为隔壁家的老李，一天被叫去了分配很多错误，连连叫苦，可邻居隔三差五的才被叫去一次。不过，我仍然一次也被叫去干活。&lt;/p>
&lt;p>又过了一段时间 ，我被交到客户手里，隔壁老李的每天的日子更忙了，老王也不再像以前那么悠闲了，他们每天都排着队的被叫去干活，有时连深夜也不休息。可是，我依然还是无事可做&amp;hellip;&lt;/p>
&lt;p>又过了很久，我终于被一个用户叫到了名字，我异常激动的冲了出去… 可以，我似乎把工作搞砸了，之后，我又被测试人员叫了两次，他和程序员盯着我看了半天，小声讨论着什么，两人眼神里流露出不悦。最后，我在最初的那个程序员手中被修复了。&lt;/p>
&lt;p>这就是我的一生！&lt;/p>
&lt;br>
&lt;p>大家好，我叫B，我的出生和前面的A差不多，不过，在把我交到测试人员不久，我就被发现了，主要可以是因为我长的比较特殊吧！长得特殊的bug总是容易引起别人的注意。&lt;/p>
&lt;p>不过，这个测试人员貌似对我很感兴趣，他并没有立刻把我交给开发人员，而是一遍又一遍的对我的处理结果进行验证，时而迷惑不解，时而又欣喜若狂，好像在试图弄明白我到底是如何产生的。&lt;/p>
&lt;p>不过，最终我还是被这个测试人员交给了开发人员，他临走的时候貌似很高兴，但我明显的看出来程序员的不开森！他用幽怨的眼神盯着我看了半天，最后，果断的就把我修复了。&lt;/p>
&lt;p>这就是我的一生。&lt;/p>
&lt;br>
&lt;p>大家好，我叫C，我也是一名bug，我不像前面两位那么平庸，从我被造出来那天起我就立志要做一个不平凡的bug，我的目标是躲过开发，闪开测试，到达用户手上，给用户造成巨大的损失，从此扬名立万，走向人生巅峰，想想还有点小激动呢！&lt;/p>
&lt;p>可是，万万没想到，我刚一出生就被发现了，然后我就被修复了。&lt;/p>
&lt;p>这就是我的一生。&lt;/p>
&lt;br>
以上是我个人的YY，不要试图寻找它的逻辑性和合理性，哈哈！！
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?w=300"
 data-srcset="https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?w=300, https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?w=300 1.5x, https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>测试圈TC：如何在实际工作开展性能测试？</title><link>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E5%A6%82%E4%BD%95%E5%9C%A8%E5%AE%9E%E9%99%85%E5%B7%A5%E4%BD%9C%E5%BC%80%E5%B1%95%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/</link><pubDate>Tue, 22 Aug 2017 11:10:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E6%B5%8B%E8%AF%95%E5%9C%88tc%E5%A6%82%E4%BD%95%E5%9C%A8%E5%AE%9E%E9%99%85%E5%B7%A5%E4%BD%9C%E5%BC%80%E5%B1%95%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/</guid><description>&lt;br>
&lt;h4 id="问题">问题：&lt;/h4>
&lt;p>&lt;strong>测试好多都是性能小白，虽学了些性能知识，但在实际工作做开展性能测试，都很茫然，求指导，应该怎么处理？&lt;/strong>&lt;/p>
&lt;hr>
&lt;h4 id="回答">回答：&lt;/h4>
&lt;p>从小入手，从简单的开始，然后慢慢的做更系统更复杂的性能测试。&lt;/p>
&lt;p>&lt;strong>确定需求&lt;/strong>&lt;/p>
&lt;p>刚接触性能测试的同学往往不知道性能测试是有需求的。比如
给我测一下系统的性能
线上xx服务器挂了，能否重现一下线上问题&lt;/p>
&lt;p>如果你是性能测试同学，假设时间有限，这两个需求你只能接一个，你是接哪个？&lt;/p>
&lt;p>很多同学会选第一个，因为第一个需求似乎是性能测试的需求，第二个跟性能测试似乎没有特别强烈的关系。&lt;/p>
&lt;p>但是第一个需求太泛泛了，如果不细化的话操作起来会很难，第二个尽管看起来是亡羊补牢的行为，但现实工作中这类的需求很多，操作起来也是有套路的，不会特别发散。&lt;/p>
&lt;p>总之，建议新人在需求分析的时候接一些具体的，可以操作的需求。需求是否可以细化分解，基本就注定了性能测试能否顺利完成&lt;/p>
&lt;p>&lt;strong>了解业务&lt;/strong>&lt;/p>
&lt;p>比如重现线上问题的需求，拿到手之后，我们就必须熟悉线上的业务。用户是怎么操作的，系统崩溃的时段是哪个，这个时段里有多少用户在使用系统，他们都在做什么？&lt;/p>
&lt;p>尽可能精确的重现用户的行为或者预测用户的行为，这是性能脚本的是否符合实际的关键。而这种精确是建立在了解业务的基础之上的。&lt;/p>
&lt;p>&lt;strong>搭建测试环境&lt;/strong>&lt;/p>
&lt;p>尽可能搭建跟线上环境一致的性能测试专用环境。&lt;/p>
&lt;p>关键字:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>一致：最好跟线上环境一样，如果不可能的话，可以减配，但是要保证架构一致。比如线上集群100台，测试环境没那么多资源的情况下，可以适量减少，比如测试环境集群2台，但是一定要是集群，不然就没意义了&lt;/p>
&lt;/li>
&lt;li>
&lt;p>专用：测试环境是性能测试专享的，其他测试不要在上面搞&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>实现脚本&lt;/strong>&lt;/p>
&lt;p>比如可以用jmeter实现测试脚本，推荐 &lt;a href="https://itest2025.pages.dev/jmeter/" rel="">JMeter教程&lt;/a>。&lt;/p>
&lt;p>对于新人来说，实现脚本往往比较困难。&lt;/p>
&lt;p>另外一些基本的性能知识也是必要的，推荐看 &lt;a href="https://itest2025.pages.dev/performance/" rel="">性能基础知识教程&lt;/a>.&lt;/p>
&lt;p>&lt;strong>脚本执行及监控&lt;/strong>&lt;/p>
&lt;p>根据负载模型去执行相应的脚本，这里就不展开了。&lt;/p>
&lt;p>&lt;strong>收集测试结果&lt;/strong>&lt;/p>
&lt;p>对于新人来说，只需要把测试结果提交给项目组的开发人员分析就好了。对于有一定经验的性能测试人员，希望可以通过监控和代码走查的方式找到系统瓶颈，并给出部署的建议方案。&lt;/p>
&lt;p>&lt;strong>持续学习&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>linux知识：比如服务器kpi指标，简单监控命令，并发模型等&lt;/li>
&lt;li>架构知识：最简单的方式，自己搭建性能测试环境或者线上环境，多搞几次就熟了&lt;/li>
&lt;li>更多知识：总之遇到不懂的就学，比如数据库优化，jvm优化等知识&lt;/li>
&lt;/ul>
&lt;br>
综上。希望对你有所帮助。
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1419332552192-47d29e59b1e0?w=300"
 data-srcset="https://images.unsplash.com/photo-1419332552192-47d29e59b1e0?w=300, https://images.unsplash.com/photo-1419332552192-47d29e59b1e0?w=300 1.5x, https://images.unsplash.com/photo-1419332552192-47d29e59b1e0?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1419332552192-47d29e59b1e0?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>视频教程发布公告</title><link>https://itest2025.pages.dev/tutorials/47-000-%E8%A7%86%E9%A2%91%E6%95%99%E7%A8%8B%E5%8F%91%E5%B8%83%E5%85%AC%E5%91%8A/</link><pubDate>Wed, 16 Aug 2017 05:02:01 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E8%A7%86%E9%A2%91%E6%95%99%E7%A8%8B%E5%8F%91%E5%B8%83%E5%85%AC%E5%91%8A/</guid><description>&lt;p>大家好，我们很开心的宣布测试教程网的视频系列教程上线了。&lt;/p>
&lt;p>目前我们有如下课程，高清视频，完全免费。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;a href="https://ke.qq.com/course/229839" target="_blank" rel="noopener noreffer ">小白从零开始使用postman学习接口测试教程&lt;/a>: 适合没有任何经验的小白测试人员，学完后可以掌握接口测试的基础知识以及postman的各种用法&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://ke.qq.com/course/225855" target="_blank" rel="noopener noreffer ">robot framework系列教程&lt;/a>: 适合有一定python基础的同学，学习rf是快速集成各种测试工具搭建测试框架的python系热门路线&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://ke.qq.com/course/232868" target="_blank" rel="noopener noreffer ">零成本实现python接口测试教程&lt;/a>: 适合接口测试入门，比postman技术含量更高，也更有扩展性，学完自己开发接口测试框架吧&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://ke.qq.com/course/232864" target="_blank" rel="noopener noreffer ">会截图就会自动化测试sikuli教程&lt;/a>: 只要会截图就可以做UI自动化，web／app／desktop通吃，学完以后自己整个高大上的截图测试平台吧&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/uploads/1411400493228e06a6315/ad711a20?w=300"
 data-srcset="https://images.unsplash.com/uploads/1411400493228e06a6315/ad711a20?w=300, https://images.unsplash.com/uploads/1411400493228e06a6315/ad711a20?w=300 1.5x, https://images.unsplash.com/uploads/1411400493228e06a6315/ad711a20?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/uploads/1411400493228e06a6315/ad711a20?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>appium系列教程发布</title><link>https://itest2025.pages.dev/tutorials/47-000-appium%E7%B3%BB%E5%88%97%E6%95%99%E7%A8%8B%E5%8F%91%E5%B8%83/</link><pubDate>Wed, 09 Aug 2017 01:42:46 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-appium%E7%B3%BB%E5%88%97%E6%95%99%E7%A8%8B%E5%8F%91%E5%B8%83/</guid><description>&lt;p>&lt;a href="https://itest2025.pages.dev/appium" rel="">appium系列教程&lt;/a>已经发布。&lt;/p>
&lt;p>这一系列教程是我多年前编写的，尽管appium这些年变化很快，但是目前看来这些教程对于入门者来说还是足够的。&lt;/p>
&lt;p>大家有更多的需求请留言，教程中如有不准确的地方也请大家斧正。&lt;/p>
&lt;p>后续我们会加入更多的appium教程，敬请期待。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1511576661531-b34d7da5d0bb?w=300"
 data-srcset="https://images.unsplash.com/photo-1511576661531-b34d7da5d0bb?w=300, https://images.unsplash.com/photo-1511576661531-b34d7da5d0bb?w=300 1.5x, https://images.unsplash.com/photo-1511576661531-b34d7da5d0bb?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1511576661531-b34d7da5d0bb?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>公告：服务器迁移完成</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%85%AC%E5%91%8A%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%BF%81%E7%A7%BB%E5%AE%8C%E6%88%90/</link><pubDate>Tue, 08 Aug 2017 10:26:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%85%AC%E5%91%8A%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%BF%81%E7%A7%BB%E5%AE%8C%E6%88%90/</guid><description>&lt;br>
__测试教程网__ 正在努力打造专业测试基础教程网站。很高兴的告诉大家，我们的备案号申请通过。我们于2017年8月7号晚进行了服务器迁移。8月8号上午发现部分页面样式问题，现已修复。在此期间给你带来的不便敬请见谅！
&lt;p>　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　2017.08.08&lt;/p>
&lt;p>　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　测试教程网&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1508163223045-1880bc36e222?w=300"
 data-srcset="https://images.unsplash.com/photo-1508163223045-1880bc36e222?w=300, https://images.unsplash.com/photo-1508163223045-1880bc36e222?w=300 1.5x, https://images.unsplash.com/photo-1508163223045-1880bc36e222?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1508163223045-1880bc36e222?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>python selenium系列教程发布</title><link>https://itest2025.pages.dev/tutorials/47-000-python-selenium%E7%B3%BB%E5%88%97%E6%95%99%E7%A8%8B%E5%8F%91%E5%B8%83/</link><pubDate>Tue, 25 Jul 2017 10:26:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-python-selenium%E7%B3%BB%E5%88%97%E6%95%99%E7%A8%8B%E5%8F%91%E5%B8%83/</guid><description>&lt;h3 id="python-selenium系列教程发布">python selenium系列教程发布&lt;/h3>
&lt;p>我们很高兴的宣布，&lt;a href="https://itest2025.pages.dev/selenium_python/" rel="">python selenium 系列教程&lt;/a>正式发布。&lt;/p>
&lt;p>本教程基本上囊括了selenium测试中所需的大部分常用操作和场景，如果大家在学习过程中遇到问题，欢迎在讨论区留言。&lt;/p>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1471978445661-ad6ec1f5ba50?w=300"
 data-srcset="https://images.unsplash.com/photo-1471978445661-ad6ec1f5ba50?w=300, https://images.unsplash.com/photo-1471978445661-ad6ec1f5ba50?w=300 1.5x, https://images.unsplash.com/photo-1471978445661-ad6ec1f5ba50?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1471978445661-ad6ec1f5ba50?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>学习线路图</title><link>https://itest2025.pages.dev/tutorials/47-000-%E5%AD%A6%E4%B9%A0%E7%BA%BF%E8%B7%AF%E5%9B%BE/</link><pubDate>Sun, 09 Jul 2017 04:54:00 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-%E5%AD%A6%E4%B9%A0%E7%BA%BF%E8%B7%AF%E5%9B%BE/</guid><description>&lt;h3 id="你是谁为什么你需要学习">你是谁？为什么你需要学习&lt;/h3>
&lt;p>你是一个测试行业的从业人员，目前主要的工作是功能测试和一些五花八门的专项测试。&lt;/p>
&lt;p>你需要经常做一些重复性的工作，这让你感到未来很苍白；你需要晚上留下来加班验证缺陷写测试报告，这让你感觉很疲惫；当项目发布上线时你需要对天祈祷，祈求不要有严重的缺陷发生，这使你感到很没安全感。&lt;/p>
&lt;p>这时候你想到了：也许学习一点新的技能会对现在的生活有所改变。&lt;/p>
&lt;p>长远一点学习可以让你有更好的未来，感性一点学习让你会更多的安全感，现实一点学习也许能让你赚的很多。&lt;/p>
&lt;h3 id="行业在发展">行业在发展&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>&lt;a href="https://www.zhihu.com/question/61776013/answer/190942176" target="_blank" rel="noopener noreffer ">测试开发是什么？为什么现在那么多公司都要招聘测试开发？&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://www.zhihu.com/question/61162236/answer/184570687" target="_blank" rel="noopener noreffer ">手工测试人员如何转测试开发？&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://www.zhihu.com/question/61414284/answer/187513342" target="_blank" rel="noopener noreffer ">优秀测试人员应该具备哪些素质？&lt;/a>&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="学习线路图">学习线路图&lt;/h3>
&lt;p>这个线路图可以让你以比较平滑的曲线上升为测试开发人员，从而具备一定的核心竞争力。&lt;/p>
&lt;ol>
&lt;li>学习一门语言，推荐java python&lt;/li>
&lt;li>掌握黑盒自动化测试技术，推荐学习selenium,sikuli, appium&lt;/li>
&lt;li>掌握接口功能测试技术， 推荐学习postman&lt;/li>
&lt;li>掌握白盒测试技术，推荐学习junit等xunit测试框架&lt;/li>
&lt;li>掌握性能测试技术， 推荐学习jmeter&lt;/li>
&lt;li>掌握安全测试技术，推荐从web安全测试入门&lt;/li>
&lt;/ol>
&lt;p>原始封面&lt;/p>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/photo-1465311440653-ba9b1d9b0f5b?w=300"
 data-srcset="https://images.unsplash.com/photo-1465311440653-ba9b1d9b0f5b?w=300, https://images.unsplash.com/photo-1465311440653-ba9b1d9b0f5b?w=300 1.5x, https://images.unsplash.com/photo-1465311440653-ba9b1d9b0f5b?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/photo-1465311440653-ba9b1d9b0f5b?w=300"
 title="课程图片" />&lt;/p></description></item><item><title>2017年度计划</title><link>https://itest2025.pages.dev/tutorials/47-000-2017%E5%B9%B4%E5%BA%A6%E8%AE%A1%E5%88%92/</link><pubDate>Wed, 05 Jul 2017 10:26:24 +0800</pubDate><guid>https://itest2025.pages.dev/tutorials/47-000-2017%E5%B9%B4%E5%BA%A6%E8%AE%A1%E5%88%92/</guid><description>&lt;h3 id="2017年度计划">2017年度计划&lt;/h3>
&lt;ul>
&lt;li>7月: ~~~python selenium 教程~~~; ~~~java selenium教程~~~&lt;/li>
&lt;li>8月: ~~~javascript selenium教程~~~;&lt;/li>
&lt;li>9月: jmeter教程; 性能测试教程;&lt;/li>
&lt;li>10月: 软件测试基础; 面试题库;&lt;/li>
&lt;/ul>
&lt;p>&lt;img
 class="lazyload"
 src="https://itest2025.pages.dev/svg/loading.min.svg"
 data-src="https://images.unsplash.com/reserve/unsplash_524010c76b52a_1.JPG?w=300"
 data-srcset="https://images.unsplash.com/reserve/unsplash_524010c76b52a_1.JPG?w=300, https://images.unsplash.com/reserve/unsplash_524010c76b52a_1.JPG?w=300 1.5x, https://images.unsplash.com/reserve/unsplash_524010c76b52a_1.JPG?w=300 2x"
 data-sizes="auto"
 alt="https://images.unsplash.com/reserve/unsplash_524010c76b52a_1.JPG?w=300"
 title="课程图片" />&lt;/p></description></item></channel></rss>