<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>博客合集 on 重定向学院</title><link>https://itest2025.pages.dev/categories/%E5%8D%9A%E5%AE%A2%E5%90%88%E9%9B%86/</link><description>Recent content in 博客合集 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/categories/%E5%8D%9A%E5%AE%A2%E5%90%88%E9%9B%86/index.xml" rel="self" type="application/rss+xml"/><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>测试圈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>《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>测试圈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>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>