﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-qileilove-随笔分类-敏捷测试</title><link>http://www.blogjava.net/qileilove/category/52524.html</link><description>不想做屌丝的码农，不是好项目经理！屌丝生涯从此开始！</description><language>zh-cn</language><lastBuildDate>Thu, 11 Dec 2014 17:44:13 GMT</lastBuildDate><pubDate>Thu, 11 Dec 2014 17:44:13 GMT</pubDate><ttl>60</ttl><item><title>敏捷开发下平衡质量和进度</title><link>http://www.blogjava.net/qileilove/archive/2014/12/11/421317.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Thu, 11 Dec 2014 15:37:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2014/12/11/421317.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/421317.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2014/12/11/421317.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/421317.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/421317.html</trackback:ping><description><![CDATA[<div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　<a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">敏捷</strong></u></a><a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">软件开发</strong></u></a>团队必须确保他们开发出来的产品质量能够满足要求，管理团队也经常希望开发团队能够提高速度以实现为客户提供更多的功能。本篇<a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">文章</strong></u></a>中多个作者探讨了质量和速度之间的关系，并提出了一些既能提高质量也能加快进度的方法。</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　Bob Galen曾今在他的博客中发表了读懂我的唇语-敏捷并不快速的文章，在其中写到了追求软件开发进度下质量的重要性。</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　敏捷是一个&#8220;质量游戏&#8221;，如果你以正直，承诺以及平衡的心态来玩这个游戏的话，那么结果将会是非常好的&#8220;速度游戏&#8221;，但它（速度）却并非没有代价。。。</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　如果你无法玩转这个质量游戏，你所采纳的<a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">敏捷开发</strong></u></a>方法甚至比你以前使用的开发方法更慢。</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　团队必须致力于把<a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">工作</strong></u></a>在一个迭代中完成，这也就意味着这些工作需要满足定义工作完成的所有标准。</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　很多敏捷团队允许返工 &#8211; 修复漏洞，完成<a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">测试</strong></u></a>自动化，重构，或者设计不良导致sprint迭代的延误。即使大多数的敏捷工具允许拆分用例故事以捕捉在sprint迭代中已经完成的工作对比延期的工作，我也还是认为这给团队传达了错误的信息，让他们认为工作不在一个sprint迭代内完成是可以接受的。</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　读懂我的唇语 &#8211; 并不是把所有事情做完，做完，做完！</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　正如Bob解释的：一个组织不应该总是力图让进度变得更快，而应该更加注重质量。</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　因此，下一次当你听到有人在激情澎湃的谈论着敏捷代表了更快的速度时，请打断他们，尝试向他们解释敏捷并不是一个&#8220;速度游戏&#8221;，而是应该强调敏捷是一个&#8220;或许能够快速运转的质量游戏&#8221;。</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　Tim Ottinger曾今写过关于敏捷团队进度的14个奇怪观点，其中一个观点中就提到了质量和速度之间的关系。</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　尽管大家通常会降低质量要求以求在较短时间内尽快完成工作，但是如果团队所开发的代码质量不高的话，经过全部sprint迭代后的进度最终都还是会被降低。</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　Stephen Haunts在他的题目为进度并不是目标或者目的博客帖子中，描述了当管理者设定团队的进度目标后对质量会产生什么影响：</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　（&#8230;）为了增加交付的功能点数目以满足绩效目标，团队会牺牲掉系统的质量，但从长远来看这样最终还是会降低团队的进度，并且会引入技术隐患。敏捷团队最好关注正在开发系统的质量与流程过程（持续交付和集成等等），以及负责开发系统的团队成员本身。</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　软件开发者必须在进度和质量之间掌握平衡，正如Blake Haswell在文章什么是代码质量中解释的那样：</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　虽然经常会有很多的外部压力向进度方面倾斜，但是如果你不够重视质量的话，进度最终还是会趋于缓慢以及停滞，以至最终整个项目走向颠覆。考虑到一个项目的代码质量决定了它能够在多大程度上适应需求的变化，一个可以持续改进的事情是你需要花费一部分时间来优化自己项目的代码质量。</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　<strong style="word-break: break-all; line-height: normal !important;">　Blake提供了一个可以用来检查代码质量的属性列表：</strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　可理解性： 代码需要在各个层面上能够被容易地理解。理想情况下，软件应该非常简单，并没有非常明显的缺陷。</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　可测试性： 代码需要被编写的非常容易被测试。</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　正确性： 代码需要满足功能和非功能性的需求。</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　有效性： 代码需要有效的使用系统资源（内存，CPU，网络连接，等）。</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　Hugo Bara&#250;na在他的博客文章名为内部质量低下软件的症状中解释了软件是如何因为变更而&#8220;变得更糟&#8221;的，最终导致质量低下并且降低进度。</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　假如你正在领导一家创业公司的技术或者产品团队，你是首席技术官，并且已经推出了你们产品的第一个版本，做的还挺成功的。你们的业务模型已经得到了验证，现在你们正处于快速发展期。这真是太棒了！但这也是有代价的，它带来了一系列新的挑战。</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　你们产品的第一个版本工作的很好，但是代码库却无法满足持续发展的要求。或许你的团队进度并没有像以前那样好了，团队成员一直在抱怨代码的质量问题，首席执行官和产品经理想要一些新的功能，但你现在代码规划根本无法满足业务的需求。</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　<strong style="word-break: break-all; line-height: normal !important;">他提供了一个指示质量低下的症状列表，这个列表能够帮助你来决定是否需要重写或者重构：</strong></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　所有事情都很艰难</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　进度慢</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　测试套件运行缓慢</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　无法避免的缺陷</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　你的团队是消极的</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　知识缺乏共享</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　新开发人员成长周期太长</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　你又是如何平衡质量和进度的呢？</div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"></div><div style="word-break: break-all; line-height: 21.6000003814697px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"></div><div id="weixin_s" style="word-break: break-all; line-height: 21.6000003814697px; margin: 0px 0px 10px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; width: 182px; height: 32px; display: inline-block; position: relative; background-image: url(http://www.51testing.com/html/wx.jpg); background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: no-repeat;"></div> <div><div id="SL_button" class="ImTranslatorLogo" style="display: none; background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/imtranslator-s.png);"></div><div id="SL_shadow_translation_result2" style="display: none;"></div><div id="SL_shadow_translator" style="display: none;"><div id="SL_planshet" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/bg2.png) #f4f5f5;"><div id="SL_TB"><div id="bubblelogo" class="ImTranslatorLogo" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/imtranslator-s.png);"></div><table cellspacing="1" border="0" id="SL_tables"><tbody><tr><td class="SL_td" align="left" width="20%"><div id="SL_lng_from">English&nbsp;&#187;</div></td><td class="SL_td" align="left" width="20%"><select id="SL_lng_to"><option value="af">Afrikaans</option><option value="sq">Albanian</option><option value="ar">Arabic</option><option value="hy">Armenian</option><option value="az">Azerbaijani</option><option value="eu">Basque</option><option value="bn">Bengali</option><option value="be">Belarusian</option><option value="bg">Bulgarian</option><option value="ca">Catalan</option><option value="zh-CN">Chinese&nbsp;(Simp)</option><option value="zh-TW">Chinese&nbsp;(Trad)</option><option value="hr">Croatian</option><option value="cs">Czech</option><option value="da">Danish</option><option value="nl">Dutch</option><option value="en">English</option><option value="eo">Esperanto</option><option value="et">Estonian</option><option value="tl">Filipino</option><option value="fi">Finnish</option><option value="fr">French</option><option value="gl">Galician</option><option value="ka">Georgian</option><option value="de">German</option><option value="el">Greek</option><option value="gu">Gujarati</option><option value="ht">Haitian&nbsp;Creole</option><option value="iw">Hebrew</option><option value="hi">Hindi</option><option value="hu">Hungarian</option><option value="is">Icelandic</option><option value="id">Indonesian</option><option value="ga">Irish</option><option value="it">Italian</option><option value="ja">Japanese</option><option value="kn">Kannada</option><option value="ko">Korean</option><option value="lo">Lao</option><option value="la">Latin</option><option value="lv">Latvian</option><option value="lt">Lithuanian</option><option value="mk">Macedonian</option><option value="ms">Malay</option><option value="mt">Maltese</option><option value="no">Norwegian</option><option value="fa">Persian</option><option value="pl">Polish</option><option value="pt">Portuguese</option><option value="ro">Romanian</option><option value="ru">Russian</option><option value="sr">Serbian</option><option value="sk">Slovak</option><option value="sl">Slovenian</option><option selected="" value="es">Spanish</option><option value="sw">Swahili</option><option value="sv">Swedish</option><option value="ta">Tamil</option><option value="te">Telugu</option><option value="th">Thai</option><option value="tr">Turkish</option><option value="uk">Ukrainian</option><option value="ur">Urdu</option><option value="vi">Vietnamese</option><option value="cy">Welsh</option><option value="yi">Yiddish</option></select></td><td class="SL_td" width="13%" align="center">&nbsp;</td><td class="SL_td" width="8%" align="center"><div id="SL_TTS_voice" title="Listen to the translation" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/tts-voice.png);"></div></td><td class="SL_td" width="8%" align="center"><div id="SL_copy" title="Select text" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/copy_hand.png);"></div></td><td class="SL_td" width="8%" align="center"><div id="SL_bbl_font_patch" onclick="alert('Not available for dictionary');"></div><div id="SL_bbl_font" title="Font size" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/font-off.png);"></div></td><td class="SL_td" width="8%" align="center"><div id="SL_TH" title="Translation history" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/history.png);"></div></td><td class="SL_td" width="5%"></td><td class="SL_td" width="8%" align="right"><div id="SL_pin" title="Pin pup-up bubble" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/pin-off.png);"></div></td></tr></tbody></table></div></div><div id="SL_shadow_translation_result" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/bg.png) #ffffff;"></div><div id="SL_bbl_donate" title="Make a small contribution" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/donate2.png);"></div><div id="SL_Balloon_options" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/bg3.png) #f4f5f5;"><a href="chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/options-bbl.html" target="_blank" class="SL_options" title="Show options">Options</a>&nbsp;:&nbsp;<a href="chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/history.html" class="SL_options" title="Translation history" target="_blank">History</a>&nbsp;:&nbsp;<a href="http://about.imtranslator.net/add-ons/chrome-extension/" target="_blank" class="SL_options" title="ImTranslator Help">Help</a>&nbsp;:&nbsp;<a href="chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/feedback.html" class="SL_options" title="Feedback" target="_blank">Feedback</a></div><div id="SL_player"></div><div id="SL_alert100" style="background: url(chrome-extension://noaijdpnepcgjemiklgfkcfbkokogabh/img/util/bg2.png);">Text-to-speech function is limited to 100 characters</div></div></div><img src ="http://www.blogjava.net/qileilove/aggbug/421317.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2014-12-11 23:37 <a href="http://www.blogjava.net/qileilove/archive/2014/12/11/421317.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何确定非功能需求？</title><link>http://www.blogjava.net/qileilove/archive/2014/08/27/417394.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Wed, 27 Aug 2014 02:33:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2014/08/27/417394.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/417394.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2014/08/27/417394.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/417394.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/417394.html</trackback:ping><description><![CDATA[<div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">非功能需求一般和系统的状态有关而与系统需要提供的功能无关。通常是系统的&#8220; ilities&#8221;功能，比如可扩展性(scalability)、互操作性(interoperability)、可维护性(maintainability)、移植性(portability)、性能和安全性都包括在此类。<a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">敏捷</strong></u></a>团队经常纠结于定义和估算项目的非功能需求。</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　Mike Cohn建议几乎所有的非功能需求都能以用户故事表述。他给出了几个例子展示非功能需求能够适用标准的用户故事模板</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　幸运的是约束/非功能需求能很容易的按用户故事处理。这里给出几个例子：</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　作为客户，我要在从<a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">Windows</strong></u></a>&nbsp;95之后的所有版本的Windows上运行产品。</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　作为CTO，我要(新)系统使用我们已有的订单<a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">数据库</strong></u></a>而不是创建新数据库，这样我们就不用再多维护一个数据库了。</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　作为用户，我要网站在99.999%的时间是可访问的，这样我就不会感到沮丧并找其它的网站来用。</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　然而，Mike也警告说用户故事模板只是用来作为一个思考工具。不应该用一个固定的模板来记录所有的非功能需求。</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　Jason建议不要试图在用户故事级别记录非功能需求，团队应该把它们作为(项目)大图景的一部分。按照Jason所说，在他的团队，他们尝试过在每个单独的用户故事级别记录非功能需求，但是没起到作用。他提到：</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　我喜欢把这些非功能需求(NFR)用户故事写在墙上并在<a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">工作</strong></u></a>区都能看到，这样可以提醒团队在给出估算时考虑这些约束的因素。</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　Mike还提出一种明确的方法来估算非功能需求。按他所说，非功能需求与两个成本相关联</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　初始遵循(非功能需求)成本&#8212;&#8212;团队满足非功能需求所用的工作量。比如，在sprint 5花在<a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">性能测试</strong></u></a>上的工作量。</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　持续遵循(非功能需求)成本&#8212;&#8212;在以后的sprint中满足非功能需求的工作量。</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　一旦团队接受非功能需求作为项目的一部分(就像我们团队在sprint 5中做的)，他们需要把持续达到非功能需求作为项目的提示。我认为这种成本就像上税。进行性能测试(或者说遵从任何非功能需求)产生了一些额外的开支(税)。这种开支，或者说税，是必须定期付出的。</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　为了估算，Mike认为这两种成本需要单独考虑。初始遵循成本应该和任何其它的用户故事或产品backlog中的任务一样被估算。持续遵循成本，团队和product owner需要决定多久要进行一次遵循验证工作。</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　例如，假设团队和product owner同意每四个两周的sprint中进行一次性能测试。团队估算每次第四个sprint有六个点的工作要做。那就是大约每个sprint1.5点。如果团队的速度(velocity)是30个点，1.5点可以认为是大约5%的税。</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　Nick Xldis对遵循成本进行了一次非常有意思的观察。据Nick所说，</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　如果这种税持续增长，那你的架构或流程上就有问题了，需要格外关注。这是对于技术债的很好的晴雨表。</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　Scott Ambler通过提升一个独立测试团队的能力分享了管理非功能需求的想法。</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　Kassab、Olga、Maya和Alain介绍了NFR大小测量方法(NFSM)来减少估算非功能需求中的不确定性。</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　因此，处理非功能需求可能不是痛苦的挣扎。关键是尽早处理它们并关注持续成本。</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　注意：关于非功能需求这一术语的使用有很多想法和争论。Mike Cohn称其为约束而Tom Glib强烈建议称之为质量需求。</div><img src ="http://www.blogjava.net/qileilove/aggbug/417394.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2014-08-27 10:33 <a href="http://www.blogjava.net/qileilove/archive/2014/08/27/417394.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>缺陷上报统一模板及缺陷管理流程</title><link>http://www.blogjava.net/qileilove/archive/2014/07/28/416246.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Mon, 28 Jul 2014 02:11:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2014/07/28/416246.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/416246.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2014/07/28/416246.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/416246.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/416246.html</trackback:ping><description><![CDATA[<div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; text-align: center; background-color: #ffffff;"><a href="http://www.51testing.com/batch.download.php?aid=47108" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><img src="http://www.51testing.com/attachments/2014/07/14982672_201407251632541ptgq.jpg" border="0" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px;"  alt="" /></a></div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　<strong style="word-break: break-all; line-height: normal !important;">　1、前置条件 ：</strong>要根据对<a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">测试</strong></u></a>理论及项目业务的理解呢，对缺陷的严重性和优先级有个清晰思路并进行正确的划分。</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　<strong style="word-break: break-all; line-height: normal !important;">2、统一缺陷报告的模板：</strong></div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　1）编号 &nbsp; 2）所属模块 3）摘要/标题（用一句话描述BUG）</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　4）测试环境 、操作步骤 、实际结果 、期望结果 、备注</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　5）bug优先级、严重性 6）测试人 &nbsp;7）日期 &nbsp;8）bug状态</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　9）截图</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　<strong style="word-break: break-all; line-height: normal !important;">　3、缺陷的管理流程或bug的生命周期</strong>（假如：发现bug，但不知道相关的开发负责人）</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　提交bug-----经理/组长审核（检查描述、优先级与严重性是否符合）---</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　--转交给相关的开发人员----修复bug并反馈回执给相关测试人员--</div><div style="word-break: break-all; line-height: 21.600000381469727px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　--回归测试验证是否修复----根据验证结果更改bug状态</div><img src ="http://www.blogjava.net/qileilove/aggbug/416246.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2014-07-28 10:11 <a href="http://www.blogjava.net/qileilove/archive/2014/07/28/416246.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个用于网站自动化测试的生态系统实现</title><link>http://www.blogjava.net/qileilove/archive/2014/03/13/410968.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Thu, 13 Mar 2014 03:34:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2014/03/13/410968.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/410968.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2014/03/13/410968.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/410968.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/410968.html</trackback:ping><description><![CDATA[<div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　这是我在从事网站<a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">自动化测试</strong></u></a>的<a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">工作</strong></u></a>当中构建出的一个&#8220;生态系统&#8221;。&#8220;生态系统&#8221;这个概念是我从公司的前辈身上学到的，他一直以来都认为自动化测试人员不应仅仅局限于编写测试代码，还应该让整个自动化测试的过程（测试代码的持续集成、分发、执行等）都自动化，形成一个&#8220;系统&#8221;，这个系统的自动化程度越高，自动化测试人员就越省力。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　<strong style="word-break: break-all; line-height: normal !important;">一、概念</strong></div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　这里我画了一张示意图：</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;"><a href="http://www.51testing.com/batch.download.php?aid=44896" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><img src="http://www.51testing.com/attachments/2014/03/14982672_201403101350321E3JG.jpg" border="0" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px;"  alt="" /></a></div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　之所以称之为&#8220;生态系统&#8221;，是因为建成之后需要的人为干涉很少，其余的时间都是系统内部循环运作。作为自动化测试人员的你只需要提交代码，之后便可以在AutomationDashboard上看到运行的结果了，其余的事情都由系统内部消化。当然，结果的分析还是需要人来完成，机器还没有聪明到可以灵活分析出各种各样让case fail掉的原因。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　我们可以把整个系统看作一个黑盒子，那么上面的图可以变成：</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;"><a href="http://www.51testing.com/batch.download.php?aid=44897" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><img src="http://www.51testing.com/attachments/2014/03/14982672_201403101350322xbVu.jpg" border="0" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px;"  alt="" /></a></div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　实际上这里画的人不仅限于自动化测试人员，也可以是：</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　（1）产品的管理者，比如产品经理需要从自动化回归测试知道这次release有无推迟风险；</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　（2）团队的管理者，比如开发经理、QA经理需要从自动化的daily/weekly regression知道最近的代码质量如何；</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　（3）开发人员，他们也许会想通过quick regression（提交的产品代码被部署到测试环境之后运行的测试）知道自己刚提交的代码有没有破坏系统的基本功能；</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　（4）其他帮忙做自动化测试的开发人员、刚刚开始<a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">学习</strong></u></a>编写自动化测试代码的手动测试人员，他们不必关心生态系统的内部实现。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;"><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　<strong style="word-break: break-all;">　二、实现</strong></div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　说完概念，接下来该说说具体实现了。我这里讲的是我认为最适合我所测试的产品的实现，工具不止一种，方式不止一种。Jenkins可以用TeamCity或其它CI替换，git也可以是svn或tfs，AutomationDahsboard可以用.NET、SpringMVC、ROR等等实现，运行测试的slave可以是Windows/Linux/Mac（土豪！），总之选择一种最适合你所测试的产品的实现。还有一点就是自动化测试代码是用关键字驱动思想实现的，这是另外一个话题了，有时间另外写篇文。</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　<strong style="word-break: break-all;">好，进入正题。依次说说系统的每个重要组成部分吧：</strong></div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　1、SCM（Source Code Management）。我选的是git，可以是git服务器（公司自己搭建了一个git&nbsp;<a target="_self" style="word-break: break-all; color: #202859;"><u style="word-break: break-all;"><strong style="word-break: break-all;">server</strong></u></a>），也可以是一个bare repo（http://www.saintsjd.com/2011/01/what-is-a-bare-git-repository/） 。</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　2、CI（continuous integration）。我选的是部署方便、插件丰富的Jenkins。</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　<strong style="word-break: break-all;">它的职责是：</strong></div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　（1）从git上取出代码，build（.NET对应msbuild，如果是ruby则不用build了，直接部署即可）；</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　（2）把build好的*.dll部署（这里即是拷贝）到所有的slave上；</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　（3）启动或停止所有slave上的AutomationService（后面还会讲到AutomationService），从而控制测试的执行。<span style="font-size: 11.818181991577148px; line-height: 21.60000228881836px;">我在Jenkins的这些个job配置起来还是比较繁琐的，要细讲又可以另外写一篇文了。这里就特别提到两个很实用的插件吧：</span></div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;">　　（1）Parameterized Trigger Plugin（https://wiki.jenkins-ci.org/display/JENKINS/Parameterized+Trigger+Plugin）：可以在一个build step中触发其它project的build。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;"><a href="http://www.51testing.com/batch.download.php?aid=44898" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><img src="http://www.51testing.com/attachments/2014/03/14982672_201403101350323MpQL.jpg" border="0" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px;"  alt="" /></a></div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;">　　它最有用的就是这个&#8220;Block until the triggered projects finish their builds&#8221;选项，勾上的话Jenkins就能在所有trigger的project完成build之后（而非仅仅trigger其它project的build，不等它们完成就继续下一个build step）再继续下一个build step，做到真正的依次执行每个build step。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;"><a href="http://www.51testing.com/batch.download.php?aid=44899" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><img src="http://www.51testing.com/attachments/2014/03/14982672_201403101350324cdMj.jpg" border="0" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px;"  alt="" /></a></div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;">　　（2）NodeLabel Parameter Plugin（https://wiki.jenkins-ci.org/display/JENKINS/NodeLabel+Parameter+Plugin）：在所有&#8220;Possible nodes&#8221;标有指定标签（&#8220;Label&#8221;）的Jenkins节点（就是Jenkins master或Jenkins slave）上触发指定project（被触发的project是参数化的）。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;">　　比如我有一个project叫&#8220;StartClassicROLATServiceOnAllNodes&#8221;，它有一个build step是这样设定的：</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;"><a href="http://www.51testing.com/batch.download.php?aid=44900" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><img src="http://www.51testing.com/attachments/2014/03/14982672_201403101350325p0dk.jpg" border="0" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px;"  alt="" /></a></div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;">　　再来看看&#8220;StartClassicROLATServiceOnASingleNode&#8221;这个project的设定：</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;"><a href="http://www.51testing.com/batch.download.php?aid=44901" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><img src="http://www.51testing.com/attachments/2014/03/14982672_2014031013503261mEf.jpg" border="0" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px;"  alt="" /></a></div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;">　　这个project有一个Node类型的参数，参数名&#8220;NodeX&#8221;与之前Label Factory中的&#8220;NodeX&#8221;对应，&#8220;Possible nodes&#8221;选的是&#8220;ALL&#8221;，那么列出的所有node（master、10.107.122.152、10.107.122.153、10.107.122.154）都在判断范围之内（判断其是否有&#8220;Node&#8221;标签，有则执行project）。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;">　　另外，列出的所有node我都为其加了一个&#8220;Node&#8221;标签。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;"><a href="http://www.51testing.com/batch.download.php?aid=44902" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><img src="http://www.51testing.com/attachments/2014/03/14982672_201403101350327qC46.jpg" border="0" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px;"  alt="" /></a></div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;">　　这样，当我trigger &#8220;StartClassicROLATServiceOnAllNodes&#8221;之后，就会在master、10.107.122.152、10.107.122.153、10.107.122.154这4个node上同时执行&#8220;StartClassicROLATServiceOnASingleNode&#8221;。<br /><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;"><strong style="word-break: break-all; line-height: normal !important;">　3、AutomationDashboard，这里姑且译作&#8220;自动化测试控制面板&#8221;吧。</strong>实际上它应该和Jenkins一起并称控制面板，不过因为Jenkins有API可以调用，所以想做的画两者也是可以统一成一个web界面的。这个dashboard完全是用.NET+IIS+SQLServer一点点从数据库设计构建、数据访问层、业务层、表现层做起来的，要细讲&#8230;&#8230;额&#8230;&#8230;又会是另外一篇文了（Oh man, not again!）。反正我觉得，虽然我是做自动化测试工作的，但不应该把自己局限于测试。为了更好地进行自动化测试，开发网站、安装配置虚拟机以及其它要用到的工具，都应该抽时间去学习、掌握。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;">　　好，来说说这个dashboard。这里只讲两个主要组成部分，一个网站（以下简称dashboard）、一个Windows Service（以下简称ATService）和一个console application（以下称ConsoleRunner）：</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;">　　<strong style="word-break: break-all; line-height: normal !important;">（1）dashboard，它的主要功能：</strong></div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;">　　a、展示测试的运行状况：有多少正在运行/执行完毕，分别在哪台slave上执行等等。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;">　　b、通过call Jenkins的API来trigger Jenkins的job，间接控制测试的执行。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;">　　c、展示测试的结果：发生错误的是哪个case、出错时间、错误信息、代码回溯（stack trace）、甚至可以包含一张出错时的截图。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;">　　主要界面如下：</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;">　　a、Summary，顾名思义是汇总信息，case有多少pass多少fail、case按分类每一类有多少等等。（其实这里我少做了一张很重要的图，就是coverage饼状图）</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;"><a href="http://www.51testing.com/batch.download.php?aid=44903" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><img src="http://www.51testing.com/attachments/2014/03/14982672_20140310135032827KJ.jpg" border="0" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px;"  alt="" /></a></div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;">　　b、Queue，测试队列，包含当前正在运行的、运行完的、等待运行的test fixture或test case（依据测试工具的不同，NUnit、JUnit、RSpec等，fixture的叫法可能不同，总之就是包含多个test case的集合）。可以启动、停止、终止（终止之后可以清空）测试执行或清空当前队列。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;"><a href="http://www.51testing.com/batch.download.php?aid=44904" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><img src="http://www.51testing.com/attachments/2014/03/14982672_201403101350329deYC.jpg" border="0" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px;"  alt="" /></a></div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;">　　c、TestCase，生态系统中的所有测试用例会展示在这里，可以看到它们最后一次执行的时间和状态（pass/fail），点击某条case可以跳转到该条case的所有test result。可以按状态（pass/fail/other）筛选用例，可以勾选部分用例重新执行、或重新执行所有fail的case。&#8220;Reload Test Cases&#8221;主要是考虑到*.dll文件中的test case可能会在某次部署之后发生变化，需要重新加载。不过后来我修改了Jenkins里的job在每次部署之后都自动重新加载，所以这个按钮其实没什么用了。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;"><a href="http://www.51testing.com/batch.download.php?aid=44905" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><img src="http://www.51testing.com/attachments/2014/03/14982672_201403101350321010y4.jpg" border="0" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px;"  alt="" /></a></div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;">　　d、TestSuite，包含多个fixture的集合是一个suite。勾选多个suite点击&#8220;Run Suite&#8221;即可把这些suite中包含的fixture添加到Queue。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;"><a href="http://www.51testing.com/batch.download.php?aid=44906" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><img src="http://www.51testing.com/attachments/2014/03/14982672_20140310135032111vpi.jpg" border="0" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px;"  alt="" /></a></div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;">　　这里的suite是对NUnit中的Category的一个补充，点击&#8220;New Suite&#8221;你可以任意选择fixture来组成自己想要的suite：</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;"><a href="http://www.51testing.com/batch.download.php?aid=44907" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><img src="http://www.51testing.com/attachments/2014/03/14982672_2014031013503212Z8mE.jpg" border="0" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px;"  alt="" /></a></div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;">　　e、TestResult，展示所有test case的运行结果，可以按test case id进行筛选，点击TC#这一列的id就只显示这条case的结果。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;"><a href="http://www.51testing.com/batch.download.php?aid=44908" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><img src="http://www.51testing.com/attachments/2014/03/14982672_20140310135032132kv4.jpg" border="0" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px;"  alt="" /></a></div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;">　　点右边的蓝色&#8220;i&#8221;图标可以跳到这条结果的详细页面，截图功能暂未启用，根据RunnerMessage和RunnerStackTrace可以知道报错的代码位置，进而尝试重现问题。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; font-size: 11.818181991577148px;"><a href="http://www.51testing.com/batch.download.php?aid=44909" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><img src="http://www.51testing.com/attachments/2014/03/14982672_2014031013503214aCLS.jpg" border="0" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px;"  alt="" /><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-size: 11.818181991577148px;">　（2）ATService。这个Windows Service（slave都是Windows，稍后会讲）被安装到了每个slave上，用以向dashboard询问&#8220;现在有没有分配给我的test fixture/case？&#8221;，如果有且当前slave空闲的话就抓过来运行，运行完毕汇报结果。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-size: 11.818181991577148px;">　　还记得Queue（队列）吧？无论你在TestCase还是TestSuite页面挑选了test case/suite想要运行，都只是把它们添加到队列当中（准确地说就是往Queue这张数据库表中INSERT记录），而不会给它们分配slave。只有当Jenkins启动了slave上的ATService之后，ATService才会去Queue表中自己抓取（就是打上标记说这条fixture/case已经有主了，其它slave就不会再去抓）还没有运行过且没有分配有slave的test fixture/case。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-size: 11.818181991577148px;">　　（3）ConsoleRunner，最开始的那个图中没有画出来。这个console程序主要供Jenkins调用。Jenkins不是可以让job定时运行么？正好，定时调用这个console application，传几个参数，就可以在指定时间往Queue里填充fixture/case，然后再启动ATService开始执行测试。这样就能实现quick/daily/weekly/full regression的无人值守运行了。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-size: 11.818181991577148px;">　<strong style="word-break: break-all; line-height: normal !important;">　4、Slave</strong></div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-size: 11.818181991577148px;">　　我选择在Windows上运行测试：</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-size: 11.818181991577148px;">　　（1）公司IT一般只提供Windows操作系统的虚拟机</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-size: 11.818181991577148px;">　　（2）产品在Windows上的用户占绝大多数（其实这个有点废话，桌面操作系统Windows依然是世界王者。诚然，我自己业余时用Linux做开发，Mac在国内外也是相当流行的，但GoogleAnalytics显示的统计结果就是大部分访问都来自Windows。什么，你说iOS/Android？额&#8230;&#8230;移动端现在仍然是产品的短板&#8230;&#8230;）</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-size: 11.818181991577148px;">　　如果选择Linux的话要注意下selenium webdriver的native event设定（http://code.google.com/p/selenium/wiki/AdvancedUserInteractions#Native_events_versus_synthetic_events）。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-size: 11.818181991577148px;">　　关于浏览器，Firefox、Chrome、IE皆可，webdriver的浏览器兼容性已经很不错了。浏览器兼容性是个有点头疼的问题，想支持很多浏览器的话有时会增加很多开发、测试成本，我一般在Firefox上跑就足够了。什么？数字？马桶？企鹅？您想多了，selenium官方不支持。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-size: 11.818181991577148px;">　　你能找到多少台slave来执行测试？多多益善哦！找不到那么多实体机就自己配虚拟机吧，分布式运行可以给你的自动化测试生态系统装上火箭！在更短的时间内运行完更多测试，从而更快地从测试中获得反馈！</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-size: 11.818181991577148px;">　　嗯，差不多就这么多了。还有很多细节就留在之后的文中再说了。自我感觉这个生态系统还是有很多可以完善、增加的功能，而且这个实现方式、运作机制可能也并非适用于你所测试的产品，不过现在对于我测的产品来说是够用的了。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-size: 11.818181991577148px;">　　不管怎样实现，我想表达的核心观点是：</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-size: 11.818181991577148px;">　　做自动化测试不要局限于自动化测试代码的编写，我们要自动化的不仅仅是manual test case，还应包括整个automation test的process！测试代码持续集成、部署（分发）、执行、结果展示，自动化的环节越多、越彻底，为你节约的时间就越多，你可以用这些节约的时间做更有意义的事情。人类发明计算机，用代码编写程序，其实就是一种自动化的过程。以前要靠手工劳动完成的现在都交给电脑做了&#8212;&#8212;服务器不正是勤勤恳恳地重复执行着我们写好的程序么？构建自动化测试生态系统是同样的道理，因为机器能比人更可靠地完成重复劳动。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-size: 11.818181991577148px;">　　如果你还在手动拷贝*.dll，还需要打开NUnit手动执行测试，还在1台机器上运行测试，那么，现在就是该提高生产力的时候了！</div></a></div></div></div><img src ="http://www.blogjava.net/qileilove/aggbug/410968.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2014-03-13 11:34 <a href="http://www.blogjava.net/qileilove/archive/2014/03/13/410968.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SpecDD系列：敏捷应用生命周期管理(ALM)</title><link>http://www.blogjava.net/qileilove/archive/2014/02/17/409924.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Mon, 17 Feb 2014 06:35:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2014/02/17/409924.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/409924.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2014/02/17/409924.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/409924.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/409924.html</trackback:ping><description><![CDATA[<div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　由于<a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">敏捷</strong></u></a>开发正成为越来越多开发团队的标准，敏捷应用生命周期管理持续呈现增长势头。一个已经被证明了的事实，那就是很多工具供应商发现把自己的产品标识成敏捷工具甚至是敏捷<a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">ALM</strong></u></a>工具，是很管用的。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　然而，何谓敏捷应用生命周期管理？应用生命周期管理结合了技术因素和功能因素，为常见的项目活动（如开发，配置，部署，发布，<a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">测试</strong></u></a>，质量，集成，和<a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">需求管理</strong></u></a>）提供一个综合方案。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　敏捷ALM用敏捷的价值观和策略，丰富了应用生命周期管理。敏捷方法下的ALM可以提高产品质量，缩短产品上市时间，并让开发者感到快乐。传统的ALM有助于为敏捷ALM提供一个架构，同时保证过程和工具链是灵活的，可更改的和高品质的。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　<strong style="word-break: break-all; line-height: normal !important;">个体和交互胜过过程和工具</strong></div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　首先，敏捷ALM是一个准则，是一种思想。从事敏捷应用生命周期管理应该从价值观和人，以及人们背后的观念开始。敏捷ALM工具是一个能够促进敏捷过程的ALM工具。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　敏捷ALM工具必须能够为项目增加价值并改善利益相关者之间的合作。这些是通过构建敏捷ALM的基石：协作和基于任务的开发，功能/技术发布，利益相关者关注点和质量保证来实现的。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　很多团队都很乐于把几个单独的好用的工具拼凑起来用。把许多轻量级的，可配置的工具整合为一个工具链。这种混搭的工具集合通常能够提供完成一个任务所需的大部分功能。很多时候，虽然工具之间存在隔阂，但这些隔阂可能不会存在于完全整合的解决方案中。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　理想的情况下，敏捷ALM工具应该有一个整合的，灵活的架构，可以让你扩展过程和功能。依托一个完全整合的工具，可以显著提高产品安全性和沟通效率，因为你可以很容易地维护各个交付件之间的关系，并且不用担心工具间传输时会遗漏细节。现在，我们来讨论一下构建敏捷ALM基石的其他重要部分。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　<strong style="word-break: break-all; line-height: normal !important;">基于任务的开发</strong></div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　基于任务的开发方法中，任务是团队<a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">工作</strong></u></a>和交互的基本单元。基于任务的开发需要能够跟踪具体变更的关联工作项，通过追溯性定位并完成这些工作。例如，你正在处理事件系统上的一个任务。你的SCM（比如SVN）与事件系统（比如DevTrack）是相集成的，从而透明化任务的工作进度和相互依赖关系。在DevTrack中，你可以看到Sprint中每个任务的计划，它们的状态，以及已完成的代码更改。此外，DevTrack作为完整DevSuite中的一个组件，你可以为DevTrack中的任务链接原始的用户需求及可用的<a target="_self" style="word-break: break-all; color: #202859; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">测试用例</strong></u></a>。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　<strong style="word-break: break-all; line-height: normal !important;">功能性和技术性发布管理</strong></div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　发布管理包括产生软件交付件，并按照既定流程发布这些交付件。发布管理可以区分为功能性的和技术性的。要想成功交付软件，这两部分都是非常重要的，并且应该相互融合。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　功能发布管理涉及到客户的需求，将这些需求分配到各个版本中，然后把功能提供给客户。经常使用敏捷实践来支撑这一过程，许多项目通过使用Scrum管理模板取得了良好的效果。通过定义一个简洁的框架，Scrum促进了规范化，并且让缺陷（软件中的以及过程中）可视化。但是，Scrum太抽象化了，有些&#8220;纸上谈兵&#8221;。你必须实施Scrum，并且使之适应软件工程。例如，实施实践可能在不同的开发阶段会存在差别，微观层面上，在一个Scrum发布内部：发布过程中，你可能会为了关闭开发阶段而考虑冻结某些新功能的开发实现，而允许开发人员只处理缺陷的修复工作。另一个有效的选择是使用一定时间间隔的代码冻结，来完成和交付最终版本。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　技术发布包括构建软件和提供最终产品给用户。构建管理（包括编译脚本，打包和分发组件）对于敏捷ALM来说是必不可少的。技术发布管理描述了以下活动：识别配置项，跟踪和审核基于需求和配置项的变更，集成和交付实施。在软件工程中，变更更像是规则，而不是例外。因为需求总是在变化的，保证需求和实施的同步是非常重要的。功能发布管理和技术发布管理之间可能存在的隔阂应该被桥接。一个完全整合的敏捷ALM工具可以通过自动创建相应的关系和链接来避免这些隔阂。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　<strong style="word-break: break-all; line-height: normal !important;">总结</strong></div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　敏捷应用生命周期管理涵盖软件工程中的许多学科。敏捷ALM关乎人和策略，以及用一个完全整合的工具套件来实施这些策略。敏捷ALM有助于为敏捷提供架构，并且通过一种果断，务实的方式来实现应用生命周期管理。使用敏捷方法来进行应用生命周期管理，你将收益更好的结果并更快的获得成功。</div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;"></div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;"></div><div style="word-break: break-all; line-height: 21.60000228881836px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff; height: 21px; position: relative; width: 627.1875px;"></div><img src ="http://www.blogjava.net/qileilove/aggbug/409924.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2014-02-17 14:35 <a href="http://www.blogjava.net/qileilove/archive/2014/02/17/409924.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>敏捷开发（Agile）中的性能测试</title><link>http://www.blogjava.net/qileilove/archive/2014/02/11/409706.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Tue, 11 Feb 2014 02:39:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2014/02/11/409706.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/409706.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2014/02/11/409706.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/409706.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/409706.html</trackback:ping><description><![CDATA[<div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">与传统开发过程相比，<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">敏捷</strong></u></a>开发能够更好、更快的提供潜在可发布版本，同时需求的变化对产品带来的冲击也降到了最小。那么如何更好，更有效的在这种快速迭代，快速集成的开发思想下做<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">性能测试</strong></u></a>也成了大家研究的方向，综合了很多大牛的思想和我对Agile开发的理解，做一个个人总结：</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;"><a href="http://www.51testing.com/batch.download.php?aid=44397" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><img src="http://www.51testing.com/attachments/2014/02/14982672_201402101100161mUbj.jpg" border="0" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px;"  alt="" /></a></div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　<strong style="word-break: break-all; line-height: normal !important;">性能测试的阶段：每个Sprint</strong></div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　在Sprint Planning之初，首先需要明确需要性能测试的Story，定义可量化的性能测试目标，然后添加性能测试的任务，性能测试是否需要单独创建user story要依产品而定：</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　1. 对于即刻发布的版本（以<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">移动</strong></u></a>应用为例）：最好在将性能测试与user story放到一块，这样才能更好地track user story的是否可交付（是否做完性能测试）。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　2. 对于周期长，潜在可发布版本不会立即到用户手中的项目：建议单独为性能测试创建user story。原因之一是这种项目比较庞大，各个user story之间的集成比较复杂，同一个性能测试关联的user story非常多，单独创建能够更清晰，也不会影响user story的commit。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　测试对象：由于一个个的story相对独立，所以测试的对象可以是小到一个个函数或接口，达到一一个端到端的场景（这种情况下需要考虑其他模块或第三方软件对性能的影响）。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　测试的执行：对与单个的性能测试任务，流程基本和传统性能测试相同，但整个流程需要对该story的每一个改动后的可测版本执行：</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　1. 定义性能场景</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　2. 选取监控指标（可参考Acceptance Criteria）</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　3. 模拟负载（可以通过自动化脚本和工具产生）</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　4. 收集数据和生成报表。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　验收：主要是参照sprint planning中定义的性能acceptance criteria来评估潜在可交付版本的性能。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;"><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">版权声明：本文出自 AlvinXu 的51Testing软件测试博客：http://www.51testing.com/?554494</div></div><img src ="http://www.blogjava.net/qileilove/aggbug/409706.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2014-02-11 10:39 <a href="http://www.blogjava.net/qileilove/archive/2014/02/11/409706.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Scrum中QA角色经验分享</title><link>http://www.blogjava.net/qileilove/archive/2014/01/22/409199.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Wed, 22 Jan 2014 01:56:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2014/01/22/409199.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/409199.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2014/01/22/409199.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/409199.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/409199.html</trackback:ping><description><![CDATA[<div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　Scrum是<a href="" target="_self" sl-processed="1" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">软件开发</strong></u></a>的<a href="" target="_self" sl-processed="1" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">敏捷</strong></u></a>方法。它以2到4周为一个迭代开发出有价值的商业功能。Scrum团队有两个明显特征：他们是多面手（例如：他们具备完成<a href="" target="_self" sl-processed="1" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">工作</strong></u></a>所必须的所有技能）；他们是自管理的（例如：团队不断探索如何把工作做的最好的方法）。通过过去两年在Scrum团队中近2年的QA角色的不断实践，我认识到Scrum中的QA不仅仅是编写<a href="" target="_self" sl-processed="1" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;"></strong></u></a><u style="word-break: break-all; line-height: normal !important;"><strong style="word-break: break-all;"><a href="" target="_self" sl-processed="1" style="word-break: break-all; color: #202859; text-decoration: none;"><u style="word-break: break-all;"><strong style="word-break: break-all;">测试</strong></u></a>用例</strong></u>和汇报缺陷那么简单。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　对比传统瀑布模型的项目中的同步活动，Scrum期望开发活动根据实际需要的顺序来执行，例如异步。这点有悖传统，让许多客户、开发和业务关系人等新手产生疑惑 &#8220;如何在代码还没有完成之前进行有效的测试？&#8221; 本文重点解释了QA如何执行<a href="" target="_self" sl-processed="1" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">敏捷测试</strong></u></a>以及Scrum团队中QA角色的重要性。我将通过本文分享在我对Scrum团队中QA角色及职责的认识。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　<strong style="word-break: break-all; line-height: normal !important;">不仅是编写测试用例</strong></div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　传统瀑布模型的项目中，QA介入的时机往往是在代码全部完成后的项目收尾阶段。这些项目中，QA拿到一份需求文档和已经完成的代码，然后开始编写和执行测试用例以检查应用程序是否符合需求文档。然而，Scrum中的QA角色不再仅仅是执行测试用例和汇报缺陷。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　参加评估用户故事（Story）在Scrum团队中，QA分析师和其他团队成员一起参与或担当大量职责。他们从项目一开始就介入，并且与业务分析者和开发者密切联系。在Scrum中，QA不是一个单独的测试应用程序的团队。取而代之的是，Scrum团队是一个业务分析师、开发者、QA一起协同工作的综合团队。除了编写用例，QA还帮助产品负责人（PO）编写接受用例，相当于承担产品负责人代理的角色。当产品负责人没有时间时，QA作为代理保持团队持续前进。QA和产品负责人通过提出问题和质疑假设进行互动交流，最终澄清业务需求。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　QA分析师一般很擅长根据用户需求创建测试用例场景。在识别和捕捉复杂和否定的用例上也很卓越。事实上，在这点上，QA往往比开发做的好，因为开发往往关注用户故事的好的方面。在版本和周期计划会议中评估用户故事时邀请QA参与能让团队不再仅仅思考好的方面，有利于产生一个综合好坏情况的客观真实的评估。评估是一个很难的事情，让所有人都参与评估是很好的实践。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　<strong style="word-break: break-all; line-height: normal !important;">有利于保持视角和目标明确</strong></div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　当团队执行测试和其他稳定产品的活动时，QA需要掌控计划、组织或让整个团队投入到测试工作中，并且像Scrum Master(SM)那样保持成员处于积极状态。很少有开发者喜欢做测试任务。QA需要和Scrum Master一起让测试对整个测试团队可见且目标明确。从而保持开发者或其他成员的积极性。有时一些测试场景的构建需要开发或其他团队成员的帮助，这样容易创新。力争让测试活动有趣，例如用刺激的测试场景、出人意料的测试数据和带有娱乐意味的竞争。总之，做任何事情，只要有助于团队乐于加入测试工作即可。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　<strong style="word-break: break-all; line-height: normal !important;">与客户和开发者紧密合作</strong></div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　QA的主要职责之一是将他们的测试结果反馈给产品负责人或收集他们的反馈。QA和产品负责人紧密合作，帮助他们制定详细的用户故事验收标准。随着团队在每个迭代中的深入了解，QA也可以帮助产品负责人修改或增强用户故事以更好地反映真实的需求。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　偶尔，QA分析师还充当产品负责人代理。这种情况下，QA和开发者将坐在一起，作为一个团队一起工作以提高产品质量。QA可以和开发者结对来写<a href="" target="_self" sl-processed="1" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">单元测试</strong></u></a>，讨论验收标准。合作的工作越多，需求也越清楚。一起工作带来的清晰需求将减少编码过程中经常遇到的各种问题或疑惑，从而给有效提高开发效率、节约开发和QA的时间。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　根据团队每个人的需求和实际情况，整个团队将成为一体，都会协助测试。这样的实践平衡了团队和工作完成必须的共同职责，早期测试反馈和持续增长的质量下，它将使项目进展更快。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　<strong style="word-break: break-all; line-height: normal !important;">提供快速反馈</strong></div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　传统瀑布模型团队不断重复的&#8220;构建-测试-修复&#8221;周期徒增了大量额外工作量，浪费了大量时间。在Scrum中，QA和开发者在整个项目中一起工作，让活动变得更简单。在开发过程中，开发者能直接咨询QA验收标准或从用户视角任何功能上的期待行为。这让测试和缺陷修复更简单。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　自动化回归测试</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　<a href="" target="_self" sl-processed="1" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">自动化测试</strong></u></a>常被誉为测试者最好的朋友，因为它可重复执行且执行一致，能得到更好的软件功能的测试覆盖率。在2到4周一个迭代的Scrum项目中这点尤为正确。因为QA大体都没有太多时间去测试应用程序。在2周的迭代中，QA必须完成迭代中所有新功能的功能点测试的同时还要完成对先前实现功能的测试。正因如此，这种职责提高了每个迭代中使用可用的自动化实践以减少QA压力的重要性。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　当团队执行持续集成时，自动化测试在快速反馈上大有用途。每发布一个软件新版本，可以执行自动化测试并快速提供反馈以反映是否新老功能都正常工作。而没有自动化测试，就必须手工执行所有的测试，不仅单调，而且容易犯错。自动化测试能更早的发现缺陷，让QA有更多时间去探索新功能的一些特殊用例。通过自动化测试，QA可以更快更有效地完成测试工作。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　<strong style="word-break: break-all; line-height: normal !important;">参与发布准备演示</strong></div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　在每个迭代结束时，团队需要召开一个迭代审阅会议来向项目责任人和其他有兴趣的关系人展示这个迭代完成的用户故事。迭代审阅会议是团队中的&#8220;良药&#8221;，可以有效激发他们去尽可能完成更多用户故事。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　在2到4周的小迭代中，为了让用户故事按时完成，团队中的每个人都必须沉浸在自己的工作。开发者关注实现用户故事和修复缺陷，QA关注用例编写、澄清产品责任人的问题、自动化之前迭代的测试。较短的迭代周期意味着开发没有多少时间去获知用户故事要求的全部功能。这样，开发一般要询问QA以更好的理解用户故事。因为QA知道完整的功能及每个需求和验收标准。在迭代审阅会议上，让QA演示项目和解答业务上的问题是很好的实践。这也让开发者更专注于处理技术层面的问题。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　<strong style="word-break: break-all; line-height: normal !important;">分析用户需求</strong></div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　QA是Scrum团队中产品负责人代理。他们擅长从用户视角理解业务需求。因为他们经常被问到用户如何使用项目。QA根据他们的测试经验给产品负责人提供反馈，帮助他们更好的从用户视角理解项目。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　<strong style="word-break: break-all; line-height: normal !important;">　完善&#8220;完成定义&#8221;</strong></div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　对于敏捷团队，清晰的完成定义(DOD)是很重要的。&#8220;完成定义&#8221;是团队定义完成标准的简单列表，是在用户故事认定为完成必须要完成的事情。完成定义一般包括完成代码、执行功能和回归测试、获得产品负责人的认可。一个简单的完成定义可能包括如下项目：</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　代码完成</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　单元测试完成</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　功能和UI测试完成</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　产品负责人认可<br /><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　定义&#8220;完成定义&#8221; 不是QA一个人的责任，QA的责任往往在于监管团队完成定义和每个完成的用户故事必须满足&#8220;完成定义&#8221;的基线要求。一个高效的敏捷团队在启动每个用户故事前都要审阅&#8220;完成定义&#8221;从而使团队每个人都了解目标。&#8220;完成定义&#8221;不是一层不变的，可能会根据Scrum的需要不断演变。&#8220;完成定义&#8221;既可以是迭代级的也可以是发布级的。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　<strong style="word-break: break-all; line-height: normal !important;">用测试策略规范测试</strong></div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　由于Scrum团队中没有测试领导甚至测试专家。构建测试计划或执行测试策略就存在问题。Scrum认为需要准备足够的文档去支持团队随时提出的需求。正因为此，需要准备足够的高层次测试策略的文档和计划来指导团队。因为没有QA领导在团队中，QA一般自己来制定测试策略。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　<strong style="word-break: break-all; line-height: normal !important;">测试者和分析者角色融合</strong></div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　测试者和分析者角色融合在敏捷团队中很常见，业务分析师的角色一般是负责创建和维护迭代和产品的Backlog、从业务角度分析用户故事、根据产品负责人要求划分用户故事优先级。而QA角色一般负责为每个故事定义或完善验收标准，确保之前完成的功能没有老的问题。QA测试每个用户故事，从终端用户视角验证定义的验收标准是否已经达到，他们也根据业务来分析用户故事。所以QA和业务分析师的角色责任、必备技能、总体目标有很多重合地方。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　一般，在项目开始之时，敏捷团队从产品负责人那里拿到用户故事和提前定义的项目范围。在敏捷模式下，鼓励团队成员提出改善终端用户体验的新功能或改变已有功能，也鼓励团队一旦发现技术依赖或发现换一种实现将更有效而改变backlog中用户故事优先级和顺序。无论是定义需求、分析用户故事、定义和澄清验收标准、编写接受性验证用例或和用户紧密合作，对于小的团队，测试者和分析者的角色融为一体有很多优点，但也存在一些缺点，最大的顾虑是没有测试者或分析者能够投入过多精力来完全尽责。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　<strong style="word-break: break-all; line-height: normal !important;">结论</strong></div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　除了编写用例和汇报缺陷，QA在Scrum团队中承担更多的职责。他们是团队的重要组成部分，并且从项目一开始就参与其中。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　过去两年在Scrum团队当QA分析师让我有了一个非常棒的体验，同时也获得了很多学习机会。我担当了很多不同的角色和职责，包括QA分析师、产品责任人代理、帮助开发写单元测试、确保团队的质量意识和跟踪问题和软件缺陷。总之，这些体验让我获得了很多 不错的技能，同时让我学习了如何做好不同的角色。更重要的是它告诉我如何去问问题而不再是仅仅遵循文档，也教会了我去做任何有助团队成功的事情。</div></div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;"></div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;"></div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff; height: 21px; position: relative; width: 627.1875px;"></div><img src ="http://www.blogjava.net/qileilove/aggbug/409199.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2014-01-22 09:56 <a href="http://www.blogjava.net/qileilove/archive/2014/01/22/409199.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>测试驱动开发TDD(3)</title><link>http://www.blogjava.net/qileilove/archive/2014/01/22/409198.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Wed, 22 Jan 2014 01:42:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2014/01/22/409198.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/409198.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2014/01/22/409198.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/409198.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/409198.html</trackback:ping><description><![CDATA[<div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　上一篇我剩下的To-Do-List:</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　猜测数字</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　输入验证</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　生成答案</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　输入次数</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　输出猜测结果</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　今天争取全部搞定。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　现在我们Guesser、生成答案、输入验证都有了。把它们组装成一起摇身一变成一个Game!</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　用一个类把这些职责单一的小模块组合起来。我暂且称它为GameManager.</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　分析剩下的需求。（1）输入6次GameOver.（2）输入合法数字返回猜测结果。（3）游戏结束提示重新开始游戏。（4）中途输入exit 退出游戏。（5）输入正确答案，GameOver。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;">　　先把之前写的Guesser提出一个接口。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;"><table align="center" style="word-break: break-all; border-style: solid; border-color: #999999; width: 612.7272338867188px; background-color: #dddddd; font-size: 12px;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;"><div style="word-break: break-all; margin: 10px 0px;">public interface IGuesser</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">string AnswerNumber { get; }</div><div style="word-break: break-all; margin: 10px 0px;">string Guess(string inputNumber);</div><div style="word-break: break-all; margin: 10px 0px;">}</div></td></tr></tbody></table></div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 11.818181991577148px; background-color: #ffffff;"><table align="center" style="word-break: break-all; border-style: solid; border-color: #999999; width: 612.7272338867188px; background-color: #dddddd; font-size: 12px;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;"><div style="word-break: break-all; margin: 10px 0px;">public class Guesser ：IGuesser</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">public string AnswerNumber { get; private set; }</div><div style="word-break: break-all; margin: 10px 0px;">public Guesser(IAnswerGenerator generator)</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">AnswerNumber = generator.Generate();</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">public string Guess(string inputNumber)</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">...</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">}</div></td></tr></tbody></table><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">&nbsp; &nbsp; Test First.</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;">　　新建GameManagerTest</div><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;"><table align="center" style="word-break: break-all; border-style: solid; border-color: #999999; width: 612.7272338867188px; background-color: #dddddd; font-size: 12px;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;"><div style="word-break: break-all; margin: 10px 0px; background-color: #ffffff;">[TestClass]</div><div style="word-break: break-all; margin: 10px 0px; background-color: #ffffff;">public class GameManagerTest</div><div style="word-break: break-all; margin: 10px 0px; background-color: #ffffff;">{</div><div style="word-break: break-all; margin: 10px 0px; background-color: #ffffff;">[TestMethod]</div><div style="word-break: break-all; margin: 10px 0px; background-color: #ffffff;">public void should_return_game_over_when_input_times_is_six_and_result_is_wrong()</div><div style="word-break: break-all; margin: 10px 0px; background-color: #ffffff;">{</div><div style="word-break: break-all; margin: 10px 0px; background-color: #ffffff;">IGuesser guess = new Guesser(new AnswerGeneratorForTest());</div><div style="word-break: break-all; margin: 10px 0px; background-color: #ffffff;">var game = new GameManager(guess);</div><div style="word-break: break-all; margin: 10px 0px; background-color: #ffffff;">var input = "1368";</div><div style="word-break: break-all; margin: 10px 0px; background-color: #ffffff;">var maxtimes = 6;</div><div style="word-break: break-all; margin: 10px 0px; background-color: #ffffff;">var actual = false;</div><div style="word-break: break-all; margin: 10px 0px; background-color: #ffffff;">for (var time = 0; time &lt; maxtimes; time++)</div><div style="word-break: break-all; margin: 10px 0px; background-color: #ffffff;">{</div><div style="word-break: break-all; margin: 10px 0px; background-color: #ffffff;">game.Guess(input);</div><div style="word-break: break-all; margin: 10px 0px; background-color: #ffffff;">}</div><div style="word-break: break-all; margin: 10px 0px; background-color: #ffffff;">actual = game.IsGameOver;</div><div style="word-break: break-all; margin: 10px 0px; background-color: #ffffff;">Assert.AreEqual(true, actual);</div><div style="word-break: break-all; margin: 10px 0px; background-color: #ffffff;">}</div><div style="word-break: break-all; margin: 10px 0px; background-color: #ffffff;">}</div></td></tr></tbody></table><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　实现GameManager让测试通过。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;"><table align="center" style="word-break: break-all; border-style: solid; border-color: #999999; width: 612.7272338867188px; background-color: #dddddd; font-size: 12px;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;"><div style="word-break: break-all; margin: 10px 0px;">public class GameManager</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">private readonly IGuesser guesser;</div><div style="word-break: break-all; margin: 10px 0px;">public bool IsGameOver { get; private set; }</div><div style="word-break: break-all; margin: 10px 0px;">private const int MAX_TIMES = 6;</div><div style="word-break: break-all; margin: 10px 0px;">private int times;</div><div style="word-break: break-all; margin: 10px 0px;">public GameManager(IGuesser guesser)</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">this.guesser = guesser;</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">public void Guess(string input)</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">times++;</div><div style="word-break: break-all; margin: 10px 0px;">IsGameOver = times == MAX_TIMES;</div><div style="word-break: break-all; margin: 10px 0px;">guesser.Guess(input);</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">}</div></td></tr></tbody></table><div style="word-break: break-all; line-height: normal !important; margin: 10px 0px;"><a href="http://www.51testing.com/batch.download.php?aid=44127" target="_blank" sl-processed="1" style="word-break: break-all; color: #202859; text-decoration: none;"><img src="http://www.51testing.com/attachments/2014/01/14982672_201401161828051JgUX.jpg" border="0" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px;"  alt="" /></a></div><div style="word-break: break-all; margin: 10px 0px; line-height: normal !important;">&nbsp; &nbsp; ok</div></div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　猜测数字</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　输入验证</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　生成答案</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　输入次数</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　输出猜测结果</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　输入猜测结果。这里包含一个猜对的情况下应该返回"you win"并且Gameover。其他输入返回的结果，在Guesser和validator中已经Cover了。挑几个来测试一下输入输出。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;"><table align="center" style="word-break: break-all; border-style: solid; border-color: #999999; width: 612.7272338867188px; background-color: #dddddd; font-size: 12px;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;"><div style="word-break: break-all; margin: 10px 0px;">[TestClass]</div><div style="word-break: break-all; margin: 10px 0px;">public class GameManagerTest</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">private _gameManager _game;</div><div style="word-break: break-all; margin: 10px 0px;">[TestInitialize]</div><div style="word-break: break-all; margin: 10px 0px;">public void Init()</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">IGuesser guesser = new Guesser(new AnswerGeneratorForTest());</div><div style="word-break: break-all; margin: 10px 0px;">_game = new _gameManager(guesser);</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">[TestMethod]</div><div style="word-break: break-all; margin: 10px 0px;">public void should_return__game_over_when_input_times_is_six_and_result_is_wrong()</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">const string input = "1368";</div><div style="word-break: break-all; margin: 10px 0px;">const int maxtimes = 6;</div><div style="word-break: break-all; margin: 10px 0px;">var actual = false;</div><div style="word-break: break-all; margin: 10px 0px;">for (var time = 0; time &lt; maxtimes; time++)</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">_game.Guess(input);</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">actual = _game.Is_gameOver;</div><div style="word-break: break-all; margin: 10px 0px;">Assert.AreEqual(true, actual);</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">[TestMethod]</div><div style="word-break: break-all; margin: 10px 0px;">public void should_return_you_win_and__game_is_over_when_input_is_equal_answer_number()</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">const string input = "2975";</div><div style="word-break: break-all; margin: 10px 0px;">var actual = _game.Guess(input);</div><div style="word-break: break-all; margin: 10px 0px;">Assert.AreEqual("You win!", actual);</div><div style="word-break: break-all; margin: 10px 0px;">Assert.AreEqual(true, _game.Is_gameOver);</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">[TestMethod]</div><div style="word-break: break-all; margin: 10px 0px;">public void should_return_try_again_input_must_be_four_digits_when_input_is_not_equal_four_digits()</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">const string input = "15243";</div><div style="word-break: break-all; margin: 10px 0px;">var actual = _game.Guess(input);</div><div style="word-break: break-all; margin: 10px 0px;">Assert.AreEqual("try again the input must be four digits.", actual);</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">[TestMethod]</div><div style="word-break: break-all; margin: 10px 0px;">public void should_return_try_again_input_can_not_be_empty_when_input_is_empty()</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">const string input = "";</div><div style="word-break: break-all; margin: 10px 0px;">var actual = _game.Guess(input);</div><div style="word-break: break-all; margin: 10px 0px;">Assert.AreEqual("try again the input can't be empty.", actual);</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">[TestMethod]</div><div style="word-break: break-all; margin: 10px 0px;">public void should_return_try_again_input_must_be_fully_digital_when_input_is_not_all_digital()</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">const string input = "a4sw";</div><div style="word-break: break-all; margin: 10px 0px;">var actual = _game.Guess(input);</div><div style="word-break: break-all; margin: 10px 0px;">Assert.AreEqual("try again the input must be fully digital.", actual);</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">}</div></td></tr></tbody></table><br /><br /><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">修改GameManager类，让所有CASE PASS.</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;"><table align="center" style="word-break: break-all; border-style: solid; border-color: #999999; width: 612.7272338867188px; background-color: #dddddd; font-size: 12px;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;"><div style="word-break: break-all; margin: 10px 0px;">public string Guess(string input)</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">times++;</div><div style="word-break: break-all; margin: 10px 0px;">IsGameOver = times == MAX_TIMES;</div><div style="word-break: break-all; margin: 10px 0px;">var validator = new Validator();</div><div style="word-break: break-all; margin: 10px 0px;">if (!validator.Validate(input))</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">return "try again " + validator.ErrorMsg;</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">var result = guesser.Guess(input);</div><div style="word-break: break-all; margin: 10px 0px;">if (result == "4a0b")</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">IsGameOver = true;</div><div style="word-break: break-all; margin: 10px 0px;">return "You win!";</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">return "try again result is " + result + ".";</div><div style="word-break: break-all; margin: 10px 0px;">}</div></td></tr></tbody></table></div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;"><a href="http://www.51testing.com/batch.download.php?aid=44128" target="_blank" sl-processed="1" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><img src="http://www.51testing.com/attachments/2014/01/14982672_201401161828052hIbH.jpg" border="0" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px;"  alt="" /></a></div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　猜测数字</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　输入验证</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　生成答案</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　输入次数</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　输出猜测结果</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　最后：完善GameManager类的work flow。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;"><table align="center" style="word-break: break-all; border-style: solid; border-color: #999999; width: 612.7272338867188px; background-color: #dddddd; font-size: 12px;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;"><div style="word-break: break-all; margin: 10px 0px;">public class GameManager</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">private const int MAX_TIMES = 6;</div><div style="word-break: break-all; margin: 10px 0px;">private int times;</div><div style="word-break: break-all; margin: 10px 0px;">private readonly IGuesser guesser;</div><div style="word-break: break-all; margin: 10px 0px;">public bool IsGameOver { get; private set; }</div><div style="word-break: break-all; margin: 10px 0px;">public GameManager(IGuesser guesser)</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">this.guesser = guesser;</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">private void Start()</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">times = 0;</div><div style="word-break: break-all; margin: 10px 0px;">IsGameOver = false;</div><div style="word-break: break-all; margin: 10px 0px;">OutputGameHeader();</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">public void Run()</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">Start();</div><div style="word-break: break-all; margin: 10px 0px;">while (!IsGameOver)</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">Console.WriteLine();</div><div style="word-break: break-all; margin: 10px 0px;">Console.WriteLine(string.Format("[The {0}st time ] : please input number!", times + 1));</div><div style="word-break: break-all; margin: 10px 0px;">var input = Console.ReadLine();</div><div style="word-break: break-all; margin: 10px 0px;">if (IsExit(input)) continue;</div><div style="word-break: break-all; margin: 10px 0px;">var result = Guess(input);</div><div style="word-break: break-all; margin: 10px 0px;">Console.WriteLine(result);</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">OutputGamefooter();</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">private bool IsExit(string input)</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">if (input.ToLower().Trim() == "exit")</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">Console.WriteLine("Make sure to exit game?(Y/N)");</div><div style="word-break: break-all; margin: 10px 0px;">var readLine = Console.ReadLine();</div><div style="word-break: break-all; margin: 10px 0px;">if (readLine != null)</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">var isexit = readLine.ToLower().Trim();</div><div style="word-break: break-all; margin: 10px 0px;">if (isexit == "y")</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">IsGameOver = true;</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">return true;</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">return false;</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">public string Guess(string input)</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">times++;</div><div style="word-break: break-all; margin: 10px 0px;">IsGameOver = times == MAX_TIMES;</div><div style="word-break: break-all; margin: 10px 0px;">var validator = new Validator();</div><div style="word-break: break-all; margin: 10px 0px;">if (!validator.Validate(input))</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">return "try again " + validator.ErrorMsg;</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">var result = guesser.Guess(input);</div><div style="word-break: break-all; margin: 10px 0px;">if (result == "4a0b")</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">IsGameOver = true;</div><div style="word-break: break-all; margin: 10px 0px;">return "You win!";</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">return "try again result is " + result + ".";</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">private void OutputGameHeader()</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">Console.Clear();</div><div style="word-break: break-all; margin: 10px 0px;">Console.WriteLine(" &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;--- Game Start! ---");</div><div style="word-break: break-all; margin: 10px 0px;">Console.WriteLine("---------------------------------------------------------------");</div><div style="word-break: break-all; margin: 10px 0px;">Console.WriteLine("| You can input a number or input exit for exiting this game! |");</div><div style="word-break: break-all; margin: 10px 0px;">Console.WriteLine("---------------------------------------------------------------");</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">private void OutputGamefooter()</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">Console.WriteLine("--------------------------------");</div><div style="word-break: break-all; margin: 10px 0px;">Console.WriteLine("| Game Over! &nbsp;[Answer] is " + guesser.AnswerNumber + " |");</div><div style="word-break: break-all; margin: 10px 0px;">Console.WriteLine("--------------------------------");</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">Program.cs</div><div style="word-break: break-all; margin: 10px 0px;">class Program</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">static void Main(string[] args)</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">var isRepeatGame = false;</div><div style="word-break: break-all; margin: 10px 0px;">do</div><div style="word-break: break-all; margin: 10px 0px;">{</div><div style="word-break: break-all; margin: 10px 0px;">IGuesser guesser = new Guesser(new AnswerGenerator());</div><div style="word-break: break-all; margin: 10px 0px;">var game = new GameManager(guesser);</div><div style="word-break: break-all; margin: 10px 0px;">game.Run();</div><div style="word-break: break-all; margin: 10px 0px;">Console.WriteLine("Try again?(Y/N)");</div><div style="word-break: break-all; margin: 10px 0px;">var line = Console.ReadLine();</div><div style="word-break: break-all; margin: 10px 0px;">if (line == null) continue;</div><div style="word-break: break-all; margin: 10px 0px;">var readLine = line.ToLower().Trim();</div><div style="word-break: break-all; margin: 10px 0px;">isRepeatGame = readLine == "y";</div><div style="word-break: break-all; margin: 10px 0px;">} while (isRepeatGame);</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">}</div></td></tr></tbody></table></div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　跑下所有的测试。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;"><a href="http://www.51testing.com/batch.download.php?aid=44130" target="_blank" sl-processed="1" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><img src="http://www.51testing.com/attachments/2014/01/14982672_201401161828054oxlK.jpg" border="0" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px;"  alt="" /><br /><br /><br /></a></div></div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">到这里。这个游戏的基本功能算做完了。做的比较简单。测试和产品代码也比较随意。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　大家也可以试着做一做。感受感受测试驱动产品代码。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　运行效果</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;"><a href="http://www.51testing.com/batch.download.php?aid=44129" target="_blank" sl-processed="1" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><img src="http://www.51testing.com/attachments/2014/01/14982672_201401161828053l91j.jpg" border="0" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px;"  alt="" /></a></div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　下面是我在实践TDD中遇到的一些问题、以及我个人对它们的理解。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　（1）先写测试在写代码开发速度降低了。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　开发前期速度确实很慢。当项目越来越大。越来越复杂的时候。改一个bug，或者修改story之后。如何确保产品代码是否正确。手动测试需要多少时间呢？或者调试的时间有多长呢？有了这些测试。可以最大限度的节省你的时间。也许跑一遍测试就可以定位BUG。测试过了。你的修改也就没问题了。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　（2）TDD驱动出来的代码。维护性、扩展性如何。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　TDD有益于设计。把一个复杂的需求拆分成若干个小模块的过程当中，其实就在思考设计。如何保证每个小模块的职责单一。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　（3）后写测试可以不？</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　我的理解是：第一 测试驱动开发是通过测试去驱动产品代码的，如果遇到一个很难的模块（你写不出来的），就可以通过测试一点点的去驱动。第二 如果在开发之后写测试的话，问问自己，会写吗？或者是能写全吗？如果有足够的信心。也可以写。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　（4）TDD的产物可以方便后期的测试。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　试想一下，项目到了后期，在庞大的系统面前，我们要修改某个类、某个方法、修改某个BUG、添加或扩展某个功能的时候。是不感觉特没安全感？会不会为了去找由修改一个小功能而导致其他功能崩溃的原因而抓狂呢？会不会为了定位一个BUG而在各个类之间不断的徘徊呢？会不会感觉到牵一发动全身的感觉呢？软件的坏味等等都会导致这种问题出现。到时候不但被老板骂，还要加班！还要陷入无止尽的各种调试中。(最主要的是你把TEAM里的MM给连累了！)。想避免这种问题吗？想尽快定位BUG的位置吗？如果你想！</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　<strong style="word-break: break-all; line-height: normal !important;">说点体会：</strong></div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　（1）清晰的测试方法命名，让我们省去了文档维护的时间。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　（2）站在不同角度分析用户需求。拆分Story有益于你的设计（DI）。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　（3）所有TDD留下来的测试。可用来做自动化测试，无论你是修BUG，或者添功能。都可以通过自动化测试，快速得到反馈。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　（4）有了重构的保证。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　（5）进度可视化。可以看出一个复杂的模块，自己完成了多少。（有多少CASE通过）。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　（6）小范围迭代。把当前工作重心放在当前这个&#8220;小步&#8221;上。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　<strong style="word-break: break-all; line-height: normal !important;">需要注意的：</strong></div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　（1）把握好测试的粒度。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　（2）测试要尽可能的简单。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　（3）测试不要依赖可变。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　（4）断言优先。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　其实TDD真正有威力的地方是Story划分。以及复杂模块代码的驱动。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　以后如果有机会。能理解的更深。会把这两个写出来与大家分享分享。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　对这段时间的TDD做个小总结。TDD的范围比较广。而且也比较抽象。以后会加深对TDD的理解。也会把这些记录下来。</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">　　代码比较简单。没源码！</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;">相关文章：</div><div style="word-break: break-all; line-height: 21.59090805053711px; margin: 10px 0px; font-size: 11.818181991577148px;"><a href="http://www.51testing.com/html/19/n-857219.html" target="_blank" sl-processed="1" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;">测试驱动开发TDD(2)</a></div></div></div><img src ="http://www.blogjava.net/qileilove/aggbug/409198.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2014-01-22 09:42 <a href="http://www.blogjava.net/qileilove/archive/2014/01/22/409198.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Maven管理的Spring Web项目集成JUnit单元测试</title><link>http://www.blogjava.net/qileilove/archive/2013/10/31/405835.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Thu, 31 Oct 2013 03:12:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2013/10/31/405835.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/405835.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2013/10/31/405835.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/405835.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/405835.html</trackback:ping><description><![CDATA[<div style="word-break: break-all; line-height: 23.99305534362793px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;">　　<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">JUnit</strong></u></a>是一套优秀的<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">单元测试</strong></u></a>框架，而Maven是优秀的Java项目构建和管理工具，两者结合可以很方便地对项目进行<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">自动化测试</strong></u></a>。</div><div style="word-break: break-all; line-height: 23.99305534362793px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;">　　一般的简单Java应用就不多说了，一些框架会提供针对junit的扩展，使得测试变得更容易，例如Spring官方就提供了spring-test，用于提供获取ApplicationContext等方面的支持。</div><div style="word-break: break-all; line-height: 23.99305534362793px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;">　　首先要做的是，改变JUnit的实际执行类，将默认的执行类Suite替换为Spring提供的SpringJUnit4ClassRunner，也就是在测试类前面加上一个注解：</div><div style="word-break: break-all; line-height: 23.99305534362793px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;">　　@RunWith(SpringJUnit4ClassRunner.class)</div><div style="word-break: break-all; line-height: 23.99305534362793px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;">　　<strong style="word-break: break-all; line-height: normal !important;">然后，我们需要告诉这个测试类Spring配置文件的位置：</strong></div><div style="word-break: break-all; line-height: 23.99305534362793px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;">@ContextConfiguration(locations={"classpath:applicationContext.xml",</div><div style="word-break: break-all; line-height: 23.99305534362793px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;">"classpath:applicationContext-security.xml"，"file:src/main/webapp/WEB-INF/servlet.xml"})</div><div style="word-break: break-all; line-height: 23.99305534362793px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;">　　笔者这里展示了两种配置文件路径的写法。前两个是spring常见的配置文件，放在classpath根目录下，而&#8220;file&#8221;开头的路径是完全限定路径，默认是相对于实际的项目路径的，例如笔者使用Eclipse进行开发，这个路径的写法是相对于项目文件所在文件夹的根目录的。该写法适用于没有直接放在classpath下的一些<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">web</strong></u></a>相关的配置文件，例如本例展示的就是放在常见的WEB-INF目录下的一个文件。</div><div style="word-break: break-all; line-height: 23.99305534362793px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;">　　<strong style="word-break: break-all; line-height: normal !important;">基于以上描述，笔者写了一个Spring测试基类：</strong></div><div style="word-break: break-all; line-height: 23.99305534362793px; margin: 10px 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;"><table align="center" style="word-break: break-all; border-style: solid; border-color: #999999; width: 612.2222290039063px; background-color: #dddddd; font-size: 12px;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;"><div style="word-break: break-all; margin: 10px 0px;">package com.test.basic;</div><div style="word-break: break-all; margin: 10px 0px;">import org.apache.commons.logging.Log;</div><div style="word-break: break-all; margin: 10px 0px;">import org.apache.commons.logging.LogFactory;</div><div style="word-break: break-all; margin: 10px 0px;">import org.junit.Before;</div><div style="word-break: break-all; margin: 10px 0px;">import org.junit.runner.RunWith;</div><div style="word-break: break-all; margin: 10px 0px;">import org.springframework.test.context.ContextConfiguration;</div><div style="word-break: break-all; margin: 10px 0px;">import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;</div><div style="word-break: break-all; margin: 10px 0px;">@RunWith(SpringJUnit4ClassRunner.class)</div><div style="word-break: break-all; margin: 10px 0px;">@ContextConfiguration(locations={/*"file:src/main/webapp/WEB-INF/wxiot-servlet.xml",*/ "classpath:applicationContext.xml",</div><div style="word-break: break-all; margin: 10px 0px;">"classpath:applicationContext-security.xml"})</div><div style="word-break: break-all; margin: 10px 0px;">public classTestBase {</div><div style="word-break: break-all; margin: 10px 0px;">protected Log logger = LogFactory.getLog(TestBase.class);</div><div style="word-break: break-all; margin: 10px 0px;">@Before</div><div style="word-break: break-all; margin: 10px 0px;">//一些公用的&#8220;初始化&#8221;代码</div><div style="word-break: break-all; margin: 10px 0px;">public void before(){</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">}</div></td></tr></tbody></table><br /><br /><div style="word-break: break-all; margin: 10px 0px;">　　有了这个基类，我们就可以动手写各个模块的测试类了，只要在定义测试类的时候继承TestBase，并在具体的方法前面加上@Test注解，笔者这里给出一个测试类的简单示例：</div><div style="word-break: break-all; margin: 10px 0px;"><table align="center" style="word-break: break-all; border-style: solid; border-color: #999999; width: 612.2222290039063px; background-color: #dddddd; font-size: 12px;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;"><div style="word-break: break-all; margin: 10px 0px;">import org.junit.Assert;</div><div style="word-break: break-all; margin: 10px 0px;">import org.junit.Test;</div><div style="word-break: break-all; margin: 10px 0px;">import org.springframework.beans.factory.annotation.Autowired;</div><div style="word-break: break-all; margin: 10px 0px;">import com.reports.util.ActiveMQSender;</div><div style="word-break: break-all; margin: 10px 0px;">import com.test.basic.TestBase;</div><div style="word-break: break-all; margin: 10px 0px;">public classActiveMQSenderTest extends TestBase {</div><div style="word-break: break-all; margin: 10px 0px;">@Autowired</div><div style="word-break: break-all; margin: 10px 0px;">ActiveMQSendersender;</div><div style="word-break: break-all; margin: 10px 0px;">@Test</div><div style="word-break: break-all; margin: 10px 0px;">public void sendQTest(){</div><div style="word-break: break-all; margin: 10px 0px;">Assert.assertNull(sender.sendInformationQ("发，布。到？队！列&#8220;的￥信息", "20131023102122", "20131025102122"));</div><div style="word-break: break-all; margin: 10px 0px;">Assert.assertNotNull(sender.sendInformationQ("发，布。到？队！列&#8220;的￥信息", "20131023102122", "2013-10-26 10:21:22"));</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">@Test</div><div style="word-break: break-all; margin: 10px 0px;">public void sendTopicTest(){</div><div style="word-break: break-all; margin: 10px 0px;">Assert.assertNull(sender.sendInformationTopic("发，布。到？Topic！的&#8221;信￥息", "20131023102122","20131025102122") );</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">}</div></td></tr></tbody></table></div><div style="word-break: break-all; margin: 10px 0px;">　　最后执行&#8220;RunAs -&gt; JUnit Test&#8221;即可开始JUnit单元测试了，使用Maven命令还可以方便地对特定目录下（通常是src/test/java目录）的所有测试类进行批量测试。</div><div style="word-break: break-all; margin: 10px 0px;">　　对于Java Web项目，某些业务类可能会带有使用ServletContext等Web容器相关类的代码，对于这些类我们就不能直接用JUnit来测试了，因为默认JUnit是没有Web容器的，我们通常需要借助其它相关的辅助类或者模拟Web容器来进行测试，例如利用struts2-junit-plugin的帮助来测试struts的action，这些内容网上的资料很多，不在本文的讨论范围之内。</div><div style="word-break: break-all; margin: 10px 0px;">　　一些用到了web容器的业务类只需稍加修改，就可以直接用于JUnit测试。假设一个业务类使用了ServletContext来获取容器内的资源，例如一个配置文件：</div><div style="word-break: break-all; margin: 10px 0px;">　　InputStream is=context.getResourceAsStream("/WEB-INF/configs/command-sender.xml");</div><div style="word-break: break-all; margin: 10px 0px;">　　其中context变量保存了Web容器的ServletContext，如果直接使用JUnit来测试，必然导致空指针异常。此时我们可以稍作修改：</div><div style="word-break: break-all; margin: 10px 0px;"><table align="center" style="word-break: break-all; border-style: solid; border-color: #999999; width: 612.2222290039063px; background-color: #dddddd; font-size: 12px;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;"><div style="word-break: break-all; margin: 10px 0px;">InputStream is = null;</div><div style="word-break: break-all; margin: 10px 0px;">if(null != context){</div><div style="word-break: break-all; margin: 10px 0px;">is= context.getResourceAsStream("/WEB-INF/configs/command-sender.xml");</div><div style="word-break: break-all; margin: 10px 0px;">}else{//JUnit Test环境下，使用ApplicationContext获取配置文件</div><div style="word-break: break-all; margin: 10px 0px;">//NearEast 2013-10-22</div><div style="word-break: break-all; margin: 10px 0px;">try {</div><div style="word-break: break-all; margin: 10px 0px;">is= SpringContextHolder.getApplicationContext().</div><div style="word-break: break-all; margin: 10px 0px;">getResource("file:src/main/webapp/WEB-INF/configs/command-sender.xml").getInputStream();</div><div style="word-break: break-all; margin: 10px 0px;">}catch(IOException e) {</div><div style="word-break: break-all; margin: 10px 0px;">e.printStackTrace();</div><div style="word-break: break-all; margin: 10px 0px;">}</div><div style="word-break: break-all; margin: 10px 0px;">}</div></td></tr></tbody></table></div><div style="word-break: break-all; margin: 10px 0px;">　　其中，SpringContextHolder是笔者在《在Java Web应用中获取Spring管理的Bean的方法》提到的一个工具类，SpringContextHolder.getApplicationContext()即获得Spring的ApplicationContext。资源的路径使用了上文提到的完全限定路径，我们也可以将其写为类似&#8220;file:E:/Workspaces/workspace_test/test/src/main/webapp/WEB-INF/configs/command-sender.xml"&#8221;的形式。经过上述修改之后，我们的业务类也可以直接利用JUnit执行测试了。</div><div style="word-break: break-all; margin: 10px 0px;">　　当然我们还可以用其它方式获取ApplicationContext，例如让业务类实现ApplicationContextAware接口，并使用一个变量保存ApplicationContext。</div><div style="word-break: break-all; margin: 10px 0px;"></div><div style="word-break: break-all; margin: 10px 0px; height: 21px; position: relative; width: 627.1875px;"></div></div><img src ="http://www.blogjava.net/qileilove/aggbug/405835.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2013-10-31 11:12 <a href="http://www.blogjava.net/qileilove/archive/2013/10/31/405835.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>持续集成之路——数据访问层单元测试遇到的问题</title><link>http://www.blogjava.net/qileilove/archive/2013/07/25/401943.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Thu, 25 Jul 2013 02:37:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2013/07/25/401943.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/401943.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2013/07/25/401943.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/401943.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/401943.html</trackback:ping><description><![CDATA[<p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 23.99305534362793px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;">　在编写数据访问层的<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">单元测试</strong></u></a>时，遇到不少问题，有些问题可以很容易<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">Google</strong></u></a>到解决方法，而有些只能自己研究解决。这里分享几个典型的问题以及解决方法。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 23.99305534362793px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;">　　先交代一下用到的测试框架 Spring&nbsp;<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">Test</strong></u></a>&nbsp;+ SpringTestDbUnit + DbUnit。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 23.99305534362793px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;"><strong style="word-break: break-all; line-height: normal !important;">　　一、先说一个低级的问题。</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 23.99305534362793px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;">　　Spring通过&lt;jdbc：embedded-database&gt;标签提供对内存数据的支持，形如：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 23.99305534362793px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;"></p><table align="center" style="word-break: break-all; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; border-style: solid; border-color: #999999; background-color: #dddddd; width: 612.2222290039063px;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;">&lt;jdbc:embeded-database id="dataSource" type="HSQL"&gt;</td></tr></tbody></table><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 23.99305534362793px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;"></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 23.99305534362793px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;">　　可是在启动时，却总是提示错误：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 23.99305534362793px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;">　　Caused by： org.xml.sax.SAXParseException； lineNumber： 31； columnNumber： 57； cvc-complex-type.2.4.c： 通配符的匹配很全面， 但无法找到元素 'jdbc：embedded-database' 的声明。<br style="word-break: break-all; line-height: normal !important;" />　　at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java：198)<br style="word-break: break-all; line-height: normal !important;" />　　at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java：134)<br style="word-break: break-all; line-height: normal !important;" />　　at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java：437)<br style="word-break: break-all; line-height: normal !important;" />　　&#8230;&#8230;</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 23.99305534362793px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;">　　翻来覆去对标签修改了很多次，文档和dtd也看了很多遍，始终没有发现问题。最后无意间看到context文件头部对标签的声明上好像有问题：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 23.99305534362793px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;"></p><table align="center" style="word-break: break-all; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; border-style: solid; border-color: #999999; background-color: #dddddd; width: 612.2222290039063px;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;">&lt;beans xmlns=http://www.springframework.org/schema/beans<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xmlns:p=http://www.springframework.org/schema/p<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xmlns:context=http://www.springframework.org/schema/context<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xmlns:tx=http://www.springframework.org/schema/tx xmlns:jpa=http://www.springframework.org/schema/data/jpa<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xmlns:task=http://www.springframework.org/schema/task xmlns:aop=http://www.springframework.org/schema/aop<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xmlns:jdbc=http://www.springframework.org/schema/jdbc<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; http://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-3.2.xsdBR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; http://www.springframework.org/schema/taskhttp://www.springframework.org/schema/task/spring-task-3.2.xsd<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/&lt;SPAN style="COLOR: #ff0000"&gt;tx&lt;/SPAN&gt;/spring-jdbc-3.2.xsd"&gt;</td></tr></tbody></table><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 23.99305534362793px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;"></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 23.99305534362793px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;">　　仔细看了下，原来当时从tx处复制声明时，只是将最后的tx改成了jdbc，却忘记了将路径中tx改为jdbc。更改后，启动正常。所有，如果有同学遇到类似的问题，应该先检查头部。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 23.99305534362793px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;">　　<strong style="word-break: break-all; line-height: normal !important;">二、外键关联导致的删除失败。</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 23.99305534362793px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;">　　在刚开始写测试时，每个用例单独运行都没有问题，可是一旦一起运行，就出现下面的异常：<br style="word-break: break-all; line-height: normal !important;" />　　Tests run: 5, Failures: 0, Errors: 3, Skipped: 0, Time elapsed: 0.879 sec &lt;&lt;&lt; FAILURE! - in com.noyaxe.nso.service.DeviceServiceTest<br style="word-break: break-all; line-height: normal !important;" />　　testInitializedForBindedSpaceForceBind(com.noyaxe.nso.service.DeviceServiceTest)&nbsp; Time elapsed: 0.309 sec&nbsp; &lt;&lt;&lt; ERROR!<br style="word-break: break-all; line-height: normal !important;" />　　<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">java</strong></u></a>.sql.SQLIntegrityConstraintViolationException: integrity constraint violation: foreign key no action; FK_L6IDVK78B2TLU8NO6EDJ0G6U8 table: CUSTOM_TABLE_COLUMN_SPACE_TYPE<br style="word-break: break-all; line-height: normal !important;" />　　at org.hsqldb.jdbc.Util.sqlException(Unknown Source)<br style="word-break: break-all; line-height: normal !important;" />　　at org.hsqldb.jdbc.Util.sqlException(Unknown Source)<br style="word-break: break-all; line-height: normal !important;" />　　at org.hsqldb.jdbc.JDBCStatement.fetchResult(Unknown Source)<br style="word-break: break-all; line-height: normal !important;" />　　&#8230;&#8230;<br style="word-break: break-all; line-height: normal !important;" />　　&#8230;&#8230;</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 23.99305534362793px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;">　　Caused by: org.hsqldb.HsqlException: integrity constraint violation: foreign key no action; FK_L6IDVK78B2TLU8NO6EDJ0G6U8 table: CUSTOM_TABLE_COLUMN_SPACE_TYPE</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 23.99305534362793px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; background-color: #ffffff;">　　at org.hsqldb.error.Error.error(Unknown Source)<br style="word-break: break-all; line-height: normal !important;" />　　at org.hsqldb.StatementDML.performReferentialActions(Unknown Source)<br style="word-break: break-all; line-height: normal !important;" />　　at org.hsqldb.StatementDML.delete(Unknown Source)<br style="word-break: break-all; line-height: normal !important;" />　　at org.hsqldb.StatementDML.executeDeleteStatement(Unknown Source)<br style="word-break: break-all; line-height: normal !important;" />　　at org.hsqldb.StatementDML.getResult(Unknown Source)<br style="word-break: break-all; line-height: normal !important;" />　　at org.hsqldb.StatementDMQL.execute(Unknown Source)<br style="word-break: break-all; line-height: normal !important;" />　　at org.hsqldb.Session.executeCompiledStatement(Unknown Source)<br style="word-break: break-all; line-height: normal !important;" />　　at org.hsqldb.Session.executeDirectStatement(Unknown Source)<br style="word-break: break-all; line-height: normal !important;" />　　at org.hsqldb.Session.execute(Unknown Source)<br style="word-break: break-all; line-height: normal !important;" />　　at org.hsqldb.jdbc.JDBCStatement.fetchResult(Unknown Source)<br style="word-break: break-all; line-height: normal !important;" />　　&#8230;&#8230;<br /><p style="word-break: break-all; margin: 10px 0px; padding: 0px;">　看异常信息，应该是删除记录时，外键级联导致的问题。在实体类里改变级联设置并不起作用。最后在StackOverflow上找了一个解决方法：编写一个类，继承AbstractTestExecutionListener，在beforeTestClass中取消级联依赖。具体如下：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px;"></p><table align="center" style="word-break: break-all; color: #333333; font-size: 12px; border-style: solid; border-color: #999999; background-color: #dddddd; width: 612.2222290039063px;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;"><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">import org.dbunit.database.DatabaseDataSourceConnection;<br style="word-break: break-all; line-height: normal !important;" />import org.dbunit.database.IDatabaseConnection;<br style="word-break: break-all; line-height: normal !important;" />import org.springframework.test.context.TestContext;<br style="word-break: break-all; line-height: normal !important;" />import org.springframework.test.context.support.AbstractTestExecutionListener;</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">import javax.sql.DataSource;</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">public class ForeignKeyDisabling extends AbstractTestExecutionListener {<br style="word-break: break-all; line-height: normal !important;" />&nbsp;&nbsp;&nbsp; @Override<br style="word-break: break-all; line-height: normal !important;" />&nbsp;&nbsp;&nbsp; public void beforeTestClass(TestContext testContext) throws Exception {<br style="word-break: break-all; line-height: normal !important;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IDatabaseConnection dbConn = new DatabaseDataSourceConnection(<br style="word-break: break-all; line-height: normal !important;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; testContext.getApplicationContext().getBean(DataSource.class)<br style="word-break: break-all; line-height: normal !important;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; );<br style="word-break: break-all; line-height: normal !important;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dbConn.getConnection().prepareStatement("SET DATABASE REFERENTIAL INTEGRITY FALSE").execute();</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">&nbsp;&nbsp;&nbsp; }<br style="word-break: break-all; line-height: normal !important;" />}</p></td></tr></tbody></table><p style="word-break: break-all; margin: 10px 0px; padding: 0px;"></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px;">　　把这个新的Listener添加测试类的注解中：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px;"></p><table align="center" style="word-break: break-all; color: #333333; font-size: 12px; border-style: solid; border-color: #999999; background-color: #dddddd; width: 612.2222290039063px;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;">@RunWith(SpringJUnit4ClassRunner.class)<br style="word-break: break-all;" />@ContextConfiguration("classpath:applicationContext-test.xml")<br style="word-break: break-all;" />@TestExecutionListeners({<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DependencyInjectionTestExecutionListener.class,<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DirtiesContextTestExecutionListener.class,<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TransactionDbUnitTestExecutionListener.class,<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ForeignKeyDisabling.class})</td></tr></tbody></table><p style="word-break: break-all; margin: 10px 0px; padding: 0px;"></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px;">　　参考：http：//stackoverflow.com/questions/2685274/tdd-with-hsqldb-removing-foreign-keys</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px;"><strong style="word-break: break-all; line-height: normal !important;">　　三、PROPERTY_DATATYPE_FACTORY引起的警告</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px;">　　在jenkins中构建时，总是可以看到如下的警告信息：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px;">　　WARN&nbsp;&nbsp; getDataTypeFactory， Potential problem found： The configured data type factory 'class org.dbunit.dataset.datatype.DefaultDataTypeFactory' might cause problems with the current database 'HSQL Database Engine' (e.g. some datatypes may not be supported properly). In rare cases you might see this message because the list of supported database products is incomplete (list=[derby]). If so please request a java-class update via the forums.If you are using your own IDataTypeFactory extending DefaultDataTypeFactory， ensure that you override getValidDbProducts() to specify the supported database products.</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px;">　　意思很好理解，就说默认的DataTypeFactory可能会引起问题，建议设置该属性值。解决方法也很明显：就是设置数据库连接的PROPERTY_DATATYPE_FACTORY属性的值。尝试了用Before、BeforeClass或者自定义ExecutionListener中都无法实现对该属性的设置。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px;">　　那就只能先找到抛出这个异常的位置，然后向前推，逐步找到获取连接的地方。最后发现，连接是在DbUnitTestExecutionListener.prepareDatabaseConnection中获取连接，并且没有做什么进一步的处理，所以前面的设置都不起作用。看来又只能通过重写源代码来达成目的了。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px;">　　直接上源码吧：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px;">　　CustomTransactionDbUnitTestExecutionListener类： 完全复制DbUnitTestExecutionListener，只是增加一句代码。注意该类的包路径和DbUnitTestExecutionListener一致。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px;"></p><table align="center" style="word-break: break-all; color: #333333; font-size: 12px; border-style: solid; border-color: #999999; background-color: #dddddd; width: 612.2222290039063px;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;">private void prepareDatabaseConnection(TestContext testContext, String databaseConnectionBeanName) throws Exception {<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object databaseConnection = testContext.getApplicationContext().getBean(databaseConnectionBeanName);<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (databaseConnection instanceof DataSource) {<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; databaseConnection = DatabaseDataSourceConnectionFactoryBean.newConnection((DataSource) databaseConnection);<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Assert.isInstanceOf(IDatabaseConnection.class, databaseConnection);<br style="word-break: break-all;" />&nbsp;&lt;SPAN style="COLOR: #33cc00"&gt;((IDatabaseConnection)databaseConnection).getConfig().setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new HsqldbDataTypeFactory());<br style="word-break: break-all;" />&lt;/SPAN&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; testContext.setAttribute(CONNECTION_ATTRIBUTE, databaseConnection);<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp; }</td></tr></tbody></table><br /><br /><p style="word-break: break-all; margin: 10px 0px; padding: 0px;">　绿色就是真正发挥作用的代码。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px;">　　可是这个类并不能直接饮用，而是通过TransactionDbUnitTestExecutionListener的CHAIN被调用的，而TransactionDbUnitTestExecutionListener同样无法更改，同样只能建一个自定义的TransactionDbUnitTestExecutionListener类，CustomTransactionDbUnitTestExecutionListener：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px;"></p><table align="center" style="word-break: break-all; color: #333333; font-size: 12px; border-style: solid; border-color: #999999; background-color: #dddddd; width: 612.2222290039063px;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;"><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">public class CustomTransactionDbUnitTestExecutionListener extends TestExecutionListenerChain {</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">&nbsp;&nbsp;&nbsp; private static final Class&lt;?&gt;[] CHAIN = { TransactionalTestExecutionListener.class,<br style="word-break: break-all; line-height: normal !important;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CustomDbUnitTestExecutionListener.class };</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">&nbsp;&nbsp;&nbsp; @Override<br style="word-break: break-all; line-height: normal !important;" />&nbsp;&nbsp;&nbsp; protected Class&lt;?&gt;[] getChain() {<br style="word-break: break-all; line-height: normal !important;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return CHAIN;<br style="word-break: break-all; line-height: normal !important;" />&nbsp;&nbsp;&nbsp; }<br style="word-break: break-all; line-height: normal !important;" />}</p></td></tr></tbody></table><p style="word-break: break-all; margin: 10px 0px; padding: 0px;"></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px;">　　那么测试类的注解也要修改：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px;"></p><table align="center" style="word-break: break-all; color: #333333; font-size: 12px; border-style: solid; border-color: #999999; background-color: #dddddd; width: 612.2222290039063px;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;">@RunWith(SpringJUnit4ClassRunner.class)<br style="word-break: break-all;" />@ContextConfiguration("classpath:applicationContext-test.xml")<br style="word-break: break-all;" />@TestExecutionListeners({<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DependencyInjectionTestExecutionListener.class,<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DirtiesContextTestExecutionListener.class,<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CustomTransactionDbUnitTestExecutionListener.class,<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ForeignKeyDisabling.class})</td></tr></tbody></table><p style="word-break: break-all; margin: 10px 0px; padding: 0px;"></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px;"><strong style="word-break: break-all; line-height: normal !important;">　　四、@Transactional标签引起的问题</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px;">　　按照spring-dbunit-test的文档中说法，可以使用@Transactional确保数据的清洁。使用简单，只需要将上面的注解增加一个@Transactional，</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px;"></p><table align="center" style="word-break: break-all; color: #333333; font-size: 12px; border-style: solid; border-color: #999999; background-color: #dddddd; width: 612.2222290039063px;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;">@RunWith(SpringJUnit4ClassRunner.class)<br style="word-break: break-all;" />@ContextConfiguration("classpath:applicationContext-test.xml")<br style="word-break: break-all;" />@Transactional<br style="word-break: break-all;" />@TestExecutionListeners({<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DependencyInjectionTestExecutionListener.class,<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DirtiesContextTestExecutionListener.class,<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CustomTransactionDbUnitTestExecutionListener.class,<br style="word-break: break-all;" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ForeignKeyDisabling.class})</td></tr></tbody></table><p style="word-break: break-all; margin: 10px 0px; padding: 0px;"></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px;">　　可是运行时，却出现了异常：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px;"></p><table align="center" style="word-break: break-all; color: #333333; font-size: 12px; border-style: solid; border-color: #999999; background-color: #dddddd; width: 612.2222290039063px;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;"><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">org.springframework.transaction.TransactionSystemException: Could not roll back JPA transaction; nested exception is javax.persistence.PersistenceException: unexpected error when rollbacking</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">at org.springframework.orm.jpa.JpaTransactionManager.doRollback(JpaTransactionManager.java:544)</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:846)</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:823)</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">at org.springframework.test.context.transaction.TransactionalTestExecutionListener$TransactionContext.endTransaction(TransactionalTestExecutionListener.java:588)</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">at org.springframework.test.context.transaction.TransactionalTestExecutionListener.endTransaction(TransactionalTestExecutionListener.java:297)</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">at org.springframework.test.context.transaction.TransactionalTestExecutionListener.afterTestMethod(TransactionalTestExecutionListener.java:192)</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">&#8230;&#8230;</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">Caused by: javax.persistence.PersistenceException: unexpected error when rollbacking</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">at org.hibernate.ejb.TransactionImpl.rollback(TransactionImpl.java:109)</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">at org.springframework.orm.jpa.JpaTransactionManager.doRollback(JpaTransactionManager.java:540)</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">... 32 more</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">Caused by: org.hibernate.TransactionException: rollback failed</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.rollback(AbstractTransactionImpl.java:215)</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">at org.hibernate.ejb.TransactionImpl.rollback(TransactionImpl.java:106)</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">... 33 more</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">Caused by: org.hibernate.TransactionException: unable to rollback against JDBC connection</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doRollback(JdbcTransaction.java:167)</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.rollback(AbstractTransactionImpl.java:209)</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">... 34 more</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">Caused by: java.sql.SQLNonTransientConnectionException: connection exception: connection does not exist</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">at org.hsqldb.jdbc.Util.sqlException(Unknown Source)</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">at org.hsqldb.jdbc.Util.sqlException(Unknown Source)</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">&#8230;&#8230;</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">... 35 more</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">Caused by: org.hsqldb.HsqlException: connection exception: connection does not exist</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">at org.hsqldb.error.Error.error(Unknown Source)</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">at org.hsqldb.error.Error.error(Unknown Source)</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">... 40 more</p></td></tr></tbody></table><br /><p style="word-break: break-all; margin: 10px 0px; padding: 0px;">　最后通过查看源代码发现，CustomDbUnitTestExecutionListener会先于TransactionalTestExecutionListener执行，而前者在执行完毕就关闭了数据库连接，后者在回滚时，就发生了连接不存在的异常。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px;">　　解决方法很简单，修改CustomTransactionalDbUnitTestExecutionListener:</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px;"></p><table align="center" style="word-break: break-all; color: #333333; font-size: 12px; border-style: solid; border-color: #999999; background-color: #dddddd; width: 612.2222290039063px;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;">private static final Class&lt;?&gt;[] CHAIN = {CustomDbUnitTestExecutionListener.class, TransactionalTestExecutionListener.class};</td></tr></tbody></table><p style="word-break: break-all; margin: 10px 0px; padding: 0px;"></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px;">　　也就是数组两个元素调换下位置。</p><br /><br /><br /><br /><br /><br /><br /></p><img src ="http://www.blogjava.net/qileilove/aggbug/401943.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2013-07-25 10:37 <a href="http://www.blogjava.net/qileilove/archive/2013/07/25/401943.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>敏捷开发中的测试——SpecDD模型2</title><link>http://www.blogjava.net/qileilove/archive/2013/06/17/400631.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Mon, 17 Jun 2013 02:19:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2013/06/17/400631.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/400631.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2013/06/17/400631.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/400631.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/400631.html</trackback:ping><description><![CDATA[<p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">下图是一张 SpecDD的基本结构图：</p><p align="center" style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"><a href="http://www.51testing.com/batch.download.php?aid=40417" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><img border="0" src="http://www.51testing.com/attachments/2013/06/346836_201306081731161ig8R.jpg" width="789" height="534" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px; width: 616px; height: 360px;"  alt="" /></a></p><p align="left" style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　从图上我们可以清楚地看到，<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">测试</strong></u></a>是贯穿于SpecDD整个过程的，从需求到开发到大规模测试，无一不显现着测试的影子。</p><p align="left" style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　不过虽然测试贯穿整个过程，但是其实是不同类别的测试，比如需求阶段的叫做&#8220;设计测试&#8220;，开发阶段的&#8220;验证测试&#8221;，而产品进入大规模测试阶段叫做&#8220;Full Cycle Testing&#8221;，而我今天想讲的 Floater QA，即使是属于开发阶段的测试，下面来主要介绍一下：</p><p align="left" style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　从英文上分析 Floater QA的意思大约是流浪的QA，引申开来大致就是这个QA不会去固定做一个<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">工作</strong></u></a>，而是会参与很多地方的测试，哪里有需要就会去哪里。（以下简称FQA）</p><p align="left" style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　那这个FQA有哪些地方需要去参与呢？</p><p align="left" style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　&#9679; 参与<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">测试用例</strong></u></a>的编写</p><p align="left" style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　&#9679; 参与功能最初的验证性测试，修改测试用例，并且给出改善建议</p><p align="left" style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　&#9679; 与开发人员与项目经理紧密合作解决所有阻碍下一步测试的问题</p><p align="left" style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　为什么需要有FQA这么一种QA的设置呢？</p><p align="left" style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　因为在实际的<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">软件开发</strong></u></a>过程中，我们可能会经常遇到一种情况，一个功能或者一个产品给QA去测试的时候，由于开发不可能把所有地方都测试过，所以一旦发现严重的问题，这些问题会阻碍QA去进一步的测试，但是开发不一定每次都是能第一时间去修复它，那也就使得对于这个功能的测试会因此暂停。如果这种问题不断累积的话，我们会发现一个更加严重的问题：开发很忙，因为有很多功能需要去做；而QA需要测试的功能也很多，但是却发现很多没法测试下去。</p><p align="left" style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　所以引入FQA这么一类人，他们跟开发与项目经理合作最紧密：</p><p align="left" style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　1、当功能还在开发的时候，先去写测试用例</p><p align="left" style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　2、当功能开始有Build可以测试的时候，FQA首先去介入测试，他的测试其实是为后面的正规测试做准备，所以要确保该功能基本功能能够工作正常，符合设计文档，发现了问题，需要直接面对面与开发沟通，快速修复，如果这个最初的测试无法通过FQA的测试，那意味着这个功能的开发部分工作还没有结束，无法让正式的QA团队去进行测试。（平常情况下，开发人员为了改进度，可能草草跑了一下功能就说做好了，导致以后发现很多问题，进而影响其他功能，影响整个进度，而FQA的出现，能让这种情况较少出现）</p><p align="left" style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　3、FQA测试完成后，开发人员可以正式把这个功能打到&#8220;待测试的状态&#8221;，让正轨的测试人员在各种的环境下进行更加细致的测试和<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">性能测试</strong></u></a>。</p><p align="left" style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　4、FQA测试的同时需要根据需要更新测试用例，让之后的正规QA测试可以做些参考。</p><p align="left" style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　所以，用一句话形容FQA的作用就是：帮助开发人员去高质量完成开发工作，帮助测试人员去顺利进行测试工作，帮助产品的开发能够在可控的范围下进行。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">相关链接：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"><a href="http://www.51testing.com/?action-viewnews-itemid-847469" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;">什么是SpecDD？</a></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"><a href="http://www.51testing.com/?action-viewnews-itemid-847470" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"></a><a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">敏捷开发</strong></u></a><a href="http://www.51testing.com/?action-viewnews-itemid-847470" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;">中的测试&#8212;&#8212;SpecDD模型</a></p><img src ="http://www.blogjava.net/qileilove/aggbug/400631.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2013-06-17 10:19 <a href="http://www.blogjava.net/qileilove/archive/2013/06/17/400631.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>五大敏捷原则——可以应用到每一种类型的开发过程</title><link>http://www.blogjava.net/qileilove/archive/2013/05/31/400017.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Fri, 31 May 2013 03:17:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2013/05/31/400017.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/400017.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2013/05/31/400017.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/400017.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/400017.html</trackback:ping><description><![CDATA[<p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;"><strong style="word-break: break-all; line-height: normal !important;">　（4）寻求快速反馈和持续改进</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;">　　改善最大的敌人是人类行为：没有人喜欢被批评，我们指的就是没有任何一个！</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;">　　这就是为什么每当我们在做某件事，我们不愿意展示给别人，除非我们认为它已经完成了，我们的观众能够&#8220;完全&#8221;理解我们所做的。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;">　　但正如你可能已经明白，这是反作用于编程的，因为如果我们等太久才得到反馈，我们不可能实现任何变更而不错过我们的交付目标。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;">　　那么，你能做些什么呢？</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;">　　基本上，克服害怕被批评的心理，作为一种政策要求，在工作中每个人展示给其他团队成员以及产品行销人员他的工作过程。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;">　　营造一种企业文化让人都知道如何给予和接受反馈。你通过确保反馈针对的是工作，而不是人，同时让人反馈产品的好和坏的方面（而不是只集中在需要修复的部分）来可以实现这一目标。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;">　　起初，这可能不是一件简单的事，但它会随着时间的推移会变得容易，从中获得的价值简直是不可思议的。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;">　　<strong style="word-break: break-all; line-height: normal !important;">（5）拥抱变化和有序工作</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;">　　这可能是敏捷实现的基石，无论你如何努力工作规划你的项目，无论你有多擅长，最终事物会改变，你需要调整你的计划。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;">　　但是，除去口号，你该怎么拥抱变化呢？</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;">　　首先，计划要少，不要深入但是要有，减少长期的，因为你无法准确地预见现实到底是几个月。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;">　　寻求反馈宜早不宜迟，确保，如果你不得不改变功能和计划，你在2.4周时知道，而不是6至9个月。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;">　　为改变做计划，并确保你的团队知道，变化确实会来，而且它会被接受，这使得他们当他们面临着这一现实和需要时，更容易应付它。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;">　　<strong style="word-break: break-all; line-height: normal !important;">小的变化应该是你工作方法的一部分</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;">　　你可以从敏捷的理解中获取最好的原则之一，正如产品和需求是不断变化的，所以你的工作流程应该是动态的，自适应。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;">　　能接受被提问关于你是否工作在最好的和最有效的方式，或者是是否你能在过程有或大或小的改进？</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;">　　能接受反馈，寻求它，甚至奖励给出反馈的人。一旦你能够引入接受反馈的企业文化，你将看到如何真正开始改善，甚至是他们自身。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;">　<strong style="word-break: break-all; line-height: normal !important;">　注：</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;">　　1、Jenkins，之前叫做Hudson，是基于Java 开发的一种持续集成工具，用于监控秩序重复的工作，包括：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;">　　I、持续的软件版本发布/测试项目。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;">　　II、监控外部调用执行的工作。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;">　　2、Atlassian Bamboo是一款持续集成构建服务器软件（Build Server）（非开源软件）。Bamboo 的特点： 简单的用户界面容易安装-顺利的话，5 分钟内就可以让运行起来！自动检测你的设置 - 如果你的Server 上使用了Maven，Ant 或者Java 设置， Bamboo 会自动检测他们； 连续的日志 - 监测你的build 的colour coded 日志；容易显示所有项目。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;">　　3、TeamCity是一款功能强大的持续集成（Continue Integration）工具，包括服务器端和客户端，目前支持Java，.NET项目开发。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;">　　TeamCity 提供一系列特性可以让团队快速实现持续继承：IDE 工具集成、各种消息通知、各种报表、项目的管理、分布式的编译等等，所有的这些，都是让你的团队快速享有持续集成带来的效率提升、高质量的软件保障。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; font-size: 12px;">　　使用 TeamCity，你能够在几分钟之内为你的项目配置一个构建服务器，它内建了持续单元测试，代码质量分析和早期的构建问题分析报告，你甚至可以在IDE 进行。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"><span style="font-size: 12px; line-height: 21.59375px; font-family: verdana, 'courier new';">　　TeamCity提供平滑的学习曲线，你可以逐步的学习经它的高级特性和功能，你很快就能加强你发布管理实践。本次发布，在可用性作了大量的改进，更新的IDE 插件支持 CVS 和SVN，另外还包括一些之前版本不具备的企业级的特性。</span>一些专业顾问可能不希望你知道的东西：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　<strong style="word-break: break-all; line-height: normal !important;">你并不需要在你的开发过程中作出重大改变就可以从<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none;"><u style="word-break: break-all;"><strong style="word-break: break-all;">敏捷</strong></u></a>原则得到很多好处</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　如果你花时间去真正了解敏捷（而并不只是在网络上重复的徘徊于支持和反对中），你就会认识到事实上<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">敏捷开发</strong></u></a>并不是一种方法论，而是一种可以应用于每个<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">软件开发</strong></u></a>的方法。当然，像SCRUM（Scrum 是一种迭代式增量软件开发过程，通常用于敏捷软件开发）和 XP（Extreme Programming 极限编程）的方法都旨在制定敏捷原则的具体使用，但这并不意味着你可以通过这些<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">工作</strong></u></a>方式来获得的敏捷开发的全部或大部分好处。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"><strong style="word-break: break-all; line-height: normal !important;">　　一些工作中使用到了敏捷可能你没有注意到</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　几个月前我们在与客户交谈的过程中，客户告诉我们，想要在工作中使用敏捷方法，但是在他们的团队中没有足够的时间实施SCRUM。该团队的经理提及曾经与一个SCRUM 顾问谈及敏捷开发的的实施，但是在进一步的考虑之后，他决定最好等待，直到当前产品发布，要在接下来6 到9 个月的时间实现所有必要过程的变动。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　顾问的建议给经理留下了非常深刻印象，他要求团队做出小的变化同时开始实施的一些顾问建议的想法。因此，每天早晨在喝咖啡和吃点心之后开15 到20 分钟小会议以及他们开始组织2或3人的程序员团队并使其尽可能在短周期内完成任务，而不是让每个程序员单独完成这样可能需要长达6 到8 周的时间才能完成的任务。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　他们所做的另一件事是让<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">测试</strong></u></a>人员更早的介入工作，更紧密地与开发人员合作，在编码阶段开始，测试人员将对尚未完成的产品执行初步测试，也告诉程序员一些他们如何改善<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">单元测试</strong></u></a>和集成测试的想法。作为这个过程的一部分，程序员也学到如何在提交修改之前自己进行部分的手工测试作为内部健全检查的一部分。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　最后，经理要求整个团队在每个月的月底与产品营销人员安排一个正式的会议，并将演示相关特性功能的开发进展。在这些营销会议提供的反馈仍然可以实现当前版本发布而不延迟版本发布。经理告诉我们，自从他们开始用这种方式工作，大大提高了团队的生产力和工作气氛，他真的很期待他们的团队实现SCRUM。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　他不理解的是，他们的工作方式并没有做任何革命性的改变，他们就已经实施了部分的敏捷开发并且从中体验到敏捷的好处。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　<strong style="word-break: break-all; line-height: normal !important;">小的变化和改进之路</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　这个经理的故事是一个很好的例子。如何在你的整个工程中使用小的改变来实现敏捷就能实现很多你想获得的结果并不需要开展一场彻底的革命。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　以下是一些想法，可以从上面的故事得到证明，我们相信，无论你的团队目前正在使用哪种开发方法都可以快速实现敏捷。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　<strong style="word-break: break-all; line-height: normal !important;">（1）小/更小块的工作</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　把工作分解成更小的，更易于管理的块，而不是少量的非常大的需求或任务，可以在更短的时间间隔内（数天或数周）完成。通过这种方式确保任务不比你原先分配的占用更多的资源（因为如果你的计划设想开始在工作中出错，你会在2周内而不是2-3个月才发现它），最重要的是，你会更快地交付功能给测试人员和产品营销人员，并得到及时反馈，进行必要的修正和调整，而不会影响你的发布日期。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　<strong style="word-break: break-all; line-height: normal !important;">（2）增加程序员和测试人员之间的协作和沟通</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　如果这个想法是为了使开发人员尽快得到功能的反馈，那么最好的办法是更早开始测试，很多时候，即使是在平行开发时也是如此。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　你可以通过多种方式实现这一目标，例如通过一准备好部分功能就邀请测试人员直接在开发环境运行其测试，（而不是等到所有部分都完成的时候）。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　另一种方法是测试人员与开发人员合作来计划和写单元和集成测试的方式，这将有助于测试人员更迅速地捕捉到更多的错误。最后，如何能让我们开始教程序员怎样运行少部分的由测试人员编写的手动和自动测试程序，作为他们在提交代码之前的健全性测试的一部分？我们看到很多的团队，在开发人员提交代码的主要分支之前他们需要运行开发自己的测试集进行测试。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　<strong style="word-break: break-all; line-height: normal !important;">（3）有更多的<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none;"><u style="word-break: break-all;"><strong style="word-break: break-all;">自动化测试</strong></u></a>以及更多经常运行它们</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　这是应用敏捷的团队的首要原则之一，事实上，也是符合每一种类型的项目逻辑。作出承诺，有意识地投资自动化。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　首先，指导你的开发人员为每一个新功能或重要的错误修复，创建单元测试和集成测试。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　你也可以让你的测试团队创建自动测试，以覆盖尽可能多的产品，并指导你的开发人员使用这个功能的自动化更简单，更强大（例如，通过使用GUI 元素中正确的仪器）编码方法。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　但是，创造你的测试是远远不够的。你需要有一个框架，尽可能多地运行这些测试，并在测试发现缺陷时即时反馈给程序员。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　现在，有很多很好的持续集成框架（如 Jenkins1，Bamboo2 或TeamCity3），所有这些都可以利用我们强大的API 集成到实践测试中。最后，你也将确保你的程序员遵守&#8220;你把它弄坏了，立刻你修复它！&#8221;的黄金规则。</p><img src ="http://www.blogjava.net/qileilove/aggbug/400017.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2013-05-31 11:17 <a href="http://www.blogjava.net/qileilove/archive/2013/05/31/400017.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>软件项目需求管理</title><link>http://www.blogjava.net/qileilove/archive/2013/05/14/399249.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Tue, 14 May 2013 03:48:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2013/05/14/399249.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/399249.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2013/05/14/399249.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/399249.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/399249.html</trackback:ping><description><![CDATA[<p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; "><strong style="word-break: break-all; line-height: normal !important; ">软件需求的概念</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　（1）宽泛地讲，需求来源于用户的一些"需要"，这些"需要"被分析、确认后形成完整的文档，该文档详细地说明了产品"必须或应当"做什么。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　（2）是用户对目标软件系统在功能、行为、性能、设计约束等方面的期望。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　（3）期望？！ 一种心理活动、笼统、不细致、不懂过程</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　<strong style="word-break: break-all; line-height: normal !important; ">需求的重要性</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　（1）Frederick Brooks在他1987年经典<a href="http://www.51testing.com/html/31/n-845431.html" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important; "><u style="word-break: break-all; "><strong style="word-break: break-all; ">文章</strong></u></a>"No Silver Bullet"中阐述了需求的重要性：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　开发软件系统最困难的部分就是准确说明开发什么。最困难的概念性<a href="http://www.51testing.com/html/31/n-845431.html" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important; "><u style="word-break: break-all; "><strong style="word-break: break-all; ">工作</strong></u></a>是编写出详细的需求，包括所有面向用户、面向机器和其它软件系统的接口。此工作一旦做错，将会给系统带来极大的损害，并且以后对它修改也极为困难。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　（2）需求是产品的根源，需求工作的优劣对产品影响最大。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　（3）国内软件业的痼疾：人们并不清楚究竟该做什么，但却一直忙碌不停地开发。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　<strong style="word-break: break-all; line-height: normal !important; ">了解客户、最终用户、间接用户的概念</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　（1）基本概念</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　"用户"（user）是一种泛称，它可细分为"客户"（customer）、"最终用户"（the end user）和"间接用户"（或称为关系人）。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　掏钱买软件的用户称为客户，而真正操作软件的用户叫最终用户。客户与最终用户可能是同一个人也可能不是同一个人。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　（2）客户是掏钱买软件的人，所以他是"上帝"</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　（a）某饭店经理在解释"先有鸡还是先有蛋"这个哲学问题时，精辟地阐述了客户的地位：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　如果顾客先点鸡，那么就先有鸡；如果顾客先点蛋，那么就先有蛋。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　（b）"现代营销学之父"菲利普o科特勒所著的《市场营销导论》是这样描述客户的：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　客户永远是本公司的座上客。客户并不依赖我们，而我们却依赖客户。客户不是我们工作的障碍，而是我们工作的目标。我们并不因为服务于他而对他有恩，他却因为给予我们服务于他的机会而有恩于我们。客户不是我们要与之争辩和斗智的人。从未有人曾在与客户的争辩中获胜。客户是把他的欲望带给我们的人，因此我们的工作就是满足这些欲望，从而使客户和我们共同获益。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　（c）与客户打交道的主要目的是：一是获取需求，二是签合同。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　<strong style="word-break: break-all; line-height: normal !important; ">软件需求的层次</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　（1）原始问题描述：对要解决问题的叙述，它是软件需求的基础</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　（2）用户需求：用自然语言和图表给出的关于系统需要提供的服务及操作的约束</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　（3）系统需求：是用户需求的映射。此时可开发一个简单原型以便给用户一个直观印象。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　（4）软件设计描述：在系统需求的基础上加入更详细的内容，它是软件详细设计和实现的基础</p><p align="center" style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　<a href="http://www.51testing.com/batch.download.php?aid=39875" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important; "><img border="0" src="http://www.51testing.com/attachments/2013/05/611095_201305101638131F6gH.thumb.jpg" width="169" height="250" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px; width: 169px; height: 202px; "  alt="" /></a></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　<strong style="word-break: break-all; line-height: normal !important; ">需求工程的组成</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　把所有与需求直接相关的活动通称为需求工程。</p><p align="center" style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; "><a href="http://www.51testing.com/batch.download.php?aid=39883" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important; "><img border="0" src="http://www.51testing.com/attachments/2013/05/611095_201305101644201CldA.jpg" width="317" height="249" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px; width: 299px; height: 235px; "  alt="" /></a>　　</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　<strong style="word-break: break-all; line-height: normal !important; ">需求工程的一些感悟</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　（1）不论是合同项目还是自主研发的产品，都必须开展需求开发和<a href="http://www.51testing.com/html/31/n-845431.html" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important; "><u style="word-break: break-all; "><strong style="word-break: break-all; ">需求管理</strong></u></a>活动。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　（2）开发者对待需求工程的态度可分"被动型"、"主动型"和"领先型"三种，只有后两种才有可能开发出成功的产品。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　"被动型"是指开发者被动地对待需求工程中的各项活动，能少干则少干，能偷懒则偷懒。他们认为需求是用户的事情而不是自己的事情。开发过程中经常发生需求变更，导致产品迷失方向，不是半途而废就是陷入半死不活的状态。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　"主动型"是指开发者积极地开展需求工程中的各项活动。他们把获取准确的需求当作自己的职责，会想尽一切办法克服需求开发和需求管理过程中的困难，而不是找借口推卸责任。俗话说"良好的开端是成功的一半"，"主动型"需求工程是开发成功产品的必备条件。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　"领先型"是需求工程的最高境界。开发者发掘了连用户自己都没有意识到的需求，导致用户跟着新产品跑而不是新产品围着用户转，这叫引导消费。需求工程做到这个份上，才能使产品立于不败之地，长盛不衰。<br /><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　<strong style="word-break: break-all; line-height: normal !important; ">需求开发的主要困难与对策</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&#183;&#183;&#183;知识技能问题</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（1）应用域的知识是无边无际的，任何人都不可能是"万事通"。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（2）当需求分析员缺乏应用域知识时，他该怎么办？</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（a）首先他要有勇气做事，否则连实践的机会都没有。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（b）其次他应当赶紧补习应用域知识。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&#183;&#183;&#183;态度问题</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（1）相当多的开发人员习惯于被动地对待需求开发。每当遇到麻烦、挫折时，他们会发牢骚，找出一堆用户的毛病。很多开发人员错误地以为：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　需求是用户的事情，不是我们的事情。我们为用户开发软件，难道用户不该告诉我们应当开发什么吗？如果用户说不清楚需求，或者经常变更需求，这类问题是用户产生的，应当由他们自己负责。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（2）用户说不清楚需求或者需求发生变更，这些都是常见的问题，并不是绝症，是人们可以设法解决的。可悲的是开发人员把这些问题当成了借口，不愿主动攻克问题，导致需求问题扩散到整个软件开发过程，产生太多的后患。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（3）软件企业的领导应当给具有错误观念的开发人员们洗脑：需求分析员的天职就是在有限的时间内获取准确而细致的用户需求，如果做不到就是失职，不要找借口。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　<strong style="word-break: break-all; line-height: normal !important; ">需求获取</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　需求获取时期的主要工作：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（1）归纳和整理用户提出的各种问题和要求；</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（2）弄清用户企图通过软件达到的目的；</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（3） 借助各种工具和方法，陈述用户提出的实际需求，并标定软件的作用范围。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　最终目的弄明白要"做什么"。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　<strong style="word-break: break-all; line-height: normal !important; ">获取需求应采用的步骤</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（1）确定产品的不同用户类型</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（2）确定用户需求的来源</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（3）挑选出每一类用户和其他涉众的代表并与他们一起工作</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（4）商定谁是项目需求的决策者</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　<strong style="word-break: break-all; line-height: normal !important; ">获取需求的方法</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（1）明确最终用户，与用户交谈，向用户提问题。向用户群体发调查问卷。透过客户所提出的表面需求理解他们的真正需求。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（2）参观用户的工作流程，观察用户的操作。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（3）与同行、专家交谈，听取他们的意见。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（4）界面原型法，是指开发方根据自己所了解的用户需求，描画出应用系统的功能界面后与用户进行交流和沟通。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（5）可运行的原型系统法</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（6）分析已经存在的同类软件产品，提取需求。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（7）从行业标准、规则中提取需求。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（8）从Internet上搜查相关资料。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp; 切记：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp; 设定用户代言人</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp;&nbsp;如果个别客户不能在需求方面达成一致意见，那么必须由用户代言人作出决策。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　<strong style="word-break: break-all; line-height: normal !important; ">需求分析</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（1）需求分析是指在需求开发过程中，对所获取的需求信息进行分析，及时排除错误和弥补不足，确保需求文档正确地反映用户的真实意图。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（2）分析方法大体有两类："问答分析法"和"建模分析法"。后者技术性比较强，写出来有学术味，故大多数软件工程书籍都有论述。前者就是一些常识而已，虽然写不成文章，但是简单易用（保你一学就会），很有实用价值。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（3）采用方法：绘制关联图、创建用户接口原型、分析可行性、确定需求优先级、编写数据字典等。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　<strong style="word-break: break-all; line-height: normal !important; ">编写需求文档</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（1）需求文档包括用户需求和详细的系统需求描述。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（2）要求</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp; 正确：正确地反映用户的真实意图；</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp; 清楚：易读易懂；</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp; 无二义性</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp; 一致</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp; 完备：没有遗漏一些必要的需求；</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp; 可实现： "可实现"意味着在技术上是可行的，并且满足时间、费用、质量等约束；</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp; 可验证</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp; 确定优先级：确定高中低三个级别，将风险降到最低。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp; 阐述"做什么"而不是"怎么做"</p><p align="center" style="word-break: break-all; margin: 10px 0px; padding: 0px; "><a href="http://www.51testing.com/batch.download.php?aid=39877" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important; "><img border="0" src="http://www.51testing.com/attachments/2013/05/611095_201305101638251yNXg.jpg" width="313" height="381" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px; width: 299px; height: 324px; "  alt="" /></a></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　<strong style="word-break: break-all; line-height: normal !important; ">需求验证</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（1）需求验证是为了确保需求规格说明准确、完整地表达了必要的质量特点。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（2）审查需求文档、依据需求文档编写测试用例、确定产品验收合格的标准。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（3）验证内容：有效性、一致性、完备性、现实性等。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　<strong style="word-break: break-all; line-height: normal !important; ">需求管理的重要性</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　如果对已经建成的大楼不满意，要求设计师把大楼的结构调整一下，别人一定会认为这很荒唐。但在软件项目中，这样的事情很常见。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　软件缺陷，发现和修复的越早则成本越低。不幸的是，需求阶段出现的错误往往很难发现，所以需求管理也需要讲究科学。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　原则：需求必须分优先级、必须文档化、需求一旦变化就必须对需求变更的影响进行评估。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　<strong style="word-break: break-all; line-height: normal !important; ">需求变更存在的必然</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　大师说："没有不变的需求，世上的软件都改动过3次以上，唯一一个只改动过两次的软件的拥有者已经死了，死在去修改需求的路上。"</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　<strong style="word-break: break-all; line-height: normal !important; ">变更管理</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　进行变更管理，首先要建立变更控制委员会，变更管理过程包括变更描述、变更分析和变更实现三个阶段：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　变更描述：始于一个被识别的需求问题或一份明确的变更提议</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　变更分析：评估被提议的变更产生的影响</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　变更实现：执行变更，需求文档、系统设计和实现都要修改</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　变更描述阶段，产生需求变更请求表</p><p align="center" style="word-break: break-all; margin: 10px 0px; padding: 0px; "><a href="http://www.51testing.com/batch.download.php?aid=39878" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important; "><img border="0" src="http://www.51testing.com/attachments/2013/05/611095_201305101638341PvpH.jpg" width="458" height="302" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px; width: 401px; height: 282px; "  alt="" /></a>　　<a href="http://www.51testing.com/batch.download.php?aid=39878" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important; "></a></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　<strong style="word-break: break-all; line-height: normal !important; ">变更影响分析</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　需求变更影响分析模板中包括的内容：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp; 变更请求号</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp; 标题</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp; 描述</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp; 分析者</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp; 分析日期</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp; 优先级评定</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp; 相关代价、收益与风险</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp; 预计对进度、成本、质量的影响</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp; 被影响的其他需求及任务</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp; 要更新的计划及文档</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　<strong style="word-break: break-all; line-height: normal !important; ">变更控制流程</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　</p><p align="center" style="word-break: break-all; margin: 10px 0px; padding: 0px; "><a href="http://www.51testing.com/batch.download.php?aid=39879" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important; "><img border="0" src="http://www.51testing.com/attachments/2013/05/611095_201305101638401a7lk.jpg" width="219" height="297" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px; width: 301px; height: 295px; "  alt="" /></a></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　<strong style="word-break: break-all; line-height: normal !important; ">需求状态</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　定义：某时间点需求的情况反映。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　客户需求的四种情况：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp; 客户可以明确且清楚地提出的需求</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp; 客户知道需要做什么，但却不能确定的需求</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp; 客户提出需求，但需求的业务不明确</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　&nbsp;&nbsp;&nbsp; 客户自己也说不清楚的需求</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　需求状态：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　已建议&nbsp;&nbsp; 已批准&nbsp; 已拒绝</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　已设计&nbsp;&nbsp; 已实现&nbsp; 已验证</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　已交付&nbsp;&nbsp; 已删除<br /><br /><p style="word-break: break-all; margin: 10px 0px; padding: 0px; "><strong style="word-break: break-all; line-height: normal !important; ">需求文档版本控制</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　对于开发人员来说，最为沮丧的事情莫过于当软件功能实现后，却发现该项功能已被项目经理取消了。原因在于需求文档版本混乱，开发人员没有得到最新的软件需求。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　<strong style="word-break: break-all; line-height: normal !important; ">需求跟踪</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　目的：建立和维护从用户需求到测试的一致性与完整性，确保实现都以客户需求为基础，实现的需求覆盖了预期的需求，并确保输出与用户需求的符合性。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　<strong style="word-break: break-all; line-height: normal !important; ">需求跟踪的作用</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（1）在需求验证中，便于确保所有需求被应用</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（2）有助于变更影响分析</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（3）便于需求的维护</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（4）便于测试时找出问题所在</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（5）便于项目跟踪和减少项目风险</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（6）简化了系统再设计，易于软件重用</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　<strong style="word-break: break-all; line-height: normal !important; ">案例分析：一个项目需求分析和处理的案例</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　<strong style="word-break: break-all; line-height: normal !important; ">1、&nbsp;案例背景</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　当地一家销售电动工具公司的董事会成员正在举行二月份的董事会会议，这家公司是一家专门制造和销售用于木工用的"黑客"牌电动工具的一家小型公司。会议室里在座的，有董事会主席贝斯&#183;史密斯（Beth Smith）和两个董事会成员罗斯玛丽&#183;奥尔森（Rosemary Olsen）和史蒂夫&#183;安德鲁（Steve Andrews）。贝斯首先发言："我们今年以来的销售非常好，打来的订货电话，已经要把我们的电话都要打爆了，但是，我们没有办法能继续招募到熟悉我们的电动工具、同时还了解我们销售过程的小姐。而与我们竞争的其他公司，都已经上了自动客户服务系统（Call Center）。所以，我们也要上这个系统，才能保住我们的市场。"</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　"我们必须建立一个计算机自动客户服务系统。"罗斯玛丽响应道。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　史蒂夫建议："难道我们不能把售后服务转给麦肯罗公司（公司下属的一家子公司，以服务为主）做吗？向他们要求一下，看他们是否能把电动工具的服务也接过去？"</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　"他们也紧张，听说明年他们甚至可能会削减一些服务项目。"贝斯回答。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　"我们需要多少钱才能搞这么一个系统？"罗斯玛丽问道。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　"大约10万美元，"贝斯回答，"如果我们不能在两个月后就开始启用这个系统，估计我们的定单可能会减少20%。"</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　"我们除了钱还需要很多东西。我们需要了解是否有更好的方案、开发这个系统需要多少时间，以及，这个系统是不是真的适合我们！"史蒂夫说。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　"哦，我想我们完全可以自己来做这个项目，这将是很有趣的！"罗斯玛丽兴奋地说。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　"这个项目不是我们的专长，我们不可能及时完成。"贝斯说道。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　罗斯玛丽回答说："我们有几个技术人员，虽然不够，但只要再招聘一二个高手，就可以解决它，并且做好。"</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　"项目是我们真正需要的吗？我们上了这个项目以后，公司的销售任务就能完成了吗？"史蒂夫问道，"此外，我们正在经历一个困难时期，我们的资金并不宽余。或许我们应当考虑一下，我们怎样能用较少的资金来运作一切。例如，我们用这个系统只处理定单，而并不包括服务，。这样系统是不是就会小一点，也省一点、快一点？"</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　罗斯玛丽插话说："多妙的主意，我们可以先完成销售定单的处理，等这部分完成投入使用后，再开发服务部分。公司可以在改进销售功能的同时，继续开发服务功能。这样，我们就可以做得更好。"</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　"好了，"贝斯说，"这些都是好主意，但是我们只有有限的资金和技术人员，并且有一个增长的需求。我们现在需要做的是，确保我们在两个月后不必担心丢失定单。我想，我们都同意必须采取行动，但是不能确定我们的目标是否一致。"</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">&nbsp;　<strong style="word-break: break-all; line-height: normal !important; ">2、案例习题</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（1） 项目目标是什么？</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（2）已识别的需求是什么？</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（3）如果有的话，准备开发的项目应具备什么样的假定条件？</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（4）项目牵涉到的风险是什么？</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　<strong style="word-break: break-all; line-height: normal !important; ">3、案例分析</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　根据本案例的背景，我们的分析简单描述如下。由于本案例比较简单，而且是自主开发，因此，有些内容可以简略。至少必须描述的内容，用下划线表示：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（1）业务需求</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　1、背景：一家小型的木工电动工具公司，今年以来的销售形势很好，接受定单的电话很多，已经忙不过来了。因此，需要开发自动客户服务系统。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　2、项目机遇：通过自动客户服务系统的开发和投入使用，使公司的销售获得增长。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　3、项目目标：开发一套为本公司销售和售后服务使用的计算机自动客户服务系统（Call Center）。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　4、市场需求：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　5、客户价值：满足公司自身发展的需要。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　6、项目风险：项目目标、方案、时间、资金、开发人员等。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（2）方案描述：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　1、功能视图：自动接听电话，对客户的定单和售后服务要求做出响应。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　2、主要特征：自动处理一些原来由人工完成的工作，有可能增加新的服务功能。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　3、假设和依赖：二个月时间内完成，总投资为10万美元，自主开发，自己使用。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（3）范围局限</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　1、首次发行范围：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　2、随后发行范围：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　3、局限和专用性：只为自己公司使用。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（4）系统环境：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　1、用户概貌：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　2、项目优先级：可以先完成定单响应，再完成售后服务功能。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　（5）成功因素：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　我们现在完成的，实在需求获取阶段中介绍的"项目视图"中的内容。在项目视图中，我们对项目做了初步的描述。在背景和目标分析阶段，我们回答本案例问题的答案是：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　1、项目目标是什么？</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　答：开发一套为本公司销售和售后服务使用的计算机自动客户服务系统（Call Center）。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　2、已识别的需求是什么？</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　答：自动接听电话，对客户的定单和售后服务要求做出响应。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　3、如果有的话，准备开发的项目应具备什么样的假定条件？</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　答：二个月时间内完成，总投资为10万美元，自主开发，自己使用。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　4、项目牵涉到的风险是什么？</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　答：项目目标、方案、时间、资金、开发人员等。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　系统的功能包括：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　1、从公司的客户方面看，新系统可以自动支持电话、FAX，E_mail、Web等多重通信方式所提供的服务，最大限度的满足客户的需要，最有效地为客户提供快捷方便的服务。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　2、从公司方面看，新系统要可以支持接入公司的交换机中继线路（24条中继），自动或智能话务分配、坐席画面与电话同步、自动录音等功能。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　3、从提供服务的内容看，可以有：公司产品查询、合同和定单查询、自动处理定单、产品售后服务信息查询、供货信息查询、方案介绍、产品推介、产品报修、故障咨询、投诉等。进一步的购买洽谈，可以转人工处理。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　4、整个系统可以与目前公司已经有的客户信息系统、产品信息系统等建立联系，形成综合的服务系统。</p><p align="center" style="word-break: break-all; margin: 10px 0px; padding: 0px; "><a href="http://www.51testing.com/batch.download.php?aid=39880" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important; "><img border="0" src="http://www.51testing.com/attachments/2013/05/611095_201305101638481XnGP.jpg" width="410" height="309" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px; width: 391px; height: 290px; "  alt="" /></a>&nbsp;</p><p align="center" style="word-break: break-all; margin: 10px 0px; padding: 0px; "><a href="http://www.51testing.com/batch.download.php?aid=39881" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important; "><img border="0" src="http://www.51testing.com/attachments/2013/05/611095_201305101638581Jio6.jpg" width="426" height="385" style="word-break: break-all; list-style: none outside none; margin: 0px; padding: 0px; border: none; max-width: 500px; width: 391px; height: 335px; "  alt="" /></a></p><br /><br /></p><div style="word-break: break-all; margin: 10px 0px; height: 21px; position: relative; width: 627.2000122070313px; "></div><br /></p><img src ="http://www.blogjava.net/qileilove/aggbug/399249.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2013-05-14 11:48 <a href="http://www.blogjava.net/qileilove/archive/2013/05/14/399249.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>接口与单元测试随想</title><link>http://www.blogjava.net/qileilove/archive/2013/05/08/398972.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Wed, 08 May 2013 02:34:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2013/05/08/398972.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/398972.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2013/05/08/398972.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/398972.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/398972.html</trackback:ping><description><![CDATA[<p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　刚才看到<a href="http://www.51testing.com/?action-viewnews-itemid-244321" target="_blank" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;">一则关于TDD的新闻</a>，挺雷的......然后又想起以前跟别人解释关于为什么在Spring里需要先写个接口XXXInterface，然后再写实现类XXXInterfaceImpl的问题。写一点自己的想法，关于<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">单元测试</strong></u></a>。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　一个情景：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　一个User类，提供一个静态方法：（这里不讨论框架或者异常控制流程的正确性）</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"></p><table align="center" style="word-break: break-all; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; border-style: solid; border-color: #999999; background-color: #dddddd; width: 612px;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;"><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">public class User{</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">&nbsp;public static User login(String username,String password) throw LoginException{<br style="word-break: break-all; line-height: normal !important;" />&nbsp;&nbsp;//取得DAO<br style="word-break: break-all; line-height: normal !important;" />&nbsp;&nbsp;//查询是否存在用户，如果存在，返回User，否则抛出异常<br style="word-break: break-all; line-height: normal !important;" />&nbsp;}<br style="word-break: break-all; line-height: normal !important;" />&nbsp;<br style="word-break: break-all; line-height: normal !important;" />&nbsp;//其他全略<br style="word-break: break-all; line-height: normal !important;" />}</p></td></tr></tbody></table><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　下面讨论如何对这个方法进行测试：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　单纯对于这个模块进行单元测试：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"></p><table align="center" style="word-break: break-all; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; border-style: solid; border-color: #999999; background-color: #dddddd; width: 612px;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;"><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">public class UserTest{</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">&nbsp;public void testLogin(){<br style="word-break: break-all; line-height: normal !important;" />&nbsp;&nbsp;User user = User.login("aaa", "123456");<br style="word-break: break-all; line-height: normal !important;" />&nbsp;&nbsp;//对于user的正确性进行判定<br style="word-break: break-all; line-height: normal !important;" />&nbsp;}<br style="word-break: break-all; line-height: normal !important;" />}</p></td></tr></tbody></table><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　这样的测试，正确性和速度实际上都保证不了。因为login中引入了<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">数据库</strong></u></a>的各种操作，各种未知的可能性都是存在的。比如说数据库并未配置正确或者数据库当前无法访问，直接会导致这个测试失败，但测试失败并不意味着User.login方法错了。同时，由于访问数据库造成的速度可能使这么一个简单的测试需要几百毫秒甚至几秒，那么大量的<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">测试用例</strong></u></a>加在一起，如文中提到的花费个几十分钟是绝对可能的。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　实际上这个简单的测试方案违背了单元测试的基本原则：单元测试应该测试独立的单元模块，这个单元不应依赖于其他模块。在这里显然这个Login的方法使用DAO中的一些方法。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　下面讨论DAO：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"></p><table align="center" style="word-break: break-all; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; border-style: solid; border-color: #999999; background-color: #dddddd; width: 612px;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;"><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">public class UserDAO implements DAO&lt;User&gt;{<br style="word-break: break-all; line-height: normal !important;" />&nbsp;//各种方法的实现<br style="word-break: break-all; line-height: normal !important;" />}</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">public class DAOFactory{<br style="word-break: break-all; line-height: normal !important;" />&nbsp;public DAO getDAO(Class pojoClass){<br style="word-break: break-all; line-height: normal !important;" />&nbsp;&nbsp;//获取各种DAO<br style="word-break: break-all; line-height: normal !important;" />&nbsp;}</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 1.8em !important;">&nbsp;public static DAOFactory getInstance(){<br style="word-break: break-all; line-height: normal !important;" />&nbsp;&nbsp;//单例工厂<br style="word-break: break-all; line-height: normal !important;" />&nbsp;}<br style="word-break: break-all; line-height: normal !important;" />}</p></td></tr></tbody></table><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　一般来说DAO部分都跟上面的差不多（或许是直接注入进User的，但实际原理是一致的）：一共两个步骤：1、获取DAO；2、使用DAO。为了不让User的测试受到DAO部分的干扰，就需要使用Mock技术，对DAO对象进行模拟，保证其各种方法的正确性。然后当User类需要获取DAO时，将MockUserDAO代替UserDAO交给它。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"></p><table align="center" style="word-break: break-all; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; border-style: solid; border-color: #999999; background-color: #dddddd; width: 612px;"><tbody style="word-break: break-all;"><tr style="word-break: break-all;"><td style="word-break: break-all;">public class MockUserDAO implements DAO&lt;User&gt;{<br style="word-break: break-all;" />&nbsp;//肯定准确的实现<br style="word-break: break-all;" />}</td></tr></tbody></table><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　而DAOFactory由于是单例，其方法getInstance是静态的，所以最后只能靠修改原始代码来实现获得另一个工厂&#8212;&#8212;也就是MockDAOFactory。如果在程序员和单元测试人员不是同一个人的时候，真的是非常麻烦的事情..... （从这个角度上将，我极力反对静态方法）虽说这种情形可以靠反射来进行伪造实例的活动，但是这种解决方案总是有一种黑客的感觉....</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　另外就是如果DAO不是接口，而只有实现（这并不是不可能的情况，在有通用DAO的前提下，完全可以达到），情况也会很麻烦。由于DAO不是接口，导致无法Mock这个DAO。也许可以使用MockDAO extends DAO的方案，但也许在DAO的构造方法中依旧有着连接数据库，初始化连接池，初始化<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">日志</strong></u></a>等等的初始化过程，由于其在构造方法中，是无法覆盖掉的。在这种情况下，就只能通过重构来实现测试了。（这也就是即使只有一个实现，也要尽量写一个接口的原因）</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　单元测试是至关重要的，我个人认为，如果一个团队中的程序员头脑都不错，那么包括getter和setter都应该测试。单元测试的度基本上可以说是宁滥勿缺的。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　挺杂乱的，不过只是随想，所以也无所谓。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.59375px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"><em style="word-break: break-all; color: #999999; line-height: normal !important;">　　原文链接：http://my.oschina.net/Jeky/blog/30354</em></p><img src ="http://www.blogjava.net/qileilove/aggbug/398972.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2013-05-08 10:34 <a href="http://www.blogjava.net/qileilove/archive/2013/05/08/398972.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>最近的一次敏捷项目Scrum经验总结</title><link>http://www.blogjava.net/qileilove/archive/2013/03/28/397090.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Thu, 28 Mar 2013 02:52:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2013/03/28/397090.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/397090.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2013/03/28/397090.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/397090.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/397090.html</trackback:ping><description><![CDATA[<div>　Team刚刚完成了一个<a target="_self"><u><strong>敏捷</strong></u></a>项目，做一下项目总结，以备以后借鉴和提高。<p><strong>　　需求 - 沟通 &#8211; 人 - 过程 - 工具</strong></p><p>　 　项目要成功的最关键因素是什么？软件要快速高效又高质量的提交靠的是什么？有人说最关键是项目经理，关键是沟通，有人说是技术设计，有人说是对需求的把 握&#8230; &#8230;  从我看来，都是盲人摸象，项目要成功，软件要快速高效又高质量的提交，靠的是多重因素的整合和平衡；首先要对需求的准确理解和把握，贯穿全流程的沟通，做 项目靠人，对人/士兵的管理（物质、心理），适合组织的先进的过程（开发，<a target="_self"><u><strong>测试</strong></u></a>，评审，组织，考核），还有工具的运用和整合大大提升组织效率，缺少那一样都是不行的。成功的模式只有一个，而失败却有各式各样，就是这个道理。</p><p><strong>　　沟通，随时随地，全方位立体的，有效的，及时的沟通</strong></p><p>　 　沟通，沟通，随时随地，全方位立体的沟通。面对面、站立会议、咖啡间、IM、Email、文档、电话。上下级、跨部门、客户，沟通，直到双方的理解没有 Gap（鸿沟），没有Misunderstanding（误解）。主动沟通，有问题随时反馈。对被动的同事，主动问他。注意沟通的效率和时间表，不要一个 会议开两个小时。如果有必要，尽量让少的人参与，除非是kick-off会议。此外，沟通会影响时间表，比如你有个问题要问某人，而这个人下周开始休假 了，要早做预防。否则，吃亏的是自己。</p><p><strong>　　白板，任务板，Sketch，Prototype</strong></p><p>　 　Team位置必须坐在一起，最好是圆圈式的座位，旁边有玻璃白板，上面画好下一个里程碑和Release的Roadmap，玻璃白板便于马上沟通。任务 板便于大家清楚当前致力的目标和Release。对于Sketch要用好，在产品或者功能还没有做出来以前，先把Sketch或者Prototype发给 客户看一下是否认可，获得用好Remarks，然后再开始动手；毕竟动手了再修改代价就更大了。所以一定要用好Sketch草图。</p><p><strong>　　Stand up meeting要不要</strong></p><p>　 　很多人说到Scrum就要每日晨会Stand Up  Meeting，但我们Team的实践来看，并不是必须的，其实敏捷也是根据组织和项目实际情况因人而异的（有人说敏捷对结对开发人员的能力要求很高，我 觉得敏捷是一种境界，良好的架构，代码规范，成员间非常好的默契，才能敏捷的起来）。不能拘泥于形式主义，我主张实用主义。现在不是有反敏捷、有瀑布敏捷 （Water-Scrum-Fall）、实用敏捷吗？关键是我们还没有领会敏捷的深刻内涵和思想体系，不会用敏捷的思想和思维方式高屋建瓴的思考我们的开 发流程，而只是依葫芦画瓢学个一招半式，那就真的不是敏捷了。我听到有人说，敏捷只适用于产品型公司和小型项目，还有人说敏捷只适合于需求不稳定的项目， 还有人说敏捷了就等于速度快，就等于客户报价可以低一些，还有人说敏捷说的什么迭代持续集成和重构都是理论，没有考虑到实际执行起来的风险&#8230;&#8230;都没有错， 关键是我们还没有领会敏捷的深刻内涵和思想体系，不会用敏捷的思想和思维方式高屋建瓴的思考我们的开发流程，而只是依葫芦画瓢学个一招半式，在这儿讨论， 说白了还是理论，坐而论道不如起而行，所以积极实践，加深对敏捷内涵的深刻理解，寻找适合自己组织的最佳敏捷实践方法才是良策。这样子思想理顺了，我们就 不会拘泥于Stand Up Meeting到底要不要的问题了。</p><p><strong>　　保证代码质量</strong></p><p>　　如何获得高代码质量？打个比方，现在要打仗了，如何打个漂亮的胜仗。我想你肯定知道答案了。那就是你的队伍必须各个是精兵，能力强，平时训练有素，而且还有实战经验，这样的一个兵强马壮的精兵队伍你拉出去，只要指挥好，士气高，就能打漂亮的胜仗。OK，现在你明白了，<a target="_self"><u><strong>软件开发</strong></u></a>何不如此？你手下的程序员是不是技术能力很强，是不是平时就对技术研究很深，对某科技术有很深的理解，还有很多项目经验，是不是干劲十足，是不是对他们做了培训，是不是做了编程规范的要求，都明白了命名规范、异常处理、<a target="_self"><u><strong>日志</strong></u></a>处理、安全性、用户权限、配置文件、设计模式、线程安全、<a target="_self"><u><strong>单元测试</strong></u></a>、调试技巧、条件编译等项目标准处理；如果还没有这些标准的贯彻，那你的士兵还需要培训（训练），这样子上战场会很危险。当然，有个变通办法，让资深程序员带小弟，小弟在一边看着，下个项目备用。当然。除了培训以外，分享、知识库都是团队很重要的机制。</p><p>　 　基础不扎实的程序员代码质量不会高起来，比如有的C#程序员根本理解Task.Factory.StartNew这句话是异步执行的线程池起线程，就把 它放到同步的循环里面，导致问题。再比如，有的程序员用匿名函数，不懂闭包，导致放在循环里面每次取到的都是最后一个值。再比如有的程序员不深刻理解 Session，就认为浏览器关了Session就没有了。再比如有的C#程序员不理解GC以为一个类只要实现了IDisposable接口就一定会内存 释放&#8230;&#8230;举不胜举，都是项目中遇到过的（注：对基础不扎实的程序员进行代码Review管用吗？我们项目实践来看不管用，因为资深程序员很忙，不可能一行 一行去看去调试。）&#8230;&#8230;所以，优秀的程序员都是建立在对该技术的深入理解的基础上的。优秀的成熟的程序员员工都有专业化（技术方面）、职业化（服务意识、 协作能力、解决问题的能力和态度）和商业化（替客户思考和解决问题）多方面的优秀特质，才能真正的为业务创造价值。</p><p>　　保证代码质量的另外一个非常重要的方面就是测试，一定要写单元测试，使用Moq做单元测试。这可以培养程序员面向接口的思维方式，如果代码不能做单元测试往往是耦合度很高的代码，所以单元测试能发现代码质量的问题。此外，测试组的<a target="_self"><u><strong>工作</strong></u></a>要及早介入，对业务的深刻理解，重复利用bug管理工具，<a target="_self"><u><strong>敏捷测试</strong></u></a>。</p></div><div><strong>为需求变化和维护早作准备</strong> <p>　　在系统设计的时候，要考虑到未来可能的需求变化，做好面向变化的架构设计。但不要过度设计。（这需要深入理解商业需求）</p> <p>　　为维护早作准备，意思是说，在编码阶段，就要考虑到系统的可维护性，设想你自己就是将来维护这个系统和这段代码的人，这种意识很重要。有的程序 员以为系统提交了上线了就没他的事情了，结果到头来上线了出现问题，系统又没有很好的log和trace，导致问题极难线上调试，而线下又不能模拟真实的 环境，这种情况下必须为维护而设计，提升系统的可维护性、可追溯性、可管理性。</p> <p><strong>　　不要过度设计和过早优化</strong></p> <p>　　过度设计是敏捷开发应该避免的，很多工程师都有过度设计的冲动。例如，在一个web系统还没有看到被大规模使用的曙光以前，就设计了系统规模 化，什么集群、负载均衡、读写分离、分布式缓存系统&#8230;&#8230;说真的，这些东西确实是好东西，但也很贵。在系统还没有被大规模的用户接受和喜爱之前，这样做是否 会抵消了我们把专注点放在核心功能和简练和简单的努力呢？时间是有限的，投资也是有限的。我们必须把有限的时间和有限的金钱用在当前最核心的功能和体验 上。有时候系统初期，可能一两台服务器就足够了。只有在看到产品有被大规模使用和用户喜爱的曙光之后，才来增加功能和规模量。当然，你的网站功能，在你只 有 10 万用户的时候，可能和你有 1  亿用户的时候会很不一样。所有太多太早太频繁的架构上的大动作可能会适得其反。这一点上，你要小心判断。系统架构需要及早规划，但不要提前实施和过早优 化。</p> <p><strong>　　关注非功能性需求</strong></p> <p>　　也许大多数客户和咨询师也会听说过神马TDD、迭代、原型、持续集成和持续部署、Agile等时髦的词语，这些也让管理者很兴奋，以为软件产品 是可以在很短的时间内高质量的完成的，即使完不成也可以在后面用TDD，快速迭代，不断重构，持续集成直至持续部署的方法在进行软件开发。这听起来好像很 美好。但其中有个很大的陷阱，那就是客户和咨询师，还有原型、TDD大都只关注功能性需求，而忽略了非功能性需求，比如性能问题，高可用性问题，系统维护 问题（模块的耦合问题），等等。客户和咨询师在项目前期闭口不提这些或很少提及，但一旦功能性需求都做完了他们就会抱怨这些隐藏的非功能性需求。而像性能 问题，高可用性问题，系统维护问题（模块的耦合问题）等并不是很容易重构，往往涉及到Re-design，  re-architect；因此这些问题往往都在后期会成为重构噩梦，甚至可以让你的软件设计重新来过！更加糟糕的是，大多数客户不愿意为这些隐藏的功能 重构而付钱。笔者曾经遇到过前期只注重功能性需求而后期发现性能不好而进行re-design，  re-architect，这对项目管理来说有很大的挑战，因为不单单是程序和架构重构的困难，还要面对时间和人力成本的增加，最难的是你还要面对的是团 队士气因为不断的rework而逐渐低落并产生厌倦和懈怠情绪。这是一个很大的陷阱。</p> <p>　　所以，前期就要关注非功能性需求，不要急于动手，如果你能有多一些时间去和客户讨论一下需求和未来可能的变化，去调查一下实现的技术难点和细 节，去和其他有经验的人讨论并推敲一下架构和设计，去思考设计上的缺陷，那么，你的coding会变得非常地直，直到你一眼就看到尽头，你的测试案例也会 写得非常地好，你会几乎不需要重构，于是，你会在未来少写很多代码，从而你的软件开发会越来越轻松，直到技术开始换代。这就好像我们修路造桥一样，我们需 要花大量的时间勘测地形地质，分析数据，思考可能出现的各种问题（各种自然灾害），评估不同的设计方案，而不是先尽快建好再说。（：磨刀不误砍柴工）  说到这里，有些反敏捷（反Scrum），没错，好的程序员要会做权衡/平衡，好的架构师要会做平衡，好的项目经理也要会做平衡，这非常重要。</p> <p>　　再补充一点，有资深经验的工程师/架构师对非功能性需求的设计和平衡很有经验，这些经验对系统设计和项目成功至关重要。如果你很不幸，手头没有 这些有经验有价值的人，而只有一堆码农，那么恭喜你，你可以在一张白纸上画画了。就开发他们的潜力吧，做好这个项目给他们积累经验的心理准备吧，量力而行 吧，小马过河吧&#8230;&#8230;实在不行你就自己上吧，毕竟公司要求用最少的钱在最短的时间内出来最优秀的东西；如果你有话语权，那就把你的困难及早让上层知晓。</p> <p><strong>　　严格控制需求和范围，和进度权衡，不出现资源空闲</strong></p> <p>　　领导一般会给项目经理压力，要求在什么时间提交一个版本赶进度等，这时候项目经理要么能调整一些需求和范围（Scope），要么就把可能出现的 问题进行报忧，因为现在如果不这样做，你就等着现在报喜，后期报忧吧。所以项目经理一定要严格控制需求和范围（scope），和进度，和质量权衡。同时要 合理调配资源，不要出现项目进行中资源空闲的情况（这个在Project工具中可以看出）。</p></div><div><p><strong>　　项目风险管控</strong></p> <p>　　项目经理要有项目风险管控能力，及时在项目进行的各个阶段进行风险的预识别和管理。项目一般是前期工期松，风险低；而后期工期紧，风险高。所以 项目经理要尽可能在项目早期能列出大部分的风险，这样在项目的风险应该是倒三角形状的，就是前期风险多，后期风险少。要预先把下阶段可能的风险明确告诉客 户，让客户提供帮助来控制风险的发生，同时迫使客户加强风险意识，不让需求任意扩散和蔓延。在各个阶段都要有双方风险认知的会议纪要记录。一般情况下，项 目的外部依赖条件是最不可管控的风险（比如要和第三方联调，要第三方提供API等）。其次是需求的不明确和需求蔓延的风险（需求问题占项目成功的40%因 素以上，你能控制需求，你就成功60%了）。然后还有资源的可用性（如：项目进行中核心人员流失，要知道项目进行中间换人和加人都很是问题）。</p> <p><strong>　　资源提供者和问题解决者</strong></p> <p>　　大家都知道，打仗的时候什么最重要？对了，补给（后勤保障）。士兵上战场了，谁做后勤？项目经理。每天都要问大家，你下一步需要什么，你还缺什 么输入？你有什么问题需要我这边配合的？程序员旁边有垃圾了，项目经理去扫一下地，这就是后勤补给。所以管理者首先要理顺管理者和人的关系，调整好服务的 意识，做好资源源源不断的提供、帮助大家解决问题，系统就有了润滑剂，有了源源不断的输入，就能顺畅的开展。否则，千里马到你手里也跑不快的。</p> <p><strong>　　管理用户期望</strong></p> <p>　　对每一个Sprint提交，谨慎选择功能集合，多和客户沟通，管理好用户期望，他下一阶段希望有什么功能，这些功能的优先级如何，实现难度如何，及早告诉他下一个版本会友什么，不会有什么。</p> <p><strong>　　增加团队成员之间的亲密感</strong></p> <p>　　有时候如果一个团队成员里面有多个牛人，大家都是很有主见的人，就很容易在一些问题上争执，甚至产生内部竞争。两个聪明人意见采取谁的呢？紧张 关系在所难免。这种纠结的合作和竞争关系是同事关系的主线。但要保持合作为重点。所以，要把这样的状况保持在一个健康的状态，需要加深团队成员的亲密感。 具体来说，坐在一起聊天、吃午餐、喝咖啡、散步、打球、打牌，都是增加亲密感的方法，这样拉近人与人的距离，就不会觉得有什么竞争的紧张感了。</p> <p><strong>　　管理团队目标和情绪</strong></p> <p>　　Scrum有一个优点就是短周期快速迭代，每周大家都有明确的目标，因为Release周期很短，大家Vision很明确，所以为什么 Sprint就是冲刺的意思。管理好团队的目标、Vision，有明确的目标，有冲刺的干劲。及时发现团队的情绪波动，采取应对措施（休整，腐败，激 励）。</p> <p><strong>　　保持耐心，不断调整</strong></p> <p>　　技术上要重构，架构改进和提炼等。信任程序员，给他们时间来重构，来调整和优化架构等。管理上要重构，代码促进委员会，评审组等等。改进适合组 织规模和业务发展的流程，目标是获得持续、快速、更好质量的交付产品和更好的客户满意度、更低的成本和更高的效率。总之，要不断努力，不断调整，不断尝试 新的方法，做的越来越好。要保持耐心，给员工/系统的成长/成熟一点信任和时间。</p> <p><strong>　　项目经理的人格魅力和以德服人</strong></p> <p>　　作为项目经理您必须与同事以团队合作方式才能保证项目的顺利完成，如何鼓舞团队成员的士气？让大家心甘情愿的与你朝着共同的目标努力。要做到这 一点，人格魅力非常重要。但要让大家真正服你，真正的服是以德服人。比如，你要求所有的手下都主动配合你的工作，但是你自己如果没有首先要求自己主动配合 大家，你就不会赢得大家的尊重。这只是一个例子而已，很多点滴细微之处会让大家感觉到你的人格魅力，究竟是一个值得尊敬的人，还是一个不值得尊敬的、自我 的、高高在上的发布命令者。总之，做人是最要紧的，做人没做好，做事肯定做不好了，项目多半要搞砸。</p> <p>　　但就项目经理的项目管理能力来说，也关系到项目的成败，比如能否引导客户需求、对问题的透彻理解、对复杂的任务紧密跟踪并设定轻重缓急、利用各 种渠道和方法来沟通解决问题、有能力做出适当的取舍、说服客户或领导的能力、推销自己解决方案的能力、突破性格制约的沟通技巧、面向全局思考的思维方式、 如何合理动态分配大家的工作项使不被Block住&#8230;&#8230;</p> <p><strong>　　总结</strong></p> <p>　　先写这么多吧，想到了再补充。</p></div><img src ="http://www.blogjava.net/qileilove/aggbug/397090.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2013-03-28 10:52 <a href="http://www.blogjava.net/qileilove/archive/2013/03/28/397090.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>紧耦合金融系统群的测试自动化策略（一）</title><link>http://www.blogjava.net/qileilove/archive/2013/03/21/396788.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Thu, 21 Mar 2013 02:25:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2013/03/21/396788.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/396788.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2013/03/21/396788.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/396788.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/396788.html</trackback:ping><description><![CDATA[<div><div><strong>三句话背景</strong><p>　　科技子公司或者IT部门在一个大金融团体里面只能算是个成本中心，对IT团队来说，核心使命就是稳定运营、降低成本。这对于<a target="_self"><u><strong>自动化测试</strong></u></a>来 说，意味着非常有限的资源预算、不稳定的测试环境、复杂的系统耦合关系、严苛的测试数据要求，还有那近乎无理的信息安全规范。如此种种，让我们并不能按照 自己想象的那样去实施自己的规划，以致会走很多弯路；而再回首你会觉得，有时候只是方法欠妥而不是资源不够，有时候只是导向错误而非技术不够高。</p><p><strong>　　关键字：</strong>金融系统；自动化测试；<a target="_self"><u><strong>单元测试</strong></u></a>；环境监控；测试数据；持续集成；</p><p><strong>　　传统金融系统</strong></p><p>　　以往，很多传统金融企业所使用的系统依赖采购和外包开发、维护的占比较大，这可能会让他们自己的IT队伍的经验少一些，而对商业工具、产品和解决方案的依赖性较强。而现在，这些IT队伍要么在新技术和<a target="_self"><u><strong>互联网</strong></u></a>的压力下做艰难的转型，要么还在坚持着古老的体制文化，要么非常年轻，经验不足。他们的开发流程也有可能会臃肿僵化，也可能会做<a target="_self"><u><strong>敏捷</strong></u></a>做得些敏而不捷，也可能测试自动化水平低下，也可能太过冒进&#8212;&#8212;在我看来，这个行业里优秀的IT队伍远少于外面精彩的大世界，但是，无论是主动地还是被动地，他们都在随着时代在慢慢改变。</p><p>　 　对于金融核心业务系统来说，大部分都是将前端按照业务属主的部门划分而做模块化设计。例如我们的保险系统，被拆分为网销、新契约、保全、理赔、渠道人 管、财务、电销与客服、查询与报表等等很多子系统；银行则可能会有客户管理、存贷款、外汇、国际结算、渠道、报表等等，有更多的模块。而无论前端如何拆 分，一个子公司的业务数据和大部分核心业务逻辑在后端都是共享的，所以整个系统群的基础业务数据和业务逻辑都是紧密耦合的。</p><p>　　在这个行业 里，我体会到，为了领先同业，仓促启动和上线的产品项目不胜枚举。因为这些项目的经营策略相关性或者政治敏感性较高，所以无论在DeadLine之前实现 了多少，只要没有致命问题，总要如期上线，而把遗留的问题通过后续排期解决。这种快餐式的设计和实现让很多项目和产品看似风光的按期上线，都附带了相当多 的系统债务的产生：紧耦合、难重构、难以自动化测试、运维成本高。而且这种债务是增量累积的，没有额外的人力很难清理掉。要么在日常<a target="_self"><u><strong>工作</strong></u></a>之外付出额外的努力，要么任其自生自灭，造就&#8220;前人宿醉、后人埋单&#8221;的奇观。</p><p>　 　在当今综合金融的大潮中，这些子系统必须满足的条件不仅是数据在系统群内共享，还要与集团其他子公司共享、与监管部门共享，以后也许会和医院与医疗机 构、社保机构甚至其他政府部门共享。看起来在我们现有的架构下，综合金融就意味着更多、更复杂的耦合，对测试来说就意味着测试数据使用难度的提升，从而对 测试的要求更高。同互联网一样，如今的金融产品也需要抢占市场先机，也需要快速的发布，但是快速发布不等于快餐式开发，否则久而久之系统维护债务的累积迟 早将达到无法负担的地步。而谢绝快餐式的发布，就需要新的开发模式，作为开发流程中的一个重要环节，<a target="_self"><u><strong>软件测试</strong></u></a>也在被逼无奈地随着改变、转型，来面临新的要求。</p><p><strong>　　时之沙聚金字塔</strong></p><p>　 　我们反复被教导，测试要越早越好：越早发现，修复成本就越低，所以就有了个分层测试的金字塔概念，而这个理论也经过很多优秀的公司的成功实践和论证，我 们不怀疑其正确性。但如果要做更多的单元测试，就需要代码有足够好的可测性，而现有的系统动辄就有着几十万、几百万行的陈旧代码，跨系统的逻辑调用比比皆 是，离传说中的高内聚、低耦合相去甚远。所以，在我们的实际操作中看起来，要做多少单元测试就要做多少代码重构，而做多少代码重构就需要多少能够守护代码 重构行为的测试。在这种情况下，只做代码重构或者只做单元测试的编写都是不靠谱的，这看起来是个死循环。</p><p>　　但是，不仅通过单元测试自动化 能够达成质量守护，通过GUI去做的自动化测试和手动测试也能够做到。虽然长期使用通过业务展示层去做测试自动化的成本很高，但是它的建设可以快速完成。 同时须知，同步做代码重构和单元测试编写的风险很大，如果在做的时候没有稳定的质量守护，作为涉费的金融核心业务系统，这种发布风险是不能被接受的。所以 比较现实的路看起来只有一条路：快速建设好GUI层驱动的自动化测试，用它来守护代码重构和单元测试。</p><p align="center"><a href="http://www.51testing.com/batch.download.php?aid=38693" target="_blank"><img src="http://www.51testing.com/attachments/2013/03/346836_201303201051401mXSR.jpg" border="0" height="280" width="358"  alt="" /></a></p><p align="left">　　我想借用这个沙漏图来说明我的观点：推动这种<a target="_self"><u><strong>系统测试</strong></u></a>的 转型，不能幻想一蹴而就的单元测试的建设，可以考虑通过GUI来做测试自动化，将其做扎实，以其为基础来推动这些陈旧的系统群的自动化测试转型。而接下 来，要慢慢地用单元测试自动化来逐步替换这个基于用户展示层的测试自动化，直到它们之间形成一个合理的比例。在测试水平提高和转型的过程中，每个类型的测 试都有可能成为瓶颈；尤其是通过业务展示层来做的自动化测试，没有它，代码重构和单元测试自动化也无法稳步地推动。在现实中的人力配比下，聚沙成塔对我们 来说是一个神话，信念支持我们朝着目标持续迈进，但是在短时间内却不易企及。</p></div><div><strong>　单元测试纵与横</strong> <p>　　对绝大多数人来说，谈到单元测试，第一个冲入脑海的是&#8220;覆盖&#8221;这两个字，而其中部分人对覆盖率这三个字的关注度要远远高于四种覆盖设计方法。假 设我们的目标测试范围内有N个功能，平均每个功能有9个逻辑分支（含Exception分支）。如果要考量单元测试的覆盖方法，我想绝大多数人会选择每个 功能点选择少于4个的主要分支去覆盖。我的确也在公司的持续集成邮件组里看到这种争论，参与讨论的开发同事无一例外地赞同这种做法，他们主要考虑的因素是 ROI，他们认为在非常有限的时间里，将单个功能点的分支覆盖太多并没有太多意义，因为用户经常使用的是主要的那两三个分支。这种看法似乎符合常理，但实 际上并没有他们想象的那么经济，我实际上并不指望他们现在这个阶段做多么好的单元测试，但是却不愿意看到他们按照这种想法做下去。</p> <p>　　我们不妨把每个功能覆盖主要分支，覆盖尽可能多的功能点的覆盖取向称做横向覆盖；对于每个功能点，争取覆盖尽可能多分支，而不计较有限的时间内 覆盖了多少功能点的覆盖取向叫做纵向覆盖。我个人的观点是：尽量采取纵向覆盖，自动化测试这同军事机械化作战一样，大纵深要比长战线好。我之所以在这种系 统群的测试转型过程中，对单元测试建设推崇纵向覆盖策略，理由如下：</p> <p>　　1）时间短、人力少，短时间无法覆盖全面，无论纵横，双方在这一点上的论据一致。</p> <p>　　2）一个功能的N个分支，如果在设计单元测试的时候只覆盖其中少数分支，在后续进行更深入覆盖的时候可能需要重构所有的测试以保证测试代码的逻 辑一致性和可维护性，这是一种重复工作的浪费。换言之，与被测代码一样，测试用例不能习惯于采取快餐式设计，而应该在一开始就针对该功能全面设计好。</p> <p>　　3）对于这些待重构代码来说，全面考量一个功能点尽可能多的分支的覆盖，能够驱动更加完美的重构，反之，测试的设计与开发一旦分批进行，必然招致额外的重构工作。</p> <p>　　4）至于有些开发认为在短时间内覆盖主要分支主要是因为用户平常只用那么几个主要的分支功能，我觉得恰恰相反。我们可以挑选用户使用最多的功能 而不是所有功能的主要分支，因为主要功能里面的&#8220;非主要分支&#8221;甚至是Exception分支同样有发生致命故障的可能。例如，对个退费转账，如果在某个异 常中没有处理好，可能会出转账数据反复生成的情况，这样的资金流入个人账户之后是基本再也无法追回的。这种故障即便快速恢复，也远比那些次要的功能不可用 招致的损失大。</p> <p>　　5）有些人认为，那些不重要的分支，在UI回归测试的时候着重测试一下就好了，这更是违背金字塔模型核心的经济原则。要知道UI回归测试的强项 在于对主流程的覆盖，而分支和异常通过它去覆盖本身就是非常难的事情；既然认同单元测试的经济性，还要依赖GUI测试去做那些非常难以实现的分支的测试， 这岂不是自相矛盾么？</p> <p>　　6）此外，这种纵深覆盖更能锻炼测试代码编写者的测试思维，完整的经验比被阻断的实践更具参考价值。后续编写新的功能模块的代码时，会因为做测 试设计时近乎完整的分支考量而更加能够兼顾所有的分支和异常。单元测试是一种高效的编码能力提升的手段，而在做单元测试的时候将分支的全面覆盖，则是高效 的设计技能的提升手段。</p> <p>　　单元测试覆盖的纵与横的概念只是一家之言，无需纠结概念。我其实只是希望大家在考虑&#8220;覆盖率&#8221;这三个字之前都去考虑一下覆盖的策略，而不要吧眼 光只放在那些乏味的覆盖率统计数字上。做测试规划，好的方略比优秀的代码更加能解决实际问题；宁可让沙子漏得慢一点，也不要为了暂时看起来流得快而对沙子 中混入的石子视而不见，否则迟早会因为石子堵住瓶口而无法继续聚沙成塔的梦想。</p> <p><strong>　　耦合关系的处理</strong></p> <p>　　对于我们讨论的这种系统，有人说mock对单元测试来说不是银弹，滥用mock会影响交互点的验证，降低测试的有效性。对这种看法，我深以为然，而且单元测试且如此，通过GUI做的测试就更不用说了，盲目的解耦会大大提高为测试有效性所付出的代价。</p> <p>　　拿我们一个较为单纯的系统为例，中间价是weblogic，数据库是oracle，部署逻辑关系如下：</p> <p>　　1）Browser通过HTTP访问单点认证系统、用户管理系统、影像系统、打印平台与印章系统等；</p> <p>　　2）Web服务通过TCP访问单点认证系统，通过LDAP访问OID，通过NFS访问NAS，通过T3访问App服务；</p> <p>　　3）App服务通过JDBC访问数据库，通过T3访问用户管理系统、工作流、单证系统、后援集中录入系统和集团公网前置系统，通过LDAP访问OID，通过NFS访问NAS&#8230;&#8230;</p> <p>　　4）核心DB通过TJS/ETL/GoldenGate与集团其他应用数据库相连。</p></div><div>　连同上文所述的系统群内部的业务逻辑和数据的共用，我们可以把我们的系统耦合分为两级：系统群内的耦合与平台级耦合。这两层耦合稍有区别，很多人 在通过GUI做自动化测试的时候，要么懒得去做mock工作，全部依赖所有的测试环境的稳定性；要么就花功夫把所有的关联系统全部mock掉。这两种做法 都是不妥当的，因为要指望所有环境都稳定无异于买彩票。另一方面，这些平台级的耦合关系，如果想通过mock的手法来解耦，将付出很大的代价，而程序的正 常功能也无法测试完整。例如，如果要绕过SSO和UM的认证，可能就要分析和运行时修改cookie，而这本身就是不安全的，也不是一定能够实现的。而 且，如果中间件的一个provider配置错误，绕过去的测试也不能发现这个问题，尤其是全部依赖自动化测试的情况下。 <p>　　那么是否要在通过GUI去测试的时候始终保持所有这种平台级耦合的测试环境稳定呢？根据我们的经验，答案是肯定的，因为如果通过GUI去做测 试，这种耦合关系是保证被测功能完整性的基本条件。无论这些平台或系统有着多么频繁的构建与发布，在我们通过GUI去做测试的时候都要保持一个稳定可用的 版本，对于我们的系统的持续集成，这种需求更甚。我曾经说过：在通过GUI快速构建的时候要彻底mock掉对关联系统的依赖，这彻底二字其实并不贴切，我 本意所指只是系统群内的关联关系而已。而理论终归是理论，根据我们公司的实际流程，我又把这种系统群内耦合关系的mock分为两种：</p> <p>　　自动化BVT/冒烟：在持续集成频繁的构建中，由于系统群内业务逻辑和数据的共用，关联系统的版本移交时间和频率不定，无法要求其保持稳定不变的版本以供关联测试，需要将这部分关联mock掉。</p> <p>　　自动化回归测试：在同一个系统群内，所有版本发布的最终日期是一致的，故尔最终的回归测试都将在一个集中的时段内完成，而这段时间内基本所有的版本都已经趋于稳定。在这种状态下，出于测试全面和有效性的考量，自动化回归测试将不mock任何关联。</p> <p>　　那么同一套测试脚本能否支持这种测试执行需求呢？我们借鉴了功能开关的特性，通过采集版本计划信息进行推算，做出一个判断是否回归测试的公共接 口。在测试脚本中调用共用接口，得到测试运行信息，决定如何处理对关联系统的依赖。持续集成对于很多公司或产品来说都不是件很难做的事情，而对于本文所述 的陈旧的紧耦合金融系统群来说却有一定的难度。我观察了我们公司一些持续集成做得比较成功的案例，大都是业务源头系统，如网销，基本不存在业务数据依赖 性，或是系统群内部关系简单或者索性就是独立不成群的系统。除了实施手段较为高明和付出的努力较多之外，最重要的是他们成功地规避了这里提到的紧耦合的问 题，或者根本就没有遇到这种问题。所以我个人的见解是：在通过GUI去做自动化测试的过程中，要确保平台级耦合系统环境的稳定性，分场景地mock系统群 内部的耦合关系，而不能一概而论。</p> <p><strong>　　监控辅助的测试</strong></p> <p>　　有人纠结测试自动化和自动化测试之间的差别，简单举个例子说明一下个人的理解：在测试环境搭建监控系统，用其辅助自动化测试运行，这个行为总的 来说可以称作测试自动化。而自动化测试主要的内容则是自动化（主要指脚本化）的测试执行动作，这二者之间还是有点差别的。如果非要咬文嚼字，我觉得其差异 在于自动化测试行为必定包含verifying，而测试自动化行为则可以只有甚至没有checking。如果将测试自动化的行为或体系在运用的时候加上 verifying，就可能变成自动化测试。</p> <p>　　提到测试环境监控，我觉得它的价值绝不亚于生产环境的监控，它能够帮助测试节省很多问题定位的成本，帮助发现一些在页面上无法发现的异常。根据 个人理解，除去基础架构统一管理的相关内容，我将其划分为5个部分（目前并未完成建设）：测试环境应用服务器监控、测试环境数据库状态监控、其他测试服务 的状态监控、自动化测试运行相关监控、业务系统逻辑健康度检查。用环境监控与自动化测试相互辅佐，可以发现更多的潜在问题，下面讲两个简单的例子来说一下 自动化测试和测试环境监控的关系。</p> <p>　　例1、数据传输自动测试（未亲自实施）</p> <p>　　很多时候，我们会使用几种商业工具和一些其他的企业级应用。在日常的测试工作中，针对这些工具或它们的特性也需要做大量的测试。例如，在平安科 技，单就数据传输管理而言，会用到：ESB/EAI/TJS、ETL（DataStage）、GoldenGate（Oracle）等。因为这些工具使用 的频率非常大，所以有想法的人就想着把这部分工作内容也做成自动化或者半自动化。</p></div><div>　大家知道，这些数据传输的service或者job本身可能存在一定的加工和转换的逻辑（GoldenGate可能会较为单纯），自动化测试可能 需要对其内部逻辑做细致的测试。而对数据加工转换的逻辑做自动化测试，无异于换个人重写一套逻辑去验证原先开发的逻辑，十分复杂，ROI并不高。 <p>　　这样一来，可能有人就把这个自动化变成了对这些service和job工作状态的checking，同时仍然简称这是在做自动化测试，并且试图 说明这样的测试通过就能够保证不出Level-1级别的故障事件。不过我认为，如果只是对这些service和job的基本可用性做checking，而 不是verifying，那么这部分自动化工作做成测试环境的一个监控即可，而不是自动化测试，而且这种checking是无法保证不出Level-1级 别事件的。</p> <p>　　例2、报表生成自动测试（指导同事实施中）</p> <p>　　我们的查询系统分三类：实时查询系统、综合报表系统和MIS系统，时效从高到低。实时查询系统自动化测试较为简单；而MIS系统由于维度和指标 非常复杂，暂时采用手动测试的方法。而这个综合报表系统有数百长单一维度的报表，每张报表使用一个独立的存储过程来生成，生成的结果文件含xls、 csv、zip、html等各多文件类型。报表之间的关联影响几乎可以忽略，而报表的正确性则会受其他公用逻辑改动的影响。此外，这种报表介于oltp和 olap之间，生成的效率从几秒到几小时不等，提交之后由quartz控制生成异步任务，是测试自动化的难题之一。</p> <p>　　因为测试执行的机器资源有限，所以一般来说自动化测试的运行都是实时的，但是报表生成的时长却长短不一。理论上，如果不想占用太多资源，只能依 赖有轮询机制的工具或者系统来检查它运行的结果。恰好，我们的监控系统就有这种机制，而且既然监控系统能够检查报表是否已经生成完毕并触发邮件发送，它就 一定可以触发对其结果正确性校验的自动化测试程序的运行。我们可以考虑在监控平台配置一个新的监控和一组规则，随后实现这种报表系统的测试：</p> <p>　　1）建立被测报表生成的存储过程代码的基线版本，存放于自动化测试的基线版本库中。</p> <p>　　2）将自动化测试代码分为自动化报表生成和自动化报表结果校验两部分。</p> <p>　　3）在任何变更引发的综合报表系统测试中，使用基线版本代码运行报表，取得报表结果文件；在最新的被测报表代码版本上，用自动化GUI测试再度生成这些报表，并取得结果文件。</p> <p>　　4）使用监控系统轮询报表生成情况，已经完成的报表则调用其自动化结果校验的代码再度运行，解析并比对两次获得的结果文件，进行报告反馈。</p> <p>　　5）被测报表逻辑发生变更，则更新被测报表基线代码。</p> <p>　　很显然，这种系统的自动化测试，决不是单靠一段单纯的自动化测试代码的运行就能解决的，辅助的方法或许有很多，但是善用已有的资源，无疑是一个很好的办法。如上文所述，监控系统的checking行为由于它联动了自动化的verifying动作，就变成了自动化测试。</p> <p>　　（未完待续）</p></div><br /><br /></div><img src ="http://www.blogjava.net/qileilove/aggbug/396788.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2013-03-21 10:25 <a href="http://www.blogjava.net/qileilove/archive/2013/03/21/396788.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何做好Code Review：思考、方法和实践</title><link>http://www.blogjava.net/qileilove/archive/2013/03/18/396579.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Mon, 18 Mar 2013 02:11:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2013/03/18/396579.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/396579.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2013/03/18/396579.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/396579.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/396579.html</trackback:ping><description><![CDATA[<p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　最近被要求做一个关于Code Review的讲演。首先要说明的是，我并不是太擅长开展Code Review的活动。做这个完全是因为答应了别人又不好反悔。不过在做准备的过程中还是有一些感想。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　关于Code Review我所了解到的行业中最著名的是Bill Gates汇报。这是<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: initial; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">微软</strong></u></a>在<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: initial; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">软件开发</strong></u></a>过程中的一个重要环节，因为Bill Gates亲自参加而备受关注，在行业中广为流传。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　Ok，进入正题了。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　我们面临的共同问题：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　1、对于开发周期较长的软件项目，可维护差的代码对项目造成了极大的困扰</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　2、结构复杂的，体系不清楚的代码会导致新成员或者外部干系人很难融入。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　3、软件项目代码质量低下，<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: initial; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">Bug</strong></u></a>众多并且有关联累积效应。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　以上三个问题是我在以往的Code Review活动中总结出来，可以被影响或者解决的问题。也就是说我的观点是如果没有上述问题，或者在目前的软件产品的规模、开发过程的成熟度还没有达到一定级别时Code Review是可以不做的。当然优秀的开发人员会做自我审查，这是另外一个问题了。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　总而言之，我认为开展Code Review活动的前提是</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　1、开发过程和质量控制达到了一定的成熟的。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　Code Review必然与重构相关联。如果开发过程中更本就没有重构这样的活动，那估计Review出来的结果不太容易得到执行。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　其次是各种标准和规范的齐备性，没有规矩是不能成方圆的，如果只有一个命名规范，那可想而知Review的内容不会太深入，效果因此大打折扣。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　2、代码达到一定那个的规模一般来说，功能单一的小型项目的体系结构不会太复杂。不太会出现Bug的累积效应。小型项目完全可以通过daily meeting和Test来保证。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　Code Review并不是一个随便就可以做，或者做了就有好结果的活动。不过无论如何，一旦条件成熟或者资源充足都应该积极的开展Code Review的活动。因为它除了进行质量控制以外，还是一个团队成员之间进行沟通和相互<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: initial; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">学习</strong></u></a>的好机会。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"><strong style="word-break: break-all; line-height: normal !important;">　　Code Review的内容：</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"><strong style="word-break: break-all; line-height: normal !important;">　　1、代码的规范性</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　　　a、混乱而散漫的命名，例如使用a、b、c这样的单字母对变量进行无意义的命名</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　　　b、随处可见的magic number或则hard code。软件中const在所难免，不过这些const应该被集中管理起来。而不是可以随意、随处的出现</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　　　c、缺少注释，或者注释不完备甚至错误</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;"><strong style="word-break: break-all; line-height: normal !important;">　　2、代码的结构问题</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　　　a、巨大的类或者巨大的方法</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　　　b、过于复杂的实现</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　　　c、紧耦合</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　　　d、重复的代码<br /><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;"><strong style="word-break: break-all; line-height: normal !important;">　3、其他问题</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　　　a、缺少验证和异常处理。例如不对数据进行验证，或者不处理异常又或者捕获无法处理的异常</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　　　b、对工具和框架的错误使用。例如有的ORM框架提供非常方便的运行时延迟加载功能，方便倒是方便，滥用却会有性能隐忧</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　　　c、缺少可读性。注释和命名规范是一个问题，不过过深的调用层次都会影响代码可读性。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　　　d、缺少扩展性。例如在没有DLR的情况下在业务层使用匿名对象。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　　　e、缺少安全控制</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　　　f、性能隐患。例如在C#中使用了非托管资源而没有进行释放，或者说有过多、过于频繁的I/O访问</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;"><strong style="word-break: break-all; line-height: normal !important;">　　4、测试问题</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　　　a、没有测试或者覆盖度不够</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　　　b、测试代码滞后，在更改逻辑后没有对测试进行同步更新</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　以上是一些通常的Code Review的内容了。当然这里再强调一点的就是规范的完备性，和开发过程的成熟度。Code Review是一种相对高级软件开发活动，没有必要一定要执行。不过一旦实施成功将会有巨大的回报。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;"><strong style="word-break: break-all; line-height: normal !important;">　　在实施过程中还有一些心得：</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　1、做好准备。如果对项目很熟的话，应该知道哪些地方会有问题，Code Review是重新审视和从内因上解决这些问题的良机。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　2、不要考虑业务逻辑。完全专注于代码的实现，例如算法的效率，抽象的粒度。整个代码体系结构的平衡性</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　3、虚心学习。不要有针对性</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　4、在原则和现实之间平衡。不可能所有事情都完美，所以有的时候我们坚持原则，有的时候修改规范。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　5、不要让自己Review自己的代码</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　6、总结跟进Review的结果，并且坚持开展这个活动。这才是最重要的</p></p><img src ="http://www.blogjava.net/qileilove/aggbug/396579.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2013-03-18 10:11 <a href="http://www.blogjava.net/qileilove/archive/2013/03/18/396579.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>快速完成和读懂测试计划</title><link>http://www.blogjava.net/qileilove/archive/2013/02/26/395733.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Tue, 26 Feb 2013 03:05:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2013/02/26/395733.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/395733.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2013/02/26/395733.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/395733.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/395733.html</trackback:ping><description><![CDATA[<p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　每个项目<a href="http://www.51testing.com/html/65/n-837365.html" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important; "><u style="word-break: break-all; "><strong style="word-break: break-all; "></strong></u></a><u style="word-break: break-all; line-height: normal !important; "><strong style="word-break: break-all; "><a href="http://www.51testing.com/html/65/n-837365.html" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; "><u style="word-break: break-all; "><strong style="word-break: break-all; ">测试</strong></u></a>计划</strong></u>都会不一样，但是一般情况下，每个公司都会有相应的模板，尤其是项目很频繁的公司，相对应的模板应该就更全面，并且更容易修改，更能适应新项目。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　并且，经常接触测试计划的人可能会察觉到，实际上很多测试的计划都大同小意，里面有很多相似的模块，像是说明，<a href="http://www.51testing.com/html/65/n-837365.html" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important; "><u style="word-break: break-all; "><strong style="word-break: break-all; ">缺陷管理</strong></u></a>，项目通过标准，暂停标准，恢复标准，风险管理，等等，都是可以直接套用的，并且这其中有过多的官方的术语，就是一种套话，客套话，很多文字是为了使<a href="http://www.51testing.com/html/65/n-837365.html" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important; "><u style="word-break: break-all; "><strong style="word-break: break-all; ">文章</strong></u></a>更好去读，读起来更舒服，充当的是绿叶的角色。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　但是基本上说包含核心的内容都是根据不同的项目量身定做的，比如具体要测试特性，测试的milestone，schedule等等，这些是测试人员的测试的依据，时间安排的标准，是绝对马虎不得的，这也是测试计划的精髓所在。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　所以总的来说测试计划可以宏观的认为包含两个部分，一个是具体项目的测试安排，日程安排，人员分工，任务分工，里程碑的成果物等等，另一个是，适用于很多项目的一些约定俗成的标准，管理的方案，风险、缺陷的管理等等，这些不必随着项目的变化而更改，只要有一份模板，针对不同的项目进行简单的更改就可以了。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　其实这种写测试计划的方法也可以减少你的时间，更高效更有速度的阅读测试计划，因为当你拿到手中的是20几页的测试计划时，如果你选择从头一点一点的看，那真的很佩服你，如果是你的母语还好，文档若是一种外语，对自己来说很闹心，对公司来说也很浪费成本呀。一旦你清楚了测试计划中的窍门，你完全可一跳过那些标准，直接找到最核心的安排，分工，这样可以为您省去很多时间，也可以为公司创造更大的价值。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　如果您不是第一次接触测试计划，想必对这些会有一些感觉，对于读测试计划而言，知道这些是不够的，而需要的是去剖析一篇测试计划，一旦将其中的各个模块都弄懂了，在以后的阅读中就会是飞速了，不管阅读那个公司的，因为他们的本质是一样的，就有点像只要你掌握了一门编程语言，在去学其他的语言，也就是几个小时的事了。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　所以，理论讲到这里开篇也开到这里，接下来，我们就以随便的一篇文档进行剖析，最后可能会给各位一些网上普遍的测试模板，可以作为练习，自己阅读一下，是否可以快速阅读。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　我的这篇文档并非母语，所以各位要有准备，我们先从目录入手，简单预览一下：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　<a href="http://www.51testing.com/html/65/n-837365.html" target="_self" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important; "><u style="word-break: break-all; "><strong style="word-break: break-all; ">Test</strong></u></a>&nbsp;plan</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　1,introduction<br style="word-break: break-all; line-height: normal !important; " />　　2,test items<br style="word-break: break-all; line-height: normal !important; " />　　3,features to be tested<br style="word-break: break-all; line-height: normal !important; " />　　4,feature not to be tested<br style="word-break: break-all; line-height: normal !important; " />　　5,approach<br style="word-break: break-all; line-height: normal !important; " />　　6,item pass/fail criteria<br style="word-break: break-all; line-height: normal !important; " />　　7,suspension criteria and resumption requirement<br style="word-break: break-all; line-height: normal !important; " />　　8,test deliverables<br style="word-break: break-all; line-height: normal !important; " />　　9,testing task and schedule<br style="word-break: break-all; line-height: normal !important; " />　　10,environmental needs<br style="word-break: break-all; line-height: normal !important; " />　　11,staffing<br style="word-break: break-all; line-height: normal !important; " />　　12risks management<br style="word-break: break-all; line-height: normal !important; " />　　13,approvals</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　看起来有点多，不过仔细分析一下，里面需要写项只有1，3，4，8，9，10，11这几项，并且每一项需要写的东西都不多，其他的模块基本上都是绿叶啦！</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　在这些需要写的模块中，有些还只是更改部分就行了，并且，在有些项目中，其中的有些东西都可以省略，但是要看具体公司的规定，有些公司测试计划是越多越好呀，显得严谨周密，结果让写的人闹心，看得人也不舒心呀！</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　第1项中，有三项需要更改：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff; ">　　product summary（产品目录），主要就是列出一些项目的功能特性，包含哪些模块，哪些软件，对与比较大的系统列出来，更有利于后面的分析，但是小的系统就没什么必要了。references（参考文献），这个就比较随意了，一般都会列出不同参与者的一些资料</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　product milestore candidates（里程碑），这个是比较重要的，但是在后期也会出现，这里就是一个概览，一般都用表格的方式。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　第3项，是核心的东西，一般的就用这项来代替需求分析了，可能额外没有具体的需求分析文档，所以阅读时这是最重要的，和需求是统一等级的，所以在编写的时候也不仅仅测试经理自己写，可能更多的回去参考开发的需求，或者开发文档中的一些特性项目，这个应该不需要原创太多，主要是需求分析人员已经做好的东西搬过来了。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　第4项相对前面，就会好理解很多，主要由于一些硬性条件没法满足，无法进行测试的东西做一些说明。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　第8项，可以和里程碑相对应起来，但是又没有里程碑那么重要，就是在测试过程的小阶段说产生的成果物提前进行的一个预计，主要就是为了把一个很大的目标（一个一年或半年的项目顺利完成），拆分成一个月的成果检验（里程碑），然后再拆分两周的小任务，可以指导你短期的工作，但是，这个也会根据时间做适当的相应的调整的。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　第9项，这里主要的就是将里程碑进行完善和优化，要能够具体看了就知道怎么实施的文档。还有就是日程的安排，要对时间把握，另外有写时候会额外加一个文档schedule，专门就是做时间方面的计划的。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　第10项是，环境要求，这个就比较容易了，有什么写什么。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　第11项也是比较重要核心的东西，但是，有写的很详细，有些写的很宽松；对于大的项目，这个就会写的很简略，因为周期半年的项目没办法一下子把人员的任务都安排好呀，只能标记上需要哪些团队，都负责什么样的任务。具体的在根据具体的情况进行人员的分配。但是有些时候，对于项目比较小，可能就几周，人员也不多的时候，就需要将具体的分工分配下去，我当时分工分的很细，所以当时这个花费我很多时间去写，对后期的影响也很大，正因为这个任务分配的仔细，后期人执行起来有计可循，按照规定，每个人完成任务也都很有成就感。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　其余的就是额外的，基本也是不用动的，这其中包含了一个大块，里面有些很多文档的内容很丰富占了整个测试计划的很大的篇幅。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　第2项，列出了使用的测试的步骤，基本每个项目都可以按照这么去测试，里面包括冒泡，功能性能之类的，还会对具体的做一些特定的说明，尤其是公司会使用特定的工具。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　第5项这是篇幅最大的一个，里面冉冉就是一个测试方案的缩写版本，所以，这部分完全可以取代测试方案了，里面包括了测试用例的设计规则，使用的测试的方法（冒烟，交互性，系统，性能等等），缺陷管理的方法，缺陷曲线，会议评审的方式，测量和度量，这些都包括目标和范围，所以里面分析的很细，想必很多公司在弄这个的时候都是集结了很多经验的。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　第12项，风险管理，就是根据公司制定的了。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　综上所述，对这一个测试计划做了简单 的分析，相信可以类比到很多的测试计划。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　最后，再小小的总结一下，测试计划，其实是很简单的文档，写起来简单，读起来也简单，因为他有太多的相似和雷同，手中只要有一个模板，就有参考，再根据实际情况做一些小的调整。要弄清楚的是测试计划中核心部分和绿叶部分。</p><img src ="http://www.blogjava.net/qileilove/aggbug/395733.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2013-02-26 11:05 <a href="http://www.blogjava.net/qileilove/archive/2013/02/26/395733.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>敏捷软件测试——初见</title><link>http://www.blogjava.net/qileilove/archive/2013/02/18/395364.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Mon, 18 Feb 2013 02:53:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2013/02/18/395364.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/395364.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2013/02/18/395364.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/395364.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/395364.html</trackback:ping><description><![CDATA[<div><strong>　<a target="_self"><u><strong>敏捷</strong></u></a></strong><p>　　反应快速灵敏。</p><p>　　在敏捷<a target="_self"><u><strong>软件开发</strong></u></a>领域，更注重的以人为核心，迭代，循序渐进的开发方法。相比传统的开发方法，这种方法能更快速的开发，上线，反馈，调整、迭代。以敏捷的姿态去发展产品。</p><p><strong>　　敏捷与传统开发的区别</strong></p><p>　 　有个非常有意思的游戏能够帮助大家理解敏捷和传统开发的差异。游戏有两个角色，一个是&#8220;老板&#8221;，另一个是&#8220;员工&#8221;，在 2  分钟内，&#8220;员工&#8221;需要在&#8220;老板&#8221;的完全指挥下，即&#8220;向前一步，向后一步，停，向左一步，向右一步&#8221;，完成  60步移动的任务。&#8220;员工&#8221;需要执行&#8220;老板&#8221;的每一个指令，不允许做出相违背的动作。&#8220;老板&#8221;则不参与行动，只发出指令指挥&#8220;员工&#8221;的活动。我们体验这个 游戏 时，当场 60% 的参与者成功完成了任务，大致估计出我们的<a target="_self"><u><strong>工作</strong></u></a>效率是50%*60%=30%。游戏后，参与者被问及对这种行为方式的感受时，无论是&#8220;员工&#8221;还是&#8220;老板&#8221;都表示非常不满。</p><p>　 　接着，大家又做了另一组游戏。2 分钟内参与者被要求独立的、自主的完成 60  步移动任务，在这次游戏里，所有参与者任务相同，大家可以自行决定、并依据自己的判断随时调整其步伐方向，快慢。最后，我们发现所有参与者不但毫无折扣的  按时完成了任务，因而工作效率也达到 100%*100%=100%，而且所有人对于这种新的工作方式更是产生了极大的兴趣。</p><p><strong>　　敏捷开发与传统开发的比较</strong></p><p align="center"><a href="http://www.51testing.com/batch.download.php?aid=38054" target="_blank"><img style="width: 456px; height: 328px" src="http://www.51testing.com/attachments/2013/02/346836_201302051033351tB2O.jpg" border="0" height="328" width="494"  alt="" /></a></p><p align="left">　　通过上面有趣的两种游游戏的对比，以及价值表述的对比就折射出了传统开发与敏捷开发的方式的对比，其中的优劣不言而喻。</p><p align="left"><strong>　　敏捷开发</strong></p><p align="left"><strong>　　敏捷宣言：</strong></p><p align="center"><a href="http://www.51testing.com/batch.download.php?aid=38055" target="_blank"><img src="http://www.51testing.com/attachments/2013/02/346836_201302051033391ftc3.jpg" border="0" height="308" width="406"  alt="" /></a></p><p align="left">　　敏捷方法分类：</p><p align="center"><a href="http://www.51testing.com/batch.download.php?aid=38056" target="_blank"><img style="width: 386px; height: 339px" src="http://www.51testing.com/attachments/2013/02/346836_201302051033431Io1F.jpg" border="0" height="339" width="414"  alt="" /></a></p><p align="left">　　除了图例中的方法外还有 Crystal, Lean Software Development, Feature&nbsp; Driven Development, Xbreed, RUP 等等。</p>             </div><div><strong>敏捷方法的共性：</strong> <p>　　虽然各种敏捷方法的名称、所需环境、适合的团队有很大差异，但是他们拥有相似、相同的以下几大特点：</p> <p>　　* 拥抱变化</p> <p>　　&#8220;唯一不变的就是变化&#8221;所以，需求的变动是必不可少的，每次的决定和需求的调整都是将产品开发推向更正确的方向。而在接受变化的同时，我们应该积极的反馈显示活动中暴露出来的可能的设计缺陷和错误。</p> <p>　　* 客户的参与</p> <p>　　最终使用者、内部使用者、客户代表、商业伙伴都可以是我们的客户。对于客户的参与更能使我们做出客户真正需要的产品。</p> <p>　　* 较少的文档</p> <p>　　传统开发的文档在敏捷中仍有大用，只是我们可以将原来的文档进行精简。在敏捷中文档不是最佳的沟通方式，更鼓励通畅的交通和沟通，而沟通的效率远高于文档。</p> <p>　　* 最大化的生产力</p> <p>　　敏捷开发模式要最大化的提高团队的工作效率。无论是依靠剪除冗余的文档工作，还是提供民主的、通畅的沟通平台都是为了帮助 团队能够集中有限的精力处理。</p> <p>　　* 测试驱动开发</p> <p>　　是让开发人员在编写功能代码之前，根据对需求的理解先设计和编写单元测试代码。先思考如何对将要实现的功能进行验证，再考虑功能的实现。然后迭代的增加新功能的单元测试和功能代码编写，直到完成全部功能的开发。</p> <p>　　* 自动化冗余工作</p> <p>　　将团队成员从冗余的劳动中解放出来，无论是自动化的测试还是自动化工具的开发只要能够节约成本都是敏捷开发、敏捷测试的目标。</p> <p>　　* 民主的团队</p> <p>　　敏捷团队是一支民主的团队，团队关系是平行的，每个团队成员能够平等的参与讨论，决策。传统开发的垂直的官僚机构在敏捷开发中已是过时的。</p> <p><strong>　　敏捷测试</strong></p> <p>　　不是说敏捷测试么？这怎么看上去测试跟敏捷没一毛钱的关系。人家都敏捷了，还要测试做什？</p> <p>　　在敏捷开发流程中，测试不再是瀑布试开发流程的一个环节，而是全程参与整个开发流程。通过各种方式来保证产品的质量，无论是原则中的&#8220;频繁交 付&#8221;，还是对&#8220;可工作的软件&#8221;的度量，或是敏捷开发实践中的&#8220;测试驱动开发&#8221;，&#8220;行为驱动开发&#8221;，都离不开测试的支持。  当然，敏捷测试对测试人员提出了更高的要求，对测试人员来说也是新的挑战。</p> <p><strong>　　敏捷测试人员的定义</strong></p> <p>　　专业的测试人员，适应变化，与技术人员和业务人员展开良好的协作，并理解利用测试记录需求和驱动开发的思想。</p> <p>　　敏捷测试人员往往具有优秀的技术能力，知道如何与他人合作以实现自动化测试，同时也擅长探索性测试，他们希望了解客户在做什么，以此更好地理解客户的软件需求。</p> <p><strong>　　敏捷测试思想</strong></p> <p>　　对于一个敏捷团队而言，需要持续关注如何最出色地工作并发布最优秀的产品。根据我们的经验，这需要大量的训练、学习、时间、试验和协同工作。</p> <p>　　对于一个敏捷测试人员，他（她）会乐于收集和分享信息，与客户或者产品负责人协作以帮助他们充分展示自已的需求，从而得到他们需要的功能，同时向所有人提供项目进展的反馈。</p> <p>　　基本要求就是敏捷测试人员和其它敏捷团队成员一样，乐于学习新技能和面对新挑战，不会仅仅局限于测试问题。这不只是测试人员的特征，所有敏捷团 队人员都应具有。敏捷测试人员帮助开发人员和客户团他解决可能出现的任何问题。测试人员提供信息以帮助团队回顾和了解哪些方案有效，哪些无效。</p> <p>　　测试人员可能在测试领域拥有特殊的技能和经验，但一名优秀的测试人员并不惧怕参与一场设计讨论，提供有且于测试性或者构建更良好方案的建议。敏捷测试思想是面向结果的、技术性的、协作的，乐于学习的、勇于不断生产业务价值的。</p></div><div><strong>　测试人员的十条法则</strong> <p>　　敏捷测试人员的十条法则：</p> <p>　　&#9679; 提供持续反馈</p> <p>　　&#9679; 为客户创造价值</p> <p>　　&#9679; 进行面对面的沟通</p> <p>　　&#9679; 勇气</p> <p>　　&#9679; 简单化</p> <p>　　&#9679; 持续改进</p> <p>　　&#9679; 响应变化</p> <p>　　&#9679; 自我组织</p> <p>　　&#9679; 关注人</p> <p>　　&#9679; 享受乐趣</p> <p><strong>　　提供持续反馈</strong></p> <p>　　既然是测试驱动敏捷项目，那么很显然反馈在敏捷团队中占据重要的地位 。既然是测试驱动敏捷项目，那么很显然反馈在敏捷团队中占据重要的地位 。</p> <p><strong>　　为客户创造价值</strong></p> <p>　　敏捷开发就是在较低的版本发布中提供客户目前最迫切需要的功能。这通常意味着限定范围。我们经常在客户团队中遇到较酷功能的需求。任何人都可以质疑这些内容，但是测试人员会判断其对故事的影响，因为他们需要考虑测试后果。</p> <p><strong>　　进行面对面的沟通</strong></p> <p>　　一个团队如果沟通不好则难以协作。如今，许多团队分布于多个地理位置，沟通变得更加重要和富有挑战性。敏捷测试人员应该尽力促进沟通。这是把工作做好的关键因素。</p> <p><strong>　　勇气</strong></p> <p>　　勇气是极限编程的核心价值，类似测试自动化和持续集成的方式允许团队实践这种价值。  测试人员固守于自己的领域，不与其他业务相关者和技术团队进行任何讨论。虽然你找机会进入了协作的敏捷环境，可能会对找客户索要实例或者找开发人员帮忙自 动化测试或者在每日例会时提出一个难题等感到不习惯。</p> <p>　　当最初加入敏捷团队或者当前的团队开始过渡到敏捷开发模式时，通常你会产生恐惧感，并且存在大量的问题需要答案。我们到底如何才能在如此短的时 间内完成对每一个用户故事的测试任务？测试如何跟上开发的节奏？如何确定需要多少测试？又或者你是功能测试经理或者质量过程经理，但不清楚在敏捷团队中如 何定位自己的角色，也没人知道答案。敏捷测试人员需要勇气找到这些问题的答案，但需要勇气的原因不仅限于此。</p> <p><strong>　　简单化</strong></p> <p>　　敏捷测试人员和他们的团队面临的挑战不仅是生产最简单的有效软件而且还需要采取简单的方法以确保软件符合客户需求。这并不意味着团队不应该花时 间分析主题和故事、思考合适的架构和设计。而是说，当业务部门的需求比较复杂的时候，团队可能需要将方案退回给他们，更简单的解决方案也会产生同样的价 值。</p> <p>　　简单并不意味着容易。对于测试人员来说，这意味着采用能够找到的最轻量级的工具和技术恰到好处地测试。工具可以简单到只是一张电子表格或者清单。需要自动化回归测试，但是应该把它们分解到最底层以获取快速反馈。甚至简单的冒烟测试也可能满足面向业务的测试自动化。</p> <p><strong>　　持续改进</strong></p> <p>　　想办法把工作做得更出色是敏捷测试人员应牢记的。</p> <p>　　敏捷测试人员和他们的团队总是在寻找工具、技能或者实践以帮助他们增加更多价值或者得到更好的客户投资回报。敏捷开发的短期迭代更易于尝试新事物，以验证是否值得长期采用。</p> <p>　　学习新技能和提高专业技能水平对敏捷测试人员非常重要。可利用各种免费的资源提高专业技能。</p></div><div><p><strong>　　响应变化</strong></p> <p>　　响应变化是敏捷实践的重要价值，但是我们发现这对测试人员来说却是最困难的概念之一。测试人员渴望的是稳定，所以他们会说：&#8220;我已经测试过了， 任务完成了&#8221;。持续的需求变化是测试人员的噩梦。但是，作为一名敏捷测试人员，我们不得不拥抱变化。周三，我们可能期望启动故事A和B，下周五做故事C。 但是到了周五，客户重新设定了优先级，现在需要故事A、X和Y。只要我们持续与客户交流，我们就能处理这些变化，因为我们与团队的其他成员保持同步。</p> <p><strong>　　自我组织</strong></p> <p>　　敏捷测试人员是自组织敏捷团队的组成部分。团队文化贯彻于敏捷测试理念。当开发人员、系统管理员、分析员、数据库专家和客户团队持续关注测试和 测试自动化，测试人员就会获得全新的视角。自动化测试很困难，但是当整个团队都在为此努力时就会简单得多。当大家具有多重技能和多层次视角时，任何测试问 题都会更容易解决。</p> <p>　　当敏捷团队面对一个严重问题时，比如进度障碍或者构建失败，该问题将是所有人的问题。最高优先级的问题需要整个团队解决。团队应该立刻讨论并决定解决的办法和相关参与人员。</p> <p><strong>　　关注人</strong></p> <p>　　只有优秀的员工出色地工作，项目才会成功。敏捷价值和准则的宗旨是确保个人和团队成功。敏捷团队成员应该有安全感。不必担心因犯错受指责或者失 去工作。敏捷团队成员互相尊重并认可个人成就。敏捷团队的所有人应该有机会提高和发展他们的技能。敏捷团队以可持续的步伐前进，使他们能够遵循严格的实践 和保持崭新的视角。正如敏捷宣言所说，我们重视个人和合作超过过程和工具。</p> <p><strong>　　享受乐趣</strong></p> <p>　　在我们看来，测试人员的理想团队是：所有成员协作，从项目的开始一直到结束，利益相关者与开发团队共同工作，整个团队负责质量和测试。相信很多人都认为每个人都应该在工作中找到乐趣。敏捷开发珍视敏捷测试人员对工作的激情。</p> <p>　　敏捷测试人员的工作特别令人满意，因为我们的角度和技能对团队产生了真正的价值。</p> <p><strong>　　敏捷测试人员应该做什么？</strong></p> <p>　　看了这么多，你一定问：</p> <p>　　测试人员在敏捷团队中应该具备什么技能？</p> <p>　　测试人员在敏捷团队中从事哪些具体的工作？</p> <p>　　在敏捷软件开发过程中开展的测试就可以被称作是敏捷软件测试。因此，敏捷软件测试并不是一个与敏捷软件开发同一层次的划分，而是敏捷软件开发中 的一部分，与传统的测试不同，敏捷软件测试并不是一个独立的过程，相反，它与整个敏捷开发中的其他活动交织在一起，处处都能看到它的影子。由于敏捷软件测 试并不倾向于一个单独的过程定义，本人认为从敏捷软件测试与传统测试观点的比较、敏捷软件测试中采用的方法、测试工程师在敏捷软件测试过程中的工作等方面 来阐述。</p> <p>　　回答的很含糊，个人认为敏捷测试人员应该具备的两个主面。</p> <p>　　首先，接纳并理解敏捷的核心价值观（沟通，简单，反馈，勇气，尊重、学习、分享）。</p> <p>　　其次，测试人员应该具备测试基本技能，当然，可以擅长某个领域，如，探索性测试、单元测试。善于学习与分享，以学习的方式不断的提高自身去适应团队的需求。</p> <p>　　我想说的是，不管是从传统开发模式转到敏捷测试，还是重新组建一个敏捷的测试团队。并不是一蹴而就的事儿，需要长期的学习、摸索与改进。当然，前提是以敏捷的价值观为指导思想。</p> <p>　　-------------------------------------------------------------</p> <p>　　本文引用资料：</p> <p>　　段念《什么是敏捷软件测试》</p> <p>　　《IBM敏捷测试的最佳实践》</p> <p>　　《敏捷软件测试：测试人员与敏捷团队的实践指南》</p></div><img src ="http://www.blogjava.net/qileilove/aggbug/395364.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2013-02-18 10:53 <a href="http://www.blogjava.net/qileilove/archive/2013/02/18/395364.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>敏捷测试团队的人员分布</title><link>http://www.blogjava.net/qileilove/archive/2013/01/23/394654.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Wed, 23 Jan 2013 08:01:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2013/01/23/394654.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/394654.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2013/01/23/394654.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/394654.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/394654.html</trackback:ping><description><![CDATA[<p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　许多考虑采用<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: initial; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">敏捷</strong></u></a>的组织没有把团队迁移到开放式环境就尝试创建项目团队。敏捷价值和原则中，当团队成员可以随时接触到所有其他团队成员、易于获得所有的项目进度图表、在鼓励交流的环境中时，团队可以更好地<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: initial; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">工作</strong></u></a>。<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: initial; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">敏捷测试</strong></u></a>专家Lisa和Janet分享了敏捷测试团队的人力资源经验。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　测试人员和客户与程序员坐在一起可以促进必要的交流。如果实际情况不允许重新迁移位置，那么团队可以创造性地解决这问题。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　Janet分享了自己的故事：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　我曾经在这样一个团队工作，空间问题使得所有团队成员不能坐在一起。程序员有一个可以使他们方便结对编程的区域，但是测试人员和客户坐在其他的区域。首先，是测试人员走到程序员坐的用户故事白板区域去参加每日站立会议，当他们有需要问程序员的问题时，也是这样。基本没有程序员走到测试人员的区域（大约50英尺的距离）。我开始准备一些招待他们的糖果，并鼓励开发人员在需要的时候拿一些。但是有一条规矩&#8212;&#8212;如果他们来拿糖果，他们必须问其中一个测试人员一个问题。随着时间的过去，所有的团队成员都会相互走到另一个区域了。不是一边总走向另一边，交流也更频繁了。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　团队规模给组织带来了不同类型的挑战。小团队意味着小的区域，所以通常更容易将成员的位置换到一起。大的团队可能分布在全球，这时需要虚拟交流工具。调动大团队的座位通常意味着整修目前的空间，很多组织不愿意这么做。明白你的限制，努力找到团队遇到的问题的解决方法，而不是仅仅接受现实并&#8220;保持现状&#8221;。Janet举了一个例子：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　我工作过的一个团队一开始在楼层的一角，但是通过三年的扩张，逐渐的占据了楼层的75%。墙被拆掉了，去掉了办公室，创建了大的开放区域。团队在这种开放区域工作地很出色，但是所有的开放空间意味着墙没有了。窗子变成用户故事板和白板，白板按顺序卷起以便团队需要时使用。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　坐在一起的团队并不总是存在于完美世界中，分布式团队有另外的一些挑战。分布式团队需要帮助团队交流和合作的技术。电话会议、视频会议、网络摄像机和即时消息是一些可以促进在不同位置的团队实时协作的工具。不管团队是在一个位置的还是分布式的，通常存在的一个同样的问题是，敏捷团队需要什么资源，如何获取它们。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　新的敏捷团队成员和他们的经理对于团队的组成有很多疑问。可以使用在传统项目中同样的测试人员吗，或者是否需要聘用那个不同类型的测试人员？需要多少测试人员？是否需要具有其他专业技能的人？</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　关于测试人员和开发人员的&#8220;正确&#8221;比例的问题已经有很多讨论。组织使用这个比例来确定项目需要的测试人员的数量，可以根据这个数量来聘用测试人员。在传统项目中，没有&#8220;正确的&#8221;比例，每个项目需要自己估计。需要的测试人员的数量是不同的，依赖于应用的复杂性、测试人员的技能和使用的工具。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　Lisa和Janet曾经工作在不同的测试人员&#8212;&#8212;开发人员比例的团队，从1：20到1：1都有。以Janet来说：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　我曾从事一个开发消息处理系统的项目，他们的比例是1：10。GUI很少，我手动测试应用的这一部分，查看可用性和是否符合客户的期望。程序员做所有的自动化回归测试，我同他们一起验证编写的<a href="" target="_self" style="word-break: break-all; color: #202859; text-decoration: initial; line-height: normal !important;"><u style="word-break: break-all;"><strong style="word-break: break-all;">测试用例</strong></u></a>的有效性。我把测试的用户故事，包括某些用户故事的负载测试，分配到开发人员。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　我从来没觉得没有足够的时间做需要的测试，因为开发人员相信质量是整个团队的责任。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　Lisa则分享了自己的故事：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: #ffffff;">　　我曾经是一个有20名程序员的团队的唯一一名专业测试人员，该团队开发在线商店网站的内容管理系统。当程序员负责手动测试和测试自动化时，团队才真正有工作效率。一个或两个程序员在每个迭代的中扮演测试人员，在编码前编写面向客户的测试并执行手动测试。其他的程序员在迭代中承担起测试自动化的任务。<br /><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">相反的，我现在的团队每三或五个程序员有两个测试人员。我们生产的基于web的财务应用有非常复杂的业务逻辑，有很高的风险，而且密集测试。测试任务通常与编码任务的时间一样多。即使是测试人员&#8212;&#8212;开发人员高比例，程序员也会做一些功能测试自动化并部分承担手动测试任务。专门的测试任务，例如编写高层次的测试用例和详细描述面向客户的测试通常由测试人员完成。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　与其关注比例，团队更应该估计他们需要的测试技能并找到合适的资源。负责测试的团队可以持续地估计是否有需要的技能和数量。使用回顾总结来确定是否需要聘用更多的测试人员是一个解决方法。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　测试人员适合敏捷团队的工作需要一定的条件。我们不会过多讨论聘用什么类型的测试人员的细节，因为每个团队的需求是不同的。但是，我们相信态度是一个重要的因素。下面是Lisa的团队如何聘用一个新的敏捷测试人员的故事：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　我们招募另一名测试人员的第一次尝试并不是很成功。第一个工作招聘公告吸引了很多人，我们面试了三名应征者，但是没有找到合适的人选。程序员希望找到&#8220;技术人员&#8221;，但是我们也需要有同业务人员合作和帮助他们描述实例和需求的技能的人。为了吸引有正确的态度和思想的应聘者，我们努力明确工作招聘公告的内容。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　在听取Janet和敏捷测试社区的其他同事的想法和建议以后，Lisa改变了工作招聘公告，包含如下的条款：</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　&#9679; 熟悉黑盒和GUI测试用例，设计测试减轻风险，帮助业务专家定义需求。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　&#9679; 熟练编写简单的SQL查询和插入/更新语句，掌握Oracle或其他关系型数据库的基础知识。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　&#9679; 至少使用某种脚本语言或编程语言和/或开源测试工具超过一年。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　&#9679; 使用基本Unix命令的能力。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　&#9679; 擅长与程序员和业务专家协作。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　&#9679; 最好有基于上下文环境的测试、探索性测试或场景测试的经验。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　&#9679; 融入自组织团队的能力，即与同事协调确定每天的任务，而不是等待分配的工作。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; line-height: 21.600000381469727px; font-size: 12px;">　　Lisa表示：这些需求带来了更适合敏捷测试工作的应聘者。我通过小心的筛选，排除了有&#8220;质量警察&#8221;思想的人。追求职业发展和对敏捷开发显示出兴趣的测试人员更倾向于有正确的思想。团队需要对测试工具和自动化领域有较强能力的人，所以学习的热情是极为重要的。这种新颖的招募测试人员的方式是值得的。当时，找到好的&#8220;敏捷测试&#8221;候选者是不容易的，但是接下来进行得更顺利。我们发现把测试职位公告放到不那么明显的位置，例如Ruby的邮件列表或者本地敏捷用户组，可以帮助延伸到更广阔范围的合适的候选者。招聘敏捷测试人员教授了我许多关于敏捷测试思想。有良好技能的测试人员对于任何传统测试团队都是有价值的，但是因为他们对测试的态度，可能不适于敏捷团队。</p><br /></p><img src ="http://www.blogjava.net/qileilove/aggbug/394654.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2013-01-23 16:01 <a href="http://www.blogjava.net/qileilove/archive/2013/01/23/394654.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>通过增加代码覆盖率提高单元测试的质量</title><link>http://www.blogjava.net/qileilove/archive/2013/01/08/393982.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Tue, 08 Jan 2013 10:13:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2013/01/08/393982.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/393982.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2013/01/08/393982.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/393982.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/393982.html</trackback:ping><description><![CDATA[<p>　<strong>简介：</strong>&nbsp;许多<a href="" target="_self"><u><strong>敏捷</strong></u></a><a href="" target="_self"><u><strong>软件开发</strong></u></a>团队都面临的一个挑战是，确保其<a href="" target="_self"><u><strong>单元测试</strong></u></a>包含大部分代码。这在确保他们创建尽可能少的缺陷并且代码可重构时非常重要。因此，重要的度量指标（除了通过的所有测试之外）之一是已包含的代码数量。从 <a href="" target="_self"><u><strong>Rational</strong></u></a> Application Developer 8.0.3 开始，您可以配置 IBM&#174; Rational&#174; Application Developer 并将它与 IBM&#174; Rational Team Concert&#8482; 集成，以便在交付代码之前运行测试并检查<a href="" target="_self"><u><strong>代码覆盖率</strong></u></a>。本文将介绍如何设置此先决条件（名为 Code Coverage Advisor），还将介绍如何使用它来增加项目中测试的代码的覆盖率。</p><p>　 　在许多类型的开发项目中，无论您使用的是敏捷开发方法、Rational Unified Process  （RUP），还是瀑布式开发方法，在开发期间，测量已执行代码的数量是一个主要度量指标。这对开发人员和测试人员都很重要，因为当开发人员生成具有高代码 覆盖率的代码时，测试团队可以关注代码是否满足业务目标，而不是陷入大量低级代码缺陷中。</p><p><strong>　　当代码覆盖率非常重要时</strong></p><p>　　下列是代码覆盖率非常重要时的一些场景的常见示例：</p><p>　　&#9679; 任何想要响应业务并以低风险方式进行更改的团队</p><p>　　&#9679; 正在开发代码、想要提供<a href="" target="_self"><u><strong>工作</strong></u></a>质量可见性或需要满足约定的 SLA 的第三方</p><p>　　&#9679; 当某个项目定义了开发和测试之间的协议，以便通过开发测试获得代码覆盖率时，这意味着测试团队在捕捉代码错误上花费的时间更少</p><p>　　&#9679; 敏捷团队可能想要在每个 sprint（冲刺阶段）结束时制定发布代码决策，因为这会提高交付物的质量，在将代码用于生产之前很少需要转换代码</p><p>　　&#9679; 一些想要减少技术债务的团队，这些团队可以逐渐增加单元测试的数量并重构代码，从而减少错误并减低复杂性</p><p>　　&#9679; 想要通过构建度量程序来衡量质量和技术债务的组织，这样做可及早发现发展趋势并进行相应的改进</p><p>　 　许多敏捷团队都面临的一个具体挑战是，确保他们的单元测试包含大部分代码。这在确保他们创建尽可能少的缺陷并且代码可重构时非常重要。（考虑到团队发展 的趋势是涉及很少的设计或没有设计，则具有良好的单元测试非常重要。）一个主要度量指标（除了通过的所有测试）是已包含的代码数量，这是新 <a href="" target="_self"><u><strong>IBM</strong></u></a>？ Rational？ Application Developer 版本发挥作用的地方。</p><p>　 　今年早些时候，我编写了一个原型扩展，用该扩展来集成 IBM？ Rational Team Concert？ 和 Rational  Application Developer。如果没有足够的代码覆盖率，就会阻止交付给 Rational Team Concert 的代码，正如在  Rational Application Developer 中测量的那样。此扩展（现在名为 Code Coverage  Advisor）已正式纳入 Rational Application Developer 中，在版本 8.0.3  之后都可以找到它。这意味着您现在可以配置 Rational Application Developer 和 IBM Rational Team  Concert，在交付代码之前检查代码覆盖率。本文将介绍如何设置它，以及在项目开发期间如何使用它来提高代码覆盖率。</p><p><strong>　　提示：</strong></p><p>　　您需要了解一些 Rational Application Developer 知识才能理解本文。</p><p>　　后面的内容包含了三个主题：</p><p>　　1、何时适合使用 Code Coverage Advisor</p><p>　　2、当使用在 Rational Application Developer 中配置的此额外过程交付代码时会发生什么事</p><p>　　3、如何配置 Rational Team Concert 以使用 Advisor</p><p><strong>　　最适合使用 Code Coverage Advisor 的情况</strong></p><p>　　如何使用 advisor？以下是两个主要场景：</p><p>　　&#9679; 第一个场景针对的是新项目，出现在您想要确保单元测试提供足够的代码覆盖率时。在这种场景下，可使用 Advisor 帮助开发团队维护高标准的单元测试和代码覆盖率。</p><p>　 　&#9679; 第二个场景针对的是您想要改进的具有糟糕的单元测试或不存在单元测试的项目。通过打开  Advisor，要求开发人员为他们修改的代码提供单元测试，这样这些团队可以一种简单、递增且可管理的方式进行改进。此外，这种方法意味着正在编写的单 元测试将包含正在修改的代码；因此，开发人员很可能会发现缺陷。</p><p>　　在这两种场景中，Code Coverage Advisor  可提供大量价值，通过帮助团队维护单元测试的高代码覆盖率来改进其代码质量。下一部分将介绍开发人员在已经配置了代码覆盖率功能时如何使用  Rational Application Developer 交付代码。<br /><br /><p><strong>　使用 Rational Application Developer 中的新流程交付代码</strong></p> <p>　　您需要做的第一件事是（如果还没有做）配置项目，以收集代码覆盖率信息。</p> <p>　　配置项目的流程</p> <p>　　1、在 Project Explorer 中右键单击项目，选择 Properties。</p> <p>　　2、然后从菜单中选择 Code Coverage ，采用与设置团队相同的方式设置项目的代码覆盖率信息（参见图 1）。</p> <p align="center">图 1.项目代码覆盖率配置</p> <p align="center"><a href="http://www.51testing.com/batch.download.php?aid=37607" target="_blank"><img style="width: 380px; height: 287px" src="http://www.51testing.com/attachments/2013/01/346836_201301051108311sb6z.jpg" border="0" height="287" width="406"  alt="" /></a></p> <p align="left"><strong>　　使用启动的流程交付代码时会发生什么事</strong></p> <p align="left">　　在配置了代码覆盖率后，Code Coverage Advisor 会检查文件的覆盖率，以确定是否交付了代码。Coverage Advisor 在下列情况下不支持交付代码：</p> <p align="left">　　&#9679; 覆盖率低于目标水平。</p> <p align="left">　　&#9679; 覆盖率过期了（例如，您已修改了其中一个文件，但没有重新运行测试）。</p> <p align="left">　　&#9679; 项目未启用代码覆盖率。</p> <p align="left">　　在这些情况下，需要开发人员在交付代码前提高覆盖率。但是，如果已大致配置了流程，并且人员具有必备的权限，那么开发人员可选择忽略警告并交付代码覆盖率不足的代码。</p> <p align="left">　　让我们看一个示例。在如图 2 所示的项目中，您可以看到，HelloWorld.java 类并不满足覆盖率要求。</p> <p align="center">图 2. Project Explorer 显示了失败的代码覆盖率</p> <p align="center"><a href="http://www.51testing.com/batch.download.php?aid=37608" target="_blank"><img style="width: 274px; height: 122px" src="http://www.51testing.com/attachments/2013/01/346836_201301051108361P93K.jpg" border="0" height="132" width="274"  alt="" /></a></p> <p align="left">　　如果您尝试交付代码，交付将失败，您将得到如图 3 所示的流程建议：重写&#8220;Prohibit Unsatisfactory Code Coverage&#8221;先决条件。</p> <p align="center">图 3. 代码覆盖率交付失败</p> <p align="center"><a href="http://www.51testing.com/batch.download.php?aid=37609" target="_blank"><img style="width: 388px; height: 140px" src="http://www.51testing.com/attachments/2013/01/346836_201301051108391voE2.jpg" border="0" height="161" width="432"  alt="" /><br /><p><strong>　在 Rational Team Concert 中设置流程</strong></p> <p>　　在流程中存储信息意味着集中存储所必需的代码百分比阈值，并在团队中平等应用它们（尽管您可要针对不同组件配置不同的代码覆盖率要求，如后面所见）。您可以在本地客户端设置不同的覆盖率设置，但是当交付代码时将使用基于服务器的设置。</p> <p><strong>　　配置流程</strong></p> <p><strong>　　提示：</strong></p> <p>　　在开始前，您需要具有修改 Project Area 的流程的相应角色。</p> <p>　　1、从 Eclipse shell，导航到 Work Item 视图，打开 Team Artifacts 视图。</p> <p>　　2、在想要配置的项目区域右键单击，并选择 Open。</p> <p>　　3、然后单击 Process Configuration 选项卡打开流程编辑器（图 4）。</p> <p align="center">图 4. 流程配置编辑器</p> <p align="center"><a href="http://www.51testing.com/batch.download.php?aid=37610" target="_blank"><img style="width: 360px; height: 164px" src="http://www.51testing.com/attachments/2013/01/346836_201301051108431VHjU.jpg" border="0" height="202" width="416"  alt="" /></a></p> <p align="left">　　1、打开 Team Configuration 视图，选择 Deliver (client) 操作，然后选择 Everyone (default) 列下面的单元格，如图 5 所示。</p> <p align="center">图 5. 交付选项</p> <p align="center"><a href="http://www.51testing.com/batch.download.php?aid=37611" target="_blank"><img src="http://www.51testing.com/attachments/2013/01/346836_201301051108471fsOR.jpg" border="0" height="150" width="492"  alt="" /></a></p> <p align="left"><strong>　　将足够的代码覆盖率配置为先决条件</strong></p> <p align="left">　　现在您准备好配置规则，然后可以检查每次有人交付代码时代码覆盖率是否足够。</p> <p align="left">　　1、添加一个先决条件来检查代码覆盖率：</p> <p align="left">　　a）在 Preconditions 部分单击 Add，选择 Prohibit Unsatisfactory Code Coverage（参见图 6）。</p> <p align="left">　　b）配置所需的各种代码覆盖率级别。</p> <p align="left">　　您可以在源代码的不同级别指定所需的覆盖率。例如，每个文件可能需要 70%  的行覆盖率；但是，开发人员对每种类型必须具有 100%  的覆盖率。您还可以正则表达式以将文件从覆盖率统计信息中排除，这在您具有一些自动生成的不在意覆盖率的代码时很有用。最后，不同的组件可以具有不同的规 则，方法是指定这些覆盖率设置应用的组件。</p> <p align="center">图 6. Prohibit Unsatisfactory Code Coverage 配置</p> <p align="center"><a href="http://www.51testing.com/batch.download.php?aid=37612" target="_blank"><img style="width: 396px; height: 273px" src="http://www.51testing.com/attachments/2013/01/346836_201301051108531RCpO.jpg" border="0" height="309" width="450"  alt="" /></a></p> <p align="left">　　2、现在保存流程，这些新规则会在您下次交付代码时生效。</p></a></p></p><img src ="http://www.blogjava.net/qileilove/aggbug/393982.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2013-01-08 18:13 <a href="http://www.blogjava.net/qileilove/archive/2013/01/08/393982.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ET道场小记</title><link>http://www.blogjava.net/qileilove/archive/2012/10/16/389634.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Tue, 16 Oct 2012 01:45:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2012/10/16/389634.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/389634.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2012/10/16/389634.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/389634.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/389634.html</trackback:ping><description><![CDATA[<p style="word-break: break-all; margin: 10px 0px; padding: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; text-align: left; background-color: #ffffff; ">　　作为<a href="" target="_self" style="word-break: break-all; color: #202859; line-height: normal !important; "><u style="word-break: break-all; "><strong style="word-break: break-all; ">测试</strong></u></a>人员，几乎人人都有意无意地做着<a href="" target="_self" style="word-break: break-all; color: #202859; line-height: normal !important; "><u style="word-break: break-all; "><strong style="word-break: break-all; ">探索式测试</strong></u></a><z style="word-break: break-all; line-height: normal !important; ">，但真正做好探索式测试的需要大量练习。为了练习和提高探索式测试的技能，我们测试团队近期又组织了一次探索式测试道场。（关于探索式测试道场，请参考<z style="word-break: break-all; ">http</z>://<z style="word-break: break-all; ">www</z>.<z style="word-break: break-all; ">testingdojo</z>.<z style="word-break: break-all; ">org</z>/<z style="word-break: break-all; ">tiki-index</z>.<z style="word-break: break-all; ">php</z>?<z style="word-break: break-all; ">page</z>=<z style="word-break: break-all; ">Testing</z>%20Dojos）这次我们沿袭上次的新老测试人员结对的方式，只是换做老测试人员执行，新测试人员观察和建议。测试的任务是在30分钟内对一个探索式测试工具<z style="word-break: break-all; ">RapidReporter</z>进行测试和评估，看是否有充足理由表明我们不能在日常</z><a href="" target="_self" style="word-break: break-all; color: #202859; line-height: normal !important; "><u style="word-break: break-all; "><strong style="word-break: break-all; ">工作</strong></u></a>中使用它。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; text-align: left; background-color: #ffffff; ">　　作为此次活动的组织者，我观察到了一些和上次新测试人员主测时不一样的一些现象。（关于上次探索式测试道场的总结，请参考<a href="http://www.51testing.com/?uid-56882-action-viewspace-itemid-814226" style="word-break: break-all; color: #202859; text-decoration: none; line-height: normal !important; ">http://www.51testing.com/?uid-56882-action-viewspace-itemid-814226</a>）本文将对这些现象进行总结。因为类似的现象或多或少在我身上也存在,本人也从个人角度提出了相应改进的建议，以供大家讨论。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; text-align: left; background-color: #ffffff; ">　　我将我观察到的主要问题总结为CUTE，即Charter，User，Thinking，Experience四个方面。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; text-align: left; background-color: #ffffff; "><strong style="word-break: break-all; line-height: normal !important; ">　　问题1：Charter定得不好</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; text-align: left; background-color: #ffffff; ">　　因为大部分人对RapidReporter不熟悉，所以本次道场大部分测试人员制定的Charter类似于&#8220;熟悉该软件基本流程，模拟用户操作&#8221;。而针对原始目标&#8220;看是否有充足理由表明我们不能在日常工作中使用RapidReporter&#8221;，其实更应该去寻找用户可能碰到的比较严重的问题或者极限情况下不能处理的问题。因为大家把熟悉软件基本流程作为了Charter，所以在整个session中大量的时间放在了摸索一些细节的功能上，而对于其它耗时较多的或者破坏性的测试即使有想到，测试时间也不多。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; text-align: left; background-color: #ffffff; ">　　缺乏清晰的指导和实例分析，我想这是我们在实践<z>SBTM</z>之初不太容易写好<z>Charter</z>的原因之一。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; text-align: left; background-color: #ffffff; "><z>　　<z>Charter</z>（测试章程）是基于测程的探索式测试(<z>SBTM</z>)中比较核心的一个概念。根据提出<z>SBTM</z>方法的<z>Bach</z>兄弟中的<z>Jonathan</z> <z>Bach</z>在<z>Session-based</z>&nbsp;</z><a href="" target="_self" style="word-break: break-all; color: #202859; line-height: normal !important; "><u style="word-break: break-all; "><strong style="word-break: break-all; ">test</strong></u></a><z>&nbsp;<z>management</z>一文中的表述：&#8220;<z>By</z>&#8216;<z>chartered</z>&#8217;, <z>we</z> <z>mean</z> <z>that</z> <z>each</z> <z>session</z> <z>is</z> <z>associated</z> <z>with</z> <z>a</z> <z>mission</z>&#8212;<z>what</z> <z>we</z> <z>are</z> <z>testing</z> <z>or</z> <z>what</z> <z>problems</z> <z>we</z> <z>are</z> <z>looking</z> <z>for</z>.&#8221;我们可以了解到<z>Charter</z>主要是为每一个<z>session</z>制定一个目标，测什么或者找什么。但在同一篇</z><a href="" target="_self" style="word-break: break-all; color: #202859; line-height: normal !important; "><u style="word-break: break-all; "><strong style="word-break: break-all; ">文章</strong></u></a><z>中稍后的部分，我们又看到了这样的描述&#8220;<z>Session</z> <z>charter</z> (<z>includes</z> <z>a</z> <z>mission</z> <z>statement</z>, <z>and</z> <z>areas</z> <z>to</z> <z>be</z> <z>tested</z>)&#8221;。这里表明<z>Charter</z>是既要包含测试目的又包含测试范围的，而不是二者之一。所以这里会让人产生一些疑问。虽然探索式方面的资料比较多，但对于什么样的<z>Charter</z>才是好的<z>Charter</z>，不好的<z>Charter</z>会带来哪些问题，我目前还没有找到太多资料。</z></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; text-align: left; background-color: #ffffff; "><strong style="word-break: break-all; line-height: normal !important; ">　　制定Charter的改进方法：</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; text-align: left; background-color: #ffffff; ">　　在<a href="" target="_self" style="word-break: break-all; color: #202859; line-height: normal !important; "><u style="word-break: break-all; "><strong style="word-break: break-all; ">敏捷</strong></u></a><z>开发中描述用户故事的时候，我们常用这样的标准格式＂<z>As</z> <z>a</z> ..., <z>I</z> <z>want</z> <z>to</z> ..., <z>so</z> <z>that</z> ..."。为了让<z>Charter</z>的制定更有效和简洁，我也想用一种标准格式＂<z>By</z> <z>testing</z> ...<z>through</z> ... <z>to</z> ..."来规范<z>Charter</z>的制定。通过这样的格式，可以强迫你在开始测试前就明确本次测试中核心的三个元素：测试范围、测试方法、测试目标。按照这样的格式，我们可以较容易地制定出有效的<z>Charter</z>。比如，通过参考需求文档测试<z>A</z>功能来熟悉此功能与其它系统的交互；通过数据的多样性变化来测试<z>B</z>流程对各种数据的容错能力；通过检查<z>UI</z>来测试<z>C</z>模块是否符合<z>UI</z>规范。</z></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; text-align: left; background-color: #ffffff; "><strong style="word-break: break-all; line-height: normal !important; ">　　问题2：从用户角度的测试还不够多，不够真实</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; text-align: left; background-color: #ffffff; ">　　针对本次道场的测试目标，如果我们从用户的角度考虑，有很多值得尝试的方向。如，不同用户环境的异构性（包括<a href="" target="_self" style="word-break: break-all; color: #202859; line-height: normal !important; "><u style="word-break: break-all; "><strong style="word-break: break-all; ">操作系统</strong></u></a>、语言包等）、工具本身对.NET 3.5的要求与我们被测系统可能的冲突、超长时间的session、记录大量数据的session、双屏下的截屏。。。从本次道场单个测试人员的思路上来看，想到的还不够多。同时，部分测试人员使用的测试数据也不够真实。比如，如果我们只用bug1这样的测试数据来作为bug记录，那么我们怎么能确认象平时一个bug的简要描述可能需要30~50个字符的时候程序确实可以正常记录呢？又如，为了造超长的字串或者特殊字符，有的测试人员在敲键盘，有的在别的文档中拷贝一段字串过来，但是是否直接把前两天你报的一个真实的带有出错<a href="" target="_self" style="word-break: break-all; color: #202859; line-height: normal !important; "><u style="word-break: break-all; "><strong style="word-break: break-all; ">日志</strong></u></a>的缺陷录入进来可能更有说服力呢？因为一个真实的出错日志，其长度和本身包含的特殊字符比我们自己臆造的要更有效。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; text-align: left; background-color: #ffffff; "><strong style="word-break: break-all; line-height: normal !important; ">　　从用户角度测试的改进方法：</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; color: #333333; font-family: Arial, Helvetica, sans-serif; font-size: 12px; text-align: left; background-color: #ffffff; ">　　如果被测系统是面向广大人民群众的，如<a href="" target="_self" style="word-break: break-all; color: #202859; line-height: normal !important; "><u style="word-break: break-all; "><strong style="word-break: break-all; ">互联网</strong></u></a><z style="word-break: break-all; line-height: normal !important; ">或移动类型的应用，那就做role play，把你自己想象成你熟悉的每个人：年老的父母，淘气的孩子，爱音乐的朋友，忙碌的自己。。。当然，还要知道你的产品最关注的人群，从而加强对他们特点的模拟。如果被测系统是有一定专业性的，那只有增强自己的专业知识，并运用专业知识来指导你的测试。如果可能的话，我们需要</z><a href="" target="_self" style="word-break: break-all; color: #202859; line-height: normal !important; "><u style="word-break: break-all; "><strong style="word-break: break-all; ">学习</strong></u></a>业务领域知识，使用业务上类似的其它软件，分析产品环境的数据，从而了解并模拟用户常用的和可能的流程、数据等。另外，去客户现场感受他们的工作环境、软硬件设备、输入习惯、出错概率、工作效率等也十分有益。当我们在戏谑不写<a href="" target="_self" style="word-break: break-all; color: #202859; line-height: normal !important; "><u style="word-break: break-all; "><strong style="word-break: break-all; ">单元测试</strong></u></a>的开发人员是不系保险绳的徒手攀岩新手，不了解用户场景的测试人员是否也一样呢？<br /><br /><br /><br /><p style="word-break: break-all; margin: 10px 0px; padding: 0px; "><strong style="word-break: break-all; line-height: normal !important; ">　　问题3：忙于敲键盘和点鼠标，主动思考太少</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　虽然探索式测试讲究的是根据上一个输出决定下一步输入，但如果全是这种＂反应＂式的被动思考，那么很容易迷失测试思路。如果我一而再再而三地走一步看一步，却处处碰壁得不到想要的结果，那么我很可能在这条纵深的路上已经走了太远，心理上感到严重受挫，从而不甘心另起炉灶从零开始，于是犹豫中还会在以前走过的路径上再次盲目搜寻。这时我的输入变成一种下意识的惯性行为，测试可以说已经失控。当我在道场中观察别人操作的时候，我发现新老测试人员都会有这样的失控时刻。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; "><strong style="word-break: break-all; line-height: normal !important; ">　　思考的改进方法：</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　我想，如果在探索式测试中，在大量反应式的被动思考的同时结合一定的主动思考，则应该会有更好的效果。比如，我们可以在设立了测试章程后花几分钟时间用思维导图的形式主动构思几个测试方向，然后在每个方向上更多地依赖观测到的现象决定下一步。当然，我们也可能会因为收获了新的信息而修改原来的方向。但真正开始动手执行测试前让脑子先行，可以在测试的广度上有一个好的基础，辅助以执行过程中每条思路下的探索，在测试的深度上也能收放更为自如。又如，当我们碰到了测试的瓶颈，脑子暂时短路的时候，不如暂停操作，换为纯思考，好好整理一下思路，理一理头绪。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; "><strong style="word-break: break-all; line-height: normal !important; ">　　问题4：被原有测试经验所累，运用新的经验较慢</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　人的经验在大部分的时候都是双刃剑。丰富的测试经验在我们身上烙下深深的烙印，它有时是一种优势，有时是一种束缚。在本次道场中，虽然我们明明知道环境的兼容性是本次测试中我们更需要测试的高风险的地方，但在不知不觉中我们已经在超长字符和快捷键这种细节处浪费了太多时间。我想这是因为在过去我们的测试中，这一类型的测试是必要（用户关心）且有效的（可以找到缺陷），而我们在进入本次测试的时候没有刻意摆脱这种经验的影响。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; "><strong style="word-break: break-all; line-height: normal !important; ">　　经验主义的改进方法：</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　善用经验的关键是知道如何根据本次测试的上下文决定多大程度利用经验和抛弃经验。当我们测试熟悉的业务系统时，当我们的被测系统使用的是我们熟悉的技术时，当与我们合作的是熟悉的开发团队时，我们当然应该更多地参考甚至相信我们的经验。而当我们测试一个不熟悉的系统时，则更明智的选择是提醒自己不去太早地做太多假设和偏向某一种熟悉的曾经好用的测试思路，回到一些更抽象的测试模型，回到最基本的不讨巧的测试方法，紧扣本次测试任务制定相应的章程，和选择更适合本次测试的方法。</p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; "><strong style="word-break: break-all; line-height: normal !important; ">　　总结</strong></p><p style="word-break: break-all; margin: 10px 0px; padding: 0px; ">　　下一次探索式测试，无论是一个人孤独地坐在工位上进行，还是如这次大家在一起认真练习和热烈讨论，我都希望能够再<z>CUTE</z>一些，以简明的章程为核心，以多样的用户场景为测试手段，积极思考，善用经验，持续练习和提高探索式测试技能。</p></p><img src ="http://www.blogjava.net/qileilove/aggbug/389634.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2012-10-16 09:45 <a href="http://www.blogjava.net/qileilove/archive/2012/10/16/389634.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>探索式测试的思维模型</title><link>http://www.blogjava.net/qileilove/archive/2012/09/19/388038.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Wed, 19 Sep 2012 01:37:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2012/09/19/388038.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/388038.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2012/09/19/388038.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/388038.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/388038.html</trackback:ping><description><![CDATA[<div><p>　　上一章介绍了<a target="_self"><u><strong>探索式测试</strong></u></a>的定义。在实际项目的测试执行过程中，读者是否曾遇到如下的几个现象：</p><p>　　测试人员按照一个<a target="_self"><u><strong>测试用例</strong></u></a>来执行测试，得到的程序输出与预期输出不一致。</p><p>　　测试人员判断程序的行为并不是缺陷，但根据新的输出想到了新的测试思路。</p><p>　　测试人员根据新的测试思路采用不同的输入并检查程序输出。</p><p>　　测试人员再次根据新的测试结果选择新的输入，反复地探索下去，最终发现了一个程序缺陷。</p><p>　　测试人员发现该缺陷的测试思路或测试用例并没有出现在最初的测试设计或测试用例文档中。</p><p>　 　相信有很多读者熟悉上述的情景，也许有些人认为这是测试设计的遗漏，但笔者要告诉读者的是，千万不要怀疑你的测试设计能力，因为这是非常正常的现象。由 于我们还没有真正深入地了解产品，不可能在测试设计的时候想到所有测试场景，且在需求分析阶段不可能评审到所有的隐含需求，所以最初的测试设计并不能捕获 程序的所有缺陷。为了发现尽可能多的缺陷，测试人员需要在测试过程中，根据测试反馈持续地优化测试模型、调整测试设计。这是一个研究、实践和探索的过程。 了解探索式测试的思维将有助于测试人员更有效地测试。</p><p>　　根据测试专家Erik  Petersen对于探索式测试的理解，笔者抽象出探索式测试的思维模型 CPIE（Collation，Prioritization，Investigation，Experimentation），如图2.1所示。该测试 模型包含迭代的4个阶段：整理、排序、调查和实验。</p><p align="center"><a href="http://www.51testing.com/batch.download.php?aid=35209" target="_blank"><img src="http://www.51testing.com/attachments/2012/09/346836_201209061125591unIF.jpg" border="0"  alt="" /></a></p><p align="center">图2.1&nbsp; 探索式测试的思维模型</p><p align="left">　　整理（Collation）：尽最大可能收集关于被测产品的信息，去了解和理解它们。</p><p align="left">　　排序（Prioritization）：确定所有测试任务的优先级。</p><p align="left">　　调查（Investigation）：对即将执行的测试任务进行仔细的分析并确定测试输入和预期输出。</p><p align="left">　　实验（Experimentation）：实际地去测试，验证我们的预测是否正确，检查我们在整理阶段获取到的信息是否正确。根据实验结果，测试人员将收集更多的信息，并调整测试任务的优先级。</p><p align="left">　 　对于探索式测试的思维过程，测试专家 James  Bach提出了如图2.2所示的思维模型。该模型包含一组启发式问题，以推动测试人员在知识（Knowledge）、分析（Analysis）、实验 （Experiment）和测试故事（Testing Story）上深入探究。</p><p align="left">　　知识：掌握产品特性、开发技术、测试技术和领域规则等测试需要的知识。</p><p align="left">　　分析：分析产品风险、测试覆盖、测试方法、测试先知 和产品缺陷等测试相关因素。</p><p align="left">　　实验：配置、操作、观察和评估被测产品。</p><p align="left">　　测试故事：用测试计划、测试报告和可<a target="_self"><u><strong>工作</strong></u></a>的产品等组成测试报告，以准确地反映测试状态和产品质量。</p><p align="center"><a href="http://www.51testing.com/batch.download.php?aid=35210" target="_blank"><img src="http://www.51testing.com/attachments/2012/09/346836_201209061126031uNcP.jpg" border="0"  alt="" /></a></p><p align="center">图2.2&nbsp; 探索式测试的思维过程</p><p align="left">　 　从图2.1和图2.2可以看出James Bach和Erik  Petersen的观点都强调通过实验（Experiment）来持续改进测试设计。他们认为瀑布式的测试设计和用例编写并不会产生优质的测试设计，测试 人员还需要在测试执行的时候持续扩展新的测试思路，完善测试设计。在探索式测试过程中，测试<a target="_self"><u><strong>学习</strong></u></a>、测试设计、测试执行和测试评估是互相支持和驱动的活动。第4章将讲述几个案例来说明探索式测试这种迭代优化的测试风格。</p></div><img src ="http://www.blogjava.net/qileilove/aggbug/388038.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2012-09-19 09:37 <a href="http://www.blogjava.net/qileilove/archive/2012/09/19/388038.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>传统团队如何转变为敏捷团队？</title><link>http://www.blogjava.net/qileilove/archive/2012/09/04/386932.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Tue, 04 Sep 2012 02:06:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2012/09/04/386932.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/386932.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2012/09/04/386932.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/386932.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/386932.html</trackback:ping><description><![CDATA[<div><p><strong>　　问题</strong></p><p>　　问：传统的团队如何转化为<a target="_self"><u><strong>敏捷</strong></u></a>团队（步骤，要点，注意事项等）？</p><p>　　问：如果使用<a target="_self"><u><strong>敏捷开发</strong></u></a>，在公司组织架构上有没有什么建议？</p><p><strong>　　分析</strong></p><p>　　在谈到何为敏捷团队之前，先看看传统团队的问题，不要把团队转化完了，问题还存在；换言之，解决问题是目标，转化团队是手段。</p><p><strong>　　1、各部门打架严重</strong></p><p>　　来自于分工中的灰色地带 / 各自目标和绩效的不一致。</p><p>　　典型的是开发/测试团队，扩展而言，还包括市场/销售团队。</p><p>　　后两者也很关键，很多时候开发和<a target="_self"><u><strong>测试团队</strong></u></a>和谐了，联合起来和销售团队打架，公司的整体效率仍然上不去。</p><p>　　不过，如果没有在市场/销售团队的<a target="_self"><u><strong>工作</strong></u></a>经验，或管理他们的经验，谈论和过问与他们跨职能的难度很大。但这不等于这个问题不存在，可以请公司更上层的人去关注这个问题。本博客未来会提到市场/销售/开发团队的跨职能问题。</p><p><strong>　　2、各部门流程/文档繁杂</strong></p><p>　　为了解决打架问题，需要流程和文档来规范接口。</p><p>　　常常被过度写作的需求文档和设计文档，就是因为要跨过多个部门，才需要被&#8220;签字&#8221;&#8220;确认&#8221;&#8220;协调一致&#8221;，所以其写作的水平，往往超过&#8220;以能编写出软件为准&#8221;，而是达到&#8220;能交给下一个部门，让他们看完以后能编写出软件&#8221;为准。</p><p>　　跨职能团队是敏捷开发提出的团队模型（自组织是跨职能的产物，下面会看到），通过消除部门分割，来解决上面的两大难题。</p><p><strong>　　直接方案</strong></p><p>　　直接方案是那些几乎不需要其他实践，就能直接使用的方案，虽然他们也有一些先决条件。</p><p>　　世界上没有无条件的事，也没有生下来就有条件的人，所以很容易把喜欢找借口胜过方法的人卡住。如果下面这个事情仍然觉得很难办，那么多半还没有到谈论团队转型的阶段，请继续努力吧！</p><p><strong>　　3～5人规模的小组内实现跨职能（小组长可推行）</strong></p><p>　　这个是无需行政授权，小组长就能做的事情。</p><p>　　本人非常推崇通过1-3-9团队形成L型代码结构（文后有链接），局部的&#8220;部门&#8221;打架和文档问题迎刃而解。</p><p>　　139团队中，整个小组的目标是一致的，而且成败都由师傅负责，因此他会成为跨人员的桥梁，把整个团队的事情当作自己的事情，解决个人的打架问题。</p><p>　　L型代码结构可以有效降低文档量。当积木代码基本形成后，所有功能大致只有界面和业务逻辑的设计，经常一个功能只有50行代码左右，很多设计都可以因此省略。</p></div><div><p><strong>　　生态方案</strong></p> <p>　　生态方案多半不能直接就上，需要另外一些条件具备。</p> <p><strong>　　10～20人规模的开发组内实现跨职能（项目经理可推行）</strong></p> <p>　　实际上没有办法让10～20人可以互相修改别人的代码，但在这个规模上，合作的需求更高，代码的复用利益更大，跨职能势在必行。</p> <p>　　这里所说的跨职能，不是代码级别的，而是在业务接口问题上，大致有以下几种情况。</p> <p>　　一是经常有一些接口类功能，说不上来该谁做，这时候项目经理（就是10～20人的头）要协调其中一方完成，并为这方争取更多的资源（工期和人数）。</p> <p>　　这里多少要建立团队可以提请要人的机制，而且项目经理能临时分配人员，比如把小李交给老王那组工作一段时间之类的。在139团队里边这个相对好办一些，如果是1个人管理12个人，就很难办。</p> <p><strong>　　组织方案</strong></p> <p><strong>　　1、进度-质量目标的合并（研发的部门经理可推行）</strong></p> <p>　　也就是无论是否还有开发-测试的分割，必须把进度绩效和质量绩效统一管理。</p> <p>　　一个项目延期了，测试也有责任；一个项目质量差，开发也有责任。结果大致会变成：</p> <p><strong>　　测试团队与开发团队融合</strong></p> <p>　　一般是测试团队分解到开发组，从事自动化测试的执行工作。</p> <p>　　多数自动化脚本开发团队可以编写，但是多半要配置一些脚本、写一些测试用例什么的，由测试人员执行。</p> <p>　　这种模式下，对测试团队的人数要求很少。</p> <p><strong>　　测试团队与需求团队融合</strong></p> <p>　　质量工作彻底交给开发团队负责，测试团队只负责业务级别的验收测试（还负责早期的需求理解和机遇需求的测试用例编写）。</p> <p>　　开发团队分化出一些人负责执行测试，这些人的数量一样要求很少；开发团队同时对进度和质量负责。</p> <p>　　这两种方法都不容易做到，而且还有无穷无尽的问题，但告诉大家一个方法来解决：那就是每当自己心里想问：&#8220;可是，怎么&#8230;&#8230;呢？&#8221;，自己要先想三个答案，然后再问；有时候会发现不用问了，答案已经被自己说出来了。</p> <p><strong>　　2、市场/销售/产品/研发的跨职能（总经理/副总经理可以推行）</strong></p> <p>　　简单说就是市场/销售/产品团队，要为研发的成本负责（比如销售要先扣除研发成本，再谈提成）；而研发要为销售/市场负责（比如如果销售额上升，研发团队也有一个提成）。</p> <p>　　日后有机会再谈这个，很多企业都已经有成功经验了，只是都不太分享而已。</p></div><br /><br /><img src ="http://www.blogjava.net/qileilove/aggbug/386932.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2012-09-04 10:06 <a href="http://www.blogjava.net/qileilove/archive/2012/09/04/386932.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Scrum中的测试：人少事不少</title><link>http://www.blogjava.net/qileilove/archive/2012/08/31/386661.html</link><dc:creator>顺其自然EVO</dc:creator><author>顺其自然EVO</author><pubDate>Fri, 31 Aug 2012 02:04:00 GMT</pubDate><guid>http://www.blogjava.net/qileilove/archive/2012/08/31/386661.html</guid><wfw:comment>http://www.blogjava.net/qileilove/comments/386661.html</wfw:comment><comments>http://www.blogjava.net/qileilove/archive/2012/08/31/386661.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qileilove/comments/commentRss/386661.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qileilove/services/trackbacks/386661.html</trackback:ping><description><![CDATA[<div><p>　　<strong>导读：</strong>Scrum团队以小著称，团队中一般只有一到两名<a target="_self"><u><strong>测试</strong></u></a>人员，那么这一两名测试人员在Scrum团队中又是如何开展测试<a target="_self"><u><strong>工作</strong></u></a>，起着什么样的作用呢？</p><p>　　Scrum敏捷开发有一个明显特征就是重团队，轻部门，每个团队里面包含了开发、设计、测试各种角色，Scrum团队以小著称，团队中的测试人员一般只有一到两名。</p><p>　　在传统的瀑布式开发 中，测试人员经常因进入测试阶段的条件不满足而需要较长的等待。而在Scrum敏捷开发中，测试人员需要尽可能早的开展工作，&#8220;等待&#8221;在Scrum开发的测试中已属一种错误概念。</p><p>　　测试人员应具备三方面的能力：编码，测试和分析。不同的阶段对测试的要求不同，在<a target="_self"><u><strong>功能测试</strong></u></a>中偏重编程能力，在系统配置测试中偏重分析能力，Scrum团队中的测试人员需要将这三种能力融会贯通，才能适应迭代过程中的诸多变化。</p><p>　　测试是<a target="_self"><u><strong>软件开发</strong></u></a>中必不可少的一部分，那么Scrum团队中测试人员又要如何开展测试工作呢？</p><p>　　首先，测试人员要尽可能早地开始测试，不要等待到功能完全做好才开始。在产品开发的过程中，新需求和新功能在迭代中不断涌现，每次迭代结束都会产生一个可工作的软件，测试人员不能等到所有迭代结束之后再开始测试，而应该尽早开始进行测试。</p><p>　　其次，测试人员要尽可能多地采用<a target="_self"><u><strong>自动化测试</strong></u></a>。<a target="_self"><u><strong>敏捷</strong></u></a>项 目初期，产品停留在初步设计中，产品功能不多，复杂度小，手动测试就可以保证质量。而到了中后期，因不断有新需求、新功能的加入，产品复杂度显著增大。若 仍然采用手动测试，恐怕难以覆盖产品的各个功能、非功能点，而且手工测试在面对功能诸多的产品时，就会暴露出易遗忘的缺点。因此，可以用自动化测试来提高 工作效率。</p><p>　　然后就是，测试人员要学会做好需求分析，做好对设计逻辑的分析。测试人员要更多的思考需求的可实现性，将自身作为第一用户积极参与项目和系统的需求分析，设计和开发。积极地参与前期工作，并迅速反馈给设计和开发人员。</p><p>　　最后要强调的是 ，测试人员需要转变测试等待开发的思想。测试人员需要了解开发，需要读懂代码，才能够更好的帮助开发人员分析和分离复杂问题。有时候，测试人员可以成为开发人员的后备力量。当团队中需要更多的人编码时，测试人员应该站出来担当其职。</p><p>　 　开发和测试是相辅相成的。一旦基本验证测试通不过，那就说明产品违反了最初客户定义的需求，也就不能够提交。如果功能测试通不过，那么测试人员要及时与 开发人员沟通。如果是缺陷，则在每日站会中提出；如果不是，那么继续下一项工作。这个过程充分体现了Scrum敏捷开发所提倡的团队交流与合作机制，也是 体现了测试人员对于整个开发工作的重要作用。</p></div><img src ="http://www.blogjava.net/qileilove/aggbug/386661.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qileilove/" target="_blank">顺其自然EVO</a> 2012-08-31 10:04 <a href="http://www.blogjava.net/qileilove/archive/2012/08/31/386661.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>