<?xml version="1.0" encoding="gb2312" ?>
<rss version="2.0">
<channel>
<title>测试驱动开发</title>
<link>http://www.ltesting.nethttp://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/</link>
<description>软件质量保证 / 测试驱动开发</description>
<language>zh-cn</language>
<item>
    <title><![CDATA[PHP测试驱动开发介绍]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2012/0314/204394.html</link>
    <description><![CDATA[<p>
	　　摘要</p>
<p>
	　　本文向你介绍测试驱动开发的概念，并用一个简单的示例项目来做示范。</p>
<p>
	　　介绍</p>
<p>
	　　开发PHP产品有很多不同的方法。我们大多数倾向于从一个简单的脚本开始，逐步向前推进。 或许我们可以预先列出我们的脚本，但是我们往往是停留在开发阶段，在需要测试的时候不会真正的去开始测试。基本上，我们是先开发后测试。</p>
<p>
	　　但是这样做或许不是最好的办法，可能会在今后带来问题。这就是为什么一些开发者提倡一种不同的开发方式，叫做测试驱动开发(TDD)的原因- 就是先测试后开发。</p>
<p>
	　　你可能会疑惑这样该怎么做，而这正是本文将讨论的。我将带领你们通过一个真实的简单项目去示范TDD如何工作。本文和示例项目都基于Noel Darlow(&ldquo;McGruff&rdquo;)在论坛中向另一个论坛成员演示TDD如何工作的讨论。</p>
<p>
	　　我们的示例项目是一个Biter类，它通过使用正则表达式可以&ldquo;咬掉&rdquo;字符串中的片段，就象这样：</p>
<p>
	　　bite (&#39;/pattern/&#39;);?&gt;</p>
<p>
	　　我们的类也将修改原始的字符串，把匹配的部分去除(所以我们叫它&ldquo;吞噬者&rdquo;)。</p>
<p>
	　　让我们从设置测试框架开始。</p>
<p>
	　　设置测试框架</p>
<p>
	　　由于我们从测试出发，我们需要有一些测试框架。我将使用SimpleTest 框架，仅仅因为我最熟悉它。</p>
<p>
	　　下载一份SimpleTest的拷贝，把它安装在你本机或者你的服务器上。然后创建一个叫做&quot;test_biter.php&quot;的新文件，里面写下面的代码：</p>
<p>
	　　require_once &#39;simpletest/unit_tester.php&#39;;</p>
<p>
	　　require_once &#39;simpletest/reporter.php&#39;;</p>
<p>
	　　class BiterTestCase extends UnitTestCase {</p>
<p>
	　　function testSetup () {</p>
<p>
	　　$this-&gt;assertTrue(false);</p>
<p>
	　　}</p>
<p>
	　　}</p>
<p>
	　　$test = new BiterTestCase(&#39;TDD Biter Test&#39;);</p>
<p>
	　　$test-&gt;run(new HtmlReporter());</p>
<p>
	　　?&gt;</p>
<p>
	　　让我们分析一下这个例子。首先我们包含了一些SimpleTest框架的文件(你要确认一下路径是否和你的一样)。接着我们建立了一个叫做BiterTestCase的新类，它将用来测试我们的Biter类。象你看到的一样，BiterTestClase类继承于UnitTestCase类，这个意味着BiterTestClass是我们第一个真正意义上的测试用例。</p>
<p>
	　　BiterTestClass类只有一个方法调用叫做&#39;testSetup&#39;。任何以&ldquo;test&rdquo;开头的方法都会被SimpleTest框架自动执行，因此它们应该是被用来测试项目中的某个部分。在上面的例子中，我们通过调用assertTrue()方法来确认框架被正确设置。</p>
<p>
	　　例子中的后面两行是建立一个测试用例的实例，然后运行所有测试。如果所有设置都正确的话，你会得到下面的输出：</p>
<center>
	<img alt="setup_thumb.jpg" border="1" height="30" src="http://www.phpit.net/demo/introduction%20tdd%20php/setup_thumb.jpg" width="125" /></center>
<p>
	　　现在我们已经设置好了测试框架并正常运行。让我们开始我们的Biter类。</p>
<p>
	　　第一个测试</p>
<p>
	　　在我们测试Biter类的任何功能之前，我们必须确认这个类存在。我们当然也是写一个测试来做这件事：</p>
<p>
	　　require_once &#39;simpletest/unit_tester.php&#39;;</p>
<p>
	　　require_once &#39;simpletest/reporter.php&#39;;</p>
<p>
	　　class BiterTestCase extends UnitTestCase {</p>
<p>
	　　function testClassExists() {</p>
<p>
	　　$this-&gt;assertTrue(class_exists(&#39;Biter&#39;), &#39;Biter class exists&#39;);</p>
<p>
	　　}</p>
<p>
	　　}</p>
<p>
	　　$test = new BiterTestCase(&#39;TDD Biter Test&#39;);</p>
<p>
	　　$test-&gt;run(new HtmlReporter());</p>
<p>
	　　?&gt;</p>
<p>
	　　现在运行上面的测试。不要创建类或者包含其他内容;先运行测试。由于&#39;Biter&#39; 类不存在，你会看到下面的输出：</p>
<center>
	<img alt="class_exists_fail_thumb.jpg" border="1" height="30" src="http://www.phpit.net/demo/introduction%20tdd%20php/class_exists_fail_thumb.jpg" width="197" /></center>
<p>
	　　如你所见，我们的测试指出&#39;Biter&#39;类不存在。在TDD中，你总是从一个失败的测试开始工作。</p>
<p>
	　　现在我们必须让测试能够通过，做到这点需要创建Biter类。建立一个叫&#39;biter.php&#39;的新文件，写入如下代码：</p>
<p>
	　　Class Biter {</p>
<p>
	　　}</p>
<p>
	　　?&gt;</p>
<p>
	　　然后把Biter类包含到我们的测试文件，加入如下行：</p>
<p>
	　　require_once &#39;biter.php&#39;;</p>
<p>
	　　现在再运行测试。这次它们会通过了，输出如下：</p>
<center>
	<img alt="class_exists_success_thumb.jpg" border="1" height="30" src="http://www.phpit.net/demo/introduction%20tdd%20php/class_exists_success_thumb.jpg" width="215" /></center>
<p>
	　　在创建Biter类的时候，我们走出了TDD的第一步。首先我们创建测试，然后再做实际的开发。</p>
<p>
	　　在目前我们的Biter类还没有任何功能，下面让我们开始我们的Biter类的第一部分：&ldquo;开始吞噬&rdquo;。</p>
<p>
	　　Biter返回正确的匹配吗?</p>
<p>
	　　我们希望第一步明确的是当我们调用bite()方法的时候Biter类将返回正确的匹配，因此，让我们就此写一个测试：</p>
<p>
	　　function testBiteReturnsAPatternMatch() {</p>
<p>
	　　$biter =&amp; new Biter;</p>
<p>
	　　$haystack = &#39;foobar&#39;;</p>
<p>
	　　$this-&gt;assertEqual(</p>
<p>
	　　$biter-&gt;bite(&#39;/foo/&#39;, $haystack),</p>
<p>
	　　&#39;foo&#39;,</p>
<p>
	　　&#39;Biter returns correct match&#39;);</p>
<p>
	　　}</p>
<p>
	　　这个测试确认biter返回正确的匹配。它使用了assertEqual()方法，从名字我们就能知道这个方法的意思。把测试增加到我们的测试集，然后再运行测试。它会出错甚至返回一个致命错误，因为我们还没提供bite()方法。你会看到下面的输出：#p#分页标题#e#</p>
<center>
	<img alt="returns_match_fail_thumb.jpg" border="1" height="30" src="http://www.phpit.net/demo/introduction%20tdd%20php/returns_match_fail_thumb.jpg" width="203" /></center>
<p>
	　　就象我们在前一个测试里面做的一样，让我们设法使这个测试通过。为了达到这点，我们必须提供bite()方法，由于我们的测试定义了bite()方法需要如何工作，我们只需要开发它，不再需要思考它应该怎么样。这个是TDD的另一个核心概念：测试定义了代码行为。</p>
<p>
	　　下面的bite()方法可以使得测试通过：</p>
<p>
	　　function bite($needle, $haystack) {</p>
<p>
	　　if(preg_match($needle, $haystack, $match)) {</p>
<p>
	　　return $match[&#39;0&#39;];</p>
<p>
	　　}</p>
<p>
	　　}</p>
<p>
	　　在你的Biter类增加bite()方法，然后再次运行测试。现在应该通过了，产生了下面的画面：</p>
<center>
	<img alt="returns_match_success_thumb.jpg" border="1" height="30" src="http://www.phpit.net/demo/introduction%20tdd%20php/returns_match_success_thumb.jpg" width="221" /></center>
<p>
	　　让我们重温一下刚才我们所做的。我们没有立刻建立bite()方法，我们先为此创建了一个测试，在那之后我们再提供bite()方法。这个就是TDD提倡的：先测试，后开发。</p>
<p>
	　　移除匹配的部分</p>
<p>
	　　我们现在还没有完全完成，因为我们的Biter类有第二个需求：它需要把匹配的部分从原始的字符串中移除。为此让我们再写一个测试：</p>
<p>
	　　function testPatternMatchIsRemovedFromHaystack() {</p>
<p>
	　　$biter =&amp; new Biter;</p>
<p>
	　　$haystack = &#39;foobar&#39;;</p>
<p>
	　　$biter-&gt;bite(&#39;/foo/&#39;, $haystack);</p>
<p>
	　　$this-&gt;assertEqual($haystack, &#39;bar&#39;, &#39;Removed matched part [%s]&#39;);</p>
<p>
	　　}</p>
<p>
	　　我们还是使用assertEqual()方法去断言两个变量完全相同，只是这次我们是去检查匹配部分是否已经被移除。</p>
<p>
	　　运行上面的测试，将得到下面的输出：</p>
<center>
	<img alt="removed_fail_thumb.jpg" border="1" height="30" src="http://www.phpit.net/demo/introduction%20tdd%20php/removed_fail_thumb.jpg" width="167" /></center>
<p>
	　　现在我们必须使得这个测试通过。这个做起来很简单，不过假设我们不写这个测试，而是通过修改其他测试来让这个测试通过，这样可能可以少些测试代码。怎么样，听起来不错?其实是错误的!</p>
<p>
	　　永远不能为了让某一个测试更容易通过而去修改其他的测试!</p>
<p>
	　　哪些其他的测试可能是为了特定需求的结果创建的。你实际运行的脚本可能会依赖于那些测试所通过的特定函数。如果你开始修改其他的测试，你就会失去TDD的所有优势。这就是为什么你永远不能为了更容易通过某个测试而去修改其他测试的原因。</p>
<p>
	　　让我们回到我们的Biter类。我们如何能让这个测试通过?我们必须修改传递进来的字符串，就好像我们处理通过引用的方式传递的参数。修改过的bite()方法看上去象下面这样：</p>
<p>
	　　function bite($needle, &amp;$haystack) {</p>
<p>
	　　if(preg_match($needle, $haystack, $match)) {</p>
<p>
	　　$haystack = str_replace($match[&#39;0&#39;], &#39;&#39;, $haystack);</p>
<p>
	　　return $match[&#39;0&#39;];</p>
<p>
	　　}</p>
<p>
	　　}</p>
<p>
	　　把它放入你的Biter类，然后运行测试。你看到什么?全部都是绿色!</p>
<center>
	<img alt="removed_success_thumb.jpg" border="1" height="30" src="http://www.phpit.net/demo/introduction%20tdd%20php/removed_success_thumb.jpg" width="185" /></center>
<p>
	　　现在我们满足了Biter类的所有需求，我们可以开始做我们的脚本里面的其他类，开发起来和我们开发Biter类一样。同时你还能得到另一个好处，就是以后你可以再运行Biter类的测试以便确认它的功能依然正确(这将有效的避免开发过程中偶然的错误修改)。</p>
<p>
	　　结论</p>
<p>
	　　本文中我演示了测试驱动开发如何工作。我们只是构造了一个真实的简单的类，它非常容易去使用TDD方法，不过做为介绍还是不错的选择。</p>
<p>
	　　值得注意的是TDD需要主要焦点的转移，因此它很难推行，它使得开发过程完全不同以往。我可以给出的最好建议是坚持尝试TDD，最终你会迷恋它。一旦习惯了，你再也不会用其他的方法。</p>
<p>
	　　如果你想了解文中的示例项目或者想得到更多的示例，可以看看SitePoint 论坛的相关讨论。非常感谢Noel Darlow使得本文得以呈现，并且提供了本文的大部分示例和信息。</p>
<p>
	　　如果你对本文有任何问题和建议，欢迎在PHPit论坛与我们讨论。</p>
]]></description>
    <pubDate>Wed, 14 Mar 2012 13:31:04 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>子非鱼.</author>
    <comments>译言网</comments>
</item>
<item>
    <title><![CDATA[你这不是测试驱动开发]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2012/0308/204342.html</link>
    <description><![CDATA[<p>
	　　几个月前，我去一个客户那里，他们在使用<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/" target="_blank" >测试驱动开发</A></STRONG>上遇到了很多问题。</p>
<p>
	　　&ldquo;我们的<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/dycs/" target="_blank" >单元测试</A></STRONG>用例要半个小时才能跑完，&rdquo;他说。</p>
<p>
	　　&ldquo;你们这不是在做驱动测试开发，&rdquo;我说。&ldquo;为了让测试发挥效能，所有的测试必须在几秒钟内能跑完，否则的话，程序员不得不频繁的停下来等待测试。&rdquo;</p>
<p>
	　　&ldquo;可是怎样才能让它们快起来?&rdquo;他问，&ldquo;光连接<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/sjk/" target="_blank" >数据库</A></STRONG>就需要30秒&rdquo;</p>
<p>
	　　于是，我想他展示了一种叫做依赖注入的技术，它能让你使用一个伪造对象来模拟数据库。&ldquo;你并不需要测试你数据库，&rdquo;我说。&ldquo;记住，测试应该是测试那些不受控制的东西，对于测试所依赖的东西，你应该使用模拟工具使它们处于控制之中。&rdquo;</p>
<p>
	　　他们遇到的另外一个问题&mdash;我最近也是听到了很多次&mdash;是他们的测试程序不但没起到好的作用，反而成了一个负担。&ldquo;我们三天两头的要重构程序，关联的就需要重构测试程序&rdquo;，这样的话从客户那里可以经常听到。</p>
<p>
	　　这种问题是他们把<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/testdirector/" target="_blank" >TD</A></STRONG>D想成了QA。<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/" target="_blank" >TDD</A></STRONG>不是QA。QA是来保证程序能正确的运行的。TDD是使用断言(assertion)来表现系统的关键特征。在QA里，我们用尽可能多的方法来测试系统中可能会出错的地方。在TDD里，我们用应尽可能少的测试来表现系统的关键特征。</p>
<p>
	　　我遇到的大多数开发人员都很重视代码质量，努力写出高质量的代码，程序看起来很整洁。但测试用程序也是程序，经常的我能看到测试程序就写的不是那么好。</p>
<p>
	　　例如，一些程序员会很认真的把产品程序里的冗余部分清理干净，但在测试程序中却留下大量的无用的代码。任何冗余都不是好事，冗余的测试也是如此，如果程序有变化，冗余的测试会花掉你额外的时间去重构。</p>
<p>
	　　当系统出问题时，测试程序就体现出来了它最大的价值，至少对我来说是最欣慰的时候。然而，对于系统，任何一个改动只应会让一个测试失败。换句话说，没有任何两个测试的失败原因是相同的。这说起来容易做起来难，但如果你尊重这个原则，你将会发现，当你重构代码时，重构测试程序是会容易多了。</p>
<p>
	　　目前就说这些问题。总之，测试也是程序，它们也要保持高质量。系统中的每个关键特征都用一个测试来表现，没有第二个测试会因为这同一个问题而失败。</p>
<p>
	　　你怎么看待这些问题?我很想听听你的想法和建议。不要犹豫，请在评论里分享你的观点。</p>
]]></description>
    <pubDate>Thu, 08 Mar 2012 10:22:32 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>不详</author>
    <comments>伯乐在线</comments>
</item>
<item>
    <title><![CDATA[.NET中的TDD]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2011/1123/203544.html</link>
    <description><![CDATA[<p>
	　　<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/testdirector/" target="_blank" >TD</A></STRONG>D(Test-Driven Development)<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/" target="_blank" >测试驱动开发</A></STRONG>，就是以<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csyl/" target="_blank" >测试用例</A></STRONG>来带动开发，也就是先做测试用例，然后根据测试用例做开发。<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/" target="_blank" >TDD</A></STRONG>的好外使是开发人员可以针对性的做开发，目标就是通过测试用例，当然，TDD更适合做逻辑的程序员，不适合更多的与UI开发相关的程序员。</p>
<p>
	　　不管是TDD也好，传统的开发也好，肯定要先做设计，设计展开后如果采用普通方法做开发，那就是开始写代码，然后<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/dycs/" target="_blank" >单元测试</A></STRONG>，<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csgl/jccs/" target="_blank" >集成测试</A></STRONG>等工作。如果用TDD，那就要先从设计中把测试列表(其实就是要实现的功能，人机交互的条目罗列出来，形成一个列表)整理出来。然后就开始开发，在TDD中，&ldquo;红-绿-重构&rdquo;的过程很多说明TDD的文章都要说到，本篇也不例外。</p>
<p>
	　　有了测试列后，先拿出一个条目，进行测试的开发，开发完成运行，因为被测的程序还没有编写肯定是失败的，然后实现程序，再测，可能还失败，改成，测试成功，然后重构来优化代码，再进入下一个测试条目的循环。</p>
<center>
	<img alt="" border="1" height="768" src="/uploads/allimg/111123/1003032593-0.jpg" width="816" /></center>
<p>
	　　在.net平台下，怎么去实现呢?</p>
<p>
	　　本例中用VS2010行进说明，设计部分，可以用vs2010的新功能Modeling，在Modeling里，可以画类图，还可以添加其中的成员，包括返回值类型，参数个数和类型，有了这些方法的签名，对我们先构建测试就提供了依据，对测试程序来说，不关心实现的细节，只用知道参数是什么，返回是什么，拿上这个方法的返回值与给定的返回值作对比，从而来确定方法实现的功能是否正确。在Visual Studio中，可以很方便的来自动创建单元测试，这些方便要归功于&ldquo;反射&rdquo;这个技术。当然，一般而然，测试不是只有一个数据，可能要一系列数据，或者更多的数据，在.net平台下，也提供了相应的功能。</p>
<p>
	　　下面来做个DEMO说明一下。</p>
<p>
	　　先看一个类图，也可以把类中的主要功能，当成一个个条目添加到测试列表中。</p>
<center>
	<img alt="" border="1" height="124" src="/uploads/allimg/111123/1003034394-1.jpg" width="173" /></center>
<p>
	　　我们选一个条目&mdash;&mdash;GetRecord，参数是一个ID的整型，返回值是一个逻辑类型，本方法用来实现在一个库中查询输入的ID，看是否存在。</p>
<p>
	　　根据类图，可以在类库项目中生成一个类，如下</p>
<p>
	&nbsp;</p>
<table align="center" id="table1" style="border-right: #999 1px solid; border-top: #999 1px solid; font-size: 12px; border-left: #999 1px solid; width: 98%; border-bottom: #999 1px solid; background-color: #dddddd">
	<tbody>
		<tr>
			<td>
				　　1 public class DataOperate<br />
				　　2&nbsp;&nbsp;&nbsp;&nbsp; {<br />
				　　3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public bool GetRecord(int id)<br />
				　　4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
				　　5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new Exception(&quot;没有实&igrave;现?&quot;);<br />
				　　6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
				　　7&nbsp;&nbsp;&nbsp;&nbsp; }<br />
				　　8</td>
		</tr>
	</tbody>
</table>
<p>
	　　接下来，可以继于这个方法，来自动创建一个单元测试，右键方法，创建测试。</p>
<p>
	　　一个测试的项目就会自动创建进来，在生成的CS文件中，重点看如下代码(关于单元测试的其他<STRONG><A href="http://www.ltesting.net/ask/" target="_blank" >知识</A></STRONG>可参照http://msdn.microsoft.com/zh-cn/library/ms182515(VS.80).aspx)</p>
<p>
	&nbsp;</p>
<table align="center" id="table2" style="border-right: #999 1px solid; border-top: #999 1px solid; font-size: 12px; border-left: #999 1px solid; width: 98%; border-bottom: #999 1px solid; background-color: #dddddd">
	<tbody>
		<tr>
			<td>
				　　1 [TestMethod()]<br />
				　　2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void GetRecordTest()<br />
				　　3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
				　　4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DataOperate target = new DataOperate();<br />
				　　5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int id = 0;<br />
				　　6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bool expected = false;<br />
				　　7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bool actual;<br />
				　　8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; actual = target.GetRecord(id);<br />
				　　9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Assert.AreEqual(expected, actual);<br />
				　　10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
				　　11</td>
		</tr>
	</tbody>
</table>
<p>
	　　在这里，测试的用例只有一个id=0，返回值为false，现在测试，肯定通不过，因为被测的方法还没有实现。此时叫做&ldquo;红&rdquo;。</p>
<p>
	　　接下来就要实现GetRecord方法。</p>
<p>
	　　新建一个类库项目，然后添加一个LINQ To SQL的子项，把下表拖放进LINQ To SQL面板。</p>
<center>
	<img alt="" border="1" height="114" src="/uploads/allimg/111123/1003035922-2.jpg" width="387" /></center>
<p>
	　　数据表结构</p>
<center>
	<img alt="" border="1" height="66" src="/uploads/allimg/111123/1003031K4-3.jpg" width="439" /></center>
<p>
	　　数据表中数据</p>
<p>
	　　然后在类库的CS文件中，添加入下代码：</p>
<p>
	&nbsp;</p>
<table align="center" id="table1" style="border-right: #999 1px solid; border-top: #999 1px solid; font-size: 12px; border-left: #999 1px solid; width: 98%; border-bottom: #999 1px solid; background-color: #dddddd">
	<tbody>
		<tr>
			<td>
				　　1 public bool GetRecord(int id)<br />
				　　2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
				　　3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DataClasses1DataContext DCDC = new DataClasses1DataContext(&quot;server=.;database=mytestdb;uid=sa;pwd=sa;&quot;);<br />
				　　4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (DCDC.GetTable&lt;Pic_Table&gt;().Where(record=&gt;record.ID ==id).Count() ==1)<br />
				　　5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
				　　6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<br />
				　　7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
				　　8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br />
				　　9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
				　　10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;<br />
				　　11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
				　　12&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
				　　13</td>
		</tr>
	</tbody>
</table>
#p#分页标题#e#<p>
	　　当然测试是不关心我们用什么技术实现方法的，它只关系输入和输出。</p>
<p>
	　　这时我们再运行测试，会发现测试通过了，这时我们叫做&ldquo;绿&rdquo;。</p>
<p>
	　　可能有的人发现，在这个测试中，只能测一个数据，没有代表性，如果要测多个数据，还得一个一个换id值和expected值。是的，这是一个头痛的事，得想们办法来解决。</p>
<p>
	　　正好，微软有提供数据驱动的单元测试，什么意思呢?就是可以把id和expected的值保存在数据源中，然后批量测试。如果全通过说明这个方法实现的没问题，如果有错，也可以针对性的能找出什么数据使GetRecord方法报错的。这个东西很不错。</p>
<p>
	　　首先来构建一个数据源，XML是个不错的选择，新建一个RecordExistTestCase.xml文档，内容如下</p>
<p>
	&nbsp;</p>
<table align="center" id="table1" style="border-right: #999 1px solid; border-top: #999 1px solid; font-size: 12px; border-left: #999 1px solid; width: 98%; border-bottom: #999 1px solid; background-color: #dddddd">
	<tbody>
		<tr>
			<td>
				　　1 &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;<br />
				　　2 &lt;DataSourses&gt;<br />
				　　3&nbsp;&nbsp; &lt;pic&gt;<br />
				　　4&nbsp;&nbsp;&nbsp;&nbsp; &lt;id&gt;0&lt;/id&gt;<br />
				　　5&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;false&lt;/value&gt;<br />
				　　6&nbsp;&nbsp; &lt;/pic&gt;<br />
				　　7&nbsp;&nbsp; &lt;pic&gt;<br />
				　　8&nbsp;&nbsp;&nbsp;&nbsp; &lt;id&gt;-1&lt;/id&gt;<br />
				　　9&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;false&lt;/value&gt;<br />
				　　10&nbsp;&nbsp; &lt;/pic&gt;<br />
				　　11&nbsp;&nbsp; &lt;pic&gt;<br />
				　　12&nbsp;&nbsp;&nbsp;&nbsp; &lt;id&gt;1&lt;/id&gt;<br />
				　　13&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;true&lt;/value&gt;<br />
				　　14&nbsp;&nbsp; &lt;/pic&gt;<br />
				　　15 &lt;/DataSourses&gt;<br />
				　　16</td>
		</tr>
	</tbody>
</table>
<p>
	　　当然你还可以添加你以为好的测试用例。</p>
<p>
	　　再改造一下测试方法</p>
<p>
	&nbsp;</p>
<table align="center" id="table2" style="border-right: #999 1px solid; border-top: #999 1px solid; font-size: 12px; border-left: #999 1px solid; width: 98%; border-bottom: #999 1px solid; background-color: #dddddd">
	<tbody>
		<tr>
			<td>
				　　1 [DataSource(&quot;Microsoft.VisualStudio.TestTools.DataSource.XML&quot;, &quot;|DataDirectory|\\RecordExistTestCase.xml&quot;, &quot;pic&quot;, DataA<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/clearcase/" target="_blank" >cc</A></STRONG>essMethod.Sequential)]<br />
				　　2&nbsp;&nbsp;&nbsp;[ DeploymentItem(&quot;TestDataOperate\\RecordExistTestCase.xml&quot;)]<br />
				　　3&nbsp;&nbsp;&nbsp;[ TestMethod()]<br />
				　　4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void GetRecordTest()<br />
				　　5&nbsp;&nbsp;&nbsp;{<br />
				　　6 &hellip;&hellip;<br />
				　　7 }<br />
				　　8</td>
		</tr>
	</tbody>
</table>
<p>
	　　OK，现在就要以用上面xml里的数据来批量测试了。</p>
<p>
	　　测试通过来，接下来就要程序员来整理一下自写的代码了，比如书写规范问题，方法是否冗余重复，注释是否完善等。也就是所说的重构了。</p>
<p>
	　　到此，一个TDD cycle就完成了，现实的cycle可能更复杂，这里只是对单个测试条目单个方法进行说明的。</p>
<p>
	　　TDD更适合在<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/zlmx/mjkf/" target="_blank" >敏捷</A></STRONG>的开发中去用，比如XP，虽然scrum是侧重管理和组织，也能很好的溶入TDD。</p>
]]></description>
    <pubDate>Wed, 23 Nov 2011 09:53:31 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/111123/1003032593-0-lp.jpg</subImagePath>
     <category>测试驱动开发</category>
    <author>领测软件测试网采编</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[你这不是测试驱动开发]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2011/1109/203477.html</link>
    <description><![CDATA[<p>
	　　几个月前，我去一个客户那里，他们在使用<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/" target="_blank" >测试驱动开发</A></STRONG>上遇到了很多问题。</p>
<p>
	　　&ldquo;我们的<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/dycs/" target="_blank" >单元测试</A></STRONG>用例要半个小时才能跑完，&rdquo;他说。</p>
<p>
	　　&ldquo;你们这不是在做驱动测试开发，&rdquo;我说。&ldquo;为了让测试发挥效能，所有的测试必须在几秒钟内能跑完，否则的话，程序员不得不频繁的停下来等待测试。&rdquo;</p>
<p>
	　　&ldquo;可是怎样才能让它们快起来?&rdquo;他问，&ldquo;光连接<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/sjk/" target="_blank" >数据库</A></STRONG>就需要30秒&rdquo;</p>
<p>
	　　于是，我想他展示了一种叫做依赖注入的技术，它能让你使用一个伪造对象来模拟数据库。&ldquo;你并不需要测试你数据库，&rdquo;我说。&ldquo;记住，测试应该是测试那些不受控制的东西，对于测试所依赖的东西，你应该使用模拟工具使它们处于控制之中。&rdquo;</p>
<p>
	　　他们遇到的另外一个问题 &mdash;&mdash; 我最近也是听到了很多次 &mdash;&mdash; 是他们的测试程序不但没起到好的作用，反而成了一个负担。&ldquo;我们三天两头的要重构程序，关联的就需要重构测试程序&rdquo;，这样的话从客户那里可以经常听到。</p>
<p>
	　　这种问题是他们把<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/testdirector/" target="_blank" >TD</A></STRONG>D想成了QA。<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/" target="_blank" >TDD</A></STRONG>不是QA。QA是来保证程序能正确的运行的。TDD是使用断言(assertion)来表现系统的关键特征。在QA里，我们用尽可能多的方法来测试系统中可能会出错的地方。在TDD里，我们用应尽可能少的测试来表现系统的关键特征。</p>
<p>
	　　我遇到的大多数开发人员都很重视代码质量，努力写出高质量的代码，程序看起来很整洁。但测试用程序也是程序，经常的我能看到测试程序就写的不是那么好。</p>
<p>
	　　例如，一些程序员会很认真的把产品程序里的冗余部分清理干净，但在测试程序中却留下大量的无用的代码。任何冗余都不是好事，冗余的测试也是如此，如果程序有变化，冗余的测试会花掉你额外的时间去重构。</p>
<p>
	　　当系统出问题时，测试程序就体现出来了它最大的价值，至少对我来说是最欣慰的时候。然而，对于系统，任何一个改动只应会让一个测试失败。换句话说，没有任何两个测试的失败原因是相同的。这说起来容易做起来难，但如果你尊重这个原则，你将会发现，当你重构代码时，重构测试程序是会容易多了。</p>
<p>
	　　目前就说这些问题。总之，测试也是程序，它们也要保持高质量。系统中的每个关键特征都用一个测试来表现，没有第二个测试会因为这同一个问题而失败。</p>
]]></description>
    <pubDate>Wed, 09 Nov 2011 11:11:45 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>领测软件测试网采编</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[软件开发项目中的关键决策:基于上下文图的策略性领域驱动开发]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2011/1101/203431.html</link>
    <description><![CDATA[<p>
	　　简介</p>
<p>
	　　当应用程序逐渐变得庞大和复杂后，很多<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/mxdx/" target="_blank" >面向对象</A></STRONG>建模的方法都达不到非常好的可伸缩性。上下文图是一种通用目的的技术，作为领域驱动<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/" target="_blank" >开发</A></STRONG>大家族的一名成员，它帮助架构师和开发人员管理他们在软件开发项目中不得不面对的形形色色的复杂性。与其他广为人知的DDD模式相比，上下文图可以应用在任何软件开发的场景中，在开发者进行策略性决策时，为他们提供一个高层视图，比如是采用全套的DDD实现，还是根据项目的特定条件进行取舍等。</p>
<p>
	　　在这篇文章中，我们将探讨界限上下文，以及如何在构建上下文图时应用它们，来支持软件开发项目中的关键决策。</p>
<p>
	　　多个模型共存</p>
<p>
	　　领域驱动开发花了很大力气强调一件事，即维护应用程序模型的概念完整性。要做到这一点，需要很多因素：</p>
<p>
	　　一种<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/zlmx/mjkf/" target="_blank" >敏捷</A></STRONG>的流程，确保能从用户和领域专家那里频繁地获得反馈，</p>
<p>
	　　确保有若干领域专家在场，并且与他们开展创造性的合作，</p>
<p>
	　　(在应用和测试代码中)维护单一的、可共享的模型，并用通用语言精确地进行定义它，</p>
<p>
	　　营造一种开放透明的环境，鼓励学习与探索。</p>
<p>
	　　这些对于营造一个可以让高质量的设计繁荣发展的环境至关重要。即使是这样的环境，那些常见的DDD元素，比如实体、值对象、聚合，也会逐渐地形成一个复杂领域模型。所以，如果不对模型的概念完整性进行妥协的话，传统的DDD方法也不能盲目地应用在一个无限大的领域模型中。</p>
<p>
	　　如图1所示，在DDD中，通用语言的关键责任是对模型进行完整性检查。无论是与领域专家的讨论，还是最终的实现代码，都可以通过使用相同的术语，并将领域<STRONG><A href="http://www.ltesting.net/ask/" target="_blank" >知识</A></STRONG>清晰准确地进行定义，以此来保证团队中的每位成员可以分享都相同的领域知识和软件。</p>
<center>
	<img alt="" border="1" height="451" src="/uploads/allimg/111101/1022145063-0.gif" width="447" /></center>
<p>
	　　图1. 通用语言应该是用于表达模型的唯一语言。团队中的每位成员应该对每个特定术语达成一致。这些术语不能有歧义，也不允许在不同角色间进行翻译。</p>
<p>
	　　代码是表达模型的主要形式。虽然其他一些工件或许也能捕获<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/xqgl/" target="_blank" >需求</A></STRONG>或者局部设计，但是只有代码自身才会与应用程序的行为永远保持一致。不过这种看上去美妙的建模方式其实非常脆弱：如果满足了前面提到的四条要求，它能做到，但是不能被无限地扩展。真正让模型得以最大程度地扩展，并且不必牺牲其概念完整性的方法叫做&ldquo;上下文&rdquo;。</p>
<p>
	　　了解&ldquo;界限上下文&rdquo;</p>
<p>
	　　在领域驱动设计的世界里，&ldquo;上下文&rdquo;是这样定义的：</p>
<p>
	　　&ldquo;一个单词或一个句子所出现的环境，这个环境会反过来影响它们的含义。&rdquo;</p>
<p>
	　　这段定义初看起来相当含糊。它并没有直接告诉我们&ldquo;上下文&rdquo;的大小、形状或者其他什么特性。但是最后我们又发现这个定义其实非常准确地描述了&ldquo;上下文&rdquo;是什么，如果要想窥得其全貌的话，大概还需要一些具体的例子。</p>
<p>
	　　示例1：术语相同，含义不同</p>
<p>
	　　第一个例子很简单，它示范了在术语层面出现歧义的情况。有些词汇根据不同的使用场景，会有不同的含义。</p>
<p>
	　　假设我们正在开发一个基于Web的个人金融管理程序(PFM)。该程序可能用于管理银行帐户(A<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/clearcase/" target="_blank" >cc</A></STRONG>ount)、股票、储蓄，未来可能用于追踪预算和开销记录等等。</p>
<p>
	　　在这个程序中，领域术语&ldquo;帐户&rdquo;可能是指不同的概念。谈论银行的时候，一个&ldquo;帐户&rdquo;在逻辑上其实是&ldquo;金钱的容器&rdquo;;于是我们自然而然地为相应的类加上&ldquo;余额&rdquo;、&ldquo;帐户号&rdquo;等属性。但是，在&ldquo;Web应用程序&rdquo;的上下文中，术语&ldquo;帐户&rdquo;会有非常不同的含义，它和用户的认证、可信度有关。如图2所示，相应的模型将是完全不同的。</p>
<center>
	<img alt="" border="1" height="270" src="/uploads/allimg/111101/102214L35-1.jpg" width="646" /></center>
<p>
	　　图2. 一个出现歧义的简单场景：当术语&ldquo;帐户&rdquo;应用在不同的上下文时，它的含义可以是完全不同的。</p>
<p>
	　　这应该是我们在对应用程序建模的时候，所遇到的最简单的歧义场景了：一个术语，有两个与上下文相关的含义。这个问题的解决办法通常是在类的全名(类名或者包名)前面加一些前缀，以此来划分名字空间。但是在概念层面上，必须清楚我们在和两个上下文打交道，有时不同上下文之间的区别很大，足以防止开发人员犯错误，但有时这样的区别却非常微妙。</p>
<p>
	　　不过，在类名层面上解决问题的方式并不能用在所有的情况下：在银行的领域里，术语&ldquo;银行帐户&rdquo;或许已经存在了，但却有不同的含义;或者领域专家坚持使用&ldquo;帐户&rdquo;作为术语。此时切记不要发明一个特殊的两头这种的术语，或者在专家术语和代码之间引入一个&ldquo;翻译层&rdquo;。否则你将不得不面对两个独立的上下文。</p>
<p>
	　　绘制第一份上下文图</p>
<p>
	　　当歧义真的到来的时候，我们需要一种工具来让开发团队明白，应用程序中正存在着两个不同的上下文。&ldquo;歧义&rdquo;是通用语言的头号大敌，我们必须铲除它。消除歧义的最好办法就是在上下文图中，将领域结构分拆在多个界限上下文中。</p>
<center>
	<img alt="" border="1" height="344" src="/uploads/allimg/111101/102214AR-2.jpg" width="333" /></center>
<p>
	　　图3. 包含两个领域上下文的上下文图</p>
<p>
	　　按照领域驱动设计一书的描述，上下文图是用于将上下文边界变得更清晰的重要工具。其基本的想法是在白板上画出上下文的边界，然后选择性地将相关类的领域术语填写在上面。它不是一幅绘制精美的<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/uml/" target="_blank" >UML</A></STRONG>图：它是一个可用的工具，允许我们描绘那种模糊不清的状况，因此它自身看上去模糊不清也就不足为其了。</p>
<p>
	　　示例2：概念相同，用法不同</p>
<p>
	　　还有一种更加令人困惑的情况，就是底层的概念相同，但是使用的方式不同，最终导致了不同的模型。银行帐户的模型是一个BankingAccount类，如图4所示。</p>
<center>
	<img alt="" border="1" height="270" src="/uploads/allimg/111101/10221463L-3.jpg" width="246" />#p#分页标题#e#</center>
<p>
	　　图4. 精简版本的BankingAccount类</p>
<p>
	　　通常，有些PFM应用也允许我们管理支付行为，并且持有一个收款人(Payee)注册器。在这个场景中，收款人可能与一个或者多个银行帐户关联，但是对于收款人来说，我们既不能获取其银行帐户的内部情况，也不能在该帐户上触发任何操作。那么将&ldquo;收款人帐户&rdquo;与刚刚定义的BookingAccount类关联在一起是否正确呢?</p>
<center>
	<img alt="" border="1" height="254" src="/uploads/allimg/111101/1022141U8-4.jpg" width="628" /></center>
<p>
	　　图5. Payee类与BankingAccount类</p>
<p>
	　　恩......这听上去有些道理：毕竟它们都是相同的概念，在现实世界中，我们的帐户和收款人的帐户甚至会处在同一个物理上的银行里。另一方面，这样做似乎又不完全正确：因为我们不允许调用收款人银行帐户的任何操作，也不能追踪他们的任何信息。更糟的是，这样做了后，可能会在我们的程序中埋下一个概念的错误。</p>
<p>
	　　我们应该如何做?我们应该再一次回到应用程序的两个不同的上下文里去：这一次我们可以采取两种不同的方式对同一个领域概念进行建模，因为对领域概念的两种使用场景明显不同，每一种都需要一个不同的模型。BankingAccount类仍然允许我们执行(或者跟踪)特定的操作(比如存款与取款)，同时另一个独立的PayeeAccount类可能有一些和BankingAccount相同的通用数据(比如accountNumber)，但是有一个简化的模型和完全不同的行为(比如我们不能访问收款人的余额信息)。图6所示的正是这种场景：尽管&ldquo;银行帐户&rdquo;有着清晰的含义，其底层概念也是惟一的，但是在应用程序中却以不同的方式被使用着。</p>
<center>
	<img alt="" border="1" height="499" src="/uploads/allimg/111101/1022143132-5.jpg" width="628" /></center>
<p>
	　　图6. BankingAccount和PayeeAccount类</p>
<p>
	　　这看着似乎挺明显的，其实不然。当你设计类图，或者使用UML建模工具时，你可能很自然地让收款人具有一个bankingAccount属性，而且会庆幸&ldquo;我刚好有一个这样的类&rdquo;。Pavlovian试图去除代码中的重复，有时，它的作用会弊大于利。</p>
<p>
	　　如图7所示的上下文图，可以用于表述上面讨论的示例。注意，只要我们关于环境的知识在增加，就将它反映在图中。在这个例子中，我们将PFM的应用上下文分成了&ldquo;银行&rdquo;和&ldquo;开销跟踪&rdquo;。</p>
<center>
	<img alt="" border="1" height="364" src="/uploads/allimg/111101/1022146340-6.jpg" width="628" /></center>
<p>
	　　图7. 非常简单的上下文图：画上了领域模型区域间的轮廓，可以看出在这些区域内保证了概念的完整性</p>
<p>
	　　在这个例子中，两个上下文拥有一些逻辑上重叠的区域，即&ldquo;银行帐户&rdquo;的概念，它在应用程序的不用区域中，使用方式也不同，这意味着我们要使用不同的模型。但是两个模型又可能有非常紧密的交互。上下文图除了能帮助我们保证模型的概念在不同上下文边界内的完整性，它还能帮助我们关注在不同上下文之间出现的情况。在这个例子中，假设同一个团队正在两个上下文上同时工作，我们就需要让团队中的每位成员的明确两个上下文的区别，并且就两个上下文中出现的术语和概念，分享同一个转换的映射关系。</p>
<p>
	　　示例3：外部系统</p>
<p>
	　　再来考虑一下PFM。很多这种应用程序都需要与某些金融在线服务进行数据交换。在这个例子中，银行会为家庭银行服务提供实时的访问。其他的例子还包括允许用户<STRONG><A href="http://www.ltesting.net/ceshi/down" target="_blank" >下载</A></STRONG>通用标准格式(比如Money或者Quicken格式)的银行对帐单。但是从上下文图的视角来看，无论是交互活动还是通讯的方向(单向或是双向)，并不重要。有一件事是要关注的，我们有了不同的模型。图8展示了PFM与在线银行应用程序的交互行为。</p>
<center>
	<img alt="" border="1" height="467" src="/uploads/allimg/111101/1022143606-7.jpg" width="628" /></center>
<p>
	　　图8. 在上下文图中，与外部应用的交互行为很自然地需要独立的界限上下文</p>
<p>
	　　即使设计两个模型之初是让它们展现相同的数据(至少在一定程度上)，但随着时间的推移，它们还是会受到不同因素的影响，而且它们也会用于不同的目的。因此，分离上下文边界是必须的。如果假设用户档案(User profiling)模块是由第三方库实现的，那么示例1也能够归入到这一类中。</p>
<p>
	　　管理多个上下文</p>
<p>
	　　当应用程序跨越了多个上下文后，我们必须管理上下文之间的关联。不同的界限上下文之间的关系，通常是我们深入观察项目的线索。</p>
<p>
	　　有一件事情非常关键，即两个上下文之间的联系是有方向的。DDD用两个专门的术语表述它们：&ldquo;上游(upstream)&rdquo;和&ldquo;下游(downstream)&rdquo;，一个上游上下文会影响到相应的下游上下文，但是反过来就不一定了。这不仅体现在代码上(一个库依赖于另一个)，还体现在技术含义较少的因素上，比如进度、对外部请求的响应，比如，当在线银行服务更改了API或者其他什么原因，我们的PFM银行应用程序都必须要快速地更新。所以我们的PFM上下文应该是下游的，而在线银行服务很明显就是上游的了。图9演示了这两种领域上下文的关系。</p>
<center>
	<img alt="" border="1" height="509" src="/uploads/allimg/111101/102214K64-8.jpg" width="599" /></center>
<p>
	　　图9. 分离的上下文之间的Upstream-downstream关系</p>
<p>
	　　如果外部系统发生变化，我们可以接受这种变化，来更新与外部系统通讯的方式。不过我们仍然需要一些保护措施隔离来自上游上下文的变化，保证我们自己的&ldquo;银行&rdquo;的上下文的概念完整性。DDD包含了几种组织模式，帮助我们描述和管理不同的上下文交互方式。最适合我们在这里使用的是模式叫做反腐化层(Anti-Corruption Layer，ACL)，它会在代码层面上实现显式的转换，转换可以在两个上下文之间，或者在&ldquo;银行&rdquo;上下文的外部边界上完成。这不仅局限于技术上的转换，比如<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcskfyy/java/" target="_blank" >Java</A></STRONG>转化为XML，同时也是一个很合适的机会，能够管理各个模型之间的所有微妙的不同。如下面的图10所示，我们在上下文图上添加了ACL。</p>
<center>
	<img alt="" border="1" height="527" src="/uploads/allimg/111101/10221454N-9.jpg" width="611" />#p#分页标题#e#</center>
<p>
	　　图10. PFM程序边界上的反腐化层，防止在线银行服务的变化影响到我们的边界上下文</p>
<p>
	　　很明显，一个外部系统需要一个独立的上下文。然而对于一个已有的遗留组件，通常也伴有一个非常难以修改的模型。尽管遗留组件是在我们组织内部来维护的，甚至这个模型也会受到不同因素的影响，它会被其他的上下文所使用。如果必须和遗留系统进行交付，不同模型之间的转换应该放在一个不同的界限上下文里。</p>
<p>
	　　上下文图中还有其他的关系吗?我们能够根据相关的DDD模式对它们进行分类吗?如果假设开发活动是在单一的团队内进行的，那这里的模式就不会引起太多的关注。但是，如果&ldquo;银行&rdquo;和&ldquo;开销&rdquo;是由不同的团队来维护的话，团队之间应该是一种合作关系：他们的开发会朝向一个共同的目标(这里谈论上游和下游没有意义，因为他们处于同一级别)。如果Web用户档案模块来自于外部，我们将会作为下游的上下文。</p>
<center>
	<img alt="" border="1" height="539" src="/uploads/allimg/111101/10221444B-10.jpg" width="636" /></center>
<p>
	　　图11. 加入了关系模式后的上下文图</p>
<p>
	　　示例4：向组织扩展</p>
<p>
	　　到目前为止，我们只考虑了包含一个开发团队的简单场景。在这种场景下，我们可以忽略沟通的开销，假设团队中的每位开发者都很明确&ldquo;模型将会如何发展&rdquo;(也许有些乐观)。更复杂的场景中还可能包含下面的影响因素：</p>
<p>
	　　领域复杂度(需要很多不同的领域专家)</p>
<p>
	　　组织复杂度</p>
<p>
	　　项目跨时很长</p>
<p>
	　　项目需要大量的人天</p>
<p>
	　　涉及到很多外部的、独立的或者遗留的系统</p>
<p>
	　　大型团队，多个开发组</p>
<p>
	　　分布的、离岸的团队</p>
<p>
	　　个人因素</p>
<p>
	　　每个因素都会影响开发团队和组织的通讯方式，并最终影响到要交付的软件。</p>
<p>
	　　每个独立的团队，尤其是一个处在敏捷环境的团队，团队内的成员间有很多共享信息的方式：面对面的交谈，多人参与的设计讨论、结对编程、会议、信息散播装置(information radiator)等等。但问题在于，当团队规模、人数增加后，这些技术很难再继续使用了，跨团队地共享模型的概念完整性也非常困难。</p>
<p>
	　　毕竟，能够对模型保持统一看法，是沟通中相当成熟的方式，这涉及到对问题具有一致的理解，以及对可行<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/jjfa/" target="_blank" >解决方案</A></STRONG>大致相似的看法。在那些沟通不顺畅的场景下，&ldquo;埋头干&rdquo;很容易取代了&ldquo;识别和确认&rdquo;。这种沟通瓶颈带来的典型后果就是在同一个代码库中的不同地方散布着不同的类，它们做着基本上同样的事情。</p>
<p>
	　　总有一天PFM应用会变得更大，这样就要有另一个团队(团队B)和我们一起工作(显然我们是团队A)，他们开发一个名为&ldquo;交易&rdquo;的新模块。团队B可能在一个不同的房间、建筑物、城市、公司里，他们全心投入到新模块的开发工作上。如下图所示，团队A与团队B共享了一些代码，虽然他们很可能会使用彼此独立的代码。最后，团队B会写一些类(比如图12所示的A&#39;)来实现自己所需的功能，不过这些功能已经存在于类A了。</p>
<center>
	<img alt="" border="1" height="539" src="/uploads/allimg/111101/10221462X-11.jpg" width="636" /></center>
<p>
	　　图12. 当不同的团队访问相同的代码库时，他们会去关心模型上的不同部分。物理上的团队分割会令信息共享的效果大打折扣</p>
<p>
	　　这是重复代码，万恶之源啊!在一个独立的、良好定义的、有界的上下文内，这是毋庸置疑的。但是由于某些原因，这种现象几乎会出现在所有复杂的项目中。这通常是个信号，告诉我们在项目的同一个区域内，或许存在没有恰当隔离的上下文。不过在有些时候，使用两个独立的上下文是组织领域模型更加有效的手段，而不会强迫两个不同的团队不断地去整合他们的模型。</p>
<p>
	　　那么，我们如何在图上画出这些呢?上下文图反映了当前我们对整个系统的理解水平。一旦我们学到了更多东西，或者环境发生了改变，还会马上更新它。现在，我们还不能准确地预知接下来会发生什么，所以这就是&ldquo;我们当前的理解水平&rdquo;。</p>
<center>
	<img alt="" border="1" height="539" src="/uploads/allimg/111101/10221419C-12.jpg" width="636" /></center>
<p>
	　　图13. 尚未很好划分的&ldquo;交易&rdquo;上下文，它还需要进一步探索或更切合实际的设计决策</p>
<p>
	　　图中的危险警告符告诉我们那里有些问题：两个上下文有局部的重叠，它们的关系还不是非常清晰。这可能是需要解决的第一类问题，可以尝试着在上下文内设置一个被广泛认可的、合理的关系，比如消费者-供应者、持续集成或者共享内核(Shared Kernel)。不过，这是明天的工作。上下文图是为今天准备的工具，而问题在今天还存在着，所以我们还把警告符号留在图中。</p>
<p>
	　　不要被图中的颜色和阴影搞迷惑了。我不过是想让上下文图的打印效果更好一些。一个真实的上下文应该是很乱的，起码和你的项目一样乱。不过这个警告符提醒我们这里有一个危险区域，此处的上下文尚未被清晰地分离，事态很容易朝着&ldquo;一团大泥球&rdquo;发展(最有弹性的DDD组织模式)，除非我们采取行动。</p>
<p>
	　　一种非传统观点的视角</p>
<p>
	　　上下文图迫使我们将非软件的因素也包含在整体考虑中，这样我们更能识别出一些污点热区，而这些热区在传统架构分析的观点中是&ldquo;不在范围内&rdquo;的。</p>
<p>
	　　比如，组织内部的信息流通方式会在很大程度上影响最终的软件。通常，在小型组织中，组件自身的用途是定义上下文边界的主要因素，而在大型组织中，这个关键因素变成了沟通效率和项目组织方式。像Wiki、email或即时消息软件会给我们一种假象&mdash;&mdash;团队中每位成员的知识都不断地保持着同步。但是我们都知道这只是个梦想罢了：在一个典型的大型项目中，我们不是Borg人(译注：源自《星际旅行》中的外星生物，所有Borg人的思想是互联的，可以完全共享知识)那样的智能联合体，很多人对于自己团队以外的情况知之甚少。</p>
<p>
	　　在大型组织中定义上下文边界是一项颇具挑战的任务，但回报却也相当丰厚。很多时候，各个团队并不清楚多个模型存在的事实;之所以概念的完整性会频遭破坏，是因为只有很少人或者没有人看到完整的图景。绘制上下文图是一个不断探索的过程，很多部分的内容在首次尝试时都是不正确的，边界在初期也是很模糊的，还需要很长的路要走，才能获得一个更清晰的完整图景。#p#分页标题#e#</p>
<center>
	<img alt="" border="1" height="539" src="/uploads/allimg/111101/10221411N-13.jpg" width="636" /></center>
<p>
	　　图14. 上下文图的最新版本。不要指望它是&ldquo;最终&rdquo;的，我们总是会学到一些新的东西。</p>
<p>
	　　涉及到的上下文还可能更多，比如&ldquo;交易&rdquo;模块可能需要链接到一些在线股票价格服务，但这是交易模块的事!这个上下文图是关于我们(团队A)的，我们的工作内容是&ldquo;银行&rdquo;和&ldquo;开销跟踪&rdquo;模块：我们只对直接关联的、会影响到自身软件的那些上下文感兴趣。</p>
<p>
	　　一旦我们收集到更多的信息，上下文图就会变得更加清晰。正如前面提到的，只要认识到应用程序中存在着各种不同的模型，而且这些模型的完整性可以在一个良好定义的有界上下文中得以保存，这会为我们的领域建模的视角提供诸多益处。很多模型都在成长的过程中逐渐失去完整性，上下文图会在这个方面给予我们很多帮助。</p>
<p>
	　　谈谈策略性DDD模式</p>
<p>
	　　此处我们使用模式的方式略有不同：尽管定义是一样的&mdash;&mdash;为一类反复出现的问题提供解决方案&mdash;&mdash;但这些模式很少能展现出可供我们选择的解决方案。更可能的场景是，组织架构会决定模式，我们惟一的希望就是在事态走到死胡同以前识别出它们。有些时候我们有机会选择最好的选项，或者改变现有的状况，但是我们必须清楚的是，在组织级别的改变所需的时间可能已经远远超过了项目持续的时间，或者这个改变根本就是不可能的。</p>
<p>
	　　如果你还在犹豫应该从那里开始，那么就从开发团队开始吧。对于有效地共享模型信息来说，一个团队应该是最大的组织单元。当识别出多个上下文后，可以由一个团队管理它们，这样很大程度上将问题归结为架构的抉择。</p>
<p>
	　　每一种模式都有不同的开销：即使它们解决的是类似的问题(相近的上下文)，也不能简单地交换。比如，反腐化层会在代码层面(一个额外层)上留下痕迹，并在组织里留下很小的痕迹。尽管Partnership或者&ldquo;客户-供应者&rdquo;模式可能需要更少的代码和一个单独的代码库，但是如果没有有效的沟通渠道和良好的过程的话，也很难应用起来。企图在没有合作的环境下安排执行Partnership模式，无异于自寻死路。</p>
<p>
	　　结论</p>
<p>
	　　让我们在回到&ldquo;上下文&rdquo;最初的定义上来&mdash;&mdash;&ldquo;一个单词或一个句子所出现的环境，这个环境会反过来影响它们的含义&rdquo;&mdash;&mdash;它非常准确，而且可以应用在设计层面、架构层面乃至组织层面上，却没有损失其准确性和有效性。尽管有些&ldquo;对统一性的期望&rdquo;是合情合理的，但是模型不能被无限地扩张。界限上下文提供了一种非常安全的机制，它允许模型在其内部不断变得复杂，同时又不牺牲概念的完整性。</p>
<p>
	　　当把上下文图应用到大型的项目上后，它还可以显示出当前组织内的隐式边界，并提供一个来自第一手的、没有PS过的项目境况的快照。一个好的上下文图能让你看到所面对的不利条件的大致状况。可能你已经知道&mdash;&mdash;但通常都是不知道&mdash;&mdash;组织是否在扮演项目成功的绊脚石，即使项目还没有开始。</p>
<p>
	　　作为一名顾问，我发现上下文图能够奇迹般地让我快速获取客户项目的细节。上下文图还充当了策略决策的支持工具(毕竟，这是&ldquo;图&rdquo;的本意)。上下文图提供了系统的全局视图，帮助我们关注在选择那些能在你的环境中真正可行的方案，而不是把钱浪费在对系统不切实际的构想中，这是UML或者架构图所做不到的。</p>
<p>
	　　关于作者</p>
<p>
	　　Alberto是来自Avanscoperta的一名咨询顾问和培训师。他致力于帮助客户管理软件开发的复杂度。他坚信只有那种全盘考虑的软件开发方法才能开发出有用的软件。</p>
]]></description>
    <pubDate>Tue, 01 Nov 2011 10:16:25 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/uploads/allimg/111101/1022145063-0-lp.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>Alberto</author>
    <comments>infoQ</comments>
</item>
<item>
    <title><![CDATA[TDD的实施细节应该怎样做]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2011/0722/202937.html</link>
    <description><![CDATA[<p>
	　　以前也有看过一些<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/testdirector/" target="_blank" >TD</A></STRONG>D的资料，但一直没有在实际的项目中实践过。最近可能有一个新的项目，不是特别大，想采用Scrum和<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/" target="_blank" >TDD</A></STRONG>小试身手。先介绍一下我们以前项目的<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/" target="_blank" >开发</A></STRONG>流程：</p>
<p>
	　　1.拿下项目，<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/xqgl/" target="_blank" >需求</A></STRONG>调研分析，编写需求用例(如果客户没有要求，需求规格说明书都不写)</p>
<p>
	　　基本上需求用例就是说明什么人，做什么事情，怎么做，达到什么目的，有什么要求这些。</p>
<p>
	　　2.然后分析领域对象，分析业务流程和场景。并最终生成<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/sjk/" target="_blank" >数据库</A></STRONG>物理模型。</p>
<p>
	　　3.概要设计，其实也没什么，就是数据库结构，还有用例描述加一些时序图。</p>
<p>
	　　4.根据需求用例，编写<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csyl/" target="_blank" >测试用例</A></STRONG>。</p>
<p>
	　　5.开发人员进行开发，有时项目紧的时候，<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/dycs/" target="_blank" >单元测试</A></STRONG>都不写(这个项目没有明文要求)，主要靠开发人员个人意愿。</p>
<p>
	　　6.根据周期定期进行打包测试。我一般会每周build两次，亲自操作一下业务流程，有问题提出修改。这个过程测试人员未参与。</p>
<p>
	　　7.测试人员进入，按模块完成的先后顺序，持续的测试修改。</p>
<p>
	　　以前的项目基本上是采用领域驱动的方式进行一步步开发的。现在打算采用TDD方式，现有一些细节疑问，打算请教一下实施了TDD的各种牛。</p>
<p>
	　　1.TDD方式是不是不用写需求说明书了?</p>
<p>
	　　2.分析领域对象，分析业务流程和场景。并最终生成数据库物理模型。这一步是不是在TDD之前完成?</p>
<p>
	　　3.不写概要设计，由需求用例直接跳入TDD开发?</p>
<p>
	　　4.测试用例是不是需求用例的细化和规范?</p>
<p>
	　　5.TDD中的test是基于单元测试，还是基于需求测试?</p>
<p>
	　　6.如果是单元测试，自然由开发人员完成。如果TDD是基于需求测试，那么开发人员是否需要测试人员配合?</p>
<p>
	　　最后一个问题是：大家有结对编程的习惯吗?在实践过程中结对是否高效?反正我是觉得结对不会太高效的，主要是基于项目人员的配置本来就有成本在那里，而且人员水平也不一样。我的观点是一个经验丰富的带一两个新手共同开发一个模块，但并不需要结对的方式。</p>
<p>
	　　ok,问题完了。等大家拍砖。</p>
<p>
	　　问题补充</p>
<p>
	　　humaeks 写道</p>
<p>
	　　个人的几点愚见，有点零乱：</p>
<p>
	　　1. 首先明确unit test和<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/gncs/" target="_blank" >功能测试</A></STRONG>不一样，参与的人也不一样。</p>
<p>
	　　2. 设计完了再入TDD阶段，写UT的过程其实也是校验测试的过程，如果测试不好写，就需要review设计。这里插播一下，既然考虑采用DDD，应该先出来CDM，然后<STRONG><A href="http://www.ltesting.net/ceshi/ruanjianceshikafajishu/rjcskfyy/java/" target="_blank" >java</A></STRONG> OO与CDM对应，剩下才是设计物理模型和持久层</p>
<p>
	　　3. 传统意义上的TDD指的是unit test。背后很重要的一个思想是先写测试有助于写出clean code that works, 或者说是just enough的代码，实践上需要权衡。对程序员的编程技巧要求高，在我的团队成员中，从零到真的能写出&ldquo;单元&rdquo;测试，需要每天抽一小时1 on 1 code review一个月以上。</p>
<p>
	　　需要程序员有逻辑拆分以及一些coding技巧，看implementation patterns / clean code 这两本书会有帮助，但关键还是每天的code review给及时反馈。</p>
<p>
	　　4. 100%覆盖是不切实际的东西，尤其是初次尝试TDD，可以采用以点带面的方式，让部分成员先尝试到TDD带来的好处，然后在团队中传播;</p>
<p>
	　　5. 成员水平不一样可以采取结对方式提升人员水平，但成本回收周期长，基本不会对本项目(3月内的项目)产生benefit，但遇到有好苗子要坚决培养，否则日后还是会死，留不留得住人，就是另外一个管理topic了。</p>
]]></description>
    <pubDate>Fri, 22 Jul 2011 09:55:30 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>领测软件测试网采编</author>
    <comments>未知</comments>
</item>
<item>
    <title><![CDATA[如何在.NET中的实施测试驱动开发TDD]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2010/1122/199906.html</link>
    <description><![CDATA[<P>TDD(Test-Driven Development)<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target="_blank" >测试驱动开发</A></STRONG>，就是以<STRONG><A href="http://www.ltesting.net/html/94/category-catid-94.html" target="_blank" >测试用例</A></STRONG>来带动开发，也就是先做测试用例，然后根据测试用例做开发。TDD的好外使是开发人员可以针对性的做开发，目标就是通过测试用例，当然，TDD更适合做逻辑的<STRONG><A href="http://www.ltesting.net/html/78/category-catid-478.html" target="_blank" >程序员</A></STRONG>，不适合更多的与UI开发相关的程序员。</P>
<P>不管是TDD也好，传统的开发也好，肯定要先做设计，设计展开后如果采用普通方法做开发，那就是开始写代码，然后<STRONG><A href="http://www.ltesting.net/html/90/category-catid-90.html" target="_blank" >单元测试</A></STRONG>，<STRONG><A href="http://www.ltesting.net/html/69/category-catid-469.html" target="_blank" >集成测试</A></STRONG>等工作。如果用TDD，那就要先从设计中把测试列表(其实就是要实现的功能，人机交互的条目罗列出来，形成一个列表)整理出来。然后就开始开发，在TDD中，“红-绿-重构”的过程很多说明TDD的文章都要说到，本篇也不例外。</P>
<P>有了测试列后，先拿出一个条目，进行测试的开发，开发完成运行，因为被测的程序还没有编写肯定是失败的，然后实现程序，再测，可能还失败，改成，测试成功，然后重构来优化代码，再进入下一个测试条目的循环。</P>
<P><IMG src="http://www.ltesting.net/uploads/2010/11/54376_201011221049551IuCf.jpg" width=485 height=483></P>
<P><STRONG>在.net平台下，怎么去实现呢?</STRONG></P>
<P>本例中用VS2010行进说明，设计部分，可以用vs2010的新功能Modeling，在Modeling里，可以画类图，还可以添加其中的成员，包括返回值类型，参数个数和类型，有了这些方法的签名，对我们先构建测试就提供了依据，对测试程序来说，不关心实现的细节，只用知道参数是什么，返回是什么，拿上这个方法的返回值与给定的返回值作对比，从而来确定方法实现的功能是否正确。在Visual Studio中，可以很方便的来自动创建单元测试，这些方便要归功于“反射”这个技术。当然，一般而然，测试不是只有一个数据，可能要一系列数据，或者更多的数据，在.net平台下，也提供了相应的功能。</P>
<P>下面来做个DEMO说明一下。</P>
<P>先看一个类图，也可以把类中的主要功能，当成一个个条目添加到测试列表中。</P>
<P><IMG src="http://www.ltesting.net/uploads/2010/11/54376_201011221049552KWsu.jpg" width=173 height=124></P>
<P>我们选一个条目——GetRecord，参数是一个ID的整型，返回值是一个逻辑类型，本方法用来实现在一个库中查询输入的ID，看是否存在。</P>
<P>根据类图，可以在类库项目中生成一个类，如下</P>
<P>1 public class DataOperate</P>
<P>2 {</P>
<P>3 public bool GetRecord(int id)</P>
<P>4 {</P>
<P>5 throw new Exception("没有实ì现?");</P>
<P>6 }</P>
<P>7 }</P>
<P>8</P>
<P>接下来，可以继于这个方法，来自动创建一个单元测试，右键方法，创建测试。</P>
<P>一个测试的项目就会自动创建进来，在生成的CS文件中，重点看如下代码(关于单元测试的其他<STRONG><A href="http://www.ltesting.net/ask/" target="_blank" >知识</A></STRONG>可参照http://msdn.microsoft.com/zh-cn/library/ms182515(VS.80).aspx)</P>
<P>1 [TestMethod()]</P>
<P>2 public void GetRecordTest()</P>
<P>3 {</P>
<P>4 DataOperate target = new DataOperate();</P>
<P>5 int id = 0;</P>
<P>6 bool expected = false;</P>
<P>7 bool actual;</P>
<P>8 actual = target.GetRecord(id);</P>
<P>9 Assert.AreEqual(expected, actual);</P>
<P>10 }</P>
<P>11</P>
<P>在这里，测试的用例只有一个id=0，返回值为false，现在测试，肯定通不过，因为被测的方法还没有实现。此时叫做“红”。</P>
<P>接下来就要实现GetRecord方法。</P>
<P>]]></description>
    <pubDate>Mon, 22 Nov 2010 10:48:40 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[软件测试驱动开发的迭代过程]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2010/1004/196372.html</link>
    <description><![CDATA[<p>　　在传统的产品研发模式中，单调从<STRONG><A href="http://www.ltesting.net/html/62/category-catid-162.html" target="_blank" >需求分析</A></STRONG>开始到测试验收结束。开发和测试始终处于产品研发的不同阶段，开发人员在产品研发的早期就介人，然后经过一段时间的开发设计，将开发的累计成果转交给<STRONG><A href="http://www.ltesting.net/html/73/category-catid-273.html" target="_blank" >测试人员</A></STRONG>从而进入到测试阶段。在测试完成并提交用户验收通过后，产品即可交付使用。这种产品研发模式最大的优点是产品研发的阶段划分明确，职责明确，易于管理。</p>
<p>　　但是随着产品复杂程度的增加，操作系统日益庞大，传统的产品研发模式会给产品<STRONG><A href="http://www.ltesting.net/html/5/category-catid-5.html" target="_blank" >质量</A></STRONG>带来极大的风险，同时也给研发人员带来很大的压力。首先针对累计开发成果的集中测试使得多个测试任务在同时爆发，在测试时问一定的情况下，经常导致分配到单个测试项的时间被一再压缩，或者优先级较低的测试项将被剔除，很难保质保量按照<STRONG><A href="http://www.ltesting.net/html/74/category-catid-474.html" target="_blank" >测试计划</A></STRONG>执行。其次即使在规定时间内完成了测试任务，但是没有充裕的时间针对市场需求、用户需求、产品定位和质量达标的<STRONG><A href="http://www.ltesting.net/html/64/category-catid-164.html" target="_blank" >度量</A></STRONG>输入进行充分和全面的测试，难以保证产品已经完全满足设计要求和用户需求。</p>
<p>　　众所周知，测试作为研发过程的常规部分，最重要的作用是发现问题和及时反馈问题。理想化模型中认为只要能发现问题就能够修改，但实际中却要求产品设计之初就必须预留有修正错误的接口和方案，否则当产品研发进行到测试阶段，产品已经基本定型，如果此时才发现了问题并进行修正，会导致耗费的成本十分昂贵。由此可见，传统的产品研发模式从本质上推迟了产品风险和问题的暴露时间，可能会导致产品的研发周期延长，研发质量低下，研发成本超支等问题，同时严重打击参与者的积极性和信心，甚至导致整个产品线的失败。</p>
<p>　　因此为了在一定程度上解决上述问题，同时满足新产品研发的需求，我们在华虹新产品的研发过程中，逐渐探索出了一套全新的产品研发模式，称之为<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target="_blank" >测试驱动开发</A></STRONG>的迭代研发过程，也称为(3+2策略)。该研发模式强调测试与开发的齐头并进，通过对新产品的不断测试与修正，将设计<STRONG><A href="http://www.ltesting.net/html/98/category-catid-98.html" target="_blank" >缺陷</A></STRONG>扼杀于萌芽状态，提供产品质量信心，实现产品价值提升。下面将着重介绍我们在实践中如何使用该迭代研发过程。迭代的概念源自<STRONG><A href="http://www.ltesting.net/" target="_blank" >软件测试</A></STRONG>，在本文中的定义为，迭代起始于模块设计，结束于模块测试通过。首先我们把一个产品研发过程划分为3个阶段(立项、研发、验收)。各阶段的]一作内容都是传统产品研发模式的流程和工作内容的延续，但是又强调新的突破点。在立项阶段，我们强调对用户需求，投入产出和升级方案的预研，考核的阶段成果将汇总为需求输出到研发团队;在研发阶段，我们强调产品定义时采用模块化的方式，分离，设计，开发和测试，已成型的模块，并逐步集成，最终构成完整的系统。考核的阶段成果将体现为把需求转化为系统实现;而在验收阶段 
， 就注重技术指标和研发成本的确认， 其阶段成果表现为产品成本的控制和客户验收通过。其中立项阶段的需求输出和研发阶段的设计实现同等重要 ， 
只有实现了二者的相互补充和相互制约， 才能保证产品验收的成功。</p>
<p>　　其次在进入研发阶段后，我们会制定2 类计划，第一是粗粒度的计划：也称为阶段计划。包括从用户需求、系统设计、概要设计、详细设计到编码， 
涵盖了整个产品的研发目录。主要用于控制产品开发进度和开发周期， 阶段计划制定完成后相对同定， 且必须严格执行。第二是细粒度的计划： 
也称为迭代计划。包括了任务的详细说明， 
并给每个参与者和参与团队分配任务，覆盖到可能的应用场景，分解出关键的技术指标。目的用于控制开发质量和开发回溯。迭代计划通常会随着开发的深入而动态变化。大家对于执行单一的阶段计划都非常熟悉， 
但是在阶段计划中加入了迭代计划， 研发过程将会发生怎样的变化呢? 。迭代计划可以看作是单个阶段计划中的移动窗口， 
所起的作用是把阶段计划进行逐级放大。首先将阶段计划中的工作分配到小集体， 继而分配到每个集体中更小的集体;其次将研发过程化整为零， 
从最基础的模块开始开发并测试， 逐级累加测试模块。最后分解出关键的技术指标( 模块) ， 要求必须尽早完成， 这样就可以在不断迭代中对其进行彻底的测试。</p>]]></description>
    <pubDate>Mon, 04 Oct 2010 09:45:02 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[TDD的3条规定]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2010/0831/188323.html</link>
    <description><![CDATA[<P>　　TDD的3条规定&nbsp;&nbsp;<STRONG><A href="http://www.ltesting.net/" target=_blank>软件测试</A></STRONG></P>
<P>　　这些年来，我喜欢用下面这三条简单的规则来描述<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target="_blank" >测试驱动开发</A></STRONG>:</P>
<P>　　◆　除非这能让失败的<STRONG><A href="http://www.ltesting.net/html/90/category-catid-90.html" target="_blank" >单元测试</A></STRONG>通过，否则不允许去编写任何的产品代码。</P>
<P>　　◆　只允许编写刚好能够导致失败的单元测试。 (编译失败也属于一种失败)</P>
<P>　　◆　只允许编写刚好能够导致一个失败的单元测试通过的产品代码。</P>
<P>　　对于任何功能，一定要从编写它的单元测试开始;但是到了原则2，你就不能再为那个单元测试写更多内容。只要一出现该<STRONG><A href="http://www.ltesting.net/html/92/category-catid-92.html" target="_blank" >单元测试代码</A></STRONG>编译失败，或是断言失败，你就必须停下来开始编写产品代码;但是到了原则3，你就只能编写产品代码，直到让测试编译成功或通过断言为准。</P>
<P>　　仔细想想，就会发现如果不是去让一些东西编译或是执行，你就根本没办法去写代码。确实，这也正是关键所在。我们所做的任何事情(无论是写测试，写产品代码，或是重构)，都要保持系统能够一直运行。跑通测试的时间间隔应该是以秒或是分钟级的，即使那只有10分钟，也都太长了。</P>
<P>　　想了解实际的操作过程，可以看看“保龄球<STRONG><A href="http://www.ltesting.net/html/03/category-catid-103.html" target="_blank" >游戏</A></STRONG>中的Kata”(译注2)一文。</P>
<P>　　现今有很多<STRONG><A href="http://www.ltesting.net/html/78/category-catid-478.html" target="_blank" >程序员</A></STRONG>，每当他们头一次听到这种技术的时候，会想：“这种做法太愚蠢了!”“这会让我慢下来，这是时间和精力的浪费，让我无法思考，无法设计，还会打乱我的思路。”然而，试想，当你走进一个房间，里面都是用这种方式工作的人们，会发生什么情况?你随便选个时间，随意找个人，一分钟以前，他们所有的代码都跑通过。</P>
<P>　　让我再重复一遍：一分钟以前每个人的代码都能跑通!不管你找谁，也不管你何时去找，一分钟以前他们所有的代码都跑通了!</P>
<P>　　如果你所有的代码自始至终都能跑通，那么你会多长时间用一次调试器?答案是，不会太经常。只要敲几下^Z就能很容易的恢复这些代码到跑通时的状态，然后再试着把前几分钟的代码写一遍即可。而如果你不经常调试，那么会省去多少时间呢?而现在你花在调试上的时间又有多少呢?一旦你有调试过，你又要花上多少时间来修复这些<STRONG><A href="http://www.ltesting.net/html/98/category-catid-98.html" target="_blank" >bug</A></STRONG>呢?如果你能够大大减少这些时间的话，又会如何呢?</P>
<P>　　好处还不只这些。如果你采用这种方法，那么每小时你都会产生好几个测试;每天就有十几个;每个月就几百个;一年下来，你所编写的测试就会有数千个。你可以保留着这些测试而且在任何你希望的时候去运行它们!什么时候运行它们呢?随时!只要你做了改动，就去运行它们!</P>
<P>　　有些代码已经混乱不堪了，可是我们为何不去清理它们呢?我们担心会破坏它们。但如果我们拥有测试，我们就有理由确信这些代码不会被破坏，或是说我们可以很快的就找到被破坏的地方。如果我们有了这些测试，我们就对代码发生改变无所忌惮。如果我们看到混乱的代码，或是一个不清晰的结构，可以毫无顾虑地清理它。因为有了测试，代码重新变得易修改了;因为有了测试，软件重新变“软”了。</P>
<P>　　好处还不只这些。如果你想要知道如何去调用一个特定的API，就会有一个测试能够告诉你;如果你想要知道如何创建一个特定的对象，就会有个测试能告诉你。你想知道的任何有关这个系统的，都有一个测试能够去示意。这些测试就像是小型的设计文档，小型的代码示例，描述了系统的工作和使用方式。</P>
<P>　　你是否曾经整合过一个第三方库到你的项目中呢?你拿到一本厚厚的精致的帮助文档，在结尾处，有一沓薄薄的示例附录。你会选择哪个去阅读呢?当然是示例了!那就是单元测试啊!它们是这份文档中最有用的部分;它们是如何使用代码的鲜活的例子;它们是极其详细、完全没有歧义的设计文档，相当的正规甚至可以执行，而且不会与产品代码相脱离。</P>
<P>　　好处还不只这些。如果你曾有过增加单元测试到一个可以工作的系统中的经历，你会发现那一点儿都不好玩。你很可能会发现想跑通测试，你一定是要么去改变系统中的部分设计，要么就在测试上作假。这是因为你试图去测试的系统并不是基于可<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csyl/" target="_blank" >测试设计</A></STRONG>的。例如，你想要测试某个函数f。然而，f调用了另外一个从<STRONG><A href="http://www.ltesting.net/html/61/category-catid-161.html" target="_blank" >数据库</A></STRONG>中删除记录的函数。在你的测试中，你不希望这条记录被删掉，但却没有办法来阻止它。这样的系统就不是基于可测试设计的系统。</P>
<P>　　当你遵循TDD的三条规则的时候，你的所有代码天生就可测试!而且另一个能形容“可测试”的词汇就是“可解耦”。为了单独的测试一个模块，你就必须把它解耦。所以TDD强制你去解耦这些模块。确实，如果你遵循这三条规则的话，你会发现你可能比起从前来能做出更多的解藕。这就强制了你去创造更好的，低耦合的设计。</P>
<P>　　收获了所有的这些好处，这些愚蠢的小规则实际上好像就没那么愚蠢了吧。他们实际上很可能是一些基本而又深刻的原则。确实，在我接触TDD之前我曾做过将近30年的程序员，我不认为曾有过什么人教过我什么非常奏效但又基本的编程实践。毕竟三十年意味着很多的经验。但当我开始了使用TDD，我就被这项技术的有效性所震撼，也沉迷其中。我不会再考虑去敲一大堆代码然后平白指望它们能运行成功。对于那种先将一组模块打散，然后希望能够再将它们整合起来，并且让它们在能下个礼拜五前运行起来的做法，我也不再能忍受。在我写程序的时候，每一个决定都由这种让现在开始写的代码能在一分钟后再次执行这样的基本<STRONG><A href="http://www.ltesting.net/html/62/category-catid-162.html" target="_blank" >需求</A></STRONG>所驱使着。</P>
<P>&nbsp;</P>
<P>&nbsp;</P>]]></description>
    <pubDate>Tue, 31 Aug 2010 13:34:20 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[测试开发过程经验总结]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2010/0819/184469.html</link>
    <description><![CDATA[<P>　　测试<STRONG><A href="http://www.ltesting.net/html/4/category-catid-4.html" target="_blank" >开发</A></STRONG>过程经验总结&nbsp;&nbsp; <STRONG><A href="http://www.ltesting.net/" target=_blank>软件测试</A></STRONG></P>
<P>　　做这个工作也有一段时间，总结几点经验，大家分享一下：</P>
<P>　　1、测试要尽早</P>
<P>　　公司的产品已经修订一段时间了，但是由于任务繁忙和人手不足，因此测试一直拖后，因此当进行集中测试的时候<STRONG><A href="http://www.ltesting.net/html/98/category-catid-98.html" target="_blank" >Bug</A></STRONG>集中爆发，因此感觉更加的繁忙，另外由于很多功能和修订，都已经修改了很长的时间，因此<STRONG><A href="http://www.ltesting.net/html/78/category-catid-478.html" target="_blank" >程序员</A></STRONG>再次进入修改的时候，往往需要重新分析和理解，造成Bug的修复周期延长了很多。</P>
<P>　　建议当完成功能修订后，要尽快进入测试状态，以缩短Bug的存在时间，降低程序员修订成本。</P>
<P>　　2、使用好的<STRONG><A href="http://www.ltesting.net/html/98/category-catid-98.html" target="_blank" >缺陷管理</A></STRONG>工具</P>
<P>　　之前公司只是使用一个BBS作为缺陷的跟踪和管理工具，但是，效果很不理想，虽然缺陷管理的工具很多，但是都有自己的长处和短处，后来使用了<STRONG><A href="http://www.ltesting.net/html/11/category-catid-111.html" target="_blank" >TD</A></STRONG>，效果的确好的多。</P>
<P>　　3、缺陷描述要准确</P>
<P>　　很多<STRONG><A href="http://www.ltesting.net/html/73/category-catid-273.html" target="_blank" >测试人员</A></STRONG>反馈的缺陷，程序员读起来十分的费劲，甚至比理解缺陷本身还要难懂，因此，如果发现缺陷后，在登记的时候，一定要尽量描述准确和清晰，以免造成错误的理解，反而更加干扰缺陷的修订。如果缺陷的确很难描述，可以将缺陷的发生过程录制下来，或者干脆手工给程序员演示一遍，效果就更好了。</P>
<P>　　4、缺陷描述不完整</P>
<P>　　很多缺陷都是有前世和今生的，因此把缺陷产生的出发条件描述的完整，对解决缺陷起着很重要的作用。</P>
<P>　　5、缺陷要分等级</P>
<P>　　缺陷都是要优先级别的，严重的当然要尽快解决，低级别的放一放。</P>
<P>　　6、开发和测试最好不同步</P>
<P>　　公司是早上8：30上班，一般是9：00左右才能给测试部一个新的测试版本，而如果Build出现意外，则新的版本发布就会推迟，因此开发和测试一定要有个时间差，开发部最好在早上第1时间给测试部一个最新的测试版本。一种是开发部早点来，一种是晚点走，最后我们的约定是下午4:30分开发部Build版本给测试部明天使用。</P>
<P>　　7、优先验证Fixed状态的缺陷</P>
<P>　　测试部每天最优先的任务就是验证新版本中Fixed状态的缺陷是否正确，这个很主要，因为开发部刚刚修正，如果没有验证通过，程序员可以立刻进行修订，如果过了很长时间才通知没有通过，那么可能程序员还得重新理解和分析代码。</P>
<P>　　8、一个缺陷报告包含多个缺陷</P>
<P>　　有些时候测试人员在一个测试报告中，包含N(N&gt;=1)个缺陷，结果程序员修订了其中一个，另一个需要拒绝掉，结果缺陷的状态就失去效果了，因此一个缺陷记录只能包含一个缺陷，如果存在多个就是测试人员的责任了。</P>
<P>　　9、交叉测试的重要性</P>
<P>　　我们最初安排测试的时候，是某个测试人员只测试其中一部分，另外的测试人员测试另外一部分，过了几天后发现，每个测试人员的Bug检测数量都下降了，原来，测试人员对自己部分已经发现不出来缺陷了，后来采用了交叉测试的方式，就是测试人员交换测试工作，结果不同的人从不同的角度进行测试，结果一些缺陷又发现了，因此交叉测试很重要。</P>
<P>　　10、测试经验的总结</P>
<P>　　测试的过程很枯燥，而<STRONG><A href="http://www.ltesting.net/html/97/category-catid-97.html" target="_blank" >测试过程</A></STRONG>中发现的测试经验是十分重要的，不断的调整测试的策略、流程，多总结和借鉴别人的测试经验，会更好的提高测试<STRONG><A href="http://www.ltesting.net/html/5/category-catid-5.html" target="_blank" >质量</A></STRONG>。</P>
<P>　　以上是个人意见，供大家分享</P>]]></description>
    <pubDate>Thu, 19 Aug 2010 10:15:18 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[PHP测试驱动开发介绍]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2010/0706/172430.html</link>
    <description><![CDATA[<P>　　PHP<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target="_blank" >测试驱动开发</A></STRONG>介绍&nbsp;&nbsp; <STRONG><A href="http://www.ltesting.net/" target=_blank>软件测试</A></STRONG></P>
<P>　　摘要</P>
<P>　　本文向你介绍测试驱动开发的概念，并用一个简单的示例项目来做示范。</P>
<P>　　介绍xml:lang="en-us"&gt;</P>
<P>　　开发PHP产品有很多不同的方法。我们大多数倾向于从一个简单的脚本开始，逐步向前推进。 或许我们可以预先列出我们的脚本，但是我们往往是停留在开发阶段，在需要测试的时候不会真正的去开始测试。基本上，我们是先开发后测试。</P>
<P>　　但是这样做或许不是最好的办法，可能会在今后带来问题。这就是为什么一些开发者提倡一种不同的开发方式，叫做测试驱动开发(<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target="_blank" >TDD</A></STRONG>)的原因- 就是先测试后开发。</P>
<P>　　你可能会疑惑这样该怎么做，而这正是本文将讨论的。我将带领你们通过一个真实的简单项目去示范TDD如何工作。本文和示例项目都基于Noel Darlow(“McGruff”)在<STRONG><A href="http://bbs.ltesting.net/" target="_blank" >论坛</A></STRONG>中向另一个论坛成员演示TDD如何工作的讨论。</P>
<P>　　我们的示例项目是一个Biter类，它通过使用正则表达式可以“咬掉”字符串中的片段，就象这样：</P>
<P>　　bite ('/pattern/');?&gt;</P>
<P>　　我们的类也将修改原始的字符串，把匹配的部分去除(所以我们叫它“吞噬者”)。</P>
<P>　　让我们从设置<STRONG><A href="http://www.ltesting.net/html/81/category-catid-481.html" target="_blank" >测试框架</A></STRONG>开始。</P>
<P>　　设置测试框架</P>
<P>　　由于我们从测试出发，我们需要有一些测试框架。我将使用SimpleTest 框架，仅仅因为我最熟悉它。</P>
<P>　　下载一份SimpleTest的拷贝，把它安装在你本机或者你的<STRONG><A href="http://www.ltesting.net/html/78/category-catid-378.html" target="_blank" >服务器</A></STRONG>上。然后创建一个叫做"test_biter.<STRONG><A href="http://www.ltesting.net/html/57/category-catid-157.html" target="_blank" >php</A></STRONG>"的新文件，里面写下面的代码：</P>
<P>　　require_once 'simpletest/unit_tester.php';</P>
<P>　　require_once 'simpletest/reporter.php';</P>
<P>　　class BiterTestCase extends <STRONG><A href="http://www.ltesting.net/html/90/category-catid-90.html" target="_blank" >UnitTest</A></STRONG>Case {</P>
<P>　　function testSetup () {</P>
<P>　　$this-&gt;assertTrue(false);</P>
<P>　　}</P>
<P>　　}</P>
<P>　　$test = new BiterTestCase('TDD Biter Test');</P>
<P>　　$test-&gt;run(new HtmlReporter());</P>
<P>　　?&gt;</P>
<P>　　让我们分析一下这个例子。首先我们包含了一些SimpleTest框架的文件(你要确认一下路径是否和你的一样)。接着我们建立了一个叫做 BiterTestCase的新类，它将用来测试我们的Biter类。象你看到的一样，BiterTestClase类继承于UnitTestCase 类，这个意味着BiterTestClass是我们第一个真正意义上的<STRONG><A href="http://www.ltesting.net/html/94/category-catid-94.html" target="_blank" >测试用例</A></STRONG>。</P>
<P>　　BiterTestClass类只有一个方法调用叫做'testSetup'。任何以“test”开头的方法都会被SimpleTest框架自动执行，因此它们应该是被用来测试项目中的某个部分。在上面的例子中，我们通过调用assertTrue()方法来确认框架被正确设置。</P>
<P>　　例子中的后面两行是建立一个测试用例的实例，然后运行所有测试。如果所有设置都正确的话，你会得到下面的输出：</P>]]></description>
    <pubDate>Tue, 06 Jul 2010 12:21:47 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[浅谈测试驱动开发(TDD)]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2010/0617/172026.html</link>
    <description><![CDATA[<P>　　浅谈测试驱动开发(TDD)&nbsp; <STRONG><A href="http://www.ltesting.net/" target=_blank>软件测试</A></STRONG></P>
<P>　　测试驱动开发(TDD)是<STRONG><A href="http://www.ltesting.net/html/68/category-catid-168.html" target="_blank" >极限编程</A></STRONG>的重要特点，它以不断的测试推动代码的开发，既简化了代码，又保证了软件<STRONG><A href="http://www.ltesting.net/html/5/category-catid-5.html" target="_blank" >质量</A></STRONG>。本文从开发人员使用的角度，介绍了 TDD 优势、原理、过程、原则、<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/" target="_blank" >测试技术</A></STRONG>、Tips 等方面。</P>
<P>　　背景</P>
<P>　　一个高效的软件开发过程对软件开发人员来说是至关重要的，决定着开发是痛苦的挣扎，还是不断进步的喜悦。国人对软件蓝领的不屑，对繁琐冗长的传统开发过程的不耐，使大多数开发人员无所适从。最近兴起的一些软件开发过程相关的技术，提供一些比较高效、实用的软件过程开发方法。其中比较基础、关键的一个技术就是测试驱动开发(Test-Driven Development)。虽然TDD光大于极限编程，但测试驱动开发完全可以单独应用。下面就从开发人员使用的角度进行介绍，使开发人员用最少的代价尽快理解、掌握、应用这种技术。下面分优势，原理，过程，原则，测试技术，Tips等方面进行讨论。</P>
<P>　　1. 优势</P>
<P>　　TDD的基本思路就是通过测试来推动整个开发的进行。而测试驱动<STRONG><A href="http://www.ltesting.net/html/4/category-catid-4.html" target="_blank" >开发技术</A></STRONG>并不只是单纯的测试工作。</P>
<P>　　需求向来就是软件开发过程中感觉最不好明确描述、易变的东西。这里说的需求不只是指用户的需求，还包括对代码的使用需求。很多开发人员最害怕的就是后期还要修改某个类或者函数的接口进行修改或者扩展，为什么会发生这样的事情就是因为这部分代码的使用需求没有很好的描述。测试驱动开发就是通过编写<STRONG><A href="http://www.ltesting.net/html/94/category-catid-94.html" target="_blank" >测试用例</A></STRONG>，先考虑代码的使用需求(包括功能、过程、接口等)，而且这个描述是无二义的，可执行验证的。</P>
<P>　　通过编写这部分代码的测试用例，对其功能的分解、使用过程、接口都进行了设计。而且这种从使用角度对代码的设计通常更符合后期开发的需求。可测试的要求，对代码的内聚性的提高和复用都非常有益。因此测试驱动开发也是一种代码设计的过程。</P>
<P>　　开发人员通常对编写文档非常厌烦，但要使用、理解别人的代码时通常又希望能有文档进行指导。而测试驱动开发过程中产生的测试用例代码就是对代码的最好的解释。</P>
<P>　　快乐工作的基础就是对自己有信心，对自己的工作成果有信心。当前很多开发人员却经常在担心：“代码是否正确?”“辛苦编写的代码还有没有严重<STRONG><A href="http://www.ltesting.net/html/98/category-catid-98.html" target="_blank" >bug</A></STRONG>?”“修改的新代码对其他部分有没有影响?”。这种担心甚至导致某些代码应该修改却不敢修改的地步。测试驱动开发提供的测试集就可以作为你信心的来源。</P>
<P>　　当然测试驱动开发最重要的功能还在于保障代码的正确性，能够迅速发现、定位bug。而迅速发现、定位bug是很多开发人员的梦想。针对关键代码的测试集，以及不断完善的测试用例，为迅速发现、定位bug提供了条件。</P>
<P>　　我的一段功能非常复杂的代码使用TDD开发完成，真实环境应用中只发现几个bug，而且很快被定位解决。您在应用后，也一定会为那种自信的开发过程，功能不断增加、完善的感觉，迅速发现、定位bug的能力所感染，喜欢这个技术的。</P>
<P>　　那么是什么样的原理、方法提供上面说的这些好处哪?下面我们就看看TDD的原理。</P>
<P>　　2. 原理</P>
<P>　　测试驱动开发的基本思想就是在开发功能代码之前，先编写测试代码。也就是说在明确要开发某个功能后，首先思考如何对这个功能进行测试，并完成测试代码的编写，然后编写相关的代码满足这些测试用例。然后循环进行添加其他功能，直到完全部功能的开发。</P>
<P>　　我们这里把这个技术的应用领域从代码编写扩展到整个开发过程。应该对整个开发过程的各个阶段进行测试驱动，首先思考如何对这个阶段进行测试、验证、考核，并编写相关的测试文档，然后开始下一步工作，最后再验证相关的工作。下图是一个比较流行的测试模型：V测试模型。</P>
<P>　　【图 V测试模型】</P>
<CENTER><IMG height=281 alt="" src="http://www.ltesting.net/uploads/2010/06/110593_201006171156211uBUY.jpg" width=400 border=1></CENTER>
<P>　　在开发的各个阶段，包括<STRONG><A href="http://www.ltesting.net/html/62/category-catid-162.html" target="_blank" >需求分析</A></STRONG>、概要设计、详细设计、编码过程中都应该考虑相对应的测试工作，完成相关的测试用例的设计、<STRONG><A href="http://www.ltesting.net/html/75/category-catid-475.html" target="_blank" >测试方案</A></STRONG>、<STRONG><A href="http://www.ltesting.net/html/74/category-catid-474.html" target="_blank" >测试计划</A></STRONG>的编写。这里提到的开发阶段只是举例，根据实际的开发活动进行调整。相关的测试文档也不一定是非常详细复杂的文档，或者什么形式，但应该养成测试驱动的习惯。</P>
<P>]]></description>
    <pubDate>Thu, 17 Jun 2010 11:55:25 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[从企业的运行价值链说起——我眼中的测试驱动开发(TDD)]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2010/0609/171893.html</link>
    <description><![CDATA[<P>　　从企业的运行价值链说起——我眼中的<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target="_blank" >测试驱动开发</A></STRONG>(<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target="_blank" >TDD</A></STRONG>)&nbsp;&nbsp; <STRONG><A href="http://www.ltesting.net/" target=_blank>软件测试</A></STRONG></P>
<P>　　看了一期中央电视台的《对话》栏目，节目对三星CEO尹钟龙进行了访谈。其中，现场一位女士的一句话令我印象深刻。她提到一个企业的运行价值链，共分为三步：首先是发现价值，找到目标市场;第二步是生产价值，将高<STRONG><A href="http://www.ltesting.net/html/5/category-catid-5.html" target="_blank" >质量</A></STRONG>的产品生产出来;最后是保护价值或收获价值，做好品牌。</P>
<P>　　怎么理解呢?这位女士以Nike作比喻。第一步是设计Nike鞋，这就是发现价值，可能获得100美元的价值;然后再拿到中国来生产，大约是10美元;最后再将生产好的鞋子，贴上Nike的商标送回到美国去卖，又可以收获90美元。一双鞋售价200美元，而生产价值所能收获的却只有10美元。这一步获取利益最低，我们中国的公司却做得最好。而怎么去发现价值，然后又怎样去巩固自己的品牌和知名度，中国的公司就做得不那么好了。</P>
<P>　　据我的了解，国内的软件开发应用TDD相对较少，很多人认为：测试驱动开发是个好东东，但似乎不符合中国国情。说到原因，最多的一条就是项目时间紧，没有时间写测试代码。在项目中，到底该不该使用TDD，大多数人持怀疑或观望的态度。这种态度与观点，就让我想起了如上《对话》中的这一段话。</P>
<P>　　再仔细分析企业运行价值链的三步走，我觉得和软件开发的TDD价值链很相似。第一步，是发现价值。应用到TDD中，就是测试先行，通过测试来驱动我们编写代码。第二步，生产价值。毋庸置疑，这正是编写代码的一个阶段。而第三步，就是收获价值，在TDD中，我们收获的不仅有开发后完整的产品，同时还收获了完整的测试套件。和Nike鞋的生产一样，我们在软件开发中，过度地重视了第二步生产价值阶段，而对于第一步和第三步，要么是忽略了，要么就是没有提高到相应的高度。</P>
<P>　　一、发现价值与生产价值</P>
<P>　　习惯了传统开发模式的<STRONG><A href="http://www.ltesting.net/html/78/category-catid-478.html" target="_blank" >程序员</A></STRONG>，非常不适应写代码之前，先写测试的方法，这其中也包括我。那么，我们一般是怎样去发现价值的呢?首先通过<STRONG><A href="http://www.ltesting.net/html/62/category-catid-162.html" target="_blank" >需求分析</A></STRONG>，然后进入设计阶段。在设计阶段期间，再围绕需求分析的结果，更多的是从实现的角度，而非从客户应用的角度出发。TDD颠覆了这种模式。因为需要测试先行，就驱动了程序员必须从功能出发、从应用出发。在写测试代码的过程中，我们需要考虑要实现那些功能，相应的类的名称、对象的创建方式，以及可能会应用到的模式和策略，如此种种，在这个过程中，如剥笋子一般逐渐地规定出来了。</P>
<P>　　在这个过程中，我们要审慎地选择测试的步子。昂首阔步虽然显得气势轩昂，行进快速，但往往会忽略沿途的风景。在测试驱动开发中，我建议你小心的规划测试样例，从测试样例的逐步完善中，渐进地驱动出你更加完善的代码。例如，我需要开发一个智能的个人助理，它目前能提供的功能是：能够让用户定制自己感兴趣的类别，然后个人助理根据用户的定制进行搜索，并将搜索得到的结果按不同的类别进行存储。</P>
<P>　　我们来尝试一下TDD的过程。根据对功能的分析，我们首先应该有一个智能助理对象，测试代码如下：</P>
<P>　　[Test]</P>
<P>　　public void TestSmartAssistor()</P>
<P>　　{</P>
<P>　　SmartAssistor assistor = new SmartAssistor();</P>
<P>　　Assert.IsNotNull(assistor);</P>
<P>　　}</P>
<P>]]></description>
    <pubDate>Wed, 09 Jun 2010 09:57:23 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[从企业的运行价值链说起——我眼中的测试驱动开发(TDD)]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2010/0608/171888.html</link>
    <description><![CDATA[<P>　　从企业的运行价值链说起——我眼中的<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target="_blank" >测试驱动开发</A></STRONG>(<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target="_blank" >TDD</A></STRONG>)&nbsp; <STRONG><A href="http://www.ltesting.net/" target=_blank>软件测试</A></STRONG></P>
<P>　　看了一期中央电视台的《对话》栏目，节目对三星CEO尹钟龙进行了访谈。其中，现场一位女士的一句话令我印象深刻。她提到一个企业的运行价值链，共分为三步：首先是发现价值，找到目标市场;第二步是生产价值，将高<STRONG><A href="http://www.ltesting.net/html/5/category-catid-5.html" target="_blank" >质量</A></STRONG>的产品生产出来;最后是保护价值或收获价值，做好品牌。</P>
<P>　　怎么理解呢?这位女士以Nike作比喻。第一步是设计Nike鞋，这就是发现价值，可能获得100美元的价值;然后再拿到中国来生产，大约是10美元;最后再将生产好的鞋子，贴上Nike的商标送回到美国去卖，又可以收获90美元。一双鞋售价200美元，而生产价值所能收获的却只有10美元。这一步获取利益最低，我们中国的公司却做得最好。而怎么去发现价值，然后又怎样去巩固自己的品牌和知名度，中国的公司就做得不那么好了。</P>
<P>　　据我的了解，国内的软件开发应用TDD相对较少，很多人认为：测试驱动开发是个好东东，但似乎不符合中国国情。说到原因，最多的一条就是项目时间紧，没有时间写测试代码。在项目中，到底该不该使用TDD，大多数人持怀疑或观望的态度。这种态度与观点，就让我想起了如上《对话》中的这一段话。</P>
<P>　　再仔细分析企业运行价值链的三步走，我觉得和软件开发的TDD价值链很相似。第一步，是发现价值。应用到TDD中，就是测试先行，通过测试来驱动我们编写代码。第二步，生产价值。毋庸置疑，这正是编写代码的一个阶段。而第三步，就是收获价值，在TDD中，我们收获的不仅有开发后完整的产品，同时还收获了完整的测试套件。和Nike鞋的生产一样，我们在软件开发中，过度地重视了第二步生产价值阶段，而对于第一步和第三步，要么是忽略了，要么就是没有提高到相应的高度。</P>
<P>　　一、发现价值与生产价值</P>
<P>　　习惯了传统开发模式的<STRONG><A href="http://www.ltesting.net/html/78/category-catid-478.html" target="_blank" >程序员</A></STRONG>，非常不适应写代码之前，先写测试的方法，这其中也包括我。那么，我们一般是怎样去发现价值的呢?首先通过<STRONG><A href="http://www.ltesting.net/html/62/category-catid-162.html" target="_blank" >需求分析</A></STRONG>，然后进入设计阶段。在设计阶段期间，再围绕需求分析的结果，更多的是从实现的角度，而非从客户应用的角度出发。TDD颠覆了这种模式。因为需要测试先行，就驱动了程序员必须从功能出发、从应用出发。在写测试代码的过程中，我们需要考虑要实现那些功能，相应的类的名称、对象的创建方式，以及可能会应用到的模式和策略，如此种种，在这个过程中，如剥笋子一般逐渐地规定出来了。</P>
<P>　　在这个过程中，我们要审慎地选择测试的步子。昂首阔步虽然显得气势轩昂，行进快速，但往往会忽略沿途的风景。在测试驱动开发中，我建议你小心的规划测试样例，从测试样例的逐步完善中，渐进地驱动出你更加完善的代码。例如，我需要开发一个智能的个人助理，它目前能提供的功能是：能够让用户定制自己感兴趣的类别，然后个人助理根据用户的定制进行搜索，并将搜索得到的结果按不同的类别进行存储。</P>
<P>　　我们来尝试一下TDD的过程。根据对功能的分析，我们首先应该有一个智能助理对象，测试代码如下：</P>
<P>　　[Test]</P>
<P>　　public void TestSmartAssistor()</P>
<P>　　{</P>
<P>　　SmartAssistor assistor = new SmartAssistor();</P>
<P>　　Assert.IsNotNull(assistor);</P>
<P>　　}</P>
<P>]]></description>
    <pubDate>Tue, 08 Jun 2010 11:20:44 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[TDD的三条军规]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2010/0608/171886.html</link>
    <description><![CDATA[<P>　　TDD的三条军规&nbsp;<STRONG><A href="http://www.ltesting.net/" target=_blank>软件测试</A></STRONG>　</P>
<P>&nbsp;&nbsp; 　这些年来，我喜欢用下面这三条简单的规则来描述<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target="_blank" >测试驱动开发</A></STRONG>:</P>
<P>　　◆　除非这能让失败的<STRONG><A href="http://www.ltesting.net/html/90/category-catid-90.html" target="_blank" >单元测试</A></STRONG>通过，否则不允许去编写任何的产品代码。</P>
<P>　　◆　只允许编写刚好能够导致失败的单元测试。 (编译失败也属于一种失败)</P>
<P>　　◆　只允许编写刚好能够导致一个失败的单元测试通过的产品代码。</P>
<P>　　对于任何功能，一定要从编写它的单元测试开始;但是到了原则2，你就不能再为那个单元测试写更多内容。只要一出现该<STRONG><A href="http://www.ltesting.net/html/92/category-catid-92.html" target="_blank" >单元测试代码</A></STRONG>编译失败，或是断言失败，你就必须停下来开始编写产品代码;但是到了原则3，你就只能编写产品代码，直到让测试编译成功或通过断言为准。</P>
<P>　　仔细想想，就会发现如果不是去让一些东西编译或是执行，你就根本没办法去写代码。确实，这也正是关键所在。我们所做的任何事情(无论是写测试，写产品代码，或是重构)，都要保持系统能够一直运行。跑通测试的时间间隔应该是以秒或是分钟级的，即使那只有10分钟，也都太长了。</P>
<P>　　想了解实际的操作过程，可以看看“保龄球<STRONG><A href="http://www.ltesting.net/html/03/category-catid-103.html" target="_blank" >游戏</A></STRONG>中的Kata”(译注2)一文。</P>
<P>　　现今有很多<STRONG><A href="http://www.ltesting.net/html/78/category-catid-478.html" target="_blank" >程序员</A></STRONG>，每当他们头一次听到这种技术的时候，会想：“这种做法太愚蠢了!”“这会让我慢下来，这是时间和精力的浪费，让我无法思考，无法设计，还会打乱我的思路。”然而，试想，当你走进一个房间，里面都是用这种方式工作的人们，会发生什么情况?你随便选个时间，随意找个人，一分钟以前，他们所有的代码都跑通过。</P>
<P>　　让我再重复一遍：一分钟以前每个人的代码都能跑通!不管你找谁，也不管你何时去找，一分钟以前他们所有的代码都跑通了!</P>
<P>　　如果你所有的代码自始至终都能跑通，那么你会多长时间用一次调试器?答案是，不会太经常。只要敲几下^Z就能很容易的恢复这些代码到跑通时的状态，然后再试着把前几分钟的代码写一遍即可。而如果你不经常调试，那么会省去多少时间呢?而现在你花在调试上的时间又有多少呢?一旦你有调试过，你又要花上多少时间来修复这些<STRONG><A href="http://www.ltesting.net/html/98/category-catid-98.html" target="_blank" >bug</A></STRONG>呢?如果你能够大大减少这些时间的话，又会如何呢?</P>
<P>　　好处还不只这些。如果你采用这种方法，那么每小时你都会产生好几个测试;每天就有十几个;每个月就几百个;一年下来，你所编写的测试就会有数千个。你可以保留着这些测试而且在任何你希望的时候去运行它们!什么时候运行它们呢?随时!只要你做了改动，就去运行它们!</P>
<P>　　有些代码已经混乱不堪了，可是我们为何不去清理它们呢?我们担心会破坏它们。但如果我们拥有测试，我们就有理由确信这些代码不会被破坏，或是说我们可以很快的就找到被破坏的地方。如果我们有了这些测试，我们就对代码发生改变无所忌惮。如果我们看到混乱的代码，或是一个不清晰的结构，可以毫无顾虑地清理它。因为有了测试，代码重新变得易修改了;因为有了测试，软件重新变“软”了。</P>
<P>　　好处还不只这些。如果你想要知道如何去调用一个特定的API，就会有一个测试能够告诉你;如果你想要知道如何创建一个特定的对象，就会有个测试能告诉你。你想知道的任何有关这个系统的，都有一个测试能够去示意。这些测试就像是小型的设计文档，小型的代码示例，描述了系统的工作和使用方式。</P>
<P>　　你是否曾经整合过一个第三方库到你的项目中呢?你拿到一本厚厚的精致的帮助文档，在结尾处，有一沓薄薄的示例附录。你会选择哪个去阅读呢?当然是示例了!那就是单元测试啊!它们是这份文档中最有用的部分;它们是如何使用代码的鲜活的例子;它们是极其详细、完全没有歧义的设计文档，相当的正规甚至可以执行，而且不会与产品代码相脱离。</P>
<P>　　好处还不只这些。如果你曾有过增加单元测试到一个可以工作的系统中的经历，你会发现那一点儿都不好玩。你很可能会发现想跑通测试，你一定是要么去改变系统中的部分设计，要么就在测试上作假。这是因为你试图去测试的系统并不是基于可<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csyl/" target="_blank" >测试设计</A></STRONG>的。例如，你想要测试某个函数f。然而，f调用了另外一个从<STRONG><A href="http://www.ltesting.net/html/61/category-catid-161.html" target="_blank" >数据库</A></STRONG>中删除记录的函数。在你的测试中，你不希望这条记录被删掉，但却没有办法来阻止它。这样的系统就不是基于可测试设计的系统。</P>
<P>　　当你遵循TDD的三条规则的时候，你的所有代码天生就可测试!而且另一个能形容“可测试”的词汇就是“可解耦”。为了单独的测试一个模块，你就必须把它解耦。所以TDD强制你去解耦这些模块。确实，如果你遵循这三条规则的话，你会发现你可能比起从前来能做出更多的解藕。这就强制了你去创造更好的，低耦合的设计。</P>
<P>　　收获了所有的这些好处，这些愚蠢的小规则实际上好像就没那么愚蠢了吧。他们实际上很可能是一些基本而又深刻的原则。确实，在我接触TDD之前我曾做过将近30年的程序员，我不认为曾有过什么人教过我什么非常奏效但又基本的编程实践。毕竟三十年意味着很多的经验。但当我开始了使用TDD，我就被这项技术的有效性所震撼，也沉迷其中。我不会再考虑去敲一大堆代码然后平白指望它们能运行成功。对于那种先将一组模块打散，然后希望能够再将它们整合起来，并且让它们在能下个礼拜五前运行起来的做法，我也不再能忍受。在我写程序的时候，每一个决定都由这种让现在开始写的代码能在一分钟后再次执行这样的基本<STRONG><A href="http://www.ltesting.net/html/62/category-catid-162.html" target="_blank" >需求</A></STRONG>所驱使着。</P>
<P>　　译注：</P>
<P>　　1，TDD，测试驱动开发。</P>
<P>　　2，Kata，可理解为武功招式</P>]]></description>
    <pubDate>Tue, 08 Jun 2010 11:14:04 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[最佳实践：测试驱动开发全功略[5]]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2010/0604/171821.html</link>
    <description><![CDATA[<P>　　最佳实践：<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target="_blank" >测试驱动开发</A></STRONG>全功略[5]&nbsp; <STRONG><A href="http://www.ltesting.net/" target=_blank>软件测试</A></STRONG></P>
<P>　　15、公司不重视测试，测试负责人如何开展测试工作?</P>
<P>　　目前国内的软件公司不重视测试仍然是一种普遍现象。尽管很多公司在意识上已经开始重视测试，但是在具体工作中，往往由于追赶进度、节省资源等方面原因而忽略测试工作。在这种情况下，测试负责人仍要对软件<STRONG><A href="http://www.ltesting.net/html/5/category-catid-5.html" target="_blank" >质量</A></STRONG>负主要责任。在这种环境下，测试负责人应该如何开展工作呢?</P>
<P>　　首先，要主动去配合开发人员完成工作。尤其是不能抱怨环境，在任何情况下抱怨是不能解决问题的，只能加重矛盾的激化。在此基础上，逐渐显出测试工作的重要性，然后再逐步健全测试体系。</P>
<P>　　其次，用实际行动来证明测试工作的重要性。只有测试工作的业绩逐步表现出来，人们才会真正的注意到测试的重要性。因此，测试负责人从点滴开始做起，才能逐步做好测试工作。</P>
<P>　　要想做好软件，把开发的软件产品形成商品，测试工作必须和开发一样重视。否则，质量不好的产品，很快会被市场淘汰的。现代的软件规模越来越大，测试工作也会越来越重要，因此测试负责人只要坚持做好工作，可发挥作用的空间会越来越大。</P>
<P>　　最后要说的是，如果真的是在一个没有希望的团队里，测试负责人可以考虑辞职。辞职也是一个不错的选择，到新的环境去发挥自己的能力，要比长时间的怀着“郁闷”的心情去工作好的多。</P>
<P>　　16、测试管理者需要是技术专家吗?</P>
<P>　　测试管理者在测试项目中的主要任务是制定测试策略，管理<STRONG><A href="http://www.ltesting.net/html/74/category-catid-474.html" target="_blank" >测试计划</A></STRONG>的落实情况，并且还要为测试项目的进行创造良好的执行环境。同时还要调动员工的创造性，对员工的工作作出评估。这些工作不一定要求测试管理者达到专家的水平。</P>
<P>　　但是在实际工作中，由于<STRONG><A href="http://www.ltesting.net/html/73/category-catid-273.html" target="_blank" >测试人员</A></STRONG>的短缺，测试管理者常常做为测试员来执行具体的测试任务。尤其在规模较小的测试团队，测试管理者的日常工作通常以具体的测试执行工作为主，这个时候更需要测试管理者有较好的背景<STRONG><A href="http://www.ltesting.net/ask/" target="_blank" >知识</A></STRONG>。</P>
<P>　　总体说来，技术方面的背景知识对测试管理者是十分有益的。例如：分配工作任务、做进度预算，以及一些具体的执行工作，都需要一定的背景知识。当然，做为一个测试管理者，没有必要精通所有的技术，那也是办不到的。测试管理者做到正确的帮助员工最好地完成工作，并且提供最好的完成工作的环境就可以了。</P>]]></description>
    <pubDate>Fri, 04 Jun 2010 11:06:35 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[最佳实践：测试驱动开发全功略[4]]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2010/0604/171820.html</link>
    <description><![CDATA[<P>　　最佳实践：<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target="_blank" >测试驱动开发</A></STRONG>全功略[4]&nbsp;&nbsp; <STRONG><A href="http://www.ltesting.net/" target=_blank>软件测试</A></STRONG>　</P>
<P>&nbsp; 　13、为什么计划定期的培训?</P>
<P>　　测试工作和开发工作一样，不但要面对日新月异的新技术，还要学习相关系统的领域<STRONG><A href="http://www.ltesting.net/ask/" target="_blank" >知识</A></STRONG>。只有在不断的学习中，才能做好工作，跟上行业的发展。如果<STRONG><A href="http://www.ltesting.net/html/97/category-catid-97.html" target="_blank" >测试管理</A></STRONG>者没有基于不断的变化而培训员工，就会给组织带来一定的损失。日常培训可以是关于特定项目或者是技术，通常采用下面几种方法：</P>
<P>　　(1)测试部门内自由交流方式的培训。这种培训的交流比较随意，可以在周五的例会上进行交流，也可以大家一起坐在茶馆里进行交流。方法可以采用“头脑风暴法”，让每个组员讨论一个特定的领域，这种交流方法特别对同时要做很多不同项目的小组比较有益处。当每个人做不同的项目，这会有助于每个人了解你小组所有的工程。</P>
<P>　　(2)跨部门的互相学习。测试工作需要很多领域以及技术知识，这些知识单靠自学是远远不够的。和其它部门的同事进行交流是一个相当好的办法，大家在工作中可以在技术等各个方面互相得到提高。</P>
<P>　　(3)外部培训。外部培训尽管投入较高，但也是值得的。这些专家一般在自己的领域非常精通，可以快速提高整个测试团队的水平。也可以通过测试小组介绍一些朋友来进行培训，这种方式可以降低成本。</P>
<P>　　培训是构造学习型组织的基本条件，也是提高员工水平的重要方法。经常的定期培训，可以增强组织凝聚力，使员工更加愿意长期留在组织中发展。做为测试负责人，定期的进行培训是十分必要的。</P>
<P>　　14、时间上不允许进行全部测试，测试负责人应该如何做?</P>
<P>　　这个问题也许十分可笑，可是现实中我们的测试经理们却不得不面对这个问题。这里的全部测试不是指对软件进行遍历测试，而是指测试负责人制定的<STRONG><A href="http://www.ltesting.net/html/74/category-catid-474.html" target="_blank" >测试计划</A></STRONG>包含的全部测试内容。</P>
<P>　　通常，不管是开发产品还是做具体的项目，都会发生耽误进度的情况。一旦整体进度不能向后延迟，项目相关人员习惯上的做法就是缩减测试时间。尤其在功能还没有开发完成的情况下，这种现象更为突出。</P>
<P>　　担负着<STRONG><A href="http://www.ltesting.net/html/5/category-catid-5.html" target="_blank" >质量</A></STRONG>重任的测试经理，如何来解决这个问题呢?比较好的做法是按照下面的步骤逐步来完成和改进工作：</P>
<P>　　(1)按照测试任务的轻重缓急，尽最大努力完成测试任务。在时间不足的情况下，我们应该对测试任务按照优先级来划分，重要紧急的任务先完成。这个时候的测试任务是一种辅助性工作，其目的就是尽最大努力来提高质量。因此，面对这种情况，测试负责人要做的就是带<STRONG><A href="http://www.ltesting.net/" target="_blank" >领测</A></STRONG>试小组充分利用所有资源来保证质量。</P>
<P>　　(2)在实际工作中和开发人员共同配合，逐步改进工作。只有整个团队的软件开发能力提高了，才能从根源上解决问题。因此，测试负责人要带领团队和开发小组共同寻找适合自己的开发模式，从而使项目规划的更加合理，进而按照预定计划来开展测试工作。</P>
<P>　　总之，在任何情况下，测试负责人都不应该抱怨。只有积极的面对问题，才能更好的解决问题。</P>]]></description>
    <pubDate>Fri, 04 Jun 2010 11:04:29 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[最佳实践：测试驱动开发全功略[3]]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2010/0604/171819.html</link>
    <description><![CDATA[<P>　　最佳实践：<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target="_blank" >测试驱动开发</A></STRONG>全功略[3]&nbsp; <STRONG><A href="http://www.ltesting.net/" target=_blank>软件测试</A></STRONG></P>
<P>　　9、测试人员工作发生问题测试经理应该如何做?</P>
<P>　　测试人员工作发生问题是测试经理经常要面对的问题，作为测试部门的领导，首先要做的是指出测试人员所犯的错误，使其尽快改正错误。</P>
<P>　　唯一不能做的就是盯着下属的错误不放。总盯着下属的失误，是一个领导者的最大失误。英国行为学家波特说：当遭受许多批评时，下级往往只记住开头的一些，其余就不听了，因为他们忙于思索论据来反驳开头的批评。身为测试经理要根据测试人员的心理来进行指导，最大限度的调动每个人员的积极性来参加工作。</P>
<P>　　10、不深入到具体测试工作时，测试经理如何考核员工?</P>
<P>　　这种现象在测试规模较大的组织中很常见。测试经理应该尽可能的安排每周与每个成员在不被打扰的环境下进行谈话，这样可以尽早发现和解决很多问题。</P>
<P>　　最为一个测试经理，主要工作之一就是定期的评定组织做了些什么并且是怎样做的。同时还要为员工做一个报告——关于充分了解测试人员正在做什么和怎样做的报告，以此来给测试人员做做工作成绩考核。这份报告要了解到每个人的动态。</P>
<P>　　测试经理和每个员工重点是谈谈目前的工作，例如大家在工作中的问题或意见;是否需要帮助等。许多管理者经常抱怨没有时间在一周会见每一个员工来谈他们的工作。但是根据作者的经验，如果不能安排时间和员工进行每周的谈话，员工会来打扰测试经理的工作，因为员工很多问题还要要来找测试经理商议。</P>
<P>　　同时对待员工要用他们能接受的方式，而不是我们自己可以接受的方式。“己之不予，勿施于人”，这条黄金法则可能会对许多生活中的纯粹的社交因素有效，但是并不是总对工作有用。有效率的管理者知道应该逐渐了解每一个员工需要怎样的对待方式。</P>
<P>　　总之，只有尽可能多的和员工接触，才能更精确的进行考核。</P>
<P>　　11、测试经理如何面对加班问题?</P>
<P>　　大多数情况下，作者是不主张加班的。当员工每周工作超过40个小时的时候，他们开始在工作的时候关心自己的事。他们花钱，会给很久没有联系的人打电话，因为员工们一直都在工作。员工不能在太疲劳的状态下完成工作，这是因为他们在工作时不能关心自己，这种情况下通常效率很低。</P>
<P>　　测试管理工作的重要任务之一就是要创造一个环境，让员工在工作时间内完成工作，同时还要鼓励他们每周不要超过40小时，甚至可以基于他们在40个小时能够完成的工作量给他们酬劳。通常情况下这样做能够提升创造力，从而会逐渐提高效率。</P>
<P>　　测试工作本身的一个突出特点就是不断重复枯燥、冗长的测试，如果在疲劳状态下，很有可能精力不集中，略过一些重要的测试环节。而且有的时候测试需要编写测试驱动程序，这种情况更需要较好的状态来工作。</P>
<P>　　12、测试管理者如何面对自己的错误?</P>
<P>　　每个人都会犯错。我们可能会因为忘记开会而使客户发怒，承认自己犯错是一件尴尬的事情，尤其是管理人员认为对自己负责的项目小组承认犯错可能会失去尊严。如果我们不是经常犯错，承认错误的时候其实能够赢得尊敬。例如我们忘记一次会议，然后为此向同事或者客户道歉，其他的人会理解我们的。</P>
<P>　　不管做了什么，不要否认或故意忽略自己的失误。故意忽略不会让错误消失，这只会让错误成长为怪物。</P>]]></description>
    <pubDate>Fri, 04 Jun 2010 11:03:10 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[最佳实践：测试驱动开发全功略[2]]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2010/0604/171818.html</link>
    <description><![CDATA[<P>　　最佳实践：<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target="_blank" >测试驱动开发</A></STRONG>全功略[2]&nbsp; <STRONG><A href="http://www.ltesting.net/" target=_blank>软件测试</A></STRONG></P>
<P>　　5、“让那些新手来做测试，反正他们也不会什么”正确吗?</P>
<P>　　在实际项目开发中，我们常常看到有些单位忽视测试团队存在的意义，当要实施测试时，往往临时找几个<STRONG><A href="http://www.ltesting.net/html/78/category-catid-478.html" target="_blank" >程序员</A></STRONG>充当<STRONG><A href="http://www.ltesting.net/html/73/category-catid-273.html" target="_blank" >测试人员</A></STRONG>。也有些单位尽管认识到了组建测试团队的重要性，但在具体落实的时候往往安排一些毫无开发经验的行业新手去做测试工作，这常常导致测试效率低下，测试人员对测试工作索然无味。</P>
<P>　　根据笔者的经验，测试团队应首先聘请一名资深的测试领域专家，他应具有极为丰富的同类项目软件测试经验，对软件开发过程中常见的<STRONG><A href="http://www.ltesting.net/html/98/category-catid-98.html" target="_blank" >缺陷</A></STRONG>或错误了然于胸;此外，他还具有较好的亲和力和人格魅力。其次，项目测试团队还具有很多具备一技之长的成员，如对某些自动化<STRONG><A href="http://www.ltesting.net/html/2/category-catid-2.html" target="_blank" >测试工具</A></STRONG>运用娴熟或能轻而易举地编写<STRONG><A href="http://www.ltesting.net/html/96/category-catid-96.html" target="_blank" >自动化测试</A></STRONG>脚本等。</P>
<P>　　另外，测试团队还应聘请一些兼职成员，如验证测试实施过程中，同行评审是最常使用的一种形式，这些同行专家就属于兼职测试团队成员的范畴。至于测试团队里里的测试新手，这部分人可以安排去从事交付验证或<STRONG><A href="http://www.ltesting.net/html/93/category-catid-93.html" target="_blank" >黑盒测试</A></STRONG>之类的。</P>
<P>　　6、测试同化现象是什么?</P>
<P>　　同化现象是指随着时间的推移，开发人员会逐渐影响测试人员的思维和对缺陷的判断能力，尤其是针对同一产品，同一组开发人员和同一组测试人员共同配合了很长时间，很多本来是缺陷的问题，由于测试人员对软件“习惯成自然”的使用，会不被当成缺陷，尤其是在开发人员的解释和说服下。同化现象发生可能意味着“恶性循环”的开始：测试人员会帮着开发人员解释一个个缺陷的合理性，一轮有一轮的测试都不会发现问题。</P>
<P>　　招聘新的人员，不同的测试项目组轮换去测试不同的产品，就可以避免。同时建议产品可以发布测试版，更多的人对其进行测试，就可以发现更多的问题。</P>
<P>　　7、<STRONG><A href="http://www.ltesting.net/html/73/category-catid-273.html" target="_blank" >测试工程师</A></STRONG>如何避免定位效应?</P>
<P>　　社会心理学家曾作过一个试验：在召集会议时先让人们自由选择位子，之后到室外休息片刻再进入室内入座，如此五至六次，发现大多数人都选择他们第一次坐过的位子。这种现象称为定位效应，说明人们习惯上凡是自己认定的，人们大都不想轻易改变它。</P>
<P>　　定位效应在开发人员和测试人员身上都有体现。例如开发工程师针对某一自己写的功能，经常进行代码移植，这种复制的“功能”，由于上一次经过调试，在新的地方往往不会认真调试，这些代码往往会带来共享变量冲突等许多种类型的缺陷。</P>
<P>　　定位效应体现在测试人员身上就是测试过的功能不再进行认真测试：在<STRONG><A href="http://www.ltesting.net/html/72/category-catid-472.html" target="_blank" >回归测试</A></STRONG>时，之前由于进行过认真的测试，往往会认为某些功能是可靠，只要验证一些以前发现的缺陷是否修改完成就可以了。这种现象在反复多次回归时表现的更加突出，因为回归测试中很多功能都会进行多次反复测试。众所周知，开发人员在修改缺陷时往往会引入新的缺陷，测试人员的疏于防范就会把这些缺陷带到用户这里。</P>
<P>　　解决这种问题的方案一般有两个：</P>
<P>　　(1)完整的执行<STRONG><A href="http://www.ltesting.net/html/94/category-catid-94.html" target="_blank" >测试用例</A></STRONG>：这种方法投入较大，但是在开发产品时最好在最后一次回归测试时测试的执行一次全部的测试用例。</P>
<P>　　(2)交叉测试：测试人员交叉测试，就可以很大程度的避免定位效应。测试工程师在回归测试时互相交换任务，反复测试某一功能的机会大大减少，从而也就不会“主观的”人员某些功能没有缺陷。</P>
<P>　　通常上面的两个方法都是结合使用的，既要进行交叉测试，又要全面执行测试用例，测试覆盖面要尽可能的广泛。</P>
<P>　　8、测试人员忽然辞职怎么办?</P>
<P>　　目前IT行业人员流动较大已经成为一种不争的事实，员工的辞职大多数都会给组织带来一定的影响，而这种影响基本是不可能避免的。在测试领域，员工忽然辞职也会带来很大的负面影响，尤其测试队伍规模较小时。面对这种情况，我们所能做的，就是如何最大限度的降低这种影响。</P>
<P>　　根据作者的经验，主要有两种方法：第一种是在测试人员内部建立一个良好的学习环境，大家互相学习，这样某些特有技术不会被某一个人所掌握，而互相学习和提高自身，也是大多数成员愿意做的;第二种就是在组织中进行<STRONG><A href="http://www.ltesting.net/ask/" target="_blank" >知识</A></STRONG>管理，把技术作为知识沉淀下来，这样新的员工在接手工作时容易上手，通过学习快速适应环境。</P>
<P>　　此外，日常还要注意工作规范化，例如形成尽可能多的文档，都可以降低员工离职带来的损失。</P>]]></description>
    <pubDate>Fri, 04 Jun 2010 11:01:43 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[最佳实践：测试驱动开发全功略[1]]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2010/0604/171817.html</link>
    <description><![CDATA[<P>　　最佳实践：<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target="_blank" >测试驱动开发</A></STRONG>全功略[1]&nbsp;&nbsp; <STRONG><A href="http://www.ltesting.net/" target=_blank>软件测试</A></STRONG></P>
<P>　　1、测试负责人要进行严格的测试进度跟踪吗?</P>
<P>　　很多时候，由于人力资源的不足，测试项目负责人都是在执行测试，这样就使整个项目缺乏控制，一些问题(例如：有些成员的缺陷<STRONG><A href="http://www.ltesting.net/html/5/category-catid-5.html" target="_blank" >质量</A></STRONG>不够合格;开发人员修改不及时，系统某些功能发生严重问题导致部分功能无法测试。)得不到解决，耽误了进度。所以测试负责任必须全程监控项目，尽可能多的掌握信息。通常，测试负责人需要完成下面这些内容的管理工作：</P>
<P>　　测试<STRONG><A href="http://www.ltesting.net/html/94/category-catid-94.html" target="_blank" >用例</A></STRONG>执行情况;</P>
<P>　　每个测试员提交的缺陷情况;</P>
<P>　　测试中是否发生突发问题。</P>
<P>　　2、 测试也有<STRONG><A href="http://www.ltesting.net/html/63/category-catid-163.html" target="_blank" >版本控制</A></STRONG>吗?</P>
<P>　　这里的版本主要是指测试对象的版本控制，也就是指对开发部提交的产品进行版本控制。在开发小组版本管理不规范的情况下，测试小组进行版本控制十分重要，要保证测试对象是可以控制的。建议开发和测试双方进行明确的约定，可以各自指定专门的测试版本负责人，制定提交原则，对提交情况进行详细的记录，这样基本避免了版本失控导致的测试失误或无效。</P>
<P>　　3、如何处理<STRONG><A href="http://www.ltesting.net/html/73/category-catid-273.html" target="_blank" >测试人员</A></STRONG>的流动问题?</P>
<P>　　人员流动不仅仅是测试部门，这是IT行业的普遍现象。从管理者角度，主管需要多多和团队内成员进行沟通，建立一个融洽的团队环境，及时掌握情况，可以早些进行相应的调整。但是只有企业建立好的用人制度，给员工提高广阔的发展空间和好的培训学习机会，才能从根本上解决这一问题。</P>
<P>　　加强<STRONG><A href="http://www.ltesting.net/html/66/category-catid-166.html" target="_blank" >项目管理</A></STRONG>，强化文档管理并保证文档的有效性，可以大大减少由于人员流失带来的损失。同时，测试部门要建立培训机制，使新到员工接受直接或者间接的培训，快速适应工作。</P>
<P>　　4、为什么开发人员经常抱怨<STRONG><A href="http://www.ltesting.net/html/73/category-catid-273.html" target="_blank" >测试工程师</A></STRONG>提交的缺陷质量太差?</P>
<P>　　我们经常听开发人员说：“这不是缺陷!”，“这个缺陷没有，因为我的系统上运行正常!”。测试工程师本身就是做质量工作的，提交的成果本身就应该质量高些，为什么还会有这种现象?</P>
<P>　　提交的缺陷引起争议是一种正常的现象，例如测试人员描述不清楚就会引起争议。减少甚至避免这种现象的方法是交叉测试，交叉测试是提高测试质量的一个有效手段，当然交叉测试会增加一定的测试成本投入。在测试任务完成后，测试工程师之间互相验证彼此提交的缺陷，就会避免了缺陷描述不清、因运行环境而产生的缺陷等一系列问题，从而大大降低了<STRONG><A href="http://www.ltesting.net/html/72/category-catid-472.html" target="_blank" >回归测试</A></STRONG>以及交流的成本，因而这种投入也是值得的，实际开发人员在<STRONG><A href="http://www.ltesting.net/html/90/category-catid-90.html" target="_blank" >单元测试</A></STRONG>阶段也会进行交叉测试，来提高开发质量。</P>
<P>　　另外，测试人员一定要按照规范描述测试中发现的缺陷，一个缺陷至少描述清楚概要描述、详细描述、重现步骤三方面的内容，<STRONG><A href="http://www.ltesting.net/html/98/category-catid-98.html" target="_blank" >缺陷管理</A></STRONG>参考第八章的内容。</P>]]></description>
    <pubDate>Fri, 04 Jun 2010 10:58:50 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[我看测试驱动开发[2]]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2010/0528/171692.html</link>
    <description><![CDATA[<P>　　我看<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target="_blank" >测试驱动开发</A></STRONG>[2]&nbsp;&nbsp; <STRONG><A href="http://www.ltesting.net/" target=_blank>软件测试</A></STRONG></P>
<P>　　在详细设计的过程当中，<STRONG><A href="http://www.ltesting.net/html/62/category-catid-162.html" target="_blank" >需求</A></STRONG>总是可以分解到模块，并且确定了模块之间的接口。之后才是正式的开发。于是对各个模块来说，“这个组件要实现什么功能?”“它将如何被使用?”这样的需求总是完整的被体现在了各个模块的接口上，也就是说，保证对接口的使用能够正确无误的进行，就保证了这个模块的最终<STRONG><A href="http://www.ltesting.net/html/5/category-catid-5.html" target="_blank" >质量</A></STRONG>。那么，我们先走一步，针对模块的接口写出测试代码，这样在以后开发的时候，就可以确定我们的模块是否达到了我们的需求。也就是说，我们把<STRONG><A href="http://www.ltesting.net/html/90/category-catid-90.html" target="_blank" >单元测试</A></STRONG>提前了，提前到单元代码的开发之前。</P>
<P>　　先写测试代码的带来了很多好处。首先，在很多时候，需求是不清晰或者说不完整的，那么写测试代码的过程就是使需求清晰化的过程，这使以后的开发免除了很多麻烦和争执。其次，这使得我们得以在整个开发过程中保持一套详尽的<STRONG><A href="http://www.ltesting.net/html/92/category-catid-92.html" target="_blank" >单元测试代码</A></STRONG>，而这在代码重构里是必不可少的。最后，先写测试代码会影响<STRONG><A href="http://www.ltesting.net/html/78/category-catid-478.html" target="_blank" >程序员</A></STRONG>的心理，使他们重视用户的需求和体验，而不是仅仅打算实现模块的功能和避免被发现错误。</P>
<P>　　然后，我们在整个开发过程中将由这些测试来决定代码如何编写，因为这些测试代码代表的是接口的标准，而接口正是需求的化身。对于这个开发模式，peter coad 给出了以下的描述：</P>
<P>　　a.. 编写和保持一套详尽的单元测试。</P>
<P>　　a.. 要先建立相关的单元测试和验收(a<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/clearcase/" target="_blank" >clearcase</A></STRONG>/" target="_blank" >cc</A></STRONG>eptance)测试，然后根据测试编写代码。</P>
<P>　　a.. 由测试来决定如何编写代码。</P>
<P>　　下面我们来总结我们上面提到的要点：</P>
<P>　　1)针对接口开发，使接口代表需求</P>
<P>　　2)用测试评价接口是否符合需求，并且在开发过程中保持足够详尽的测试</P>
<P>　　3)在代码的修改、重构等变化时，用测试保证代码质量</P>
<P>　　在更高层的视野看来，测试驱动编程事实上是把测试对软件整体质量的保证引入到软件单元的开发中来，使得整个开发过程中的质量得到更进一步的监护 。</P>]]></description>
    <pubDate>Fri, 28 May 2010 11:48:08 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[我看测试驱动开发[1]]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2010/0528/171691.html</link>
    <description><![CDATA[<P>　　我看<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target="_blank" >测试驱动开发</A></STRONG>[1]&nbsp;&nbsp;<STRONG><A href="http://www.ltesting.net/" target=_blank>软件测试</A></STRONG></P>
<P>　　软件工程界一直存在这样的看法，“<STRONG><A href="http://www.ltesting.net/html/78/category-catid-478.html" target="_blank" >程序员</A></STRONG>不应该测试他们自己的代码”，原因是程序员在代码开发中形成的思维定势将不可避免的导致测试的盲区，同时，就个人感情而言，个人很难否决自己努力完成的工作成果。</P>
<P>　　这样的观念使得专业的测试团队的出现成为可能，于是，在现代软件开发中，专业测试团队的介入使得软件的质量得到了相当程度上的保障。测试成为对<STRONG><A href="http://www.ltesting.net/html/5/category-catid-5.html" target="_blank" >软件质量保证</A></STRONG>的最后哨卡，开始随着人们对软件质量和<STRONG><A href="http://www.ltesting.net/html/95/category-catid-95.html" target="_blank" >可靠性</A></STRONG>的关注而取得了日渐重要的位置。</P>
<P>　　但是，软件工程的研究同样告诉我们另外一个观点：在软件开发周期的越早期发现错误，那个错误将带来的损失将越小。 下面这些图表摘自&lt;&lt;实用<STRONG><A href="http://www.ltesting.net/html/64/category-catid-164.html" target="_blank" >软件度量</A></STRONG>&gt;&gt;(capers jones，mcgraw-hill 1991)，它列出了准备测试，执行测试，和修改<STRONG><A href="http://www.ltesting.net/html/98/category-catid-98.html" target="_blank" >缺陷</A></STRONG>所花费的时间(以一个功能点为基准)，这些数据显示<STRONG><A href="http://www.ltesting.net/html/90/category-catid-90.html" target="_blank" >单元测试</A></STRONG>的成本效率大约是<STRONG><A href="http://www.ltesting.net/html/69/category-catid-469.html" target="_blank" >集成测试</A></STRONG>的两倍 <STRONG><A href="http://www.ltesting.net/html/70/category-catid-470.html" target="_blank" >系统测试</A></STRONG>的三倍。</P>
<P>　　尽管在传统测试理论中，测试几乎已经伴随了整个开发周期：单元测试、集成测试、系统测试、<STRONG><A href="http://www.ltesting.net/html/71/category-catid-471.html" target="_blank" >验收测试</A></STRONG>。但是，更多的时候我们遇到的情况是：至少在项目开始集成之前，测试是基本不存在的。程序员不愿意在模块完成之后再花时间来写测试代码(事实上，很多程序员连文档都欠奉)，而<STRONG><A href="http://www.ltesting.net/html/73/category-catid-273.html" target="_blank" >测试人员</A></STRONG>则不会写测试代码(能写代码的话通常都已经被抓去写代码了)。事实上，即使测试人员愿意写测试代码来完成对代码的单元测试，这样的分工也是不划算的，因为这引入了额外的人与人之间的交流成本。于是我们的测试通常是在集成阶段开始进入的，于是我们不得不在这个时候在来面对可能的模块质量问题、模块设计问题以及其他许多早在那之前就应该已经解决的问题。</P>
<P>　　这个情况在传统工业里是不可想象的。你无法想象波音飞机在开始总装之前没有对它的零件进行过像样的测试，但是你却常常看到我们对一大堆没有进行过单元测试的代码进行集成。这个模块有内部逻辑错误吗?它有内存泄漏吗?它能够应付那些极端的边界条件吗?它达到了<STRONG><A href="http://www.ltesting.net/html/62/category-catid-162.html" target="_blank" >需求</A></STRONG>的要求了吗?不知道，先拼起来再说，到时候测试发现不了问题就会放我们过关的。然后你盯着每周的<STRONG><A href="http://www.ltesting.net/html/98/category-catid-98.html" target="_blank" >bug</A></STRONG> 列表看，看到bug 数渐渐下降，渐渐的接近出厂要求，然后你擦擦头上的冷汗：“感谢上帝，看来这次又过关了”。但是，难免会有一天，你的邮箱里塞满了来自用户的抱怨，告诉你你的程序又在某个你想不到的地方出了问题。</P>
<P>　　问题在哪?问题在于我们要求程序员在完成开发之后再完成一套东西的开发，而这些东西并不是要开发的软件的一部分，并且将在项目结束时被抛弃。对程序员而言，这等于叫他额外的多完成一些原本不需要的任务，这是很难被接受的，即使他能理解这样做的重要性。这是人性的弱点。那么，我们如何让测试更进一步的深入开发过程，尽可能保证软件每个组件的质量呢?这就要求我们放手让测试驱动开发的过程，让对需求的承诺直接的传递到每个组件的开发当中。</P>]]></description>
    <pubDate>Fri, 28 May 2010 11:43:30 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[测试开发过程总结]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2010/0429/171091.html</link>
    <description><![CDATA[<P>　　测试<STRONG><A href="http://www.ltesting.net/html/4/category-catid-4.html" target="_blank" >开发</A></STRONG>过程总结&nbsp; <STRONG><A href="http://www.ltesting.net/" target=_blank>软件测试</A></STRONG></P>
<P>　　最近公司的产品一直忙于测试，看着每天的<STRONG><A href="http://www.ltesting.net/html/98/category-catid-98.html" target="_blank" >Bug</A></STRONG>不断的增加和修正，真是痛并快乐着，痛苦是因为Bug不断的出现，快乐是看着Bug一个一个的被消灭，把这些天的测试开发过程总结一下。</P>
<P>　　1、测试要尽早</P>
<P>　　公司的产品已经修订一段时间了，但是由于任务繁忙和人手不足，因此测试一直拖后，因此当进行集中测试的时候Bug集中爆发，因此感觉更加的繁忙，另外由于很多功能和修订，都已经修改了很长的时间，因此<STRONG><A href="http://www.ltesting.net/html/78/category-catid-478.html" target="_blank" >程序员</A></STRONG>再次进入修改的时候，往往需要重新分析和理解，造成Bug的修复周期延长了很多。</P>
<P>　　建议当完成功能修订后，要尽快进入测试状态，以缩短Bug的存在时间，降低程序员修订成本。</P>
<P>　　2、使用好的<STRONG><A href="http://www.ltesting.net/html/98/category-catid-98.html" target="_blank" >缺陷管理</A></STRONG>工具</P>
<P>　　之前公司只是使用一个BBS作为缺陷的跟踪和管理工具，但是，效果很不理想，虽然缺陷管理的工具很多，但是都有自己的长处和短处，后来使用了<STRONG><A href="http://www.ltesting.net/html/11/category-catid-111.html" target="_blank" >TD</A></STRONG>，效果的确好的多。</P>
<P>　　3、缺陷描述要准确</P>
<P>　　很多<STRONG><A href="http://www.ltesting.net/html/73/category-catid-273.html" target="_blank" >测试人员</A></STRONG>反馈的缺陷，程序员读起来十分的费劲，甚至比理解缺陷本身还要难懂，因此，如果发现缺陷后，在登记的时候，一定要尽量描述准确和清晰，以免造成错误的理解，反而更加干扰缺陷的修订。如果缺陷的确很难描述，可以将缺陷的发生过程录制下来，或者干脆手工给程序员演示一遍，效果就更好了。</P>
<P>　　4、缺陷描述不完整</P>
<P>　　很多缺陷都是有前世和今生的，因此把缺陷产生的出发条件描述的完整，对解决缺陷起着很重要的作用。</P>
<P>　　5、缺陷要分等级</P>
<P>　　缺陷都是要优先级别的，严重的当然要尽快解决，低级别的放一放。</P>
<P>　　6、开发和测试最好不同步</P>
<P>　　公司是早上8：30上班，一般是9：00左右才能给测试部一个新的测试版本，而如果Build出现意外，则新的版本发布就会推迟，因此开发和测试一定要有个时间差，开发部最好在早上第1时间给测试部一个最新的测试版本。一种是开发部早点来，一种是晚点走，最后我们的约定是下午4:30分开发部Build版本给测试部明天使用。</P>
<P>　　7、优先验证Fixed状态的缺陷</P>
<P>　　测试部每天最优先的任务就是验证新版本中Fixed状态的缺陷是否正确，这个很主要，因为开发部刚刚修正，如果没有验证通过，程序员可以立刻进行修订，如果过了很长时间才通知没有通过，那么可能程序员还得重新理解和分析代码。</P>
<P>　　8、一个缺陷报告包含多个缺陷</P>
<P>　　有些时候测试人员在一个测试报告中，包含N(N&gt;=1)个缺陷，结果程序员修订了其中一个，另一个需要拒绝掉，结果缺陷的状态就失去效果了，因此一个缺陷记录只能包含一个缺陷，如果存在多个就是测试人员的责任了。</P>
<P>　　9、交叉测试的重要性</P>
<P>　　我们最初安排测试的时候，是某个测试人员只测试其中一部分，另外的测试人员测试另外一部分，过了几天后发现，每个测试人员的Bug检测数量都下降了，原来，测试人员对自己部分已经发现不出来缺陷了，后来采用了交叉测试的方式，就是测试人员交换测试工作，结果不同的人从不同的角度进行测试，结果一些缺陷又发现了，因此交叉测试很重要。</P>
<P>　　10、测试经验的总结</P>
<P>　　测试的过程很枯燥，而<STRONG><A href="http://www.ltesting.net/html/97/category-catid-97.html" target="_blank" >测试过程</A></STRONG>中发现的测试经验是十分重要的，不断的调整测试的策略、流程，多总结和借鉴别人的测试经验，会更好的提高测试<STRONG><A href="http://www.ltesting.net/html/5/category-catid-5.html" target="_blank" >质量</A></STRONG>。</P>]]></description>
    <pubDate>Thu, 29 Apr 2010 10:59:09 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[业务驱动测试方法[2]]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2010/0423/170888.html</link>
    <description><![CDATA[<P>　　业务驱动<STRONG><A href="http://www.ltesting.net/html/news.html" target="_blank" >测试方法</A></STRONG>[2]&nbsp;&nbsp;&nbsp; <STRONG><A href="http://www.ltesting.net/" target=_blank>软件测试</A></STRONG>　</P>
<P>&nbsp;&nbsp; 　(2)业务层测试</P>
<CENTER><IMG height=252 alt="" src="http://www.ltesting.net/uploads/2010/04/110593_201004231035231gYJW.jpg" width=477 border=1></CENTER>
<P>　　图3：业务层测试</P>
<P>　　(3)接入层测试</P>
<CENTER><IMG height=245 alt="" src="http://www.ltesting.net/uploads/2010/04/110593_201004231035232Awz6.jpg" width=482 border=1></CENTER>
<P>　　图4：接入层测试</P>
<P>　　(4)<STRONG><A href="http://www.ltesting.net/html/95/category-catid-95.html" target="_blank" >性能测试</A></STRONG></P>
<CENTER><IMG height=324 alt="" src="http://www.ltesting.net/uploads/2010/04/110593_201004231035233rsD0.jpg" width=555 border=1></CENTER>
<P>　　图5：性能测试</P>]]></description>
    <pubDate>Fri, 23 Apr 2010 10:34:13 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[业务驱动测试方法[1]]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2010/0423/170887.html</link>
    <description><![CDATA[<P>　　业务驱动<STRONG><A href="http://www.ltesting.net/html/news.html" target="_blank" >测试方法</A></STRONG>[1]&nbsp;&nbsp;&nbsp; <STRONG><A href="http://www.ltesting.net/" target=_blank>软件测试</A></STRONG><IMG height=279 alt="" src="http://www.ltesting.net/uploads/2010/04/110593_201004231033021H6f6.jpg" width=554 border=1></P>
<P>　　图1：<STRONG><A href="http://www.ltesting.net/html/97/category-catid-97.html" target="_blank" >测试流程</A></STRONG></P>
<P>　　1、测试用例</P>
<P>　　测试用例是<STRONG><A href="http://www.ltesting.net/html/73/category-catid-273.html" target="_blank" >测试人员</A></STRONG>根据业务与技术规范以及<STRONG><A href="http://www.ltesting.net/html/62/category-catid-162.html" target="_blank" >需求</A></STRONG>规格书编写，用以验证厂家的系统是否满足规范中所定义的体系框架、功能要求、<STRONG><A href="http://www.ltesting.net/html/95/category-catid-95.html" target="_blank" >性能</A></STRONG>要求、接口要求以及数据规范性的要求。<STRONG><A href="http://www.ltesting.net/html/94/category-catid-94.html" target="_blank" >测试用例的设计方法</A></STRONG>包括等价类划分法、边界值分析法、场景法、错误推测法、因果图法、判定表驱动法、正交试验设计法、功能图法等。具体到特定的测试行为中，最后采用什么样的测试方法，还要针对系统的特点加以选择</P>
<P>　　2、测试驱动</P>
<P>　　测试驱动<STRONG><A href="http://www.ltesting.net/html/4/category-catid-4.html" target="_blank" >开发</A></STRONG>(Test Driven Development，英文缩写<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target="_blank" >TDD</A></STRONG>)是<STRONG><A href="http://www.ltesting.net/html/68/category-catid-168.html" target="_blank" >极限编程</A></STRONG>的一个重要组成部分，它的基本思想就是在开发功能代码之前，先编写测试代码。也就是说在明确要开发某个功能后，首先思考如何对这个功能进行测试，并完成测试代码的编写，然后编写相关的代码满足这些测试用例。然后循环进行添加其他功能，直到完成全部功能的开发。代码整洁可用(clean code that works) 是<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target="_blank" >测试驱动开发</A></STRONG>所追求的目标。</P>
<P>　　3、业务测试</P>
<P>　　(1)数据层测试</P>
<CENTER><IMG height=252 alt="" src="http://www.ltesting.net/uploads/2010/04/110593_201004231033022WdyB.jpg" width=439 border=1></CENTER>
<P>　　图2：数据层测试</P>]]></description>
    <pubDate>Fri, 23 Apr 2010 10:30:44 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[测试驱动需求分析--需求文档评审实例]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2010/0423/170885.html</link>
    <description><![CDATA[<P>　　测试驱动<STRONG><A href="http://www.ltesting.net/html/62/category-catid-162.html" target="_blank" >需求分析</A></STRONG>--需求文档评审实例&nbsp;&nbsp;<STRONG><A href="http://www.ltesting.net/" target=_blank>软件测试</A></STRONG></P>
<P>　　软件的<STRONG><A href="http://www.ltesting.net/html/4/category-catid-4.html" target="_blank" >开发</A></STRONG>文档<STRONG><A href="http://www.ltesting.net/html/5/category-catid-5.html" target="_blank" >质量</A></STRONG>一般只能通过评审来进行保证，如何有效发现文档中的问题，是一个令许多人头疼的问题。先看一段关于日志文件的需求描述如下：</P>
<P>　　“软件要将所有的访问者都要记录下来，对每次访问要记录访问开始时间、访问结束时间、访问者的IP地址这三个信息作为一条日志记录。要求以天为单位每天生成一个访问记录日志文件。”</P>
<P>　　在这段需求描述中，要发现问题的话，首先要想象自己是日志模块的开发者，根据这段需求描述，是否能够开发出日志模块来呢?日志文件要记录的信息内容上面都提到了：访问开始时间、结束时间、IP地址。初一看好像可以根据这个需求描述进行开发。</P>
<P>　　如果用用元素分析法来分析一下这段需求的话，就会发现并不是想象的那样乐观。先找出需求中涉及的三个显性元素：</P>
<P>　　访问者</P>
<P>　　访问记录</P>
<P>　　日志文件</P>
<P>　　首先对访问者和访问记录这两个元素进行分析，先看访问者有那些属性，除了描述中提及的访问时间和IP地址外，访问者还有那些属性呢?显然访问者的访问内容是最重要的属性，仅记录访问时间和访问者的IP地址是否足够呢，从日志能分析出什么有用的信息呢?从时间信息上最多只能看出那段时间访问的人数较多，得到用户的时间分布规律，很难对用户的行为有深入的分析，只有知道访问者在访问那些内容才能得到更有价值的信息。象Web<STRONG><A href="http://www.ltesting.net/html/78/category-catid-378.html" target="_blank" >服务器</A></STRONG>软件要记录下访问的URL信息以便知道访问者访问的内容，所以访问记录中遗漏了关于访问内容的信息。</P>
<P>　　从访问记录这个元素来分析，访问记录主要属性是记录格式，每条记录是以什么格式来记录呢?没有描述出来。有经验的开发者就知道日志记录格式是一个很重要的问题，因为日志记录的分析一般是需要使用专门的分析软件或者写专门的分析程序来分析的。如何设计合理的记录格式来利用已有的日志分析软件来进行分析是首要考虑的问题。</P>
<P>　　再对日志文件这个元素进行分析，先看看日志文件有那些属性，首先日志文件具有文件名，还有存放位置，文件格式，文件内容、文件创建时间、文件大小、文件权限等属性。</P>
<P>　　需求描述中提到了每天要生成一个日志文件，从文件创建时间属性来看，每天有24小时，到底从什么时候开始创建文件，从0点开始还是从几点开始，没有描述出来。</P>
<P>　　从文件名属性来看，如何命名日志文件，需求中也没有提及。从存放位置属性来看，日志文件存放在什么地方也没有说明。是不是所有的日志文件都存放在应用程序同一子目录下?</P>
<P>　　从文件格式属性来看，首先日志文件是以文本方式存储还是以二进制格式存储?再者，文件的内容是以何种格式记录，每条访问记录间如何分隔，是以回车换行作为分隔还是以其他字符作为分隔?都没有描述。</P>
<P>　　从文件内容属性来分析，除了存放上述描述的内容外，是否还可以保存其他内容，如果不能保存其他内容的话，需求描述中应该加上一句“日志文件中只能存储访问记录信息，不得储存其他记录信息”。</P>
<P>　　从文件大小属性来分析，日志文件的大小有没有限制?如果某天处于访问高峰期，访问特别多，是否需要将日志文件分拆成多个是一个需要考虑的问题。</P>
<P>　　从文件权限属性来分析，日志文件是否机器上的所有用户都可以访问还是只有特定的用户可以访问?文件是否需要设置权限是一个需要考虑的问题。</P>
<P>　　所以通过元素分析法对上述需求描述进行分析后，你会发现需求描述中有很多的问题没有描述清楚。也许有人会有疑问，如果将所有上面说到的问题都描述出来的话会不会工作量太大了?仅从需求分析的角度来讲，需求规格描述得较细的话确实会增大很多工作量，但从整个开发过程来看，需求描述完整的话，后续阶段的开发产生歧义和遗漏的可能性就很小，实际上后续阶段节约的时间会大大超过需求所多花的时间。</P>
<P>　　实际上不仅检视需求时需要使用<STRONG><A href="http://www.ltesting.net/html/94/category-catid-94.html" target="_blank" >测试用例设计方法</A></STRONG>，还应该采取测试用例设计来驱动需求分析，即在需求设计的过程中就设计测试用例，通过测试用例设计来驱动需求分析，完善需求分析的内容。</P>]]></description>
    <pubDate>Fri, 23 Apr 2010 10:26:38 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[3月份将进行TD用户测试和试商用]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2010/0413/170615.html</link>
    <description><![CDATA[<P>　　3月份将进行<STRONG><A href="http://www.ltesting.net/html/11/category-catid-111.html" target="_blank" >TD</A></STRONG>用户测试和试商用&nbsp; <STRONG><A href="http://www.ltesting.net/" target=_blank>软件测试</A></STRONG></P>
<P>　　3月3日消息，近日有专家向腾讯科技表示，为了在奥运之前优化TD-SCDMA<STRONG><A href="http://www.ltesting.net/html/77/category-catid-377.html" target="_blank" >网络</A></STRONG>及终端<STRONG><A href="http://www.ltesting.net/html/95/category-catid-95.html" target="_blank" >性能</A></STRONG>，目前备受关注的国产3G标准TD-SCDMA在8城市完成技术测试之后，3月份即将进行用户测试和试商用。据推测，参加用户测试的用户主要分为两类，即通信业专家学者和动感地带用户。</P>
<P>　　分析人士指出，上述两类用户分别代表了数据业务使用最多的高端和低端用户，TD终端的实测所包括用户类型可以说是相当广泛，运营商也是在通过友好测试来收集用户反馈，总结市场<STRONG><A href="http://www.ltesting.net/html/62/category-catid-162.html" target="_blank" >需求</A></STRONG>。</P>
<P>　　据了解，本轮友好测试将在3月份启动，4月进入试商用阶段。在北京奥运会期间，TD-SCDMA网络及终端可以支持用户进行<STRONG><A href="http://www.ltesting.net/ceshi/video" target="_blank" >视频</A></STRONG>通话、手机电视等数据业务。</P>
<P>　　据了解，TD扩大规模试验网建设共涉及10个城市，其中北京由中兴承建，上海和广州则由大唐移动承建。在建设过程中，北京和上海的进度较慢，知情人士透露，主要原因是这些地区的居民环保意识较强，造成基站进入小区和市区困难重重，从而导致工程进度延迟。</P>]]></description>
    <pubDate>Tue, 13 Apr 2010 12:34:14 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[对测试驱动开发的感悟[2]]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2010/0119/168699.html</link>
    <description><![CDATA[<P>　　对测试驱动<STRONG><A href="http://www.ltesting.net/html/4/category-catid-4.html" target="_blank" >开发</A></STRONG>的感悟[2]&nbsp;&nbsp; <STRONG><A href="http://www.ltesting.net/html/2/category-catid-2.html" target=_blank>软件测试工具</A></STRONG></P>
<P>　　成熟</P>
<P>　　经过了一段时间的迷茫和设计的不断返工，计划的不断延误。终于开始认清了真相，也真的理解了一句话，"<STRONG><A href="http://www.ltesting.net/html/5/category-catid-5.html" target="_blank" >质量</A></STRONG>是设计出来!"，同时明白了"抽象"的必要性，并且还是会使用MOCK了!</P>
<P>　　哎~，这些收获付出了很多的代价呀!项目的合伙人因为计划不断厌恶，想杀我心都有，每次去用户那里，用户总语气很怪强调"专家"这两个字(我朋友为了接项目，忽悠客户说我是很牛的专家...)，我顶着这些压力，还在不停的重构，不停的写着测试代码。</P>
<P>　　不过，<STRONG><A href="http://www.ltesting.net/html/90/category-catid-90.html" target="_blank" >单元测试</A></STRONG>的过程并没有很大的改善，主要还是一个复杂的方法里面的业务规则很多，而且代码也多，方法内部依赖的环境因素和依赖对象也很多，当出现这种情况的时候，去写它的测试代码简直是一个十分痛苦的事情，而且这种应付不了以后的变化。这种代码代码本来就多，当需要变化的时候，看代码就需要N久时间，更别说还有心情在去理会测试代码了!我对于这种问题并没有太多的解决办法，只是用时间去填补。</P>
<P>　　其实经过了这些，我知道自己欠缺什么?!那就是设计，由于设计的不够抽象，对于复杂事物分解的不够简单...，接着跑出去书城，拿着刚发的工资买了N多的关于设计的书籍。把它们抱回家，当看着这些书的时候，看着正在进行的项目，和那一大堆比代码还复杂的测试代码，觉得值了!</P>
<P>　　飞跃</P>
<P>　　"单一职责"</P>
<P>　　"依赖倒置"</P>
<P>　　"开放封闭"</P>
<P>　　"Liskov替换原则"</P>
<P>　　"迪米特法则"</P>
<P>　　这些设计的基本原则，大家是否是已经看过了太多次了，但是这些你真的每个都理解了吗?23种设计模式，每种模式都会了吗!会使用吗!你做设计的时候，是否会去思考我应该用何种模式呢?!......</P>
<P>　　这是我花了N久时间才慢慢理解和学会的东西。时间大概过了半年多，我的小项目已经开始运行，看着它正常的运行和VS2005上测试项目中的一排"测试通过"的标志，无限的喜悦。我学会了设计，理解了<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target="_blank" >测试驱动开发</A></STRONG>，并且写测试代码不在烦恼，而是如此的简单，"设计完后就马上去构思测试代码，如果觉得测试代码复杂，又回来修改设计，直到交互都简单为止"，这成为我现在的一种习惯。学会这些的同时我又拿到了项目Money，真是爽呀!</P>
<P>　　经历过这些，我的领会是：在做单元测试之前，你必须要学会设计。设计原则和设计模式是你需要要去掌握和理解的，要让自己在做设计的时候，不会去想"我是否应该用哪种模式"，而已灵活运用，根据具体的情况去做，因为你要做到"无剑胜有胜"!</P>
<P>　　只有简单的东西才容易写，容易测试。代码变的简单，单元测试同样会变的简单。所以其中最关键的就是你如何将复杂的东西简化。虽然谁都知道这个道理，但是要真正做到还是很不容易的。需要理解，需要实践，需要时间去积累...</P>
<P>　　这是我做单元测试，并学会测试驱动开发的一个过程，现在虽然自己还是一只"小鸟"，但是我可以让代码看上去简单，有了一大堆测试代码的保证，降低了变更的风险。</P>
<P>　　工作还在继续，还向着新的目标前进......</P>]]></description>
    <pubDate>Tue, 19 Jan 2010 10:42:53 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[对测试驱动开发的感悟[1]]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2010/0119/168698.html</link>
    <description><![CDATA[<P>　　对测试驱动开发的感悟[1]&nbsp;&nbsp; <STRONG><A href="http://www.ltesting.net/html/2/category-catid-2.html" target=_blank>软件测试工具</A></STRONG></P>
<P>　　最近听到了很多关于软件<STRONG><A href="http://www.ltesting.net/html/5/category-catid-5.html" target="_blank" >质量</A></STRONG>的话题，自己前段时间也参加个<STRONG><A href="http://www.ltesting.net/html/66/category-catid-166.html" target="_blank" >PMP</A></STRONG>(<STRONG><A href="http://www.ltesting.net/html/66/category-catid-166.html" target="_blank" >项目管理</A></STRONG>)的培训，所以一时对于质量控制特别感兴趣，在这里想和大家共同讨论下!</P>
<P>　　软件质量，是所有人都很关心的东西。我们在开发过程中为了保证质量，从中引进了软件测试。它在整个的过程中起到的作用不言而预，但是它也存在一些问题:</P>
<P>　　1、在软件测试中要保证软件的高质量就必须增加项目的成本，从而需要增加<STRONG><A href="http://www.ltesting.net/html/73/category-catid-273.html" target="_blank" >测试人员</A></STRONG>，延长项目时间，购买或学习测试工具的成本。</P>
<P>　　2、因为这种测试是依赖与开发完后才提交给测试人员的，所以如果测试中出现BUG，就会出现BUG打回，再次提交测试...，这中间还需要测试人员和开发人员的沟通，这也是一个成本的增加</P>
<P>　　3、这种方式会使得开发人员对测试人员产生依赖，从而降低代码的质量，减少自己的测试.....</P>
<P>　　我们为什么不能把测试前移呢!让开发人员自己对软件的业务就做个完整的测试，然后把代码提交给测试人员，这样就可以减少BUG的数量，同时可以让测试人员不只关注与功能性的问题，可以关注更深层次的问题(<STRONG><A href="http://www.ltesting.net/html/95/category-catid-95.html" target="_blank" >性能</A></STRONG>，用户体验...)，这种方式就是做<STRONG><A href="http://www.ltesting.net/html/90/category-catid-90.html" target="_blank" >单元测试</A></STRONG>。其实这个东西很早就有了，每个人都知道它，只是如何做的问题，我相信其实很多公司都做到，有些做的很好，但也有些是失败的!我自己经历过失败，体会过它的麻烦和迷惑，也经历了成功，体会到了它的好处。所以把这些写出来分享下!</P>
<P>　　软件就是由代码组成的，所以软件的质量就是代码的质量，我们出了BUG就从代码开始入手找问题，然后修改代码。但是当你的软件从小慢慢变大时候，代码越来越多，彼此之间的关联越来越紧密，这样就带来了一个问题"修改一部分代码后会影响多少?"，如果你拿这个问题去问那些项目中没有单元测试的开发人员，他们给出的答案都是通过"拍脑袋"来的，这样绝对会给你的项目带来风险。为了降低风险，项目开始要求开发人员做单元测试，但是做过后得出，这真的可以降低成本吗!花了太多的时间去写测试代码(甚至比开发时间还要多)，对于质量的保证也没有达到预期的效果...，项目做完后，发现做单元测试的和没有做成本多很多，所以接着就放弃了!..... 这种现象我想是我们都想做它但又不做它的最大因素。</P>
<P>　　其实我想大家对它的理解有点误差，我认为他最大的用处不是用来测试代码，而是<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/csyl/" target="_blank" >测试设计</A></STRONG>!!代码从是设计来的，保证了设计的正确性不也保证了代码嘛!软件中的未知风险太多了，其实很多出于设计，对于设计很难去评价好，还是坏，很难找到一个衡量的标准，但是我想<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target="_blank" >TDD</A></STRONG>，给了我们一个标准，虽然不能去完整的评价，但至少可以是一部分，可以降低它的风险。</P>
<P>　　这里慢慢开始引入了本文的主题，测试驱动开发(TDD)。我的理解上，单元测试如果不是TDD这种模式，就没有太多的必要去做，因为那样投入做单元测试的成本和收益之间找不到平衡点。</P>
<P>　　"测试驱动开发"的经历</P>
<P>　　测试驱动开发简称TTD，全名Test-Driven Developmen<STRONG><A href="http://www.ltesting.net/html/11/category-catid-111.html" target="_blank" >td</A></STRONG>。它是<STRONG><A href="http://www.ltesting.net/html/68/category-catid-168.html" target="_blank" >敏捷开发</A></STRONG>的一个重要组成部分，来源与"<STRONG><A href="http://www.ltesting.net/html/68/category-catid-168.html" target="_blank" >极限编程</A></STRONG>"。我接触它是从一年前的那天(具体时间不记得了~ 呵呵!)开始的.....</P>
<P>　　接触</P>
<P>　　记得两年前的某天，我正在公司偷偷地看电视剧"奋斗"，这时看到邮箱中的一封邮件: 部门下了一个确定"要求每个项目开发过程中加入单元测试"。当我听到"单元测试"的时候，满头的问号，"它是什么东西，做什么用的....?"(当时还很菜，居然还听过单元测试...!)，接着不停的开始找资料，足足花了一个星期才把它了解，然后做了一个简单的DEMO，写些简单的测试代码，把它放到 <STRONG><A href="http://www.ltesting.net/html/42/category-catid-442.html" target="_blank" >Nunit</A></STRONG>上，看着都是通过的提示，兴奋呀!</P>
<P>　　这时就和项目中的一个"大牛"开始讨论它了，忽然"大牛"的口中蹦出了三个英文单词"TDD"，然后和我讲了一大堆，我根本就不知道他说什么(水平有限，当时理解不了)，只是重复着三个字"明白了"。接着他说，项目的这个版本你设计的时候，加入单元测试吧，如果可以的话，也试下TDD.....</P>
<P>　　我是一个喜欢挑战的人，所以一开始就玩先写测试代码，结果呢!大家都明白，菜鸟嘛!一定失败咯，其中的原因是：根本就没有"测试驱动开发"的思想，完全不知道如何开始先写测试代码，而且还没有理解MOCK!下面只有乖乖地和别人一样，等代码写完后再写测试代码。</P>
<P>]]></description>
    <pubDate>Tue, 19 Jan 2010 10:32:36 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[什么是测试驱动开发]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2009/1229/168253.html</link>
    <description><![CDATA[<P>　　什么是<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target="_blank" >测试驱动开发</A></STRONG>&nbsp;&nbsp; <STRONG><A href="http://www.ltesting.net/html/2/category-catid-2.html" target=_blank>软件测试工具</A></STRONG></P>
<P>
<TABLE id=content style="TABLE-LAYOUT: fixed; WIDTH: 650px" cellSpacing=10 cellPadding=0 width=650 border=0>
<TBODY>
<TR>
<TD>
<DIV style="FONT-SIZE: 10pt; WORD-BREAK: break-all; POSITION: relative; WORD-WRAP: break-word">
<DIV>一、什么是TDD<BR><BR>简单的说，即在写任何功能代码之前，先写它的测试代码。具体步骤：<BR>·根据需要编写一个<STRONG><A href="http://www.ltesting.net/html/94/category-catid-94.html" target="_blank" >测试用例</A></STRONG><BR>·编写功能代码，以让刚才的测试用例通过<BR>·逐步补充测试用例<BR>·修改功能代码使新增的测试用例和原来的都通过<BR>·重构，包括功能代码和测试用例<BR><BR><BR>二、为什么使用TDD<BR><BR>提高代码<STRONG><A href="http://www.ltesting.net/html/5/category-catid-5.html" target="_blank" >质量</A></STRONG>。由于功能代码的高质量和完善的测试用例集，增强了开发者信心，从而赢得他人信任。<BR><BR>改进设计。TDD保证了功能代码的可测试性，降低了耦合度，改善组件对象模型，使设计在开发过程中逐步完善和改进。<BR><BR>为功能代码提供了良好的文档，并能维护代码和文档的同步。<STRONG><A href="http://www.ltesting.net/html/68/category-catid-168.html" target="_blank" >敏捷</A></STRONG>宣言主张：能够运行的软件胜过面面俱到的文档。测试用例集就是一份准备可靠，且能运行的文档。<BR><BR>在一定程度上可代替程序调试。当每个<STRONG><A href="http://www.ltesting.net/html/90/category-catid-90.html" target="_blank" >单元测试</A></STRONG>关注每一个具体功能时，问题被更早和更好地避免。另外调试是手动而不可重复，TDD的测试用例集则是自动可回归的。<BR><BR>有效的质量控制和<STRONG><A href="http://www.ltesting.net/html/66/category-catid-166.html" target="_blank" >项目管理</A></STRONG>。对管理者来说，通过单元测试每日构建的结果，每天都清楚的知道项目的质量和开发进度<BR><BR><BR>三、TDD是测试，更是设计<BR><BR>当开始写<STRONG><A href="http://www.ltesting.net/html/92/category-catid-92.html" target="_blank" >单元测试代码</A></STRONG>时，其实也正在开发。在编写功能代码前，站在功能代码的使用者角度设计测试用例，运用针对接口编程等原则降低耦合度，改进设计。由此可见，TDD也是<STRONG><A href="http://www.ltesting.net/html/74/category-catid-174.html" target="_blank" >面向对象</A></STRONG>的分析，设计和开发方法。在贯彻TDD的开发过程中，对于每个类分别进行测试，对于每部分都进行简单设计，频繁重构，最终形成了一整套可运行的测试用例集，TDD体现持续改进的过程，是一种增量式设计。<BR><BR>TDD（Test Driven Development），是一种<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/" target="_blank" >测试技术</A></STRONG>，更是一种设计方法。其重心不在Test，而在于Development，是一种以意图来驱动的软件开发方法——意图编程。</DIV></DIV></TD></TR></TBODY></TABLE></P>]]></description>
    <pubDate>Tue, 29 Dec 2009 12:01:28 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[数据驱动测试]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2009/1224/168155.html</link>
    <description><![CDATA[<U><FONT color=#800080></FONT></U>
<P>　　数据驱动<STRONG><A href="http://www.ltesting.net" target="_blank" >测试</A></STRONG>&nbsp;&nbsp; <STRONG><A href="http://www.ltesting.net/html/61/category-catid-161.html" target=_blank>数据库设计</A></STRONG>　</P>
<P>&nbsp;&nbsp;&nbsp; 　关键字: 数据驱动</P>
<P>　　我们从一个最简单的登录例子开始。</P>
<P>　　最开始我们需要验证在用户名和密码都正确的情况下，能够正常登录系统，我们这样编写测试代码(以下都是伪代码，使用<STRONG><A href="http://www.ltesting.net/ceshi/open/kydycsgj/testng/" target="_blank" >TestNG</A></STRONG>和<STRONG><A href="http://www.ltesting.net/html/37/category-catid-437.html" target="_blank" >Selenium</A></STRONG>)：</P>
<P>Java代码 </P>
<CENTER><IMG height=15 alt=复制代码 src="http://ronghao.javaeye.com/images/icon_copy.gif" width=14 border=1></CENTER>
<P>　　@Test</P>
<P>　　def should_login_su<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/clearcase/" target="_blank" >clearcase</A></STRONG>/" target="_blank" >cc</A></STRONG>ess_with_exist_username_and_correct_password(){</P>
<P>　　LoginPage page = user.open(LoginPage,"/login.html")</P>
<P>　　user.perform("login",['user1','1234'],on(page))</P>
<P>　　assert page.successLogin</P>
<P>　　}</P>
<P>　　@Test</P>
<P>　　def should_login_success_with_exist_username_and_correct_password(){</P>
<P>　　LoginPage page = user.open(LoginPage,"/login.html")</P>
<P>　　user.perform("login",['user1','1234'],on(page))</P>
<P>　　assert page.successLogin</P>
<P>　　}</P>
<P>　　恩，很不错，运行一下，出现红条。为什么呢?原来测试数据库里没有用户名为user1的用户，好吧，写个数据库数据初始化脚本。再运行，OK，绿条!</P>
<P>　　那么，接下来我们再增加一个测试，需要覆盖密码错误时不能登录系统的情况，很快测试就完成了：</P>
<P>Java代码 </P>
<CENTER><IMG height=15 alt=复制代码 src="http://ronghao.javaeye.com/images/icon_copy.gif" width=14 border=1></CENTER>
<P>　　@Test</P>
<P>　　def should_login_success_with_exist_username_and_incorrect_password(){</P>
<P>　　LoginPage page = user.open(LoginPage,"/login.html")</P>
<P>]]></description>
    <pubDate>Thu, 24 Dec 2009 13:28:25 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[测试驱动开发与极限编程]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2009/1127/167588.html</link>
    <description><![CDATA[<P>测试驱动<STRONG><A href="http://www.ltesting.net/html/4/category-catid-4.html" target="_blank" >开发</A></STRONG>与极限编程&nbsp;&nbsp;&nbsp; <STRONG><A href="http://www.ltesting.net/" target=_blank>软件测试 </A></STRONG></P>
<P>&nbsp;</P>
<P>一、测试驱动开发与极限编程核心价值的关系</P>
<P>&nbsp;</P>
<P>极限编程思想有其自身的核心价值，它们是：交流、简单、反馈、勇气。测试驱动开发作为极限编程中的基本开发原则，也充分体现了这种新型开发思想的价值。 <BR><BR>（１）交流在软件开发过程中的作用是毋庸置疑的，交流可以最大程度的减少开发人员、客户、管理人员之间由于沟通不畅造成的误解。极限编程的很多实践都是必须依靠交流来实现的，缺少交流是不能够进行下去的，比如<STRONG><A href="http://www.ltesting.net/html/90/category-catid-90.html" target="_blank" >单元测试</A></STRONG>、结对编程、工作的评估等。测试驱动开发与这些方法密不可分，只有进行结对编程等方法进行的测试驱动开发才是有意义的。这种情况下，同样需要大量的交流，可见交流原则的重要性。 <BR><BR>（２）简单这一价值在极限编程的思想中有着很重要的体现，整个极限编程的过程中都体现着简单二字，设计简单、代码简单，只要能简单行事，决不复杂办理。只要符合现在的要求，可以工作，那么简单解决就是最佳的方法。与其实现一个复杂的系统，不如设计一个简单的能满足当前需要的系统，因为你永远考虑不到下一个需求是什么。测试驱动开发正是如此。<STRONG><A href="http://www.ltesting.net/html/94/category-catid-94.html" target="_blank" >测试用例</A></STRONG>的编写本着简单的原则，在符合设计的要求下进行编写，越简单越好。只需要注重眼前的需求，不要考虑以后的需要变化。现阶段的设计满足现阶段的需求即可，显然现阶段的测试也只需满足现阶段的需要即可。测试用例的编写是根据设计而定的,而且可以说,测试用例的编写也是设计的一部分,简单的原则同样在起着指导作用。所以代码的编写亦是根据此原则，算法实现越简单越好，百分之百通过测试即可。 <BR><BR>（３）反馈是一项宝贵的资源。在极限编程中，无论是设计、测试、开发过程中，反馈都是非常重要的信息。例如在设计时，尽快获得用户的反馈，并且越详细越好，使得开发人员能够保证自己的成果符合用户的需要。测试亦是如此。测试驱动开发便是贯彻了这一价值。先进行测试用例的编写，利用没有通过测试的错误信息反馈，了解到代码没有通过测试用例的原因，根据该信息了解到出错的地方，再根据出现的问题有针对性的逐步地修改代码，让其渐渐符合测试用例的要求，在运行数次测试用例后，最终让其反馈回百分之百通过的成功信息。 <BR><BR>（４）勇气，这是最重要的核心价值。因为<STRONG><A href="http://www.ltesting.net/html/68/category-catid-168.html" target="_blank" >XP</A></STRONG>强调要\"拥抱变化\"，因此对于用户的反馈，要勇于对自己的代码进行修改，丢掉坏的代码。该条价值反映了开发人员应有的心态，而测试驱动开发正是进一步鼓励开发人员，而且在实践方便提供了很好的机制。先写测试后写代码的过程正是这一机制的体现。面对测试用例运行时报出的错误反馈要勇于面对。例如在xUnit<STRONG><A href="http://www.ltesting.net/html/81/category-catid-481.html" target="_blank" >测试框架</A></STRONG>的使用中就要于面对测试时出现的Red&nbsp;Bar，错误信息并不可怕，这正是测试驱动开发的意义所在。针对错误信息来编写及修改代码，勇于面对，最终解决问题顺利通过测试，显示出所期望的Green&nbsp;Bar。勇气又可以进一步的增强信心，提高效率，使得整个过程良性循环发展。 </P>
<P>&nbsp;</P>
<P>二、测试驱动开发与极限编程中设计的关系</P>
<P>&nbsp;</P>
<P>极限编程中提出的设计思想与传统<STRONG><A href="http://www.ltesting.net/html/67/category-catid-167.html" target="_blank" >软件工程</A></STRONG>的大相径庭，它摒弃了传统方法中对设计近乎苛求的原则，弱化了全面细致的设计。在极限编程中，不要求对需求做出非常详细的设计，而是遵循简单的原则，对现有的需求做出简单的设计。不需要为以后考虑，因为你永远不知道将来会增加哪些需求。Martin&nbsp;Fowler提出所谓的设计是要能够让你可以长期很简单地修改软件。 <BR><BR>极限编程看似对设计的简化，削弱了开发的依据。但其实它的思想却是进一步明确了软件开发的时候应该更注重眼前的问题，全力去考虑当前的需求，满足客户当前的需要，而不要为以后的需要费时费力，只有这样，才能使做出的软件符合客户的需求。测试驱动开发在实现设计方面有着很大的优势。测试驱动开发的特点之一就是先写测试再写代码。而此时，测试用例编写的意义就非同一般了。一方面，测试用例有着测试代码的通用作用，开发人员在代码编写完成后对其正确性进行判断。另一方面，在极限编程中，设计是一个持续的过程，&nbsp;测试用例在一定程度是也是需求文档的一种体现。对测试用例的编写其实也就是一个对需求进行分析设计的过程。这一点是极限编程和测试驱动开发独特的一点。测试用例的编写其实就是针对单元的输入输出的判断，对输入输出的设计就是对系统<STRONG><A href="http://www.ltesting.net/html/62/category-catid-162.html" target="_blank" >需求分析</A></STRONG>的过程，不能简单的随便设计，而是最好利用真实的系统数据进行设定。测试用例的编写完成后，代码才开始编写，这里的一切目的只为通过测试，而意义却是为了百分之百地满足系统的需求。测试的编写不再是一件令开发人员痛苦的事情，而是一件为了解系统需求而进行的设计过程，这种转变可以说对软件开发有着极大的积极的影响，这也是测试驱动开发的精髓所在。 <BR><BR>将设计融入开发，在开发中完善设计，两者相辅相成的关系在极限编程中体现的充分彻底。也就是这个原因，才使得测试驱动开发这一新思想迅速推广开来。 </P>
<P>&nbsp;</P>
<P>三、测试驱动开发与极限编程中人的关系</P>
<P>&nbsp;</P>
<P>极限编程的思想是以人为本的思想，它不同于CMM等重量级的开发方法，完全是从工程的角度来进行系统的开发，人在其中完全成为了条条框框下的忠实执行者。极限编程从人性方面考虑的更多，比如每周四十小时工作时，结对编程等。测试驱动开发也体现出了这一原则。 <BR><BR>人类的活动具有高度的目的性，建立适当的目标具有重要的心理作用。例如在<STRONG><A href="http://www.ltesting.net/html/97/category-catid-97.html" target="_blank" >测试过程</A></STRONG>中，体现出的现象更是如此。如果我们的主要目的是为了证明程序里面没有错误，那潜意识里就会不自觉地朝这个方向去做，所以在编写测试的过程中，我们就会选择一些尽量使程序不出错的测试数据；但是，如果我们的目标是要证明程序中有错，那就会选择一些易于发现程序所含错误的测试数据。而后一种态度会比前者给程序增添更多的价值。传统测试的定义意味着程序测试的过程是具有破坏性的，其程度甚至达到了不可容忍的地步。 <BR><BR>测试驱动开发一改以往的那种破坏性的思想，从人性的角度出发，测试在先，编码在后。而不是像传统的编码完成后再进行破坏性的测试。这样一来，我们的编码就有很明确的目的，每一条代码的目的就是为了能通过测试。从以前的破坏性的方法转移到一种建设性的方法中来。如何来满足这些测试，有了明确的目标，开发人员可以以一种正常人的心态去解决眼前出面的问题，编写高<STRONG><A href="http://www.ltesting.net/html/5/category-catid-5.html" target="_blank" >质量</A></STRONG>的代码去通过这些测试。在这种积极心态的影响下，开发人员的工作效率会有很大的提高，与此同时，这种建设性的方法对整个团队的开发也起着很重要的作用。</P>
<P>&nbsp;</P>
<P>&nbsp;</P>]]></description>
    <pubDate>Fri, 27 Nov 2009 14:37:39 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[关于持续集成]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2009/1127/167587.html</link>
    <description><![CDATA[<P>关于持续集成&nbsp;&nbsp;&nbsp;<STRONG><A href="http://www.ltesting.net/" target=_blank>软件测试</A></STRONG></P>
<P><STRONG></STRONG>&nbsp;</P>
<P>一、什么是持续集成</P>
<P>这个名词已经在软件<STRONG><A href="http://www.ltesting.net/html/4/category-catid-4.html" target="_blank" >开发</A></STRONG>领域持续了N年，一个比较简单的定义如下： <BR>　　持续集成（CI）是一种实践，可以让团队在持续的基础&nbsp;上收到反馈并进行改进，不必等到开发周期后期才寻找和修复<STRONG><A href="http://www.ltesting.net/html/98/category-catid-98.html" target="_blank" >缺陷</A></STRONG>。通俗一点儿说，就是指对于开发人员的每一次代码提交，都自动地把Repository中所有代码Check&nbsp;out到一个空目录，并且自动运行所有Test&nbsp;Case。如果成功则接受这次提交，否则告诉所有人，这是一个失败的Revision。更具体的解释可以参考Martin&nbsp;fowler的Continuous&nbsp;Integration&nbsp;&nbsp;。</P>
<P>&nbsp;</P>
<P>二、持续集成<STRONG><A href="http://www.ltesting.net/html/78/category-catid-378.html" target="_blank" >服务器</A></STRONG>的选择</P>
<P>在进行持续集成实践前，应当正确的选择并配置持续集成服务器。比较成熟的持续集成服务器包括：CruiseControl,&nbsp;Anthill,&nbsp;Bamboo,&nbsp;TeamCity,&nbsp;Continuum&nbsp;等。CruiseControl作为<STRONG><A href="http://www.ltesting.net/html/3/category-catid-3.html" target="_blank" >开源</A></STRONG>产品，以其对于各种SCM以及构建工具的广泛支持而被许多开发团队所接受。而开发自动化专家&nbsp;Duvall&nbsp;采用一致的评估标准和很多说明性示例，介绍了一些开源&nbsp;CI&nbsp;服务器，包括&nbsp;Continuum、CruiseControl&nbsp;和&nbsp;Luntbuild。并指出“要根据&nbsp;自己的&nbsp;具体技术和政策<STRONG><A href="http://www.ltesting.net/html/62/category-catid-162.html" target="_blank" >需求</A></STRONG>对工具进行分析”。并用以下五个指标来评估CI工具，它们分别是：(1)&nbsp;&nbsp;特性；(2)&nbsp;&nbsp;<STRONG><A href="http://www.ltesting.net/html/95/category-catid-95.html" target="_blank" >可靠性</A></STRONG>；(3)&nbsp;&nbsp;寿命；(4)&nbsp;目标环境；(5)&nbsp;易用性。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </P>
<P>而CruiseControl是我唯一真正用过的持续集成工具，它现在灵活而又强大功能也让我瞠目，而且配置与管理也较两年前容易得多啦。为什么说它强大呢？因为你只要想得到的问题，它也都会有所考虑。朋友的Blog上有些CruiseControl的最佳实践足以证明这一点，只要你肯去实践。</P>
<P>&nbsp;</P>
<P>&nbsp;</P>
<P>三、持续集成的价值与成本</P>
<P>&nbsp;</P>
<P>有句时髦的话，叫做“存在即为合理”。既然持续集成已经存在了这么长的时间，而且没有消失的迹象，那就是有价值的东西。那么它的价值何在？有人概括如下：(1)&nbsp;减小风险；(2)&nbsp;减少手动过程；(3)&nbsp;生成构建结果；(4)&nbsp;<STRONG><A href="http://www.ltesting.net/html/04/category-catid-104.html" target="_blank" >安全</A></STRONG>感。 <BR>　　而持续集成的成本在于对持续集成代码的维护成本和集成的时间成本。因为随着项目进行，软硬件环境会越来越复杂，成品代码也会不断膨胀。此时，需要团队而修改或增加原有的测试代码，以适应这些变化，同时，每次集成所需时间也会变长，这就是持续集成的成本。某个blog中提道：“这种集成是如此的频繁，多少次的代码Commit就有多少次持续集成。前提是集成的成本很低，或者说是完全自动化的。”</P>
<P>&nbsp;</P>]]></description>
    <pubDate>Fri, 27 Nov 2009 14:23:52 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[软件测试之每日构造与冒烟测试]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2009/0923/166068.html</link>
    <description><![CDATA[<P>软件测试之每日构造与冒烟测试&nbsp; <STRONG><A href="http://www.ltesting.net/" target=_blank>软件测试方法</A></STRONG></P>
<P>如果你想创建一个只包含一个源程序文件的简单程序，那么你只需要编译、连接那一个文件就可以了。如果是一个团队项目组，有着许多甚至上千个源程序文件，那么要创建一个可执行程序的过程就变得更复杂、更耗时。你必须用各种各样的组件将程序逐步建立起来。 </P>
<P>&nbsp;</P>
<P>在微软或其它一些软件公司中惯例是：每日构造并做“冒烟测试”。每天都对已完成的源程序进行编译，然后连接组合成可执行的程序，并做“冒烟测试”，以简单的检查该执行程序在运行时是否会“冒烟”。 </P>
<P>&nbsp;</P>
<P>带来的好处 </P>
<P>虽然这是一个非常简单的过程，但却有非常重要的意义： </P>
<P>&nbsp;</P>
<P>1、能最小化集成风险 </P>
<P>项目组可能遇到的一个很大的风险是，项目组成员根据不同的系统功能各自<STRONG><A href="http://www.ltesting.net/html/4/category-catid-4.html" target="_blank" >开发</A></STRONG>不同的代码，但是当这些代码集成为一个系统的时候，也许系统完成不了预期的功能。这种风险的发生取决于项目中的这种不<STRONG><A href="http://www.ltesting.net/html/80/category-catid-480.html" target="_blank" >兼容性</A></STRONG>多久才被发现，由于程序界面已经发生了变化，或者系统的主要部分已经被重新设计和重新实现了，相应的排错工作将非常困难和耗时。极端情况下，集成的错误可能回导致项目被取消掉。每日构造和冒烟测试可以使这种集成错误变得非常小，而且便于解决，防止了很多集成问题的产生。 </P>
<P>&nbsp;</P>
<P>2、能减小产品低<STRONG><A href="http://www.ltesting.net/html/5/category-catid-5.html" target="_blank" >质量</A></STRONG>的风险 </P>
<P>&nbsp;&nbsp;&nbsp;这种风险是和集成不成功、集成出错相关联的。每天对集成的代码做一些少量的冒烟测试，即可杜绝项目中那些基本的质量问题。通过这种方式，使系统达到一种周知的良好状态，维护这样的系统可以防止系统逐步恶化到耗费大量时间排查质量问题的地步。 </P>
<P>3、能简单化错误诊断 </P>
<P>当系统每天都进行build和测试时，系统任何一天发生的错误都能够变得十分精细，便于排查。比如在17日系统还运行正常，18日就出错了，那么只需要检查这两次build之间的代码变化就可以了。 </P>
<P>&nbsp;</P>
<P>4、能极大鼓舞项目组的士气 </P>
<P>看到产品的不断成长，能够极大的鼓舞项目组的士气，有时甚至不管这个产品到底用来做什么。开发人员可能会为系统显示了一个矩形而感到激动。通过每日构造，产品每天进步一点点，保证项目士气的持续高涨。 </P>
<P>&nbsp;</P>
<P>进行每日构造和冒烟测试 </P>
<P>虽然说这是一个简单枯燥的活，每天进行build，每天进行测试，但也有着一些值得注意的细节： </P>
<P>&nbsp;</P>
<P>]]></description>
    <pubDate>Wed, 23 Sep 2009 11:20:30 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[如何坚持TDD──使用者出现的问题以及解决方案]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2009/0811/164980.html</link>
    <description><![CDATA[如何坚持TDD──使用者出现的问题以及<STRONG><A href="http://www.ltesting.net/html/81/category-catid-381.html" target="_blank" >解决方案</A></STRONG>&nbsp; <STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target=_blank>测试驱动开发</A></STRONG>
<P>关键字：TDD 问题 解决 方案 </P>
<P>　　我们组织里曾有许多团队努力采用测试驱动开发(TDD)[1]。偶尔会有一两个开发者成功，但是大多数都失败了。为了更好地找出原因，我调查了团队 的一些成员，发现即使经过了课堂培训，还有更多的事情需要做。虽然这里介绍的问题和想法只适用于中大型的公司，但理解这一点能够帮我们在组织中更好地引入 TDD。</P>
<P>　　我对组员(他们全都接受过培训)的调查显示，以下问题影响了他们：</P>
<P>　　由于经验不足，大家发现自己直接TDD比较困难。</P>
<P>　　TDD培训的例子比实际应用简单得多。</P>
<P>　　需要更多的时间来实验和尝试，不要有赶紧发布软件的压力。</P>
<P>　　实际中应用的语言，比如Visual Basic和<STRONG><A href="http://www.ltesting.net/html/54/category-catid-154.html" target="_blank" >Java</A></STRONG>Script，在<STRONG><A href="http://www.ltesting.net/html/90/category-catid-90.html" target="_blank" >单元测试</A></STRONG>文档或者课堂练习中从来不会用到。</P>
<P>　　常常会碰到很多遗留代码，而培训时不会介绍如何改进这些代码。</P>
<P>　　永远没有足够的时间用来学习──随时都有尽早交付产品的(人为的)压力，于是没有时间学习提高自己。</P>
<P>　　隐藏的问题</P>
<P>　　我们已经列举了这么多症状，那么冰山下面隐藏的问题是什么呢?</P>
<P>　　测试驱动开发并不是很难学。学习阶段(指形成根深蒂固的习惯的这段时间)一般会持续2到4个月，期间生产效率有所降低[2]。最终的好处显而易见，开发者也能自己保持该项技术，但问题是：怎么才能做到这样?很多开发者仅仅几天之后就放弃了。</P>
<P>　　就我见过的方法而言，大多数依赖于课堂培训(或者e-learning)和一对一的辅导。如果做得好的话，这些方法当然不错，可以作为整个解决方案的一部分，但是我认为还需要更多的方法。</P>
<P>　　课程培训有两个主要的问题：例子太简单，与实际问题关系不大;给大家练习的机会不多。</P>
<P>　　在线培训(Object Mentor和Industrial Logic，以及其它机构提供的培训)，其优点是更有深度。然而练习的机会仍然不多。而且在这些课程里，你与其他学生通常没有交互。听一听你同学和同事的问题，能够加深你的理解。</P>
<P>　　一对一的辅导只能用于团队中的几个人，很难推而广之。在大型企业里面，专家只有几个，而需要帮助的人有成千上万，所以一对一的辅导更是困难。</P>
<P>　　看书是个很好的方法，但是很少有开发者喜欢通过读书学习TDD技术，即使有些人发现看书可以缓慢提高其TDD水平。与其它在线教程类似，看书仍然是只能一个人学习。</P>
<P>　　最后：遗留代码使得TDD难上加难。开发者当然会问这样的问题：“这些对象紧密耦合，怎样才能测试它们?这些代码太复杂了，怎样才能测试这个算法?”</P>
<P>　　一个解决方法</P>
<P>　　那怎样才是好的解决办法呢?前面的方法主要有两个问题：没有深度、缺乏协作。一个完整的解决方案需要结合使用多种学习模式，并需要包含以下多种因素。</P>
<P>　　</P>
<P>]]></description>
    <pubDate>Tue, 11 Aug 2009 10:11:12 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[顿悟软件测试驱动开发]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2009/0708/164262.html</link>
    <description><![CDATA[<P>顿悟软件<STRONG><A href="http://www.ltesting.net" target="_blank" >测试</A></STRONG>驱动<STRONG><A href="http://www.ltesting.net/html/4/category-catid-4.html" target="_blank" >开发</A></STRONG></P>
<P>很早就听闻过<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target="_blank" >测试驱动开发</A></STRONG>，在加入ThoughtWorks之前，在参加ThoughtWorks&nbsp;University之前。但是一直都不得其法，没有登堂入室。这次从印度参加了“有史以来最好的一届”的TWU，顿悟了测试驱动开发（以下简称<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target="_blank" >TDD</A></STRONG>），算是最大的收获。&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;其实TDD很简单，只要你不把它当测试。没错，就这么简单。把TDD当测试来写，你想着的就是如何找出已有代码的错误。想象着的是一副从迷宫中拯救出受困公主的图景。这个时候你就会受困于该如何去测与测什么的问题。假若你不把TDD当测试来写，顿时就会豁然开朗，拨云见日。&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;我认为TDD的本质在于，通过写测试来写代码。也就是在每一行产品代码落笔之前，先写一个测试来给这行代码找一个存在的理由。在参加TWU期间，一位名叫Garret&nbsp;Smith的培训师（Coach）反复和我们强调任何一行代码都要有测试。而且给我们举了一个实际例子：公司的英国办公室的一位同事编写一个软件专门用来对付无测试的代码。方式就是一行行地删除产品代码，如果测试仍然能够通过，这行代码就被删除了。这个例子给我的印象很深刻，因为我觉得它一语道破了天机。TDD其实就这么简单，让你的产品代码不能随便被别人“删除”。&nbsp; <STRONG><A href="http://www.ltesting.net/" target="_blank" >软件测试</A></STRONG>培训<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当用这个视角去实践TDD的时候。测试的名字就会很细节化。具体到描述什么条件时以什么参数调用什么方法时会有什么返回值。回头一想，这些测试对应着是什么呢？其实就是<STRONG><A href="http://www.ltesting.net/html/54/category-catid-154.html" target="_blank" >java</A></STRONG>doc文档！那么TDD又是什么一个过程呢？就是先写文档再写代码的过程。这么一说来，TDD就很自然了。你先想到一个很简单的功能要实现，有很多的代码要写。从一堆要写的代码中选择出最简单的部分（比如边界的情况）来写。把这部分代码的外部行为想好，写出对应的测试来，并给测试取一个能够当文档使的名字。&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;知道了TDD的本质与<STRONG><A href="http://www.ltesting.net/html/90/category-catid-90.html" target="_blank" >单元测试</A></STRONG>的本质之后，再来看一下我认为唯一关键的一个实践，那就是Mock。没有Mock的单元测试就很可能不是单元测试，也许是<STRONG><A href="http://www.ltesting.net/html/69/category-catid-469.html" target="_blank" >集成测试</A></STRONG>，也许是<STRONG><A href="http://www.ltesting.net/html/93/category-catid-93.html" target="_blank" >功能测试</A></STRONG>，总之不是TDD中所需要的那种能够驱动你开发的测试。任何牵涉到两个有行为的类之间交互的测试，都要Mock一个测另外一个，不然就会对象之间的互相影响就会使得测试测不准，无法确知问题所在，也无法让你的测试能够清晰地表达意图。&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;也许以前有一些书籍或者人讲过TDD只适合测算法，单元测试要做到<STRONG><A href="http://www.ltesting.net/html/93/category-catid-93.html" target="_blank" >黑盒</A></STRONG>，写Mock要适度之类的话。我目前的认识是这些见解容易让人把单元测试真当测试来看了。其实矫枉过正也无妨，就把TDD测试不当测试吧。总结一下就是TDD是确保你的代码不被别人意外“删掉”的开发方式，单元测试是你产品代码的文档，Mock是编写单元测试时最重要的技术，用于隔离测试对象行为。 </P>]]></description>
    <pubDate>Wed, 08 Jul 2009 15:12:30 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[TDD，软件测试代码可以代替文档吗？]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2009/0706/164212.html</link>
    <description><![CDATA[<P>TDD，<STRONG><A href="http://www.ltesting.net/" target="_blank" >软件测试</A></STRONG>代码可以代替文档吗？<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target=_blank>开发测试</A></STRONG></P>
<P>曾经，我认为只要做好详细设计工作，软件编码就成为一种体力活。在我印象中传统<STRONG><A href="http://www.ltesting.net/html/67/category-catid-167.html" target="_blank" >软件工程</A></STRONG>理论好像是这么说得：分析和设计是软件生产过程中最重要的两个阶段，好的设计产生好的结果，坏的设计产生坏的结果，详细设计文档是软件过程中最重要的部分，甚至比代码还重要。国内某人的书中还提到，“只要有了详细设计，哪怕原来的开发人员都离开了，换一批人照着详细设计仍然能把软件做完”。一提到详细设计我的脑子里也已经出现了这样的影子：长长的（或者厚厚的）文档，详细到每个函数，甚至是每个函数参数的名字都定义好了，用这样的详细设计指导代码编写应该是一件多么惬意的事情啊。我推崇这种事无巨细的详细设计，认为只要是设计好就能够适应变化，并把软件项目的失败归咎与设计人员的<STRONG><A href="http://www.ltesting.net/ask/" target="_blank" >知识</A></STRONG>、能力或经验不足。这种想法持续了很长时间，直到我有了实际软件项目的经验并开始单独做设计为止。 </P>
<P>　　促使我思想转变的原因就是两个字：变化。我原来也知道变化对设计的影响，但是还是低估了变化对设计带来的冲击。现实中的详细设计只是一个看上去很美的东西，开始编写代码一个月后的详细设计就基本上不能指导代码编写了，甚至变成和实际代码完全两回事的东西，成了一堆废纸，原因还是那两个字：变化。是的，变化，在某个时间已经很缜密的设计，在下个时间就会变得漏洞百出，因为计划赶不上变化，通常情况下，详细设计文档从其完成的那一刻起就开始散发出“腐败”的味道。只有没有任何软件开发经验的人才会天真地认为一次做好完备的详细设计，然后就可以在其指导下完成软件开发，最终得到产品。</P>
<P>　　在传统的软件过程中，面对逐渐散发出“腐败”味道的设计文档，通常有两种对策，一种是安排专职的文档开发人员，每次在代码中修改设计都及时更新到设计文档中，以保持文档的“新鲜”。其实这种方法也只是一种看上去很美的东西，且不说多数项目组都不会有多余的人手专职做文档开发（有哪个项目组敢在项目还在进行中就说自己的人手足够了？），就算有这样一个文档开发人员，那么是否每次设计上的小修改都会通知到他（她）呢？显然不会，他（她）必须Review 每一个开发人员的代码，并与大家随时沟通，发现与原始设计不一致的修改，这样会累死人的。那么是否可以由开发人员自己负责维护与自己工作相关的那部分文档呢？试想一下，当轰轰烈烈地代码编写开始后，或者头顶着产品交付倒计时牌，开发人员是否还有“闲情逸致”时不时停下正在Coding的手去重新修改一下设计文档呢？另一种对策是任由设计文档慢慢“腐败”，把主要力量集中在代码上，毕竟最终交付产品依靠代码而不是设计文档。这种情况下原来花费大量时间完成设计文档纯粹是浪费时间，哪怕是对自己人也没有丝毫用处，如果我是这个项目组中补充进来的新人，看到这样的文档和那样的代码，可能会得精神分裂症。</P>]]></description>
    <pubDate>Mon, 06 Jul 2009 11:31:47 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[TDD，测试代码可以代替文档吗？]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2009/0703/164175.html</link>
    <description><![CDATA[曾经，我认为只要做好详细设计工作，软件编码就成为一种体力活。在我印象中传统<STRONG><A href="http://www.ltesting.net/html/67/category-catid-167.html" target="_blank" >软件工程</A></STRONG>理论好像是这么说得：分析和设计是软件生产过程中最重要的两个阶段，好的设计产生好的结果，坏的设计产生坏的结果，详细设计文档是软件过程中最重要的部分，甚至比代码还重要。国内某人的书中还提到，“只要有了详细设计，哪怕原来的<STRONG><A href="http://www.ltesting.net/html/4/category-catid-4.html" target="_blank" >开发</A></STRONG>人员都离开了，换一批人照着详细设计仍然能把软件做完”。一提到详细设计我的脑子里也已经出现了这样的影子：长长的（或者厚厚的）文档，详细到每个函数，甚至是每个函数参数的名字都定义好了，用这样的详细设计指导代码编写应该是一件多么惬意的事情啊。我推崇这种事无巨细的详细设计，认为只要是设计好就能够适应变化，并把软件项目的失败归咎与设计人员的<STRONG><A href="http://www.ltesting.net/ask/" target="_blank" >知识</A></STRONG>、能力或经验不足。这种想法持续了很长时间，直到我有了实际软件项目的经验并开始单独做设计为止。 
<P>　　促使我思想转变的原因就是两个字：变化。我原来也知道变化对设计的影响，但是还是低估了变化对设计带来的冲击。现实中的详细设计只是一个看上去很美的东西，开始编写代码一个月后的详细设计就基本上不能指导代码编写了，甚至变成和实际代码完全两回事的东西，成了一堆废纸，原因还是那两个字：变化。是的，变化，在某个时间已经很缜密的设计，在下个时间就会变得漏洞百出，因为计划赶不上变化，通常情况下，详细设计文档从其完成的那一刻起就开始散发出“腐败”的味道。只有没有任何软件开发经验的人才会天真地认为一次做好完备的详细设计，然后就可以在其指导下完成软件开发，最终得到产品。</P>
<P>　　在传统的软件过程中，面对逐渐散发出“腐败”味道的设计文档，通常有两种对策，一种是安排专职的文档开发人员，每次在代码中修改设计都及时更新到设计文档中，以保持文档的“新鲜”。其实这种方法也只是一种看上去很美的东西，且不说多数项目组都不会有多余的人手专职做文档开发（有哪个项目组敢在项目还在进行中就说自己的人手足够了？），就算有这样一个文档开发人员，那么是否每次设计上的小修改都会通知到他（她）呢？显然不会，他（她）必须Review 每一个开发人员的代码，并与大家随时沟通，发现与原始设计不一致的修改，这样会累死人的。那么是否可以由开发人员自己负责维护与自己工作相关的那部分文档呢？试想一下，当轰轰烈烈地代码编写开始后，或者头顶着产品交付倒计时牌，开发人员是否还有“闲情逸致”时不时停下正在Coding的手去重新修改一下设计文档呢？另一种对策是任由设计文档慢慢“腐败”，把主要力量集中在代码上，毕竟最终交付产品依靠代码而不是设计文档。这种情况下原来花费大量时间完成设计文档纯粹是浪费时间，哪怕是对自己人也没有丝毫用处，如果我是这个项目组中补充进来的新人，看到这样的文档和那样的代码，可能会得精神分裂症。</P><BR>]]></description>
    <pubDate>Fri, 03 Jul 2009 11:27:28 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[测试驱动开发实践——入门篇]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2009/0626/164018.html</link>
    <description><![CDATA[　这个示例所使用的<STRONG><A href="http://www.ltesting.net/html/81/category-catid-481.html" target="_blank" >测试框架</A></STRONG>为<STRONG><A href="http://www.ltesting.net/html/42/category-catid-442.html" target=_blank>NUnit</A></STRONG>，大家可以到http://www.nunit.org/下载该工具。 
<P>　　测试项目中需要引用NUnit中的nunit.framework.dll</P>
<P>　　我们就以一个简单的需求开始吧。</P>
<P>　　需求</P>
<P>　　员工登陆系统，输入登陆名密码，系统返回是否登陆成功</P>
<P>　　我们首先先对这个需求写<STRONG><A href="http://www.ltesting.net/html/94/category-catid-94.html" target=_blank>测试用例</A></STRONG>：</P>
<P>&nbsp;1[TestFixture]<BR>&nbsp;2public class EmployeeTest<BR>&nbsp;3{<BR>&nbsp;4&nbsp;&nbsp;&nbsp; [Test]<BR>&nbsp;5&nbsp;&nbsp;&nbsp; public void LoginTest()<BR>&nbsp;6&nbsp;&nbsp;&nbsp; {<BR>&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Employee em = new Employee();<BR>&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Assert.IsTrue(em.Login("admin", "admin"), "用户登陆测试失败");<BR>&nbsp;9&nbsp;&nbsp;&nbsp; }<BR>10}</P>　　这样的代码在这里是编译不通过的，我们首先要去创建一个Employee类，并创建Login(string loginName,string password)方法： 
<P>&nbsp;1/**//// &lt;summary&gt;<BR>&nbsp;2/// 员工类<BR>&nbsp;3/// &lt;/summary&gt;<BR>&nbsp;4public class Employee<BR>&nbsp;5{<BR>&nbsp;6&nbsp;&nbsp;&nbsp; /**//// &lt;summary&gt;<BR>&nbsp;7&nbsp;&nbsp;&nbsp; /// 员工登陆<BR>&nbsp;8&nbsp;&nbsp;&nbsp; /// &lt;/summary&gt;<BR>&nbsp;9&nbsp;&nbsp;&nbsp; /// &lt;param name="loginName"&gt;登陆名&lt;/param&gt;<BR>10&nbsp;&nbsp;&nbsp; /// &lt;param name="password"&gt;密码&lt;/param&gt;<BR>11&nbsp;&nbsp;&nbsp; /// &lt;returns&gt;&lt;/returns&gt;<BR>12&nbsp;&nbsp;&nbsp; public bool Login(string loginName, string password)<BR>13&nbsp;&nbsp;&nbsp; {<BR>14&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;<BR>15&nbsp;&nbsp;&nbsp; }<BR>16}</P><BR>]]></description>
    <pubDate>Fri, 26 Jun 2009 10:22:16 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[测试驱动开发实践——重构篇]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2009/0626/164017.html</link>
    <description><![CDATA[前一篇文章《<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target=_blank>测试驱动开发</A></STRONG>实践-入门篇》我们我们讲了一些基本的测试驱动开发流程： 
<P>　　1、写<STRONG><A href="http://www.ltesting.net/html/90/category-catid-90.html" target=_blank>单元测试</A></STRONG>使他亮红灯</P>
<P>　　2、写代码使测试变成绿灯</P>
<P>　　3、重构代码</P>
<P>　　接下来我们需要开始重构了，大家有可能会问，为什么需要重构，什么时候开始重构。</P>
<P>　　对与为什么需要重构，其实就是为了使代码结构清晰，去除一些重复的代码，比如我们执行<STRONG><A href="http://www.ltesting.net/html/18/category-catid-418.html" target="_blank" >sql</A></STRONG>语句操作，我们起初这样写：</P>
<P>Code<BR>&nbsp;1private connStr="server=.;database=TestDB;uid=sa;pwd=123"<BR>&nbsp;2public int Add(string loginName)<BR>&nbsp;3{<BR>&nbsp;4&nbsp;&nbsp;&nbsp; int count = 0;<BR>&nbsp;5&nbsp;&nbsp;&nbsp; using (SqlConnection conn = new SqlConnection(connStr))<BR>&nbsp;6&nbsp;&nbsp;&nbsp; {<BR>&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.Open();<BR>&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SqlCommand cmd = new SqlCommand("insert(loginName) value('" + loginName + "')", conn);<BR>&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; count = cmd.ExecuteNonQuery();<BR>10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmd.Dispose();<BR>11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.Close();<BR>12&nbsp;&nbsp;&nbsp; }<BR>13&nbsp;&nbsp;&nbsp; return count;<BR>14}<BR>15<BR>16public int Delete(string loginName)<BR>17{<BR>18&nbsp;&nbsp;&nbsp; int count = 0;<BR>19&nbsp;&nbsp;&nbsp; using (SqlConnection conn = new SqlConnection(connStr))<BR>20&nbsp;&nbsp;&nbsp; {<BR>21&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.Open();<BR>22&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SqlCommand cmd = new SqlCommand("delete from LoginUsers where loginName='" + loginName + "'", conn);<BR>23&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; count = cmd.ExecuteNonQuery();<BR>24&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmd.Dispose();<BR>25&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.Close();<BR>26&nbsp;&nbsp;&nbsp; }<BR>27&nbsp;&nbsp;&nbsp; return count;<BR>28}</P>　　我们发现这里除了sql语句不一样之外，其他都是一样的，那我们就可以这样重构： 
<P>&nbsp;1private int ExecuteSql(string sql)<BR>&nbsp;2{<BR>&nbsp;3&nbsp;&nbsp;&nbsp; int count = 0;<BR>&nbsp;4&nbsp;&nbsp;&nbsp; using (SqlConnection conn = new SqlConnection(connStr))<BR>&nbsp;5&nbsp;&nbsp;&nbsp; {<BR>&nbsp;6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.Open();<BR>&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SqlCommand cmd = new SqlCommand(sql, conn);<BR>&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; count = cmd.ExecuteNonQuery();<BR>&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmd.Dispose();<BR>10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.Close();<BR>11&nbsp;&nbsp;&nbsp; }<BR>12&nbsp;&nbsp;&nbsp; return count;<BR>13}<BR>14public int Add(string loginName)<BR>15{<BR>16&nbsp;&nbsp;&nbsp; return ExecuteSql("insert(loginName) value('" + loginName + "')");<BR>17}<BR>18public int Delete(string loginName)<BR>19{<BR>20&nbsp;&nbsp;&nbsp; return ExecuteSql("delete from LoginUsers where loginName='" + loginName + "'");<BR>21}</P>]]></description>
    <pubDate>Fri, 26 Jun 2009 10:08:29 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[测试驱动开发全攻略]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2009/0618/163854.html</link>
    <description><![CDATA[<P>{关键字}</P>
<P><STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target=_blank>测试驱动开发</A></STRONG>/Test Driven Development/TDD<BR><STRONG><A href="http://www.ltesting.net/html/94/category-catid-94.html" target=_blank>测试用例</A></STRONG>/TestCase/TC<BR>设计/Design<BR>重构/Refactoring</P>
<P>{TDD的目标}</P>
<P>Clean Code That Works</P>
<P>这句话的含义是，事实上我们只做两件事情：让代码奏效（Work）和让代码洁净（Clean），前者是把事情做对，后者是把事情做好。想想看，其实我们平时所做的所有工作，除去无用的工作和错误的工作以外，真正正确的工作，并且是真正有意义的工作，其实也就只有两大类：增加功能和提升设计，而<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target=_blank>TDD </A></STRONG>正是在这个原则上产生的。如果您的工作并非我们想象的这样，（这意味着您还存在第三类正确有意义的工作，或者您所要做的根本和我们在说的是两回事），那么这告诉我们您并不需要TDD，或者不适用TDD。而如果我们偶然猜对（这对于我来说是偶然，而对于Kent Beck和Martin Fowler这样的大师来说则是辛勤工作的成果），那么恭喜您，TDD有可能成为您显著提升工作效率的一件法宝。请不要将信将疑，若即若离，因为任何一项新的技术——只要是从根本上改变人的行为方式的技术——就必然使得相信它的人越来越相信，不信的人越来越不信。这就好比学游泳，唯一能学会游泳的途径就是亲自下去游，除此之外别无他法。这也好比成功学，即使把卡耐基或希尔博士的书倒背如流也不能拥有积极的心态，可当你以积极的心态去成就了一番事业之后，你就再也离不开它了。相信我，TDD也是这样！想试用TDD的人们，请遵循下面的步骤：</P>
<P>编写TestCase –&gt; 实现TestCase –&gt; 重构<BR>（确定范围和目标） （增加功能） （提升设计）</P>
<P>[友情提示：<STRONG><A href="http://www.ltesting.net/html/68/category-catid-168.html" target="_blank" >敏捷</A></STRONG>建模中的一个相当重要的实践被称为：Prove it With Code，这种想法和TDD不谋而合。]</P>
<P>{TDD的优点}</P>
<P>『充满吸引力的优点』</P>
<P>完工时完工。表明我可以很清楚的看到自己的这段工作已经结束了，而传统的方式很难知道什么时候编码工作结束了。<BR>全面正确的认识代码和利用代码，而传统的方式没有这个机会。<BR>为利用你成果的人提供Sample，无论它是要利用你的源代码，还是直接重用你提供的组件。<BR>开发小组间降低了交流成本，提高了相互信赖程度。<BR>避免了过渡设计。<BR>系统可以与详尽的测试集一起发布，从而对程序的将来版本的修改和扩展提供方便。<BR>TDD给了我们自信，让我们今天的问题今天解决，明天的问题明天解决，今天不能解决明天的问题，因为明天的问题还没有出现(没有TestCase)，除非有TestCase否则我决不写任何代码；明天也不必担心今天的问题，只要我亮了绿灯。</P>
<P>『不显而易见的优点』</P>
<P>逃避了设计角色。对于一个敏捷的开发小组，每个人都在做设计。<BR>大部分时间代码处在高<STRONG><A href="http://www.ltesting.net/html/5/category-catid-5.html" target="_blank" >质量</A></STRONG>状态，100％的时间里成果是可见的。<BR>由于可以保证编写测试和编写代码的是相同的<STRONG><A href="http://www.ltesting.net/html/78/category-catid-478.html" target="_blank" >程序员</A></STRONG>，降低了理解代码所花费的成本。<BR>为减少文档和代码之间存在的细微的差别和由这种差别所引入的<STRONG><A href="http://www.ltesting.net/html/98/category-catid-98.html" target="_blank" >Bug</A></STRONG>作出杰出贡献。<BR>在预先设计和紧急设计之间建立一种平衡点，为你区分哪些设计该事先做、哪些设计该迭代时做提供了一个可靠的判断依据。<BR>『有争议的优点』</P>
<P>事实上提高了开发效率。每一个正在使用TDD并相信TDD的人都会相信这一点，但观望者则不同，不相信TDD的人甚至坚决反对这一点，这很正常，世界总是这样。<BR>发现比传统测试方式更多的Bug。<BR>使IDE的调试功能失去意义，或者应该说，避免了令人头痛的调试和节约了调试的时间。<BR>总是处在要么编程要么重构的状态下，不会使人抓狂。（两顶帽子）<BR>单元测试非常有趣。</P>
<P>{TDD的步骤}<BR>编写TestCase –&gt; 实现TestCase –&gt; 重构<BR>（不可运行） （可运行） （重构）</P>
<P>步骤 制品<BR>（1）快速新增一个测试用例 新的TestCase<BR>（2）编译所有代码，刚刚写的那个测试很可能编译不通过 原始的TODO List<BR>（3）做尽可能少的改动，让编译通过 Interface<BR>（4）运行所有的测试，发现最新的测试不能编译通过 －(Red Bar)<BR>（5）做尽可能少的改动，让测试通过 Implementation<BR>（6）运行所有的测试，保证每个都能通过 －(Green Bar)<BR>（7）重构代码，以消除重复设计 Clean Code That Works</P>
<P>{FAQ}</P>
<P>[什么时候重构？]<BR>如果您在软件公司工作，就意味着您成天都会和想通过重构改善代码质量的想法打交道，不仅您如此，您的大部分同事也都如此。可是，究竟什么时候该重构，什么情况下应该重构呢？我相信您和您的同事可能有很多不同的看法，最常见的答案是“该重构时重构”，“写不下去的时候重构”，和“下一次迭代开始之前重构”，或者干脆就是“最近没时间，就不重构了，下次有时间的时候重构吧”。正如您已经预见到我想说的——这些想法都是对重构的误解。重构不是一种构建软件的工具，不是一种设计软件的模式，也不是一个软件开发过程中的环节，正确理解重构的人应该把重构看成一种书写代码的方式，或习惯，重构时时刻刻有可能发生。在TDD中，除去<STRONG><A href="http://www.ltesting.net/html/94/category-catid-94.html" target="_blank" >编写测试用例</A></STRONG>和实现测试用例之外的所有工作都是重构，所以，没有重构任何设计都不能实现。至于什么时候重构嘛，还要分开看，有三句话是我的经验：实现测试用例时重构代码，完成某个特性时重构设计，产品的重构完成后还要记得重构一下测试用例哦。</P>
<P>[什么时候设计？]<BR>这个问题比前面一个要难回答的多，实话实说，本人在依照TDD开发软件的时候也常常被这个问题困扰，总是觉得有些问题应该在写测试用例之前定下来，而有些问题应该在新增一个一个测试用例的过程中自然出现，水到渠成。所以，我的建议是，设计的时机应该由开发者自己把握，不要受到TDD方式的限制，但是，不需要事先确定的事一定不能事先确定，免得捆住了自己的手脚。</P>
<P>[什么时候增加新的TestCase？]<BR>没事做的时候。通常我们认为，如果你要增加一个新的功能，那么先写一个不能通过的 TestCase；如果你发现了一个<STRONG><A href="http://www.ltesting.net/html/98/category-catid-98.html" target="_blank" >bug</A></STRONG>，那么先写一个不能通过的TestCase；如果你现在什么都没有，从0开始，请先写一个不能通过的 TestCase。所有的工作都是从一个TestCase开始。此外，还要注意的是，一些大师要求我们每次只允许有一个TestCase亮红灯，在这个 TestCase没有Green之前不可以写别的TestCase，这种要求可以适当考虑，但即使有多个TestCase亮红灯也不要紧，并未违反TDD 的主要精神。</P>
<P>[TestCase该怎么写？]<BR>测试用例的编写实际上就是两个过程：使用尚不存在的代码和定义这些代码的执行结果。所以一个 TestCase也就应该包括两个部分——场景和断言。第一次写TestCase的人会有很大的不适应的感觉，因为你之前所写的所有东西都是在解决问题，现在要你提出问题确实不大习惯，不过不用担心，你正在做正确的事情，而这个世界上最难的事情也不在于如何解决问题，而在于ask the right question！</P>
<P>[TDD能帮助我消除Bug吗？]<BR>答：不能！千万不要把“测试”和“除虫”混为一谈！“除虫”是指程序员通过自己的努力来减少bug的数量（消除bug这样的字眼我们还是不要讲为好^_^），而“测试”是指程序员书写产品以外的一段代码来确保产品能有效工作。虽然TDD所编写的测试用例在一定程度上为寻找bug提供了依据，但事实上，按照TDD的方式进行的软件开发是不可能通过TDD再找到bug的（想想我们前面说的“完工时完工”），你想啊，当我们的代码完成的时候，所有的测试用例都亮了绿灯，这时隐藏在代码中的bug一个都不会露出马脚来。</P>
<P>但是，如果要问“测试”和“除虫”之间有什么联系，我相信还是有很多话可以讲的，比如TDD事实上减少了bug的数量，把查找bug战役的关注点从全线战场提升到代码战场以上。还有，bug的最可怕之处不在于隐藏之深，而在于满天遍野。如果你发现了一个用户很不容易才能发现的bug，那么不一定对工作做出了什么杰出贡献，但是如果你发现一段代码中，bug的密度或离散程度过高，那么恭喜你，你应该抛弃并重写这段代码了。TDD避免了这种情况，所以将寻找bug的工作降低到了一个新的低度。</P>
<P>[我该为一个Feature编写TestCase还是为一个类编写TestCase？]<BR>初学者常问的问题。虽然我们从TDD 的说明书上看到应该为一个特性编写相应的TestCase，但为什么著名的TDD大师所写的TestCase都是和类/方法一一对应的呢？为了解释这个问题，我和我的同事们都做了很多试验，最后我们得到了一个结论，虽然我不知道是否正确，但是如果您没有答案，可以姑且相信我们。</P>
<P>我们的研究结果表明，通常在一个特性的开发开始时，我们针对特性编写测试用例，如果您发现这个特性无法用TestCase表达，那么请将这个特性细分，直至您可以为手上的特性写出TestCase为止。从这里开始是最<STRONG><A href="http://www.ltesting.net/html/04/category-catid-104.html" target="_blank" >安全</A></STRONG>的，它不会导致任何设计上重大的失误。但是，随着您不断的重构代码，不断的重构 TestCase，不断的依据TDD的思想做下去，最后当产品伴随测试用例集一起发布的时候，您就会不经意的发现经过重构以后的测试用例很可能是和产品中的类/方法一一对应的。</P>
<P>[什么时候应该将全部测试都运行一遍？]<BR>Good Question！大师们要求我们每次重构之后都要完整的运行一遍测试用例。这个要求可以理解，因为重构很可能会改变整个代码的结构或设计，从而导致不可预见的后果，但是如果我正在开发的是一个ERP怎么办？运行一遍完整的测试用例可能将花费数个小时，况且现在很多重构都是由工具做到的，这个要求的可行性和前提条件都有所动摇。所以我认为原则上你可以挑几个你觉得可能受到本次重构影响的TestCase去run，但是如果运行整个测试包只要花费数秒的时间，那么不介意你按大师的要求去做。</P>
<P>[什么时候改进一个TestCase？]<BR>增加的测试用例或重构以后的代码导致了原来的TestCase的失去了效果，变得无意义，甚至可能导致错误的结果，这时是改进TestCase的最好时机。但是有时你会发现，这样做仅仅导致了原来的TestCase在设计上是臃肿的，或者是冗余的，这都不要紧，只要它没有失效，你仍然不用去改进它。记住，TestCase不是你的产品，它不要好看，也不要怎么太科学，甚至没有<STRONG><A href="http://www.ltesting.net/html/95/category-catid-95.html" target="_blank" >性能</A></STRONG>要求，它只要能完成它的使命就可以了——这也证明了我们后面所说的“用Ctrl-C/Ctrl-V编写测试用例”的可行性。</P>
<P>]]></description>
    <pubDate>Thu, 18 Jun 2009 11:13:21 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[极限编程的重要特点---测试驱动开发]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2009/0612/163761.html</link>
    <description><![CDATA[背景<BR>　　一个高效的软件开发过程对软件开发人员来说是至关重要的，决定着开发是痛苦的挣扎，还是不断进步的喜悦。国人对软件蓝领的不屑，对繁琐冗长的传统开发过程的不耐，使大多数开发人员无所适从。最近兴起的一些软件开发过程相关的技术，提供一些比较高效、实用的软件过程开发方法。其中比较基础、关键的一个技术就是<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target=_blank>测试驱动开发</A></STRONG>（Test-Driven Development）。虽然TDD光大于<STRONG><A href="http://www.ltesting.net/html/68/category-catid-168.html" target="_blank" >极限编程</A></STRONG>，但测试驱动开发完全可以单独应用。下面就从开发人员使用的角度进行介绍，使开发人员用最少的代价尽快理解、掌握、应用这种技术。下面分优势，原理，过程，原则，<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/" target="_blank" >测试技术</A></STRONG>，Tips等方面进行讨论。<BR>　　<BR>　　1. 优势<BR>　　TDD的基本思路就是通过测试来推动整个开发的进行。而测试驱动<STRONG><A href="http://www.ltesting.net/html/4/category-catid-4.html" target="_blank" >开发技术</A></STRONG>并不只是单纯的测试工作。<BR>　　<BR>　　需求向来就是软件开发过程中感觉最不好明确描述、易变的东西。这里说的需求不只是指用户的需求，还包括对代码的使用需求。很多开发人员最害怕的就是后期还要修改某个类或者函数的接口进行修改或者扩展，为什么会发生这样的事情就是因为这部分代码的使用需求没有很好的描述。测试驱动开发就是通过<STRONG><A href="http://www.ltesting.net/html/94/category-catid-94.html" target="_blank" >编写测试用例</A></STRONG>，先考虑代码的使用需求（包括功能、过程、接口等），而且这个描述是无二义的，可执行验证的。<BR>　　<BR>　　通过编写这部分代码的测试用例，对其功能的分解、使用过程、接口都进行了设计。而且这种从使用角度对代码的设计通常更符合后期开发的需求。可测试的要求，对代码的内聚性的提高和复用都非常有益。因此测试驱动开发也是一种代码设计的过程。<BR>　　<BR>　　开发人员通常对编写文档非常厌烦，但要使用、理解别人的代码时通常又希望能有文档进行指导。而测试驱动开发过程中产生的<STRONG><A href="http://www.ltesting.net/html/94/category-catid-94.html" target=_blank>测试用例</A></STRONG>代码就是对代码的最好的解释。<BR>　　<BR>　　快乐工作的基础就是对自己有信心，对自己的工作成果有信心。当前很多开发人员却经常在担心：“代码是否正确？”“辛苦编写的代码还有没有严重<STRONG><A href="http://www.ltesting.net/html/98/category-catid-98.html" target="_blank" >bug</A></STRONG>？”“修改的新代码对其他部分有没有影响？”。这种担心甚至导致某些代码应该修改却不敢修改的地步。测试驱动开发提供的测试集就可以作为你信心的来源。<BR>　　<BR>　　当然测试驱动开发最重要的功能还在于保障代码的正确性，能够迅速发现、定位bug。而迅速发现、定位bug是很多开发人员的梦想。针对关键代码的测试集，以及不断完善的测试用例，为迅速发现、定位bug提供了条件。<BR>　　<BR>　　我的一段功能非常复杂的代码使用<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target=_blank>TDD</A></STRONG>开发完成，真实环境应用中只发现几个bug，而且很快被定位解决。您在应用后，也一定会为那种自信的开发过程，功能不断增加、完善的感觉，迅速发现、定位bug的能力所感染，喜欢这个技术的。<BR>　　<BR>　　那么是什么样的原理、方法提供上面说的这些好处哪？下面我们就看看TDD的原理。<BR>　　<BR>　　2. 原理<BR>　　测试驱动开发的基本思想就是在开发功能代码之前，先编写测试代码。也就是说在明确要开发某个功能后，首先思考如何对这个功能进行测试，并完成测试代码的编写，然后编写相关的代码满足这些测试用例。然后循环进行添加其他功能，直到完全部功能的开发。<BR>　　<BR>　　我们这里把这个技术的应用领域从代码编写扩展到整个开发过程。应该对整个开发过程的各个阶段进行测试驱动，首先思考如何对这个阶段进行测试、验证、考核，并编写相关的测试文档，然后开始下一步工作，最后再验证相关的工作。下图是一个比较流行的测试模型：V测试模型。<BR>　　 　<BR>　　在开发的各个阶段，包括<STRONG><A href="http://www.ltesting.net/html/62/category-catid-162.html" target="_blank" >需求分析</A></STRONG>、概要设计、详细设计、编码过程中都应该考虑相对应的测试工作，完成相关的测试用例的设计、<STRONG><A href="http://www.ltesting.net/html/75/category-catid-475.html" target="_blank" >测试方案</A></STRONG>、<STRONG><A href="http://www.ltesting.net/html/74/category-catid-474.html" target=_blank>测试计划</A></STRONG>的编写。这里提到的开发阶段只是举例，根据实际的开发活动进行调整。相关的测试文档也不一定是非常详细复杂的文档，或者什么形式，但应该养成测试驱动的习惯。<BR>　　<BR>　　关于测试模型，还有X测试模型。这个测试模型，我认为，是对详细阶段和编码阶段进行建模，应该说更详细的描述了详细设计和编码阶段的开发行为。及针对某个功能进行对应的测试驱动开发。<BR>　　 <BR>　　基本原理应该说非常简单，那么如何进行实际操作哪，下面对开发过程进行详细的介绍。<BR>　　<BR>　　3. 过程<BR>　　软件开发其他阶段的测试驱动开发，根据测试驱动开发的思想完成对应的测试文档即可。下面针对详细设计和编码阶段进行介绍。<BR>　　<BR>　　
<P>]]></description>
    <pubDate>Fri, 12 Jun 2009 10:43:04 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[(一)让开发自动化: 持续测试]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2009/0608/163653.html</link>
    <description><![CDATA[准备好开始在您的<STRONG><A href="http://www.ltesting.net/html/4/category-catid-4.html" target="_blank" >开发</A></STRONG>人员测试活动中大获全胜吗？在本期的 让开发自动化 中，开发自动化专家 Paul Duvall 介绍了几种自动化的开发人员测试，每一次改变源代码都能够运行这些测试。Paul 提供了 Selenium、DbUnit 和 JUnitPerf 测试的例子，即，如果经常 运行这些测试可以帮助您尽早发现应用程序的问题。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在像 Eclipse 那样的 IDE 中或者比如在 Ant 构建脚本中运行<STRONG><A href="http://www.ltesting.net/html/90/category-catid-90.html" target=_blank>单元测试</A></STRONG>是确保应用程序<STRONG><A href="http://www.ltesting.net/html/5/category-catid-5.html" target="_blank" >质量</A></STRONG>的一个很好的开始；然而，<STRONG><A href="http://www.ltesting.net/html/63/category-catid-163.html" target="_blank" >版本控制</A></STRONG>库（如 Subversion）中的源代码一改变，在单独无变动的构建机上运行单元测试就有助于检验开发生命周期中的问题。而且，运行各种类型的开发人员测试，如组件测试、<STRONG><A href="http://www.ltesting.net/html/93/category-catid-93.html" target=_blank>功能测试</A></STRONG>和<STRONG><A href="http://www.ltesting.net/html/95/category-catid-95.html" target=_blank>性能测试</A></STRONG>，能够在开发生命周期中更早地 将问题显示出来。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 通常在持续集成（CI）环境中运行的开发人员测试有效地扮演着代码质量聚光灯的角色。这是因为如果能有效地编写这些测试，则几乎能够在问题（如<STRONG><A href="http://www.ltesting.net/html/98/category-catid-98.html" target="_blank" >缺陷</A></STRONG>）产生之时就将其发现。不经常运行测试通常就不怎么有效，因为从产生缺陷到发现该缺陷的时间相隔很长，但持续地（即，每一次代码改变时）运行测试能确保快速发现无意识的行为。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 本文涵盖下列内容：<BR>&nbsp;&nbsp; 通过 Ant 运行 JUnit 测试<BR>&nbsp;&nbsp; 使用 JUnit 和 DbUnit 执行更长时间的运行组件测试<BR>&nbsp;&nbsp; 使用 JUnitPerf 确定哪些方法花费时间过久而执行失败<BR>&nbsp;&nbsp; 用 Selenium 运行基于 Web 的功能测试<BR>&nbsp;&nbsp; 用 Cobertura 访问代码覆盖率<BR>&nbsp;&nbsp; 用 CruiseControl 进行持续测试&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;我提供一个关于不同类型开发人员测试的概览，和一些可以添加到构建过程并使用 Continuous Integration 系统持续运行的例子。<BR>按 JUnit 进行单元测试<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 有时，我听到开发人员将开发人员测试这一术语与简单的单元测试相混淆；然而，我发现将单元测试这一术语提练得更加明确很有帮助。对我来说，单元测试是快速运行的 测试，通常测试没有大的外部依赖项（如<STRONG><A href="http://www.ltesting.net/html/61/category-catid-161.html" target="_blank" >数据库</A></STRONG>）的单独的类。例如，清单 1 定义了一个单元测试，该测试使用 JUnit 来验证一个叫做 BeerDaoStub 的存根数据类。针对并未真正连接到数据库的接口的<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/" target="_blank" >测试技术</A></STRONG>是一种验证业务功能的方法，使用该方法不会导致花费昂贵的设置成本。另外，这样做可使测试保持为一个真正的单元测试。 
<P>清单 1. 一个简单的单元测试<BR>public void setUp() {<BR>&nbsp; beerService = new BeerDaoStub();<BR>}</P>
<P>public void testUnitGetBeer() {<BR>&nbsp; Collection beers = beerService.findAll();<BR>&nbsp; assertTrue(beers != null &amp;&amp; beers.size() &gt; 0);<BR>}</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一旦编写了一些单元测试，就可以一直通过 IDE 运行这些测试，但您也想要将这些测试作为构建过程的一部分来运行。确保该测试通过构建过程成功运行意味着也能从 CI 构建的上下文中启动这些相同的测试。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 清单 2 是一个 Ant 脚本片段，介绍了执行一批单元测试的<STRONG><A href="http://www.ltesting.net/html/32/category-catid-432.html" target=_blank>junit </A></STRONG>任务。这项任务与 JUnit 一起运作，其妙处在于：定义过的所有测试现在都能自动运行并且如果其中任何一个测试失败，则构建也将失败 —— 通过使用 haltonfailure 属性实现。</P>
<P>清单 2. 在 Ant 中运行单元测试<BR>&lt;junit fork="yes" haltonfailure="true" dir="${basedir}" printsummary="yes"&gt;<BR>&nbsp; &lt;classpath refid="test.class.path" /&gt;<BR>&nbsp; &lt;classpath refid="project.class.path"/&gt;<BR>&nbsp; &lt;formatter type="plain" usefile="true" /&gt;<BR>&nbsp; &lt;formatter type="xml" usefile="true" /&gt;<BR>&nbsp; &lt;batchtest fork="yes" todir="${logs.junit.dir}"&gt;<BR>&nbsp;&nbsp;&nbsp; &lt;fileset dir="${test.unit.dir}"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;patternset refid="test.sources.pattern"/&gt;<BR>&nbsp;&nbsp;&nbsp; &lt;/fileset&gt;<BR>&nbsp; &lt;/batchtest&gt;<BR>&lt;/junit&gt;&nbsp;</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </P>
<P>]]></description>
    <pubDate>Mon, 08 Jun 2009 11:26:06 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[(二)让开发自动化: 持续测试]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2009/0608/163652.html</link>
    <description><![CDATA[使用清单 6 中基于表格的格式，可以定义多个接受<FONT color=#000000><STRONG><A href="http://www.ltesting.net" target="_blank" >测试</A></STRONG></FONT>。也可以将测试分组成套，一次执行一整套测试。<BR>使用 Ant 驱动 Selenium<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Selenium 的伟大之处在于它是在考虑了 CI 的基础上从头创建的，因为你能在像 Ant 那样的构建工具中运行 Selenium。此外，由于框架设计者的高瞻远瞩，如果任何 Selenium 接受测试失败，您也可以让整个构建失败。例如，清单 7 展示了一个 Ant 任务，该任务使用 Selenium 远程控制<STRONG><A href="http://www.ltesting.net/html/78/category-catid-378.html" target="_blank" >服务器</A></STRONG>在一个 Web 应用程序中执行一系列表格驱动测试：
<P>清单 7. 使用 Ant 运行 Selenium<BR>&lt;?xml version="1.0" encoding="iso-8859-1"?&gt;<BR>&lt;project name="functional-tests" default="run-<STRONG><A href="http://www.ltesting.net/html/37/category-catid-437.html" target="_blank" >selenium</A></STRONG>-tests" basedir="."&gt;<BR>&nbsp; &lt;property file="${basedir}/selenium.properties"/&gt;<BR>&nbsp; &lt;import file="${basedir}/common-environment.xml"/&gt;<BR>&nbsp; &lt;property name="a<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/<STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/rational/clearcase/" target="_blank" >clearcase</A></STRONG>/" target="_blank" >cc</A></STRONG>eptance.test.lib.dir"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value="${functional.test.dir}" /&gt;<BR>&nbsp; &lt;property name="firefox" value="*firefox" /&gt;<BR>&nbsp; &lt;property name="base.url"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value="<FONT color=#000000>http://${web.host.name}:${web.port</FONT>}" /&gt;<BR>&nbsp; &lt;property name="acceptance.test.list.dir"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value="${functional.test.dir}" /&gt;<BR>&nbsp; &lt;property name="acceptance.test.report.dir"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value="${functional.test.dir}" /&gt;<BR>&nbsp; &lt;target name="run-selenium-tests"&gt;<BR>&nbsp;&nbsp;&nbsp; &lt;mkdir dir="${reports.dir}" /&gt;<BR>&nbsp;&nbsp;&nbsp; &lt;java jar="${acceptance.test.lib.dir}/selenium-server.jar"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fork="true"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;arg line="-htmlSuite "${firefox}""/&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;arg line=""${base.url}""/&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;arg line=""${acceptance.test.list.dir}/${test.suite}""/&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;arg line=""${reports.dir}/index.html""/&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;arg line="-timeout ${timeout}"/&gt;<BR>&nbsp;&nbsp;&nbsp; &lt;/java&gt;<BR>&nbsp; &lt;/target&gt;<BR>&nbsp; &lt;target name="stop-server"&gt;<BR>&nbsp;&nbsp;&nbsp; &lt;get taskname="selenium-shu<STRONG><A href="http://www.ltesting.net/html/11/category-catid-111.html" target="_blank" >td</A></STRONG>own"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; src="<FONT color=#000000>http://${web.host.name</FONT>}:<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ${selenium.rc.port}/selenium-server/driver/?cmd=shutDown"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dest="result.txt" ignoreerrors="true" /&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp; &lt;echo taskname="selenium-shutdown"<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; message="Errors during shutdown are expected" /&gt;<BR>&nbsp; &lt;/target&gt;<BR>&lt;/project&gt;</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 执行 Selenium 测试时，当框架打开 Web 浏览器、闪电般执行测试，然后关闭该浏览器并生成 HTML 报告时，不要被吓到。这是一种在<STRONG><A href="http://www.ltesting.net/html/4/category-catid-4.html" target="_blank" >开发</A></STRONG>生命周期的早期更快更容易地发现问题的方法（此时它们更易处理）。<BR>使用 Cobertura 报告代码覆盖率<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 现在已经编写了一些测试，如何确定所有这些测试执行什么 呢？幸运的是，此问题可由像 Cobertura 这样的代码覆盖工具来解答。代码覆盖工具可报告测试覆盖率 —— 以行覆盖或分支覆盖形式表示 —— 它表示测试运行时所涉及的代码量。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 清单 8 展示了一个 Ant 脚本。该脚本使用 Cobertura 生成一份关于代码覆盖率的 HTML 报告，代码覆盖率通过运行一系列 JUnit 测试获得：</P>
<P>]]></description>
    <pubDate>Mon, 08 Jun 2009 11:22:23 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[浅谈测试驱动开发（TDD）]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2009/0526/163228.html</link>
    <description><![CDATA[&nbsp;<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target=_blank>测试驱动开发</A></STRONG>(TDD)是<STRONG><A href="http://www.ltesting.net/html/68/category-catid-168.html" target="_blank" >极限编程</A></STRONG>的重要特点，它以不断的测试推动代码的开发，既简化了代码，又保证了软件<STRONG><A href="http://www.ltesting.net/html/5/category-catid-5.html" target="_blank" >质量</A></STRONG>。本文从开发人员使用的角度，介绍了 TDD 优势、原理、过程、原则、<FONT color=#202859><STRONG><A href="http://www.ltesting.net/ceshi/ceshijishu/" target="_blank" >测试技术</A></STRONG></FONT>、Tips 等方面。<BR>背景<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一个高效的软件开发过程对软件开发人员来说是至关重要的，决定着开发是痛苦的挣扎，还是不断进步的喜悦。国人对软件蓝领的不屑，对繁琐冗长的传统开发过程的不耐，使大多数开发人员无所适从。最近兴起的一些软件开发过程相关的技术，提供一些比较高效、实用的软件过程开发方法。其中比较基础、关键的一个技术就是测试驱动开发（Test-Driven Development）。虽然TDD光大于极限编程，但测试驱动开发完全可以单独应用。下面就从开发人员使用的角度进行介绍，使开发人员用最少的代价尽快理解、掌握、应用这种技术。下面分优势，原理，过程，原则，测试技术，Tips等方面进行讨论。
<P>1. 优势<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target=_blank>TDD</A></STRONG>的基本思路就是通过测试来推动整个开发的进行。而测试驱动<STRONG><A href="http://www.ltesting.net/html/4/category-catid-4.html" target="_blank" >开发技术</A></STRONG>并不只是单纯的测试<FONT color=#202859><U>工作</U></FONT>。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <STRONG><A href="http://www.ltesting.net/html/62/category-catid-162.html" target="_blank" >需求</A></STRONG>向来就是软件开发过程中感觉最不好明确描述、易变的东西。这里说的需求不只是指用户的需求，还包括对代码的使用需求。很多开发人员最害怕的就是后期还要修改某个类或者函数的接口进行修改或者扩展，为什么会发生这样的事情就是因为这部分代码的使用需求没有很好的描述。测试驱动开发就是通过编写<U><STRONG><FONT color=#202859><A href="http://www.ltesting.net/html/94/category-catid-94.html" target=_blank>测试用例</A></FONT></STRONG></U>，先考虑代码的使用需求（包括功能、过程、接口等），而且这个描述是无二义的，可执行验证的。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 通过编写这部分代码的测试用例，对其功能的分解、使用过程、接口都进行了设计。而且这种从使用角度对代码的设计通常更符合后期开发的需求。可测试的要求，对代码的内聚性的提高和复用都非常有益。因此测试驱动开发也是一种代码设计的过程。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 开发人员通常对编写文档非常厌烦，但要使用、理解别人的代码时通常又希望能有文档进行指导。而测试驱动开发过程中产生的测试用例代码就是对代码的最好的解释。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 快乐工作的基础就是对自己有信心，对自己的工作成果有信心。当前很多开发人员却经常在担心：“代码是否正确？”“辛苦编写的代码还有没有严重<STRONG><A href="http://www.ltesting.net/html/98/category-catid-98.html" target="_blank" >bug</A></STRONG>？”“修改的新代码对<FONT color=#202859>其他</FONT>部分有没有影响？”。这种担心甚至导致某些代码应该修改却不敢修改的地步。测试驱动开发提供的测试集就可以作为你信心的来源。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当然测试驱动开发最重要的功能还在于保障代码的正确性，能够迅速发现、定位bug。而迅速发现、定位bug是很多开发人员的梦想。针对关键代码的测试集，以及不断完善的测试用例，为迅速发现、定位bug提供了条件。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我的一段功能非常复杂的代码使用TDD开发完成，真实环境应用中只发现几个bug，而且很快被定位解决。您在应用后，也一定会为那种自信的开发过程，功能不断增加、完善的感觉，迅速发现、定位bug的能力所感染，喜欢这个技术的。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 那么是什么样的原理、方法提供上面说的这些好处哪？下面我们就看看TDD的原理。</P>
<P>2. 原理<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 测试驱动开发的基本思想就是在开发功能代码之前，先编写测试代码。也就是说在明确要开发某个功能后，首先思考如何对这个功能进行测试，并完成测试代码的编写，然后编写相关的代码满足这些测试用例。然后循环进行添加其他功能，直到完全部功能的开发。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</P>
<P>]]></description>
    <pubDate>Tue, 26 May 2009 11:06:32 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[TDD中的三个关键点]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2009/0526/163218.html</link>
    <description><![CDATA[&nbsp;测试驱动开发的操作非常简单。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1、编写测试代码<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2、运行<STRONG><A href="http://www.ltesting.net/html/94/category-catid-94.html" target=_blank>测试用例</A></STRONG>，发现用例不通过<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3、增加少量实现代码<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4、运行测试用例，用例通过<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5、重构 
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其中有三个比较关键的因素：测试、节奏、驱动。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target=_blank>测试驱动开发</A></STRONG>首先要讲的就是测试了。以前在一个项目中，我需要写一个带有非常复杂业务的计算类。当时对于能否写出来完全没有信心，主要是情况太复杂，分支特别多。其中涉及到表达式的解析，自定义变量的引用关系，数据的汇总计算等。这时候如果采用传统的开发方式是很难保证代码的正确性，糟糕的情况就是在后台计算类中的<STRONG><A href="http://www.ltesting.net/html/98/category-catid-98.html" target="_blank" >Bug</A></STRONG>只有在界面部分才能测试出来。后来决定采用测试驱动开发的方式，先构造用例，然后写实现代码。一方面可以从用例的角度分析这个模块的功能，更重要的另外一个方面可以确保计算类的低Bug率。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在有了测试代码的基础上，在去实现这样的<STRONG><A href="http://www.ltesting.net/html/62/category-catid-162.html" target="_blank" >需求</A></STRONG>心里是更加有底气的。并且检查复杂的程序内部逻辑比检查一个个的测试用例要复杂得多。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 重构是建立在拥有测试代码的基础上的。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 节奏确定了效率。从上面介绍的测试驱动开发的五步中可以明确地看到一种节奏感。如果使用现在流行的<STRONG><A href="http://www.ltesting.net/html/81/category-catid-481.html" target="_blank" >测试框架</A></STRONG>，如：XUnit，在运行的时候可以看到“红绿交替”的现象。（红色代表用例未通过、绿色代表用例通过）。并且上面说的五步循环的时间非常短，往往以分钟为单位衡量。<BR>有了一个好的节奏，可以有力地支撑结对编程的实践。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 结对编程的概念很容易理解：两个人共用一台计算机编写代码。但实践的时候会遇到很多问题。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 以前在做结对编程的时候出现两个人不“合拍”的情况。表现就是一个人在写代码，另外一个人在“思考”或者“发呆”。有的时候是觉得其中一个写代码写累了，再换成另外一个。或者总是一个人在写代码，另外一个在旁辅导。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TDD中有一个节奏的问题。一个任务被分解成“红条”、“绿条”的交替。结对的两个人注意力全部放在“红绿交替”上。这样可以确保两个人的步调一致，双方都知道现在我们做到了第几步。通常可以一个人<STRONG><A href="http://www.ltesting.net/html/94/category-catid-94.html" target="_blank" >编写测试用例</A></STRONG>，另外一个人实现，然后交换。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 怎样编写让对方出错的用例，怎样不让自己的代码有漏洞。开发就在这种合作、竞争的互动<STRONG><A href="http://www.ltesting.net/html/03/category-catid-103.html" target="_blank" >游戏</A></STRONG>中进行。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 体会到了测试与节奏带来的好处之后，最近发现<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target=_blank>TDD</A></STRONG>与简单设计也有着比较紧密的关系。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果能真的做到“驱动”这个效果，不编写任何一行测试用例不需要的冗余代码，在没有用例证明的情况下不做结构上的设计。这样将未做的工作最大化的艺术就是简单设计的核心。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 并不是说不需要设计，而是说设计的意图必须要有相应的用例证明。</P><BR>]]></description>
    <pubDate>Tue, 26 May 2009 10:29:08 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[使用 RSpec 进行行为驱动测试]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2009/0525/163180.html</link>
    <description><![CDATA[&nbsp;&nbsp;&nbsp; 测试热潮现在传播到了 Ruby 编程社区，并且愈演愈热。在过去一年里，测试领域中最为瞩目的创新应属 RSpec 的引入和快速发展，这是一种行为驱动<STRONG><A href="http://www.ltesting.net/html/2/category-catid-2.html" target="_blank" >测试工具</A></STRONG>。通过本文了解 RSpec 如何改变人们思考测试的方式。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在过去十年中，软件<STRONG><A href="http://www.ltesting.net/html/4/category-catid-4.html" target="_blank" >开发</A></STRONG>人员对测试的热情日渐低迷。同一时期出现的动态语言并没有提供编译程序来捕捉最基本的错误，这使得测试变得更加重要。随着测试社区的成长，开发人员开始注意到，除了捕获 bug 等最基本的优点外，测试还具有以下优势： 
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 测试能够改进您的设计。进行测试的每个目标对象必须具备至少两个客户机：生产代码和测试用例。这些客户机强制您对代码进行解耦。测试还鼓励开发人员使用更小、更简单的方法。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 测试减少了不必要的代码。在<STRONG><A href="http://www.ltesting.net/html/94/category-catid-94.html" target="_blank" >编写测试用例</A></STRONG>时，您养成了很好的测试习惯，即只编写运行测试用例所需的最少代码。您抵制住了对功能进行编码的诱惑，因为您目前还不需要它。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 推动了测试优先开发。您编写的每个<STRONG><A href="http://www.ltesting.net/html/94/category-catid-94.html" target=_blank>测试用例</A></STRONG>会确定一个小问题。使用代码解决这个问题非常有用并且可以推动开发。当我进行<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target="_blank" >测试驱动开发</A></STRONG>时，时间过得飞快。<BR>测试提供了更多的自主权。在使用测试用例捕获可能的错误时，您会发现自己非常愿意对代码进行改进。</P>
<P><BR>测试驱动的开发和 RSpec<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 有关测试的优点无需赘述，我将向您介绍一个简单的使用 RSpec 的测试驱动开发示例。RSpec 工具是一个 Ruby 软件包，可以用它构建有关您的软件的规范。该规范实际上是一个描述系统行为的测试。使用 RSpec 的开发流程如下：</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 编写一个测试。该测试描述系统中某个较小元素的行为。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 运行测试。由于尚没有为系统中的相应部分构建代码，测试失败。这一重要步骤将测试您的测试用例，检验测试用例是否在应当失败的时候失败。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 编写足够的代码，使测试通过。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 运行测试，检验测试是否成功。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 实质上，RSpec 开发人员所做的工作就是将失败的测试用例调试为成功的测试用例。这是一个主动的过程。本文中，我将介绍 RSpec 的基本用法。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 首先，假设您已安装了 Ruby 和 gems。您还需要安装 RSpec。输入下面的内容：</P>
<P>gem install rspec</P>
<P>使用示例<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 接下来，我将逐步构建一个状态机。我将遵循 <STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target=_blank>TDD</A></STRONG> 规则。首先编写自己的测试用例，并且直到测试用例需要时才编写代码。Rake 的创建者 Jim Weirich 认为这有助于角色扮演。在编写实际的生产代码时，您希望充当一回 jerk 开发人员的角色，只完成最少量的工作来使测试通过。在编写测试时，您则扮演<STRONG><A href="http://www.ltesting.net/html/73/category-catid-273.html" target="_blank" >测试人员</A></STRONG>的角色，试图为开发人员提供一些有益的帮助。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 以下的示例展示了如何构建一个状态机。如果您以前从未接触过状态机，请查阅 参考资料。状态机具有多种状态。每种状态支持可以转换状态机状态的事件。测试驱动开发入门的关键就是从零入手，尽量少地使用假设条件。针对测试进行程序设计。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用清单 1 的内容创建名为 machine_spec.rb 的文件。该文件就是您的规范。您还不了解 machine.rb 文件的作用，目前先创建一个空文件。</P>
<P>清单 1. 最初的 machine_spec.rb 文件<BR>　&nbsp;&nbsp; require 'machine'</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 接下来，需要运行测试。始终通过输入 spec machine_spec.rb 运行测试。清单 2 展示了预料之中的测试失败：</P>
<P>清单 2. 运行空的规范<BR>　</P>
<P>]]></description>
    <pubDate>Mon, 25 May 2009 10:23:07 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[TDD中的三个关键点]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2009/0525/163179.html</link>
    <description><![CDATA[&nbsp;<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target=_blank>测试驱动开发</A></STRONG>的操作非常简单。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1、编写测试代码<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2、运行<STRONG><A href="http://www.ltesting.net/html/94/category-catid-94.html" target=_blank>测试用例</A></STRONG>，发现用例不通过<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3、增加少量实现代码<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4、运行测试用例，用例通过<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5、重构 
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其中有三个比较关键的因素：测试、节奏、驱动。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 测试驱动开发首先要讲的就是测试了。以前在一个项目中，我需要写一个带有非常复杂业务的计算类。当时对于能否写出来完全没有信心，主要是情况太复杂，分支特别多。其中涉及到表达式的解析，自定义变量的引用关系，数据的汇总计算等。这时候如果采用传统的开发方式是很难保证代码的正确性，糟糕的情况就是在后台计算类中的<STRONG><A href="http://www.ltesting.net/html/98/category-catid-98.html" target="_blank" >Bug</A></STRONG>只有在界面部分才能测试出来。后来决定采用测试驱动开发的方式，先构造用例，然后写实现代码。一方面可以从用例的角度分析这个模块的功能，更重要的另外一个方面可以确保计算类的低Bug率。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在有了测试代码的基础上，在去实现这样的<STRONG><A href="http://www.ltesting.net/html/62/category-catid-162.html" target="_blank" >需求</A></STRONG>心里是更加有底气的。并且检查复杂的程序内部逻辑比检查一个个的测试用例要复杂得多。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 重构是建立在拥有测试代码的基础上的。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 节奏确定了效率。从上面介绍的测试驱动开发的五步中可以明确地看到一种节奏感。如果使用现在流行的<STRONG><A href="http://www.ltesting.net/html/81/category-catid-481.html" target="_blank" >测试框架</A></STRONG>，如：XUnit，在运行的时候可以看到“红绿交替”的现象。（红色代表用例未通过、绿色代表用例通过）。并且上面说的五步循环的时间非常短，往往以分钟为单位衡量。<BR>有了一个好的节奏，可以有力地支撑结对编程的实践。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 结对编程的概念很容易理解：两个人共用一台计算机编写代码。但实践的时候会遇到很多问题。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 以前在做结对编程的时候出现两个人不“合拍”的情况。表现就是一个人在写代码，另外一个人在“思考”或者“发呆”。有的时候是觉得其中一个写代码写累了，再换成另外一个。或者总是一个人在写代码，另外一个在旁辅导。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TDD中有一个节奏的问题。一个任务被分解成“红条”、“绿条”的交替。结对的两个人注意力全部放在“红绿交替”上。这样可以确保两个人的步调一致，双方都知道现在我们做到了第几步。通常可以一个人<STRONG><A href="http://www.ltesting.net/html/94/category-catid-94.html" target="_blank" >编写测试用例</A></STRONG>，另外一个人实现，然后交换。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 怎样编写让对方出错的用例，怎样不让自己的代码有漏洞。开发就在这种合作、竞争的互动<STRONG><A href="http://www.ltesting.net/html/03/category-catid-103.html" target="_blank" >游戏</A></STRONG>中进行。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 体会到了测试与节奏带来的好处之后，最近发现<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target=_blank>TDD</A></STRONG>与简单设计也有着比较紧密的关系。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果能真的做到“驱动”这个效果，不编写任何一行测试用例不需要的冗余代码，在没有用例证明的情况下不做结构上的设计。这样将未做的工作最大化的艺术就是简单设计的核心。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 并不是说不需要设计，而是说设计的意图必须要有相应的用例证明。</P><BR><BR>]]></description>
    <pubDate>Mon, 25 May 2009 10:21:03 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[追求代码质量: 亲身体验行为驱动开发]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2009/0522/163143.html</link>
    <description><![CDATA[&nbsp; <STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target=_blank>测试驱动的开发</A></STRONG>（TDD）在实践中是一个很好的思想，但有些开发人员还不能接受 “测试” 这个词所产生的概念上的骤变。在本文中，学习一种更自然的方法，将 TDD 元素整合到编程实践中。开始采用行为驱动开发（BDD）（通过 JBehave），亲身体验将注意力集中在程序行为（而不是输出）时获得的效果。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 显然，测试本身是件好事。而在早期进行测试 — 例如在编写代码时 — 则更有益处，这特别有利于提高代码<STRONG><A href="http://www.ltesting.net/html/5/category-catid-5.html" target="_blank" >质量</A></STRONG>。在开发早期编写测试，您将获益良多。您能够检查代码的行为，并预先对它进行调试，这种动力无疑是巨大的。 
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 即使了解了这种重要性，我们也没有达到关键的一点：使在编写代码之前 编写测试成为一种标准实践。正如 TDD 是<STRONG><A href="http://www.ltesting.net/html/68/category-catid-168.html" target="_blank" >极限编程</A></STRONG>（Extreme Programming）的下一个演化阶段（后者推出了单元<STRONG><A href="http://www.ltesting.net/html/81/category-catid-481.html" target="_blank" >测试框架</A></STRONG>），以 TDD 为基础，新的飞跃也将到来。本月，我邀请您和我一起实现从 TDD 到更具直观性的行为驱动测试（BDD）的演化。<BR>行为驱动开发</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 虽然测试优先编程对于有些人比较管用，但是并不适用于每一个人。虽然有的应用程序开发人员狂热拥护 TDD，但也有人坚决抵制它。即使现在已经有了很多测试框架，例如 <STRONG><A href="http://www.ltesting.net/ceshi/open/kydycsgj/testng/" target="_blank" >TestNG</A></STRONG>、 Selenium 和 FEST，但不对 代码进行测试的理由仍然充分。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不采用 <STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target=_blank>TDD </A></STRONG>的两个常见理由是 “没有足够的时间进行测试” 和 “代码太复杂，难以测试”。测试优先编程的另一个障碍是测试优先概念本身。很多人把测试看作一种反应型活动，仅比抽象具体一点。经验告诉我们，不能测试不存在的东西。对于某些开发人员来说，对于这种概念框架，测试优先 是一种矛盾的说法。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 但是，如果不考虑编写测试和如何测试，而是考虑行为，结果会如何呢？这里所说的行为，是指一个应用程序应该 如何运行 — 实际上就是指它的规范。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 实际上，您已经想到了这种方法。我们都想到过。请看下面的对话。</P>
<P>Frank: 什么是栈？</P>
<P>Linda: 它是一种数据结构，按先进后出（或后进先出）的方式收集对象。它通常有一个 API，其中包括 push() 和 pop() 等方法。有时也有 peek() 方法。</P>
<P>Frank: push() 有什么功能？</P>
<P>Linda: push() 接受一个输入对象，比如说 foo，并将它放入到一个内部容器（例如一个数组）中。push() 通常不返回结果。</P>
<P>Frank: 如果我 push() 两个对象，比如先是 foo，然后是 bar，结果会怎样？</P>
<P>Linda: 第二个对象 bar 应该在栈（至少包含两个对象）的顶部，所以如果调用 pop()，那么返回的应该是 bar，而不是 foo。如果再次调用 pop()，那么应该返回 foo，然后栈为空（假设在添加这两个对象之前栈中没有对象）。</P>
<P>Frank: 也就是说，pop 移除最近放入栈中的项目？</P>
<P>Linda: 是的，pop() 应该移除最上面的项目（假设栈中还有可移除的项目）。peek() 与此类似，只是不移除栈中的对象。peek() 应该保留栈顶的项目。</P>
<P>Frank: 如果之前没有 push 任何项目，那么调用 pop() 时会怎样？</P>
<P>Linda: pop() 应该抛出一个异常，表明栈中尚未 push 任何项。</P>
<P>Frank: 如果 push() null 会怎样？</P>
<P>Linda: 栈应该抛出一个异常，因为 null 不是一个有效的可 push() 的值。<BR>在这段对话中，有没有注意到什么特别的地方呢（除了 Frank 不是计算机科学专业的）？这里从头到尾没有用到 “测试” 这个词。但是，“应该” 这个词却非常自然地随处闪现。</P>
<P>怎么做才自然？</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BDD 并不是什么新生事物，更不具备什么革命性的突破。它只是 TDD 的一个分支，其中 “测试” 这个词换成了 “应该”。除了语义，很多人还发现，与测试 概念相比，应该 这个概念是一种更自然的开发驱动因素。考虑行为（应该）会自然而然地促使您先编写规范类，而后者可以成为一个非常有效的实现驱动因素。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 以 Frank 和 Linda 的对话为基础，让我们看看 BDD 如何以 TDD 希望推广的方式驱动开发。</P>
<P>]]></description>
    <pubDate>Fri, 22 May 2009 10:58:15 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>
<item>
    <title><![CDATA[(一)测试驱动开发(tdd) 学习笔记：基本思想原则和术语]]></title>
    <link>http://www.ltesting.net/ceshi/ruanjianzhiliangbaozheng/csqdkf/2009/0522/163134.html</link>
    <description><![CDATA[这几天学习了一下<STRONG><A href="http://www.ltesting.net/html/76/category-catid-176.html" target=_blank>测试驱动开发</A></STRONG>（<STRONG><A href="http://www.ltesting.net/html/11/category-catid-111.html" target="_blank" >td</A></STRONG>d） 实用指南，感觉相见恨晚，收获很大。以前也听别人说过测试驱动开发，也用过<STRONG><A href="http://www.ltesting.net/html/56/category-catid-456.html" target="_blank" >dunit</A></STRONG>,但是当时不知道具体的含义，也没有仔细研究一下，真是遗憾。 
<P>&nbsp;&nbsp; Test-Driven Development&nbsp; A Practical Guide 测试驱动开发，实用指南，作者David Astels</P>
<P>　　测试驱动开发的主要思想是 测试先行，在写一个类的具体实现之前，先写类的测试代码，类的测试代码通过调用各种public 的方法，对类进行测试。在写测试代码的过程中，思考类的调用方法，也就是类的外在表现形式。</P>
<P>　　我觉得这种做法的很大一个好处是：因为设计一个类是从它的外部形态开始的，所以设计类的时候就会自然的考虑类的封装。</P>
<P>　　测试驱动开发采用的主要方法之一是重构（refactoring）。重构两个字的字面意思，并不能涵括它的具体涵义，在tdd中重构具体指什么，下面通过一个简单的例子来说明：</P>
<P>　　我们想编写一个math 类，来实现简单的加(sum)、减(minus)运算,首先我们编写math 类的初步<STRONG><A href="http://www.ltesting.net/html/news.html" target="_blank" >测试方法</A></STRONG>。</P>
<P>public class testMath extends <STRONG><A href="http://www.ltesting.net/html/94/category-catid-94.html" target="_blank" >TestCase</A></STRONG>{</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp; public void testSum(){</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; math math1 = new math ;</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assertEquals("3加2应该等于5",5,math1.sum(3,2));</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P>}</P>
<P>然后我们编写具体的math 类</P>
<P>public class math {</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp; public int sum(int a,int b){</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 5;</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P>}</P>
<P>　　运行测试，测试通过。但是很明显，sum方法的算法是不对的，这是因为测试不够全面。我们重新修改测试</P>
<P>]]></description>
    <pubDate>Fri, 22 May 2009 10:39:04 GMT</pubDate>
    <subImagePath>http://www.ltesting.net/images/defaultpic.gif</subImagePath>
     <category>测试驱动开发</category>
    <author>秩名</author>
    <comments>领测软件测试网_专业软件测试工程师探讨软件测试技术第一门户</comments>
</item>

</channel>
</rss>
