﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>IT博客-Joinclass Inc-文章分类-软件测试</title><link>http://www.cnitblog.com/tilan/category/4242.html</link><description>软件开发 软件配置 项目管理 软件工程</description><language>zh-cn</language><lastBuildDate>Wed, 28 Sep 2011 03:57:07 GMT</lastBuildDate><pubDate>Wed, 28 Sep 2011 03:57:07 GMT</pubDate><ttl>60</ttl><item><title>每日构建采用软件的评估报告</title><link>http://www.cnitblog.com/tilan/articles/21912.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Tue, 16 Jan 2007 03:21:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/21912.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/21912.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/21912.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/21912.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/21912.html</trackback:ping><description><![CDATA[<h1 align="left">
				<font size="5">一、目的：</font>
		</h1>
		<div>选择一个符合本公司软件开发实际需求的每日构建软件，并有一定前瞻性。</div>
		<h2>二、评估项目</h2>
		<div>             1、基本功能 ：</div>
		<div>                     （1）、能调用多种版本控制软件取得代码。</div>
		<div>                     （2）、对代码进行编译，并自动管理版本号。</div>
		<div>                     （3）、对编译结果能及时并且自动反馈，编译时的任何错误都能被追踪。</div>
		<div>                     （4）、可以调用测试软件进行测试。</div>
		<div>                     （5）、构建成功完成后能作出软件“快照”，可直接供测试和发布。</div>
		<div>                     （6）、是否支持多语言编译。</div>
		<div>                     （7）、可灵活定义构建流程。</div>
		<div>              2、易用性：</div>
		<div>                            界面是否简单易用。</div>
		<div>              3、后期维护和扩展性：</div>
		<div>                     （1）、每日构建流程的创建是否简便</div>
		<div>                     （2）、项目进行中对每日构建的流程的变更是否简便。</div>
		<div>                     （3）、其他功能的支持，比如集成文件复制，删除，属性更改；压缩、ftp文件传输等。</div>
		<div>                     </div>
		<div>              4、软件费用：</div>
		<div>                     每日构建软件自身成本，以及使用和维护时产生的费用成本。</div>
		<div> </div>
		<h3>
				<font size="5">三、评估对象</font>
		</h3>
		<div>              由于时间等方面的原因，只对两个每日构建软件进行评估。</div>
		<div>       分别是FinalBuilder2和开源软件Want。</div>
		<h3>
				<font size="5">四、评估方法</font>
		</h3>
		<div>       从实际开发流程出发，从VSS取代码，进行编译和发布</div>
		<h3>
				<font size="5">五、评估结果</font>
		</h3>
		<div>       </div>
		<div>   1、针对评估项目：</div>
		<table cellspacing="0" cellpadding="0" width="569" border="0">
				<tbody>
						<tr>
								<td nowrap="" width="53">
										<div align="left">　</div>
								</td>
								<td nowrap="" width="144">
										<div align="left">　</div>
								</td>
								<td nowrap="" width="180">
										<div align="center">
												<b>FinalBuilder2</b>
										</div>
								</td>
								<td nowrap="" width="192">
										<div align="center">
												<b>Want</b>
										</div>
								</td>
								<td width="0" height="28">
								</td>
						</tr>
						<tr>
								<td nowrap="" width="53" rowspan="7">
										<div align="center">
												<b>基本功能</b>
										</div>
								</td>
								<td nowrap="" width="144">
										<div>支持多种版本控制软件</div>
								</td>
								<td nowrap="" width="180">
										<div align="left">VSS、CVS、QVCS等多种，没有的可以扩充</div>
								</td>
								<td nowrap="" width="192">
										<div align="left">不直接支持，可以改代码</div>
								</td>
								<td width="0" height="23">
								</td>
						</tr>
						<tr>
								<td nowrap="" width="144">
										<div>编译代码，生成版本号</div>
								</td>
								<td nowrap="" width="180">
										<div align="left">支持</div>
								</td>
								<td nowrap="" width="192">
										<div align="left">支持</div>
								</td>
								<td width="0" height="24">
								</td>
						</tr>
						<tr>
								<td nowrap="" width="144">
										<div>及时自动反馈编译结果</div>
								</td>
								<td nowrap="" width="180">
										<div align="left">可以通过日志、e-mail等多种方式反馈</div>
								</td>
								<td nowrap="" width="192">
										<div align="left">日志和界面</div>
								</td>
								<td width="0" height="27">
								</td>
						</tr>
						<tr>
								<td nowrap="" width="144">
										<div>支持测试软件</div>
								</td>
								<td nowrap="" width="180">
										<div align="left">支持AQTIME，可以用命令行扩充</div>
								</td>
								<td nowrap="" width="192">
										<div align="left">支持DUNIT单元测试，其余的要改代码或调用</div>
								</td>
								<td width="0" height="24">
								</td>
						</tr>
						<tr>
								<td nowrap="" width="144">
										<div>构建成功完成可直接供测试和发布</div>
								</td>
								<td nowrap="" width="180">
										<div align="left">可以通过文件复制、ftp等方式直接发布</div>
								</td>
								<td nowrap="" width="192">
										<div align="left">不直接支持，可以改代码</div>
								</td>
								<td width="0" height="30">
								</td>
						</tr>
						<tr>
								<td nowrap="" width="144">
										<div>支持多语言编译。</div>
								</td>
								<td nowrap="" width="180">
										<div align="left">支持DELPHI、JAVA、.NET等</div>
								</td>
								<td nowrap="" width="192">
										<div align="left">只支持DELPHI，但可以改代码</div>
								</td>
								<td width="0" height="23">
								</td>
						</tr>
						<tr>
								<td nowrap="" width="144">
										<div>灵活定义构建流程</div>
								</td>
								<td nowrap="" width="180">
										<div align="left">可以，并可以对构建程序编写脚本事件</div>
								</td>
								<td nowrap="" width="192">
										<div align="left">不太方便</div>
								</td>
								<td width="0" height="25">
								</td>
						</tr>
						<tr>
								<td nowrap="" width="53" rowspan="2">
										<div align="center">
												<b>易用性</b>
										</div>
								</td>
								<td nowrap="" width="144" rowspan="2">
										<div>界面是否简单易用</div>
								</td>
								<td nowrap="" width="180" rowspan="2">
										<div>是，完全GUI界面，也支持命令行</div>
								</td>
								<td nowrap="" width="192" rowspan="2">
										<div align="left">不太方便，控制台程序，配置时需编写XML文件</div>
								</td>
								<td width="0" height="21">
								</td>
						</tr>
						<tr>
								<td width="0" height="21">
								</td>
						</tr>
						<tr>
								<td nowrap="" width="53" rowspan="3">
										<div align="center">
												<b>后期维护和扩展性</b>
										</div>
								</td>
								<td nowrap="" width="144">
										<div>快速创建构建流程</div>
								</td>
								<td nowrap="" width="180">
										<div align="left">是</div>
								</td>
								<td nowrap="" width="192">
										<div align="left">需花时间熟悉，编写XML文件</div>
								</td>
								<td width="0" height="26">
								</td>
						</tr>
						<tr>
								<td nowrap="" width="144">
										<div align="left">快速变更构建的流程</div>
								</td>
								<td nowrap="" width="180">
										<div align="left">是</div>
								</td>
								<td nowrap="" width="192">
										<div align="left">需花时间熟悉，修改XML文件</div>
								</td>
								<td width="0" height="25">
								</td>
						</tr>
						<tr>
								<td nowrap="" width="144">
										<div>其他功能的支持，比如集成文件复制，删除，属性更改；压缩、ftp文件传输等。</div>
								</td>
								<td nowrap="" width="180">
										<div align="left">是</div>
								</td>
								<td nowrap="" width="192">
										<div align="left">支持压缩等，但大部分要动代码</div>
								</td>
								<td width="0" height="49">
								</td>
						</tr>
						<tr>
								<td nowrap="" width="53" rowspan="2">
										<div align="center">
												<b>软件费用：</b>
										</div>
								</td>
								<td nowrap="" width="144" rowspan="2">
										<div align="left">费用</div>
								</td>
								<td nowrap="" width="180" rowspan="2">
										<div align="left">EUR:300,后期费用少</div>
								</td>
								<td nowrap="" width="192" rowspan="2">
										<div align="left">免费，后期费用多</div>
								</td>
								<td width="0" height="21">
								</td>
						</tr>
						<tr>
								<td width="0" height="21">
								</td>
						</tr>
				</tbody>
		</table>
		<div> </div>
		<div>2、总体描述：</div>
		<div> （1）、二者在测试时都发现小BUG，由于WANT是开源软件，迅速解决问题，但FB2有新闻组支持，第二天也得到反馈。</div>
		<div>                          在SOURCEFORGE上，对WANT的BUG提交最迟是去年10月，要么是很成熟，要么是人气不足了。后者可能性更大。</div>
		<div>（2）、WANT的架构是比较灵活的，比如对多语言编译的扩充，从代码上看，是可以在其架构上进行。</div>
		<div>              而FB2的扩充只能是通过调用批文件等或版本升级来进行，但它已经提供了大多数主流语言的编译。</div>
		<div>（3）、在构建流程的配置上，WANT是通过手写XML文件配置，虽然有它附带辅助工具DOF2WANT来自动从DOF文件生成xml，但实际情况是生成的文件并不能直接或少许改动后使用，还是有比较大的工作量。单个WANT程序只能编译一个工程文件，如果是群组，必须依次调用，日后组织困难。</div>
		<div>FB2是通过图形界面配置，直观易用，流程的顺序和是否使用通过鼠标控制就可以配置，并可以方便的把多个流程组合并顺序使用。</div>
		<div>（4）、FB2还提供了一些其他功能：构建过程中人机交换功能、注册表的读写、检测磁盘剩余空间、创建虚拟驱动器，调用InstallShield，对INTERNET的访问、运行脚本（支持四种脚本语言）等功能。</div>
		<div>（5）、从每日构建的理论来说，WANT更像是每日编译，虽然它比直接写编译批文件功能强大一些。FB2相对来说是比较完善的，它的流程化更加清晰，更人性化。</div>
		<div>WANT的优势在于开源，可以不断进行完善来达到FB2的功能和便利优势，但所需人工费用很大。</div>
		<div>因此，从性价比上看，FB2对一个想通过实施每日构建来提高软件质量和管理质量的公司来说，应该是个比较好的选择。</div><img src ="http://www.cnitblog.com/tilan/aggbug/21912.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2007-01-16 11:21 <a href="http://www.cnitblog.com/tilan/articles/21912.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> 在ant中使用cvs功能自动完成每日构建</title><link>http://www.cnitblog.com/tilan/articles/21907.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Tue, 16 Jan 2007 02:58:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/21907.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/21907.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/21907.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/21907.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/21907.html</trackback:ping><description><![CDATA[<p>实现的主要功能是：自动从cvs中check out模块，然后编译，把编译后的class打成jar，再commit到cvs服务器的指定位置。 <br />build.xml <br /></p>
		<div class="code_title">代码</div>
		<div class="code_div">
				<div class="dp-highlighter">
						<div class="bar">
						</div>
						<ol class="dp-xml">
								<li class="alt">
										<span>
												<span class="tag">&lt;?</span>
												<span class="tag-name">xml</span>
												<span> </span>
												<span class="attribute">version</span>
												<span>=</span>
												<span class="attribute-value">"1.0"</span>
												<span class="tag">?&gt;</span>
												<span>  </span>
										</span>
								</li>
								<li class="">
										<span>
										</span>
										<span class="tag">&lt;</span>
										<span class="tag-name">project</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"gnt Auto build"</span>
										<span> </span>
										<span class="attribute">basedir</span>
										<span>=</span>
										<span class="attribute-value">"."</span>
										<span> </span>
										<span class="attribute">default</span>
										<span>=</span>
										<span class="attribute-value">"build"</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="comments">&lt;!-- The CVSROOT value --&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"cvsroot"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>=</span>
										<span class="attribute-value">":pserver:dhf:@192.168.0.200:D:/cvs_repository_z"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"cvs.password"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>=</span>
										<span class="attribute-value">""</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>     </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"ywzcpt.dir"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>=</span>
										<span class="attribute-value">"${basedir}/ywzcpt"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"ywzcpt.module.name"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>=</span>
										<span class="attribute-value">"ywzcpt"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>       </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"zfyw.dir"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>=</span>
										<span class="attribute-value">"${basedir}/zfyw"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"zfyw.module.name"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>=</span>
										<span class="attribute-value">"zfyw"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"external.dir"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>=</span>
										<span class="attribute-value">"${basedir}/external"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"external.module.name"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>=</span>
										<span class="attribute-value">"external"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>       </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"cvs-op"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>=</span>
										<span class="attribute-value">"co "</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="comments">&lt;!-- Initializing --&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">target</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"init"</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">tstamp</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>            </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">format</span>
										<span> </span>
										<span class="attribute">property</span>
										<span>=</span>
										<span class="attribute-value">"today"</span>
										<span> </span>
										<span class="attribute">pattern</span>
										<span>=</span>
										<span class="attribute-value">"yyyy-MM-dd hh:mm:ss"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">tstamp</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"${today}"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">target</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>       </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">target</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"prepare"</span>
										<span> </span>
										<span class="attribute">depends</span>
										<span>=</span>
										<span class="attribute-value">"init"</span>
										<span> </span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">cvspass</span>
										<span> </span>
										<span class="attribute">cvsroot</span>
										<span>=</span>
										<span class="attribute-value">"${cvsroot}"</span>
										<span> </span>
										<span class="attribute">password</span>
										<span>=</span>
										<span class="attribute-value">"${cvs.password}"</span>
										<span> </span>
										<span class="attribute">passfile</span>
										<span>=</span>
										<span class="attribute-value">"ant-cvs.cvspass"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">target</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>       </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">target</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"external-check-out"</span>
										<span> </span>
										<span class="attribute">depends</span>
										<span>=</span>
										<span class="attribute-value">"prepare"</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">cvs</span>
										<span> </span>
										<span class="attribute">cvsRoot</span>
										<span>=</span>
										<span class="attribute-value">"${cvsroot}"</span>
										<span> </span>
										<span class="attribute">package</span>
										<span>=</span>
										<span class="attribute-value">"${external.module.name}"</span>
										<span>    </span>
								</li>
								<li class="">
										<span>             </span>
										<span class="attribute">passfile</span>
										<span>=</span>
										<span class="attribute-value">"ant-cvs.cvspass"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">target</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>       </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="comments">&lt;!-- Retrieve the ywzcpt module --&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">target</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"ywzcpt-check-out"</span>
										<span> </span>
										<span class="attribute">depends</span>
										<span>=</span>
										<span class="attribute-value">"external-check-out"</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">delete</span>
										<span> </span>
										<span class="attribute">dir</span>
										<span>=</span>
										<span class="attribute-value">"${ywzcpt.module.name}"</span>
										<span class="tag">/&gt;</span>
										<span>    </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">cvs</span>
										<span> </span>
										<span class="attribute">cvsRoot</span>
										<span>=</span>
										<span class="attribute-value">"${cvsroot}"</span>
										<span> </span>
										<span class="attribute">package</span>
										<span>=</span>
										<span class="attribute-value">"${ywzcpt.module.name}"</span>
										<span>    </span>
								</li>
								<li class="alt">
										<span>             </span>
										<span class="attribute">passfile</span>
										<span>=</span>
										<span class="attribute-value">"ant-cvs.cvspass"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">target</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">target</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"zfyw-check-out"</span>
										<span> </span>
										<span class="attribute">depends</span>
										<span>=</span>
										<span class="attribute-value">"external-check-out"</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">delete</span>
										<span> </span>
										<span class="attribute">dir</span>
										<span>=</span>
										<span class="attribute-value">"${zfyw.module.name}"</span>
										<span class="tag">/&gt;</span>
										<span>    </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">cvs</span>
										<span> </span>
										<span class="attribute">cvsRoot</span>
										<span>=</span>
										<span class="attribute-value">"${cvsroot}"</span>
										<span> </span>
										<span class="attribute">package</span>
										<span>=</span>
										<span class="attribute-value">"${zfyw.module.name}"</span>
										<span>    </span>
								</li>
								<li class="alt">
										<span>             </span>
										<span class="attribute">passfile</span>
										<span>=</span>
										<span class="attribute-value">"ant-cvs.cvspass"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">target</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="comments">&lt;!-- cvs checkout --&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>       </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">target</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"check-out"</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">antcall</span>
										<span> </span>
										<span class="attribute">target</span>
										<span>=</span>
										<span class="attribute-value">"external-check-out"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">antcall</span>
										<span> </span>
										<span class="attribute">target</span>
										<span>=</span>
										<span class="attribute-value">"ywzcpt-check-out"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">antcall</span>
										<span> </span>
										<span class="attribute">target</span>
										<span>=</span>
										<span class="attribute-value">"zfyw-check-out"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">target</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>       </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="comments">&lt;!-- build XSP framework --&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">target</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"build"</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+=============================================+"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"|     Start Building GNT for compilation      |"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+=============================================+"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>           </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">antcall</span>
										<span> </span>
										<span class="attribute">target</span>
										<span>=</span>
										<span class="attribute-value">"ywzcpt-build"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>           </span>
								</li>
								<li class="">
										<span>           </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+=============================================+"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"|      End Building GNT for compilation       |"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+=============================================+"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>           </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">target</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>       </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">target</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"ywzcpt-build"</span>
										<span> </span>
										<span class="attribute">depends</span>
										<span>=</span>
										<span class="attribute-value">"ywzcpt-check-out"</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+---------------------------------------------+"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"|    Start Building ywzcpt for compilation    |"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+---------------------------------------------+"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">ant</span>
										<span> </span>
										<span class="attribute">antfile</span>
										<span>=</span>
										<span class="attribute-value">"build.xml"</span>
										<span> </span>
										<span class="attribute">dir</span>
										<span>=</span>
										<span class="attribute-value">"${ywzcpt.module.name}"</span>
										<span> </span>
										<span class="attribute">output</span>
										<span>=</span>
										<span class="attribute-value">"ywzcpt.log"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"ywzcpt.add"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>=</span>
										<span class="attribute-value">"add ./build/log/*.log ./build/*.jar ./build/*.war"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"ywzcpt.commit"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>="commit -m '${today}' ./build/log/*.log ./build/*.jar    </span>
								</li>
								<li class="">
										<span>  </span>
								</li>
								<li class="alt">
										<span>./build/*.war"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>           </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">ant</span>
										<span> </span>
										<span class="attribute">antfile</span>
										<span>=</span>
										<span class="attribute-value">"build.xml"</span>
										<span> </span>
										<span class="attribute">dir</span>
										<span>=</span>
										<span class="attribute-value">"${ywzcpt.module.name}"</span>
										<span> </span>
										<span class="attribute">target</span>
										<span>=</span>
										<span class="attribute-value">"commit-build"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>           </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+---------------------------------------------+"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+     End Building ywzcpt for compilation     |"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+---------------------------------------------+"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">target</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>       </span>
								</li>
								<li class="">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">target</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"zfyw-build"</span>
										<span> </span>
										<span class="attribute">depends</span>
										<span>=</span>
										<span class="attribute-value">"zfyw-check-out, ywzcpt-build"</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+---------------------------------------------+"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"|    Start Building ywzcpt for compilation    |"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+---------------------------------------------+"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">ant</span>
										<span> </span>
										<span class="attribute">antfile</span>
										<span>=</span>
										<span class="attribute-value">"build.xml"</span>
										<span> </span>
										<span class="attribute">dir</span>
										<span>=</span>
										<span class="attribute-value">"${zfyw.module.name}"</span>
										<span> </span>
										<span class="attribute">output</span>
										<span>=</span>
										<span class="attribute-value">"zfyw.log"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"zfyw.add"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>=</span>
										<span class="attribute-value">"add ./build/log/*.log ./build/*.jar ./build/*.war"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">property</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"zfyw.commit"</span>
										<span> </span>
										<span class="attribute">value</span>
										<span>="commit -m '${today}' ./build/log/*.log ./build/*.jar    </span>
								</li>
								<li class="alt">
										<span>  </span>
								</li>
								<li class="">
										<span>./build/*.war"</span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>           </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">ant</span>
										<span> </span>
										<span class="attribute">antfile</span>
										<span>=</span>
										<span class="attribute-value">"build.xml"</span>
										<span> </span>
										<span class="attribute">dir</span>
										<span>=</span>
										<span class="attribute-value">"${zfyw.module.name}"</span>
										<span> </span>
										<span class="attribute">target</span>
										<span>=</span>
										<span class="attribute-value">"commit-build"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>           </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+---------------------------------------------+"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+     End Building ywzcpt for compilation     |"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">echo</span>
										<span> </span>
										<span class="attribute">message</span>
										<span>=</span>
										<span class="attribute-value">"+---------------------------------------------+"</span>
										<span> </span>
										<span class="tag">/&gt;</span>
										<span>  </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">target</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>  </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">target</span>
										<span> </span>
										<span class="attribute">name</span>
										<span>=</span>
										<span class="attribute-value">"clean"</span>
										<span> </span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>        </span>
										<span class="tag">&lt;</span>
										<span class="tag-name">delete</span>
										<span> </span>
										<span class="attribute">dir</span>
										<span>=</span>
										<span class="attribute-value">"${ywzcpt.module.name}"</span>
										<span class="tag">/&gt;</span>
										<span>    </span>
								</li>
								<li class="alt">
										<span>    </span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">target</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
								<li class="">
										<span>     </span>
								</li>
								<li class="alt">
										<span>
										</span>
										<span class="tag">&lt;/</span>
										<span class="tag-name">project</span>
										<span class="tag">&gt;</span>
										<span>  </span>
								</li>
						</ol>
				</div>
		</div>
		<script><![CDATA[ender_code();]]&gt;</script>
		<br />ywzcpt/build.xml片断： <br /><div class="code_title">代码</div><div class="code_div"><div class="dp-highlighter"><div class="bar"></div><ol class="dp-xml"><li class="alt"><span><span>主要实现commit功能   </span></span></li><li class=""><span></span><span class="tag">&lt;</span><span class="tag-name">target</span><span> </span><span class="attribute">name</span><span>=</span><span class="attribute-value">"commit-build"</span><span class="tag">&gt;</span><span>  </span></li><li class="alt"><span>    </span><span class="tag">&lt;</span><span class="tag-name">cvs</span><span> </span><span class="attribute">cvsRoot</span><span>=</span><span class="attribute-value">"${cvsroot}"</span><span> </span><span class="attribute">passfile</span><span>=</span><span class="attribute-value">"${root.dir}/ant-cvs.cvspass"</span><span>  </span></li><li class=""><span>         </span><span class="attribute">command</span><span>=</span><span class="attribute-value">"${ywzcpt.add}"</span><span class="tag">/&gt;</span><span>  </span></li><li class="alt"><span>    </span><span class="tag">&lt;</span><span class="tag-name">cvs</span><span> </span><span class="attribute">cvsRoot</span><span>=</span><span class="attribute-value">"${cvsroot}"</span><span> </span><span class="attribute">passfile</span><span>=</span><span class="attribute-value">"${root.dir}/ant-cvs.cvspass"</span><span>  </span></li><li class=""><span>         </span><span class="attribute">command</span><span>=</span><span class="attribute-value">"${ywzcpt.commit}"</span><span class="tag">/&gt;</span><span>  </span></li><li class="alt"><span></span><span class="tag">&lt;/</span><span class="tag-name">target</span><span class="tag">&gt;</span><span>  </span></li></ol></div></div><script><![CDATA[ender_code();]]&gt;</script><br />最后，在win2k中制定一个计划任务，就可以了。


<script type="text/javascript"><!--
google_ad_client = "pub-3874079075380071";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
//2007-03-19: 3G-move, 三星, 摩托罗拉, 索爱, 诺基亚
google_ad_channel = "1730597762+1709572468+0778807001+6838187825+8377398382";
//--></script><script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script><img src ="http://www.cnitblog.com/tilan/aggbug/21907.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2007-01-16 10:58 <a href="http://www.cnitblog.com/tilan/articles/21907.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>软件工程</title><link>http://www.cnitblog.com/tilan/articles/21893.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Mon, 15 Jan 2007 15:03:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/21893.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/21893.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/21893.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/21893.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/21893.html</trackback:ping><description><![CDATA[<font face="Verdana"> </font>
		<a href="http://www.itisedu.com/phrase/200602281725525.html" target="_new">
				<font face="Verdana">软件工程</font>
		</a>
		<font face="Verdana">(</font>
		<a href="http://www.itisedu.com/phrase/200604240910235.html" target="_new">
				<font face="Verdana">Software Engineering</font>
		</a>
		<font face="Verdana">，简称为SE)是一门研究用工程化方法构建和维护有效的、实用的和高质量的</font>
		<a href="http://www.itisedu.com/phrase/200604232134205.html" target="_new">
				<font face="Verdana">软件</font>
		</a>
		<font face="Verdana">的学科。它涉及到</font>
		<a href="http://www.itisedu.com/phrase/200602281700255.html" target="_new">
				<font face="Verdana">程序设计语言</font>
		</a>
		<font face="Verdana">，</font>
		<a href="http://www.itisedu.com/phrase/200602271218062.html" target="_new">
				<font face="Verdana">数据库</font>
		</a>
		<font face="Verdana">，</font>
		<a href="http://www.itisedu.com/phrase/200603282233345.html" target="_new">
				<font face="Verdana">软件开发</font>
		</a>
		<font face="Verdana">工具，系统平台，标准，</font>
		<a href="http://www.itisedu.com/phrase/200603061631585.html" target="_new">
				<font face="Verdana">设计模式</font>
		</a>
		<font face="Verdana">等方面。</font>
		<p>
				<font face="Verdana">      在现代社会中，软件应用于多个方面。典型的软件比如有电子邮件，</font>
				<a href="http://www.itisedu.com/phrase/200603112246585.html" target="_new">
						<font face="Verdana">嵌入式系统</font>
				</a>
				<font face="Verdana">，人机界面，办公套件，</font>
				<a href="http://www.itisedu.com/phrase/200602281634075.html" target="_new">
						<font face="Verdana">操作系统</font>
				</a>
				<font face="Verdana">，编译器，数据库，游戏等。同时，各个行业几乎都有</font>
				<a href="http://www.itisedu.com/phrase/200602281627065.html" target="_new">
						<font face="Verdana">计算机软件</font>
				</a>
				<font face="Verdana">的应用，比如工业，农业，银行，航空，政府部门等。这些应用促进了经济和社会的发展，使得人们的工作更加高效，同时提高了生活质量。</font>
		</p>
		<p>
				<font face="Verdana">      软件工程师是对应用软件创造软件的人们的统称，软件工程师按照所处的领域不同可以分为系统分析员，软件设计师，系统<a href="http://www.itisedu.com/phrase/200604231335565.html" target="_new">架构师</a>，<a href="http://www.itisedu.com/phrase/200604232224305.html" target="_new">程序</a>员，测试员等等。人们也常常用程序员来泛指各种软件工程师。</font>
		</p>
		<p>
				<font face="Verdana">     软件工程(SoftWare Engineering)的<a href="http://www.itisedu.com/phrase/200603061723295.html" target="_new">框架</a>可概括为：目标、过程和原则。</font>
		</p>
		<p>
				<font face="Verdana">     (1)软件工程目标：生产具有正确性、可用性以及开销合宜的产品。正确性指软件产品达到预期功能的程度。可用性指软件基本结构、实现及文档为用户可用的程度。开销合宜是指软件开发、运行的整个开销满足用户要求的程度。这些目标的实现不论在理论上还是在实践中均存在很多待解决的问题，它们形成了对过程、过程模型及工程方法选取的约束。</font>
		</p>
		<p>
				<font face="Verdana">     (2)软件工程过程：生产一个最终能满足<a href="http://www.itisedu.com/phrase/200603101518295.html" target="_new">需求</a>且达到工程目标的软件产品所需要的步骤。软件工程过程主要包括开发过程、运作过程、维护过程。它们覆盖了需求、设计、实现、确认以及维护等活动。需求活动包括问题分析和<a href="http://www.itisedu.com/phrase/200603062220345.html" target="_new">需求分析</a>。问题分析获取需求定义，又称<a href="http://www.itisedu.com/phrase/200603061756235.html" target="_new">软件需求</a>规约。需求分析生成功能规约。设计活动一般包括概要设计和详细设计。概要设计建立整个<a href="http://www.itisedu.com/phrase/200602281706245.html" target="_new">软件系统</a>结构，包括<a href="http://www.itisedu.com/phrase/200604161433025.html" target="_new">子系统</a>、模块以及相关层次的说明、每一模块的接口定义。详细设计产生程序员可用的模块说明，包括每一模块中数据结构说明及加工描述。实现活动把设计结果转换为可执行的程序代码。确认活动贯穿于整个开发过程，实现完成后的确认，保证最终产品满足用户的要求。维护活动包括使用过程中的扩充、修改与完善。伴随以上过程，还有管理过程、支持过程、培训过程等。</font>
		</p>
		<p>
				<font face="Verdana">      (3)软件工程的原则是指围绕工程设计、工程支持以及工程管理在软件开发过程中必须遵循的原则。</font>
		</p>
		<p>
				<font face="Verdana">
						<strong>一、软件工程概述</strong>
				</font>
		</p>
		<p>
				<font face="Verdana">      概念：应需而生</font>
		</p>
		<p>
				<font face="Verdana">　　软件工程是一<a href="http://www.itisedu.com/phrase/200603090857555.html" target="_new">类</a>工程。工程是将理论和知识应用于实践的科学。就软件工程而言，它借鉴了传统工程的原则和方法，以求高效地开发高质量软件。其中应用了<a href="http://www.itisedu.com/phrase/200603021438435.html" target="_new">计算机</a>科学、数学和管理科学。计算机科学和数学用于构造模型与算法，工程科学用于制定规范、设计范型、评估成本及确定权衡，管理科学用于计划、资源、质量和成本的管理。</font>
		</p>
		<p>
				<font face="Verdana">      软件工程这一概念，主要是针对20世纪60年代“<a href="http://www.itisedu.com/phrase/200603112323405.html" target="_new">软件危机</a>”而提出的。它首次出现在1968年NATO（北大西洋公约组织）会议上。自这一概念提出以来，围绕软件项目，开展了有关开发模型、方法以及支持工具的研究。其主要成果有：提出了瀑布模型，开发了一些结构化<a href="http://www.itisedu.com/phrase/200602281641255.html" target="_new">程序设计</a>语言（例如PASCAL语言，Ada语言）、<a href="http://www.itisedu.com/phrase/200602281749185.html" target="_new">结构化方法</a>等。并且围绕<a href="http://www.itisedu.com/phrase/200604240825565.html" target="_new">项目管理</a>提出了费用估算、文档<a href="http://www.itisedu.com/phrase/200604161505135.html" target="_new">复审</a>等方法和工具。综观60年代末至80年代初，其主要特征是，前期着重研究系统实现技术，后期开始强调开发管理和软件质量。</font>
		</p>
		<p>
				<font face="Verdana">      70年代初，自“<a href="http://www.itisedu.com/phrase/200603061612405.html" target="_new">软件工厂</a>”这一概念提出以来，主要围绕<a href="http://www.itisedu.com/phrase/200602282140185.html" target="_new">软件过程</a>以及<a href="http://www.itisedu.com/phrase/200602281831545.html" target="_new">软件复用</a>，开展了有关软件生产技术和软件生产管理的研究与实践。其主要成果有：提出了应用广泛的<a href="http://www.itisedu.com/phrase/200603010948085.html" target="_new">面向对象语言</a>以及相关的<a href="http://www.itisedu.com/phrase/200602281513385.html" target="_new">面向对象方法</a>，大力开展了计算机辅助软件工程的研究与实践。尤其是近几年来，针对软件复用及软件生产，软件<a href="http://www.itisedu.com/phrase/200604161439595.html" target="_new">构件</a>技术以及软件质量控制技术、质量保证技术得到了广泛的应用。目前各个软件企业都十分重视资质认证，并想通过这些工作进行企业管理和技术的提升。软件工程所涉及的要素可概括如下： </font>
		</p>
		<p>
				<font face="Verdana">      根据这一框架，可以看出：软件工程涉及了软件工程的目标、软件工程原则和软件工程活动。</font>
		</p>
		<p>
				<font face="Verdana">      目标：我的眼里只有“产品”</font>
		</p>
		<p>
				<font face="Verdana">      软件工程的主要目标是：生产具有正确性、可用性以及开销合宜的产品。正确性意指软件产品达到预期功能的程度。可用性指软件基本结构、实现及文档为用户可用的程度。开销合宜性是指软件开发、运行的整个开销满足用户要求的程度。这些目标的实现不论在理论上还是在实践中均存在很多问题有待解决，它们形成了对过程、过程模型及工程方法选取的约束。</font>
		</p>
		<p>
				<font face="Verdana">      软件工程活动是“生产一个最终满足需求且达到工程目标的软件产品所需要的步骤”。主要包括需求、设计、实现、确认以及支持等活动。需求活动包括问题分析和需求分析。问题分析获取需求定义，又称软件需求规约。需求分析生成功能规约。设计活动一般包括概要设计和详细设计。概要设计建立整个<a href="http://www.itisedu.com/phrase/200603131358465.html" target="_new">软件体系结构</a>，包括子系统、模块以及相关层次的说明、每一模块接口定义。详细设计产生程序员可用的模块说明，包括每一模块中数据结构说明及加工描述。实现活动把设计结果转换为可执行的程序代码。确认活动贯穿于整个开发过程，实现完成后的确认，保证最终产品满足用户的要求。支持活动包括修改和完善。伴随以上活动，还有管理过程、支持过程、培训过程等。 </font>
		</p>
		<p>
				<font face="Verdana">      框架：四项基本原则是基石 </font>
		</p>
		<p>
				<font face="Verdana">　　软件工程围绕工程设计、工程支持以及工程管理，提出了以下四项基本原则：</font>
		</p>
		<p>
				<font face="Verdana">      第一，选取适宜开发范型。该原则与系统设计有关。在系统设计中，软件需求、硬件需求以及其他因素之间是相互制约、相互影响的，经常需要权衡。因此，必须认识需求定义的易变性，采用适宜的开发范型予以控制，以保证软件产品满足用户的要求。</font>
		</p>
		<p>
				<font face="Verdana">      第二，采用合适的设计方法。在软件设计中，通常要考虑软件的模块化、抽象与信息隐蔽、局部化、一致性以及适应性等特征。合适的设计方法有助于这些特征的实现，以达到软件工程的目标。</font>
		</p>
		<p>
				<font face="Verdana">      第三，提供高质量的工程支持。“工欲善其事，必先利其器”。在软件工程中，<a href="http://www.itisedu.com/phrase/200602282117345.html" target="_new">软件工具</a>与环境对软件过程的支持颇为重要。软件工程项目的质量与开销直接取决于对软件工程所提供的支撑质量和效用。</font>
		</p>
		<p>
				<font face="Verdana">      第四，重视开发过程的管理。软件工程的管理，直接影响可用资源的有效利用，生产满足目标的软件产品，提高软件组织的生产能力等问题。因此，仅当软件过程得以有效管理时，才能实现有效的软件工程。</font>
		</p>
		<p>
				<font face="Verdana">      这一软件工程框架告诉我们，软件工程的目标是可用性、正确性和合算性；实施一个软件工程要选取适宜的开发范型，要采用合适的设计方法，要提供高质量的工程支撑，要实行开发过程的有效管理；软件工程活动主要包括需求、设计、实现、确认和支持等活动，每一活动可根据特定的软件工程，采用合适的开发范型、设计方法、支持过程以及过程管理。根据软件工程这一框架，软件工程学科的研究内容主要包括：软件开发范型、软件开发方法、软件过程、软件工具、<a href="http://www.itisedu.com/phrase/200602282250045.html" target="_new">软件开发环境</a>、计算机辅助软件工程(CASE) 及软件经济学等。 </font>
		</p>
		<p>
				<font face="Verdana">      作用：高效开发高质量软件 </font>
		</p>
		<p>
				<font face="Verdana">　　自从软件工程概念提出以来，经过30多年的研究与实践,虽然“软件危机”没得到彻底解决，但在软件开发方法和技术方面已经有了很大的进步。尤其应该指出的是，自80年代中期，美国工业界和政府部门开始认识到，在软件开发中，最关键的问题是软件开发组织不能很好地定义和管理其软件过程，从而使一些好的开发方法和技术都起不到所期望的作用。也就是说，在没有很好定义和管理软件过程的软件开发中，开发组织不可能在好的软件方法和工具中获益。</font>
		</p>
		<p>
				<font face="Verdana">      根据调查，中国的现状几乎和美国10多年前的情况一样，软件开发过程没有明确规定，文档不完整，也不规范，软件项目的成功往往归功于软件开发组的一些杰出个人或小组的努力。这种依赖于个别人员上的成功并不能为全组织的软件生产率和质量的提高奠定有效的基础，只有通过建立全组织的过程改善，采用严格的软件工程方法和管理，并且坚持不懈地付诸实践，才能取得全组织的软件过程能力的不断提高。</font>
		</p>
		<p>
				<font face="Verdana">      这一事实告诉我们，只有坚持软件工程的四条基本原则，既重视软件技术的应用，又重视软件工程的支持和管理，并在实践中贯彻实施，才能高效地开发出高质量的软件。 </font>
		</p>
		<p>
				<font face="Verdana">
						<strong>二、软件工程的七条基本原理</strong>
				</font>
		</p>
		<p>
				<font face="Verdana">      自从1968年提出“软件工程”这一术语以来，研究软件工程的专家学者们陆续 提出了100多条关于软件工程的准则或信条。 美国著名的软件工程专家 Boehm 综合这些专家的意见，并总结了TRW公司多年的开发软件的经验，于1983年提出了软件工程的七条基本原理。 </font>
		</p>
		<p>
				<font face="Verdana">　　Boehm 认为，着七条原理是确保软件产品质量和开发效率的原理的最小集合。 <br />　　它们是相互独立的，是缺一不可的最小集合；同时，它们又是相当完备的。 </font>
		</p>
		<p>
				<font face="Verdana">　　人们当然不能用数学方法严格证明它们是一个完备的集合，但是可以证明，在此之前已经提出的100多条软件工程准则都可以有这七条原理的任意组合蕴含或派生。 </font>
		</p>
		<p>
				<font face="Verdana">　　下面简要介绍软件工程的七条原理： </font>
		</p>
		<p>
				<font face="Verdana">　　1 用分阶段的生命周期计划严格管理 <br />　　这一条是吸取前人的教训而提出来的。统计表明，50%以上的失败项目是由于计划不周而造成的。在软件开发与维护的漫长生命周期中，需要完成许多性质各异的工作。这条原理意味着，应该把<a href="http://www.itisedu.com/phrase/200603061230195.html" target="_new">软件生命周期</a>分成若干阶段，并相应制定出切实可行的计划，然后严格按照计划对软件的开发和维护进行管理。 Boehm 认为，在整个软件生命周期中应指定并严格执行6类计划：项目概要计划、里程碑计划、项目控制计划、产品控制计划、验证计划、运行维护计划。 </font>
		</p>
		<p>
				<font face="Verdana">　　2 坚持进行阶段评审 <br />　　统计结果显示： 大部分错误是在编码之前造成的，大约占63%; &lt;2&gt; 错误发现的越晚，改正它要付出的代价就越大，要差2到3个数量级。 因此，软件的质量保证工作不能等到编码结束之后再进行，应坚持进行严格的阶段评审，以便尽早发现错误。 </font>
		</p>
		<p>
				<font face="Verdana">　　3 实行严格的产品控制 <br />　　开发人员最痛恨的事情之一就是改动需求。但是实践告诉我们，需求的改动往往是不可避免的。这就要求我们要采用科学的产品控制技术来顺应这种要求。也就是要采用变动控制，又叫基准<a href="http://www.itisedu.com/phrase/200602271137552.html" target="_new">配置管理</a>。当需求变动时，其它各个阶段的文档或代码随之相应变动，以保证软件的一致性。 </font>
		</p>
		<p>
				<font face="Verdana">　　4 采纳现代程序设计技术 <br />　　从六、七时年代的结构化软件开发技术，到最近的<a href="http://www.itisedu.com/phrase/200603101726185.html" target="_new">面向对象</a>技术，从第一、第二代语言，到第四代语言，人们已经充分认识到：方法大似气力。采用先进的技术即可以提高软件开发的效率，又可以减少软件维护的成本。 </font>
		</p>
		<p>
				<font face="Verdana">　　5 结果应能清楚地审查 <br />　　软件是一种看不见、摸不着的逻辑产品。软件开发小组的工作进展情况可见性差，难于评价和管理。为更好地进行管理，应根据软件开发的总目标及完成期限， 尽量明确地规定开发小组的责任和产品标准，从而使所得到的标准能清楚地审查。 </font>
		</p>
		<font face="Verdana">
				<p>
						<br />　　6 开发小组的人员应少而精 <br />　　开发人员的素质和数量是影响软件质量和开发效率的重要因素，应该少而精。 <br />　　这一条基于两点原因：高素质开发人员的效率比低素质开发人员的效率要高几倍到几十倍，开发工作中犯的错误也要少的多； 当开发小组为N人时，可能的通讯信道为N(N-1)/2, 可见随着人数N的增大，通讯开销将急剧增大。 </p>
				<p>　　7 承认不断改进软件工程实践的必要性 <br />　　遵从上述六条基本原理，就能够较好地实现软件的工程化生产。但是，它们只是对现有的经验的总结和归纳，并不能保证赶上技术不断前进发展的步伐。因此，Boehm提出应把承认不断改进软件工程实践的必要性作为软件工程的第七条原理。根据这条原理，不仅要积极采纳新的软件开发技术，还要注意不断总结经验，收集进度和消耗等数据，进行出错<a href="http://www.itisedu.com/phrase/200603051002565.html" target="_new">类型</a>和问题报告统计。这些数据既可以用来评估新的 软件技术的效果，也可以用来指明必须着重注意的问题和应该优先进行研究的工具和技术。 </p>
				<p>      面向方面的编程（Aspect Oriented <a href="http://www.itisedu.com/phrase/200604232129205.html" target="_new">Programming</a>，简称<a href="http://www.itisedu.com/phrase/200604231341385.html" target="_new">AOP</a>）被认为是近年来软件工程的另外一个重要发展。这里的方面指的是完成一个功能的<a href="http://www.itisedu.com/phrase/200603090845215.html" target="_new">对象</a>和函数的集合。在这一方面相关的内容有泛型编程（Generic Programming）和模板。</p>
				<p>参考<br />      胡崑山，《中国软件产业发展现状与人才需求》，2003年9月1日，            http://software.ccidnet.com/pub/article/c372_a62973_p1.html </p>
				<p>
						<font face="Verdana">
								<strong>三、软件工程的目标与常用模型</strong>
						</font>
				</p>
				<p>
						<font face="Verdana">      软件工程的目标是提高软件的质量与生产率，最终实现软件的工业化生产。质量是软件需求方最关心的问题，用户即使不图物美价廉，也要求个货真价实。生产率是软件供应方最关心的问题，老板和员工都想用更少的时间挣更多的钱。质量与生产率之间有着内在的联系，高生产率必须以质量合格为前提。如果质量不合格，对供需双方都是坏事情。从短期效益看，追求高质量会延长软件开发时间并且增大费用，似乎降低了生产率。从长期效益看，高质量将保证软件开发的全过程更加规范流畅，大大降低了软件的维护代价，实质上是提高了生产率，同时可获得很好的信誉。质量与生产率之间不存在根本的对立，好的软件工程方法可以同时提高质量与生产率。 </font>
				</p>
				<p>
						<font face="Verdana">      软件供需双方的代表能在餐桌上谈笑风生，归功于第一线开发人员的辛勤工作。质量与生产率的提高就指望程序员与程序经理。对开发人员而言，如果非得在质量与生产率之间分个主次不可，那么应该是质量第一，生产率第二。这是因为：（1）质量直接体现在软件的每段程序中，高质量自然是开发人员的技术追求，也是职业道德的要求。（2）高质量对所有的用户都有价值，而高生产率只对开发方有意义。（3）如果一开始就追求高生产率，容易使人急功近利，留下隐患。宁可进度慢些，也要保证每个环节的质量，以图长远利益。 </font>
				</p>
				<p>
						<font face="Verdana">      软件的质量因素很多，如正确性，性能、可靠性、容错性、易用性、灵活性、可扩充性、可理解性、可维护性等等。有些因素相互重叠，有些则相抵触，真要提高质量可不容易啊！ </font>
				</p>
				<p>
						<font face="Verdana">      软件工程的主要环节有：人员管理、项目管理、可行性与需求分析、系统设计、程序设计、测试、维护等，如图1.1所示。 </font>
				</p>
				<p align="center">
						<img src="http://www.itisedu.com/manage/Upload/image/200632922318332.gif" border="0" />
				</p>
				<p>
						<font face="Verdana">      软件工程模型建议用一定的流程将各个环节连接起来，并可用规范的方式操作全过程，如同工厂的生产线。常见的软件工程模型有：线性模型（图1.2），渐增式模型（图1.3），螺旋模型，快速原型模型，形式化描述模型等等 [Pressmam 1999, Sommerville 1992]。 </font>
				</p>
				<font face="Verdana">
						<p align="center">
								<img src="http://www.itisedu.com/manage/Upload/image/2006329223120904.gif" border="0" />
								<br />  </p>
				</font>
				<p>
						<font face="Verdana">      最早出现的软件工程模型是线性模型（又称瀑布模型）。线性模型太理想化，太单纯，已不再适合现代的软件开发<a href="http://www.itisedu.com/phrase/200603061709535.html" target="_new">模式</a>，几乎被业界抛弃。偶而被人提起，都属于被贬对象，未被留一丝惋惜。但我们应该认识到，“线性”是人们最容易掌握并能熟练应用的思想方法。当人们碰到一个复杂的“非线性”问题时，总是千方百计地将其分解或转化为一系列简单的线性问题，然后逐个解决。一个软件系统的整体可能是复杂的，而单个子程序总是简单的，可以用线性的方式来实现，否则干活就太累了。线性是一种简洁，简洁就是美。当我们领会了线性的精神，就不要再呆板地套用线性模型的外表，而应该用活它。例如渐增式模型实质就是分段的线性模型，如图1.3所示。螺旋模型则是接连的弯曲了的线性模型。在其它模型中都能够找到线性模型的影子。 </font>
				</p>
				<p>
						<font face="Verdana">      套用固定的模型不是程序员的聪明之举。比如“程序设计”与“测试”之间的关系，习惯上总以为程序设计在先，测试在后，如图1.4（a）所示。而对于一些复杂的程序，将测试分为同步测试与总测试更有效，如图1.4（b）所示。 </font>
				</p>
				<p align="center">
						<img src="http://www.itisedu.com/manage/Upload/image/2006329223139948.gif" border="0" />
				</p>
				<font face="Verdana">
						<p>
								<br />      不论是什么软件工程模型，总是少不了图1.1中的各个环节。本书擗开具体的软件工程模型，顺序讲述人员管理、项目管理、可行性与需求分析、系统设计、程序设计、测试，以及维护与再生工程。其中程序设计部分以C++/C语言为例。 </p>
				</font>
				<p>
				</p>
		</font>
		<font face="Verdana">
				<strong>四、软件<a href="http://www.itisedu.com/phrase/200603122156385.html" target="_new">体系结构</a>和工具的选择</strong>
		</font>
		<p>
				<font face="Verdana">　　软件体系结构表示了一个软件系统的高层结构，主要特点有：1）软件系统结构是一个高层次上的抽象，它并不涉及具体的系统结构（比如<a href="http://www.itisedu.com/phrase/200604291152445.html" target="_new">B/S</a>还是<a href="http://www.itisedu.com/phrase/200604291148225.html" target="_new">C/S</a>），也不关心具体的实现。2）软件体系结构必须支持系统所要求的功能，在设计软件体系结构的时候，必须考虑系统的动态行为。3）在设计软件体系结构的时候，必须考虑有现有系统的兼容性、安全性和可靠性。同时还要考虑系统以后的扩展性和伸缩性。所以有时候必须在多个不同方向的目标中进行决策。</font>
		</p>
		<p>
				<font face="Verdana">　　当前已经有一些关于规范化软件体系结构，比如：ISO的开放系统互联模型、X Window系统等等。软件系统的结构通常被定义为两个部分：一个是计算部件。另一个就是部件之间的交互。如果把软件系统看成一幅图的话，计算部件就是其中的节点，而部件之间的交互就是节点之间的弧线。部件之间的连接可以被认为是一种连接器，比如过程调用、事件广播、数据库查询等等。正确的体系结构设计是软件系统成功的关键。</font>
		</p>
		<p>
				<font face="Verdana">　　我们理解了软件工程的重要性以后，我们没有相应的工具，我们也很难很好的完成一个系统。在需求分析和设计阶段，我们需要什么样的工具呢？</font>
		</p>
		<p>
				<font face="Verdana">　　当然最好是基于<a href="http://www.itisedu.com/phrase/200602271429302.html" target="_new">UML</a>的CASE工具。当前比较流行的就是Rose，它是一个很好的分析和建立对象和对象关系的工具。在具体编码的时候，我们需要<a href="http://www.itisedu.com/phrase/200603292355295.html" target="_new">版本控制</a>工具，MS的SourceSafe就是一个很好的版本管理工具和项目管理工具。具体的开发工具当然很多，但是如果你是一个对VC侵淫了多年的程序员，你一定会选择它，因为它会让你感到什么是真正的面向对象的编程，而你在用VB，<a href="http://www.itisedu.com/phrase/200604041117205.html" target="_new">PowerBuilder</a>，<a href="http://www.itisedu.com/phrase/200604042241255.html" target="_new">Delphi</a>时很少会有同样的感受。至于数据库模式构建，我一向是采用<a href="http://www.itisedu.com/phrase/200604040934365.html" target="_new">Sybase</a>的S-Design，更好的工具就不知道了。</font>
		</p>
		<p>
				<font face="Verdana">　　另外需要注意的是，我们需要建立文档编写的若干模板，以便开发人员按照这个模板编写规范的技术和说明文档。帮助文档可以用微软的HTML Help Workshop(hhw.exe)制作，你也可以编译成.chm格式，它打包了文本和图形，只有一个<a href="http://www.itisedu.com/phrase/200602282323195.html" target="_new">文件</a>，使用和分发比较方便。最后，如果开发人员不是集中在一个地方的话，最好建立一个邮件列表，开发人员可以通过邮件系统讨论开发中的各项事宜。 </font>
		</p>
		<p>
				<font face="Verdana">
						<strong>五、软件开发方法综述</strong>
				</font>
		</p>
		<font face="Verdana">
				<p>
						<br />　　国外大的软件公司和机构一直在研究软件开发方法这个概念性的东西，而且也提出了很多实际的开发方法，比如：生命周期法、原型化方法、面向对象方法等等。下面介绍几种流行的开发方法：</p>
				<p>　　1、结构化方法 </p>
				<p>　　结构化开发方法是由E.Yourdon 和 L.L.Constantine 提出的，即所谓的SASD 方 法， 也可称为面向功能的软件开发方法或面向数据流的软件开发方法。Yourdon方法是80年代 使用最广泛的软件开发方法。它首先用结构化分析（SA）对软件进行需求分析，然后用结构化设计（SD）方法进行总体设计，最后是结构化编程（SP）。它给出了两类典型的<a href="http://www.itisedu.com/phrase/200602282202575.html" target="_new">软件结构</a>（变换型和事务型）使软件开发的成功率大大提高。 </p>
				<p>　　2、面向数据结构的软件开发方法 </p>
				<p>　　Jackson方法是最典型的面向数据结构的软件开发方法，Jackson方法把问题分解为可由三种基本结构形式表示的各部分的层次结构。三种基本的结构形式就是顺序、选择和重复。三种数据结构可以进行组合，形成复杂的结构体系。这一方法从目标系统的输入、输出数据结构入手，导出程序框架结构，再补充其它细节，就可得到完整的程序结构图。这一方法对输入、输出数据结构明确的中小型系统特别有效，如商业应用中的文件表格处理。该方法也可与其它方法结合，用于模块的详细设计。</p>
				<p>　　3、 面向问题的分析法 </p>
				<p>　　PAM（Problem Analysis Method）是80年代末由日立公司提出的一种软件开发方法。 它的基本思想是考虑到输入、输出数据结构，指导系统的分解，在系统分析指导下逐步综 合。这一方法的具体步骤是：从输入、输出数据结构导出基本处理框；分析这些处理框之间的先后关系；按先后关系逐步综合处理框，直到画出整个系统的PAD图。这一方法本质上是综合的自底向上的方法，但在逐步综合之前已进行了有目的的分解，这个目的就是充分考虑系统的输入、输出数据结构。PAM方法的另一个优点是使用PAD图。这是一种二维树形结构图，是到目前为止最好的详细设计表示方法之一。当然由于在输入、输出数据结构与整个系统之间同样存在着鸿沟，这一方法仍只适用于中小型问题。</p>
				<p>　　4、原型化方法</p>
				<p>　　产生原型化方法的原因很多，主要随着我们系统开发经验的增多，我们也发现并非所有的需求都能够预先定义而且反复修改是不可避免的。当然能够采用原型化方法是因为开发工具的快速发展，比如用VB，DELPHI等工具我们可以迅速的开发出一个可以让用户看的见、摸的着的系统框架，这样，对于计算机不是很熟悉的用户就可以根据这个样板提出自己的需求。</p>
				<p>　　开发原型化系统一般由以下几个阶段：<br />（1） 确定用户需求<br />（2） 开发原始模型<br />（3） 征求用户对初始原型的改进意见<br />（4） 修改原型。</p>
				<p>　　原型化开发比较适合于用户需求不清、业务理论不确定、需求经常变化的情况。当系统规模不是很大也不太复杂时采用该方法是比较好的。</p>
				<p>　5、面向对象的软件开发方法</p>
				<p>　　当前计算机业界最流行的几个单词就是分布式、并行和面向对象这几个术语。由此可以看到面向对象这个概念在当前计算机业界的地位。比如当前流行的两大面向对象技术<a href="http://www.itisedu.com/phrase/200604152041495.html" target="_new">DCOM</a>和<a href="http://www.itisedu.com/phrase/200604031336425.html" target="_new">CORBA</a>就是例子。当然我们实际用到的还是面向对象的编程语言，比如C++。不可否认，面向对象技术是软件技术的一次革命，在软件开发史上具有里程碑的意义。 </p>
				<p>　　随着<a href="http://www.itisedu.com/phrase/200604240956125.html" target="_new">OOP</a>（<a href="http://www.itisedu.com/phrase/200603050951565.html" target="_new">面向对象编程</a>）向<a href="http://www.itisedu.com/phrase/200604231256315.html" target="_new">OOD</a>（<a href="http://www.itisedu.com/phrase/200603050045535.html" target="_new">面向对象设计</a>）和<a href="http://www.itisedu.com/phrase/200603050028345.html" target="_new">OOA</a>（<a href="http://www.itisedu.com/phrase/200604231254345.html" target="_new">面向对象分析</a>）的发展，最终形成面向对象的软件开发方法OMT (<a href="http://www.itisedu.com/phrase/200604231338435.html" target="_new">Object</a> Modeling Technique）。这是一种自底向上和自顶向下相结合的方法，而且它以对象建模为基础，从而不仅考虑了输入、输出数据结构，实际上也包含了所有对象的数据结构。所以OMT彻底实现了PAM没有完全实现的目标。不仅如此，<a href="http://www.itisedu.com/phrase/200604231401365.html" target="_new">OO</a>技术在需求分析、可维护性和可靠性这三个软件开发的关键环节和质量指标上有了实质性的突破，基本地解决了在这些方面存在的严重问题。</p>
				<p>　　综上所述，面向对象系统采用了自底向上的归纳、自顶向下的分解的方法，它通过对对象模型的建立，能够真正建立基于用户的需求，而且系统的可维护性大大改善。当前业界关于面向对象建模的标准是UML（<a href="http://www.itisedu.com/phrase/200604231301515.html" target="_new">Unified Modeling Language</a>）。</p>
				<p>　　这里我们需要谈一下微软的<a href="http://www.itisedu.com/phrase/200604231607095.html" target="_new">MSF</a>（Microsoft Solutions <a href="http://www.itisedu.com/phrase/200604241001145.html" target="_new">Framework</a>）的框架，它简单的把系统设计分成三个阶段：概念设计、逻辑设计和物理设计。概念设计阶段就是从用户的角度出发可以得到多少个对象，并且以对象为主体，画出业务框架。逻辑设计阶段就是对概念设计阶段的对象进行再分析、细分、整合、删除。并建立各个对象的方法属性以及对象之间的关系。而物理设计实际上就是要确定我们实际需要的<a href="http://www.itisedu.com/phrase/200603302222545.html" target="_new">组件</a>、服务和采用的框架结构、具体的编程语言等。MCF整个结构比较清楚是基于对象开发的一个比较好的可操作的框架系统。</p>
				<p>　　6、可视化开发方法 </p>
				<p>　　其实可视化开发并不能单独的作为一种开发方法，更加贴切的说可以认为它是一种辅助工具，比如用过SYBASE的S-Design的人都知道，用这个工具可以进行显示的图形化的数据库模式的建立，并可以导入到不同的数据库中去。当然用过S-Design的人不一定很多，但用过VB，DELPHI，C++ Builder等开发工具的人一定不少，实际上你就是在使用可视化开发工具。</p>
				<p>　　当然，不可否认的是，你只是在编程这个环节上用了可视化，而不是在系统分析和系统设计这个高层次上用了可视化的方法。实际上，建立系统分析和系统设计的可视化工具是一个很好的卖点，国外有很多工具都致力于这方面产品的设计。比如<a href="http://www.itisedu.com/phrase/200604240816305.html" target="_new">Business Object</a>就是一个非常好的数据库可视化分析工具。</p>
				<p>　　可视化开发使我们把注意力集中在业务逻辑和业务流程上，用户界面可以用可视化工具方便的构成。通过操作界面元素，诸如菜单、按钮、对话框、编辑框、单选框、复选框、 列表框和滚动条等，由可视开发工具自动生成应用软件。 </p>
				<p>
						<strong>六、怎样培养软件工程的思维与方法</strong>
				</p>
				<p>
						<br />　　作为软件开发人员的一个通病是在项目初期的时候，就喜欢谈论实现的细节，并且乐此不疲。我们更喜欢讨论如何用灵活而简短的代码来实现一个特定的功能，而忽略了对整个系统<a href="http://www.itisedu.com/phrase/200604241328115.html" target="_new">架构</a>的考虑。所以作为一个开发人员，尤其是一个有经验的开发人员，应该把自己从代码中解脱出来，更多的时候在我们的脑子里甚至暂时要放弃去考虑如何实现的问题，而从项目或产品的总体去考虑一个软件产品。</p>
				<p>　　以下是我个人的一些经验：</p>
				<p>　　1．考虑整个项目或者产品的市场前景。作为一个真正的系统分析人员，不仅要从技术的角度来考虑问题，而且还要从市场的角度去考虑问题。也就是说我们同时需要考虑我们产品的用户群是谁，当我们产品投放到市场上的时候，是否具有生命力。比如即使我们采用最好的技术实现了一个单进程的操作系统，其市场前景也一定是不容乐观的。</p>
				<p>　　2．从用户的角度来考虑问题。比如一些操作对于开发人员来讲是非常显而易见的问题。但是对于一般的用户来说可能就非常难于掌握，也就是说，有时候，我们不得不在灵活性和易用性方面进行折中。另外，在功能实现上，我们也需要进行综合考虑，尽管一些功能十分强大，但是如果用户几乎不怎么使用它的话，就不一定在产品的第一版的时候就推出。从用户的角度考虑，也就是说用户认可的才是好的，并不是开发人员觉的好才好。</p>
				<p>　　3．从技术的角度考虑问题。虽然技术绝对不是唯一重要的，但是技术一定是非常重要的，是成功的必要环节。在产品设计的时候，必须考虑采用先进的技术和先进的体系结构。比如，如果可以采用多<a href="http://www.itisedu.com/phrase/200603091754305.html" target="_new">线程</a>进行程序中各个部分并行处理的话，就最好采用多线程处理。在Windows下开发的时候，能够把功能封装成一个单独的COM构件就不作成一个简单的DLL或者是以源代码存在的函数库或者是对象。比如能够在<a href="http://www.itisedu.com/phrase/200604291151335.html" target="_new">B/S结构</a>下运行并且不影响系统功能的话就不一定要在C/S下实现。</p>
				<p>4．合理进行模块的分割。从多层模型角度来讲，一般系统可以分成用户层、业务层和<a href="http://www.itisedu.com/phrase/200604241152425.html" target="_new">数据库层</a>三部分。当然每以部分都还可以进行细分。所以在系统实现设计的时候，尽量进行各个部分的分割并建立各个部分之间进行交互的标准。并且在实际开发的时候，确实有需要的话再进行重新调整。这样就可以保证各个部分齐头并进，开发人员也可以各施其职。</p>
				<p>　　5．人员的组织和调度。这里很重要的一点是到考虑人员的特长，有的人喜欢做界面，有的人喜欢做核心。如果有可能要根据人员的具体的情况进行具体的配置。同时要保证每一个开发人员在开发的时候首先完成需要和其他人员进行交互的部分，并且对自己的项目进度以及其他开发人员的进度有一个清晰的了解，保证不同部分的开发人员能够经常进行交流。</p>
				<p>　　6．开发过程中文档的编写。在开发过程中会碰到各种各样的问题和困难，当然还有各种各样的创意和新的思路。应该把这些东西都记录下来并进行及时整理，对于困难和问题，如果不能短时间解决的，可以考虑采用其他的技术替代，并在事后做专门的研究。对于各种创意，可以根据进度计划安排考虑是在本版本中实现还是在下一版本中实现。</p>
				<p>　　7．充分考虑实施时可能遇到的问题。开发是一回事情，用户真正能够使用好它又是另外一回事情。比如在<a href="http://www.itisedu.com/phrase/200604241249435.html" target="_new">MIS</a>系统开发中，最简单的一个问题就是用户如果数据输入错误的时候，如何进行操作。在以流程方式工作的时候，如何让用户理解自己在流程中的位置和作用，如何让用户真正利用计算机进行协作也是成败的关键。</p>
				<p>　　以上是我个人的一点体会，实际上，作为一个软件开发人员，我也喜欢看到问题就坐在计算机前面直接编码，但是我确实认为软件工程对于我们系统开发的指导作用是巨大的。作为软件工程的拥戴者，下面我简单结合自己的开发经历介绍基于软件工程的开发方法、编程规范和工具使用等方面的问题。 </p>
				<p>
						<br />
						<strong>七、软件开发的发展变化</strong>
				</p>
				<p>
						<br />　　国外很多项目的开发都是基于一些图形化的东西来做的，他们的目的是尽量少写代码甚至不写代码。代码能够通过图形化的方式自动生成，这样的一个好处就是如果用户的需求变化或者业务逻辑发生变化，我们需要做的就是对图形表示的调整，然后重新自动生成代码，这也就是国外开发很注重对项目的概念和逻辑分析的原因。</p>
				<p>　　他们的重点是把业务规则和需求用图形化的方式表现出来，然后通过CASE工具自动生成代码。所以当国人还在不停的开发一个又一个的MIS工具的时候，国外已经把很多精力放到了CASE工具的制作上。</p>
				<p>　　我们很多公司人员忙着写具体业务过程的相关代码，而国外很多都把精力放到对不同应用，不同行业的模型的建立和共性的提取上。所以，他们做出来的东西就相对具有很强的灵活性和扩展性，而我们是用户的需求稍微有一点变化，就要忙着改代码，甚至改体系结构。</p>
				<p>　　另外，因为他们注重模型的建立，所以在建立其他应用的时候，能够借鉴原先的模型，在高层次上做调整和优化，同时能够有效的提取原有系统中可以被使用的部分。所以我们应该从以代码为核心的软件开发模式转化到以模型为中心的、基于CASE的开发上来。</p>
				<p>　　关于协作与个人英雄主义</p>
				<p>　　社会进步的一个很明显的现象就是社会分工越来越细，软件的开发也不例外。为什么在软件开发的今天已经不能出现象裘伯君这样的软件英雄的原因也在这里，单凭个人之力，我们也许穷尽有生之年也开发不出象Windows这样的操作系统。<br />因为，当前软件行业的壁垒无非就是两个，一个就是以技术创新取胜，你模仿的了其中的界面，但是你没有办法实现其中的核心功能。结果是你只能购买其技术核心，而你作一些边角工作。不举别的例子，比如VB这样的开发工具，其核心部分是它和第三方提供的COM控件或者是DLL函数库，你所做的就是一个整合的工作。</p>
				<p>　　第二个就是以细致取胜，也就是说功能很多而且做的很精致，即使技术本身不是很复杂，你真要想做出一个这样的东西来没有一两年的工夫是不可能的。而真等你做出来了，它的新版本也早已经推出。真正能够在市面上叫得想、经得起考验得产品都是具有这两方面的特点。</p>
				<p>　　这两方面的特点决定了你一个人绝对是不可能胜任的，也许你可以独立的完成技术创新，但是你绝对不可能一个人实现所有这些纷繁复杂的功能。所以，这个时代需要创新的英雄，也更需要人与人之间的协作。<br />当今的软件发展已经不是一个人可以包打天下的年代。软件开发的管理、系统体系结构的设计、模块之间的衔接、核心算法的实现、灵活界面的制定、软件再开发接口的实现都需要专门的人来做。而把这些有效的集成显然就需要有效的利用软件工程的思想和方法。所以，真正的软件英雄绝对不再是写着别人看不懂代码的程序员，而是整个体系结构的分析、设计、标准制定、协调人员。</p>
				<p>
						<strong>八、我们是否需要软件工程</strong>
				</p>
				<p>
						<br />　　有一点大家可以达成共识的就是，如果一个象Windows这样的操作系统，不进行全面的规划，不采用软件工程的思想和方法，是绝对搞不出来的。</p>
				<p>　　Windows的成功不在于它在进程管理和调度，文件系统、内存管理、界面设计等方面有多少成功的创新，它的成功最大的一点就是把所有的技术能够合理的整合起来，并集中到一个Window操作系统特有的框架结构中去。</p>
				<p>　　更为重要的是，Windows的每一项技术创新都能够有效的整合到Windows框架中去，比如COM、<a href="http://www.itisedu.com/phrase/200604231236585.html" target="_new">XML</a>等技术，通过ActiveX、DCOM等技术使Windows从桌面操作系统发展成为一个基于网络的操作系统。</p>
				<p>　　OLE2技术把整个Office中相关的软件进行了有效的整合，显然，这里我们可以把Office的设计和WPS的设计进行比较，客观的讲，WPS对中国用户来说实在也是一个很好的产品。但是从整个系统设计概念上来讲，Office显然要比WPS高一个层次，它能够把WORD，EXCEL，POWERPOINT，ACCESS有效的整合在一起，使我们所有办公相关的文档、图表、数据库、演示变成了一个一体化的东西。而且通过宏调用，用户可以自己定制用户界面并编制适当的模板，单是这个二次开发功能就不是WPS现在所能及项背的，当然限于当前用户的水平还很少有人使用二次开发的功能。</p>
				<p>　　从微软产品系列可以看到软件工程的作用，微软的所有产品都有一个整体的框架结构，比如Office软件，通过OLE技术进行有效的通讯和联系。比如Visual系列开发工具，提供了相似的开发界面使用户学会一种开发工具以后能够很容易的学习其他的开发工具。比如<a href="http://www.itisedu.com/phrase/200604040933575.html" target="_new">SQL SERVER</a>和ACCESS，尽管它们适用的范围不同，但是它们表现给用户的界面，特别是在查询和分析上表现了高度的一致性。</p>
				<p>　　更值得一提的是，因为设计结构的合理性，因为在开发前期作了很多分析和调研，考虑了扩展性和伸缩性，微软的系列产品能够很快的利用新的技术并采用统一的结构形式表现出来。比如当网络成为计算机发展的主流的时候，几乎微软所有的工具都能够快速的支持基于网络的开发和应用。</p>
				<p> </p>
				<p>　　相比之下，我们国内很多公司的产品很少具有连续性，往往是新的一个产品完全重起炉灶，和老的产品没有半点关系。这就是我们在设计产品的时候，没有很好的进行抽象和概念、逻辑设计，造成的结果是从旧的产品中提取不出一些有用的、共性的东西为后来的产品所使用。</p>
				<p>　　当然，很多开发人员从心里也承认一个大的系统确实需要软件工程的依托，但是一个小的工程项目是否就可以仓促上马呢？答案是否定的。所谓麻雀碎小，五脏俱全。无论是大项目、还是小项目。它们作为一个项目，都需要有一个需求分析、系统结构建立、设计、编码、测试等阶段。这是任何一个项目都不可缺少的。</p>
				<p>　　往往可以看到很多大公司的IT部门的人员都在不停的作各种各样的报表，当各个部门提出一种新类型的报表的时候，就从数据库中提取相应的数据并画出业务人员所需要的样式结构，很少是提供了一个通用的模板，当然提供高层<a href="http://www.itisedu.com/phrase/200604241228185.html" target="_new">API</a>接口进行这种操作的就更少了。这样不可避免的使开发人员陷入一些琐碎的报表编制工作。而造成这个局面的很重要的一个原因就是没有在系统开发的前期进行很好的调研、需求分析和系统体系结构的设计。</p>
				<p>　　这里就我们开发过的一些小型软件项目来谈一些开发的总结和体会，一般来说，小型软件项目功能比较单一，而且模块与模块之间的衔接不是很多，同时对开发周期要求比较短。</p>
				<p>　　小项目虽然看起来比较简单，所以很多开发人员容易犯一些错误，记得我们在开发一个基于Internet的有偿服务系统的时候，有三个开发人员：一个负责前端界面的编写，一个负责数据通讯协议和实现（基于TCP基础上的应用协议），一个负责对数据库数据的查询、整理和提取。我们在开发的时候没有认真地进行项目实际前途和工作量的估计。没有认真地估计项目难度，比如对于通讯中多用户并发访问时的多线程问题和缓存处理问题，用户批量请求处理的实现复杂度问题等等。三个人之间的接口也是在开发中休息的时候，口头定义一下。结果发现有不严密的地方(比如在通讯服务器端是用VC编写的，开发人员是通过stream来传送数据的，<a href="http://www.itisedu.com/phrase/200603082208195.html" target="_new">客户端</a>是用Delphi编写，在接收数据的时候发现数据不准确，后来研究发现VC利用CSocket在传送数据流的时候对数据进行了自己定义的格式化，结果服务器端数据发送模块只好重写)，而且其中关于一个接口双方的理解不同，然后又返工重新修改。最后到系统基本完成的时候没有一份较正式的文档。然后因为有人毕业离开这个项目，然后他编写的模块需要升级，新的接收的人不得不花很多时间去阅读他的源代码。</p>
				<p>所以在开发小项目的时候也必须要建立合理的模式：而所谓合理的模式就是软件工程告诉我们的在开发一个项目的时候所需要的五步曲：获取需求、需求分析、设计、编码、测试。</p>
				<p>　　1．理解用户真正的需求。在进入正式开发之前，必须先从用户处获取准确的需求。在这上面花费相当时间是很必要的。</p>
				<p>　　我们软件项目可以大致分为专用软件和通用软件两大类。对于专用软件，一般用户对于软件要完成哪些功能已经有了一个比较清楚的轮廓，而且往往在开发合同中已经大致地规定了。</p>
				<p>　　但是，开发合同上规定的只是一个大概的框架，在进入开发之前必须与用户进行比较具体的交流和讨论，了解清楚用户心目中的产品究竟是什么样子，这里最好就采用原型化的方法作出一个简单的框架给用户看。</p>
				<p>　　对于通用软件，在开发之前必须做一定的市场调查工作，一方面是从经济效益考虑，调查产品的潜在市场有多大，一方面是从技术的角度，了解清楚潜在用户对软件的各种技术上的要求，另一方面是确定我们软件的定位，即我们软件具体是为哪一些用户群体服务的。然后对该群体用户现有硬件配置，软件配置，网络使用情况，数据库使用情况，计算机熟悉程度做一定的调研，根据调查的统计结果决定即将开发的软件的一些技术指标。 <br />　　<br />　　2．需求分析。需求分析需要做的事情有：高层构思、确立系统目标、划分业务领域、现行业务分析、建立业务模型(Enterprise Model)、信息需求分析、用户<a href="http://www.itisedu.com/phrase/200603141659315.html" target="_new">视图</a>规范化、数据元素标准化与一致性控制。</p>
				<p>　　在了解用户的需求之后，将需求用一种模型来表示，就是需求分析，一般我们可以<a href="http://www.itisedu.com/phrase/200604231249365.html" target="_new">面向对象的方法</a>，通过分析用户需求，用类、类之间的各种关系来表示整个系统。</p>
				<p>　　为了讨论软件运行的流程，可以采用UML的<a href="http://www.itisedu.com/phrase/200603042249305.html" target="_new">Use Case</a>图。在系统分析的时候需要明确应用域（application domain）的范围，然后明确我们系统需要做什么。同时我们需要决定用什么方法来完成需求的获取，这在很大程度上影响了需求分析的做法。</p>
				<p>　　例如可以采用Use Case来表示用户需求，那么从各种<a href="http://www.itisedu.com/phrase/200603101549275.html" target="_new">序列图</a>中选出相互交互的各个实体，就是一个个类。另外分析需要与设计过程相衔接。分析过程的内容是用对象和对象之间的关系来表示整个系统和系统的流程的，并不设计具体实现，如采用什么编程语言，在什么操作系统平台上运行等等。这些具体实现是在设计阶段来完成的。</p>
				<p>　　面向对象方法的优点是分析、设计、编码过程表示法统一，能比较好的衔接。现在很多CASE工具并不区分分析和设计的阶段。但是，这并不意味着开发就可以对分析和设计不加区分，如何用好辅助设计(case)工具还是开发人员的事情。</p>
				<p>　　3．设计过程。设计阶段的工作包括对分析模型进行必要的修改，同时可能需要对某些类结构做一些修改，确定用户表示层(也就是通俗所说的界面定义)、用户服务层、业务逻辑层、数据库服务层和具体数据库所需要做的工作。同时需要确定使用的体系结构（比如B/S还是C/S）和开发工具（如VB，VC，VI，C++ Builder，DELPHI，PowerBuiler等等）</p>
				<p>　　4．编码。进入编码工作之后，依然可能会发现前面分析或设计阶段的某些错误，这时应返回到前面的阶段进行必要的修改。同时在编码前规定编码的风格并在开发过程中保持一致的风格。</p>
				<p>
						<br />　　5．测试。测试是系统投入使用前最关键的一个步骤。即使是小项目也应该严格地进行测试。就实际上就是一个把错误留给自己还是留给客户的问题。</p>
				<p>　　最后，我们知道软件项目主要是由开发人员完成的，所以对人员的合理安排和配置也很重要，一般在开发过程中，需要有一位项目负责人，负责分析、设计和协调的工作。另外需要几个程序员完成不同层的代码（比如用户服务层、业务逻辑层、数据库服务层等等）。</p>
				<p>　　同时需要有一个文档整理人员随时整理系统开发过程中相关的文档。如果条件可能的话，要配置一个测试工程师，专门进行代码的测试工作，当然如果条件不允许的话，也可以由开发人员<a href="http://www.itisedu.com/phrase/200604240926075.html" target="_new">交叉测试</a>。这里需要注意的是，对于项目负责人而言，协调几个人的工作比自己完成一段编码更重要。</p>
				<p>　　由于协调上出了漏洞，可能导致很大的问题，所以项目负责人必须随时监控各开发人员的工作，包括内容是否与要求发生偏差，进度是否滞后等等。同时必须给每个开发人员明确的任务书。具体开发时每个开发人员必须非常明确自己的任务，这些任务应该采用明确的文档来表示。每个开发人员需要清楚自己所做的工作在整个系统中处于什么地位，这样就有可能会发现<a href="http://www.itisedu.com/phrase/200604161258515.html" target="_new">设计模型</a>中的漏洞，避免了各人的代码编写完毕之后又要修改的后果。 </p>
				<p>
						<strong>九、我国软件工程发展的现状</strong>
				</p>
				<p>
						<br />      很多国内搞计算机的专家都认为：国内的软件研发过程，个人色彩比较浓。过分地依靠个人无法形成产业规模，而没有规模就谈不上产业化了。</p>
				<p>　　不管怎么样，我们大家还是先要来看一看国内软件厂商到底提供给我们多少有震撼力的软件产品，从技术和利润的角度讲，软件系统最核心的部分还是操作系统、编译系统然后就是开发平台之类的东西，接下来就是一些应用系统，比如图形开发、游戏开发、企业应用、网站建设、杀毒、网络工具等等。</p>
				<p>　　操作系统以中科院为中心，做了一个COSIX，这个本质上是一个UNIX系统，UNIX最初的源代码是公开的，尽管COSIX是一个被称为中国的操作系统并是UNIX系列的（IX就代表UNIX系列），但是其中到底有多少独创的技术成分我们暂时还不知道，但有一点可以肯定，它现在的市场覆盖率绝对不大，而且能否在上面运行各种各样的编译系统、数据库、群件和应用系统可能还需要进一步测试。然后就是对硬件平台的支持也需要进一步完善。</p>
				<p>　　然后就是轰轰烈烈的Linux系统，Linux是遵守GNU标准的操作系统，中国有很多家公司推出了自己的Linux并且还有汉化的Linux，这就有比较疑惑的一点，为什么不在Linux上构架一个类似UNICODE这样的东西，而只做汉化这么本地化的产品呢？不知道是眼光还是市场的问题了。<br />MIS系统、财务软件是中国软件行业的重头戏，它们彻底的暴露了中国软件开发无序和重复低效劳动的一面。教育软件在某一种层面上看就是电子题库，当然也有优点，比如加入了多媒体教学（可视化程度不错）和所谓寓教于乐的特点，但是从本质上说还是题库。杀毒软件据说是中国软件的骄傲，由中国权威机构评测是达到了世界领先水平，但是好象还没有得到国际权威机构的认可。游戏软件就不用提了，国内业界能够流行的游戏软件成功的秘诀众所周知，不是技术和创意，实在是归功于我们悠久的历史。字处理软件和排版软件客观的说国内的也做的不错，但是从系统的扩展性和体系结构上说和MS和Adobe相比，差距也放在那里。其实这种现状的原因很简单，一个是我们缺少创新的能力，另一个就是我们欠缺软件工程的概念，系统开发前期的需求分析、设计没有做好或者做的不够好。</p>
				<p>　　当然，我们很少怀疑自己的技术能力，我们很多时候认为这是地理环境和经济环境的原因造成了中国软件业现在的局面。当然中国软件开发人员绝对可以算是优秀的，但是想想我们软件行业龙头企业到底有多少有技术创新和专利技术呢？姑且不论这个，实际上把一个操作系统分解开来，比如文件系统、进程管理和调度、IO调度等等，也许我们可以实现其中某一块的内容，但是如何把它们合理的整合起来绝对是一个涉及到软件工程的问题。</p>
				<p>　　作为一个开发人员，我们已经习惯了自己那一套编程模式，而且我们的这种习惯也不自觉的影响着新的开发人员。所以在头脑中建立一个软件工程的作用，从某种角度上讲，要比会几种开发语言、几个编程技巧实在是重要的多。</p>
				<p>　　举一个例子来说，我们也许可以写MFC中的几个类或者是用自己的类扩展MFC，但是我们又有几个人真正去认真分析和考虑MFC架构的设计和原理呢？扪心自问，我们又有多少人能够设计出MFC这样的框架系统呢？下面就我们的题目谈一些相关的话题。 </p>
				<p>
						<strong>十、我有一个梦</strong>
				</p>
				<p>　　毋庸质疑的是，计算机的发展和人类的历史相比甚至和其他很多科技产品相比都是非常短的，从第一台计算机的研制成功到现在也没有百年的历史，但是计算机及其相关技术的发展却绝对可以说是最快的。抛开硬件的发展（硬件的发展基本上是按照摩尔定律来的，每18个月，机器的速度性能都要提高一倍），单从软件的发展来说，从体系结构来讲，我们经历了从主机结构到文件服务器结构，从客户服务器系统到基于Internet的服务器浏览器结构的体系结构的变化。从编码的角度来讲，我们经历了从最开始的机器代码到汇编代码，从高级程序语言到<a href="http://www.itisedu.com/phrase/200603011759495.html" target="_new">人工智能</a>语言，从专用的程序设计语言到通用的程序设计语言。从开发工具来讲，我们经历了从分离的开发工具（有代码编辑器，中间代码生成器和连接器）到集成的开发系统，从最简单的单行命令式调试器到方便灵活的多功能的调试器。</p>
				<p>　　但是，今天所有的软件厂商和软件开发人员依然会想起当年的黑人人权运动领袖马丁？路德？金曾经说过的一句名言我有一个梦想。是的，所有的开发人员依然怀着梦想，希望能够有一个万能的系统开发的框架和方法，只要我们沿着这个框架，我们将能开发出适合所有领域的应用系统，于是，我们在念书的时候把这个希望投到了一门课上，这么课就是软件工程。但是当我们在学完这门课的时候，我们依然没有找到这么一个框架甚至连接近这么一个框架的东西也没有碰到。</p>
				<p>　　不管我们认为软件工程可能是多么的虚无，但是所有学工科并且有逻辑头脑的人都坚信理论对实践的指导意义，因为有了爱因斯坦及其许多伟大的科学家关于能量和质量方面的理论以后，我们才造出了原子弹。但是，遗憾的是软件工程并不是一个具体的理论，它更象一门抽象的科学。软件工程是一种方法论，而不是一种具体的摸的着，看的见的产品。它告诉我们在设计一个系统的时候，我们需要进行可行性研究、计划制订、需求分析、系统设计、编码、测试、维护等等。并且对这些过程中应该做什么提出了一个指导性的东西。但是没有任何专家和标准委员会保证只要按照这些标准，我们的系统肯定会顺利完成。而且事实上，软件开发针对的领域是如此之多并不没有一种对所有领域适用的万能框架。<br />　　不管认为软件工程已经到了非常成熟的阶段还是认为软件工程依然是一个搞不懂的黑箱子，软件工程确实已经经历了三个不同的阶段。第一个阶段是软件结构化生产阶段，以结构化分析与设计、结构化评审、结构化程序设计以及结构化测试为特征。从80年代中期，软件生产开始进入以过程为中心的第二阶段，以提出过程成熟模型<a href="http://www.itisedu.com/phrase/200603051508215.html" target="_new">CMM</a>、<a href="http://www.itisedu.com/phrase/200603061000265.html" target="_new">个体软件过程</a><a href="http://www.itisedu.com/phrase/200604231319415.html" target="_new">PSP</a>和<a href="http://www.itisedu.com/phrase/200604231333525.html" target="_new">群组软件过程</a><a href="http://www.itisedu.com/phrase/200604231334415.html" target="_new">TSP</a>为标志。第三个阶段就是以软件过程、面向对象和构件重用三把斧头出现的软件工业化生产阶段。</p>
				<p>　　言归正传，我们还是回到我们的文章标题上来，我们在开发的时候是兵马未动、粮草先行还是摸着石子过河。兵马未动、粮草先行当然意味着我们在开发的时候先不忙着编写代码做程序，我们先要制订一个关于开发的方法。这点就象<a href="http://www.itisedu.com/phrase/200603141328355.html" target="_new">元数据</a>（metadata）的概念，元数据并不定义数据，它是对数据的说明，也就是通常所说的关于数据的数据。我们设计的时候也是这样，定义开发的标准，如何进行开发、怎样开发。摸着石子过河就意味着我们先不管什么理论，方法，科学的问题，我们先动手做起来，如果做的也算成功的话，那就可以按照这种模式来，实际上，在任何事情的最初，我们都是这样。从辨证唯物主义者的观点来说，就是从实践中来，然后升华到理论，再用理论来指导实践。记得一个笑话说：外国人搞软件工程是在一个黑屋子里面抓黑猫，不过到现在还是没有抓住，而中国人是在一个黑屋子里面，而里面连猫都没有，然后有人说，我已经抓到猫了。这个笑话一方面是说明直到现在，软件工程还是一个在继续探索、发展的过程，另一个侧面也说明中国搞软件工程摸不着边的局面。</p>
				<p>　　实际上，不管有没有软件工程，不管是否存在一个万能的框架系统，我们的应用系统还是要做，各种各样的软件还是要开发。说到底，软件系统是因为有需求才存在的。有了应用域才有了软件存在的意义。很多时候，我们可以看到国外有各种各样的软件和创新，而我们没有，我们更多的是模仿和一些重复的功能相近的软件的原因就是因为我们没有这方面的需求，这也正解释了为什么ERP系统能在国外开展的很好，而在国内失败多于成功的原因。一方面当然是因为我们的企业按照市场经济发展的时间还不长，另一方面是我们的企业确实也没有这方面的需求。</p>
				<p>
				</p>
				<p>
						<font face="Verdana">
						</font>
				</p>
				<font face="Verdana">
						<strong>十一、软件工程的发展方向</strong>
				</font>
				<p>
				</p>
				<p>
						<font face="Verdana">      “<a href="http://www.itisedu.com/phrase/200603291800375.html" target="_new">敏捷开发</a>”（<a href="http://www.itisedu.com/phrase/200604240917025.html" target="_new">Agile Development</a>）被认为是软件工程的一个重要的发展。它强调软件开发应当是能够对未来可能出现的变化和不确定性作出全面反应的。</font>
				</p>
				<p>
						<font face="Verdana">      敏捷开发被认为是一种“轻量级”的方法。在轻量级方法中最负盛名的应该是“<a href="http://www.itisedu.com/phrase/200603071747045.html" target="_new">极限编程</a>”（<a href="http://www.itisedu.com/phrase/200604231325295.html" target="_new">Extreme Programming</a>，简称为<a href="http://www.itisedu.com/phrase/200604231325145.html" target="_new">XP</a>）。而与轻量级方法相对应的是“重量级方法”的存在。重量级方法强调以开发过程为中心，而不是以人为中心。重量级方法的例子比如CMM/PSP/TSP。</font>
				</p>
				<p>
				</p>
		</font>
		<font face="Verdana"> </font><img src ="http://www.cnitblog.com/tilan/aggbug/21893.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2007-01-15 23:03 <a href="http://www.cnitblog.com/tilan/articles/21893.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>QTP描述性编程（descriptive programming）</title><link>http://www.cnitblog.com/tilan/articles/19638.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Mon, 27 Nov 2006 08:11:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/19638.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/19638.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/19638.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/19638.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/19638.html</trackback:ping><description><![CDATA[<table style="TABLE-LAYOUT: fixed" cellspacing="0" cellpadding="5" width="100%" align="center" border="0">
				<tbody>
						<tr>
								<td class="arttag">标签：<a href="http://itcat.it.com.cn/tags/13673.htm">功能测试</a></td>
						</tr>
						<tr>
								<td class="artcontent">文章出处：www.51testing.com / 作者：周坚<br /><br />描述性编程（descriptive programming）<br /><br />1、descriptive programming概述<br /><br />通常情况下，当在录制一个操作时，QTP会将被操作对象加入到对象库里（Object Repository）。一旦对象存在于对象库里，我们就可以在专家视图里通过添加相关的对象方法来对该对象进行操作。我们可以通过引用层次型对象库里的对象描述（Object Description）来添加相应的方法。<br /><br />因为QTP对象库中的每个对象都具有唯一名称，所以在引用时对象名是必须需要指定的。然后在测试运行期间，QTP在对象库中根据这个对象的名称和父对象来查找对象，并使用为这个测试对象存储的测试对象描述，在网站或应用程序中标识该对象。<br /><br />例如我们用QTP录制Yahoo Mail登录情况时我们需要输入用户名，于是在录制时我们就会录下一个WebEdit对象，它的缺省逻辑名为“login”，该编辑字段位于名为“Yahoo! Mail - The best” 的页面上，并且该页面在浏览器中使用名称Yahoo!进行录制。<br /><br />那么如果我们想要应用该对象，就可以在专家视图输入以下信息：<br /><br />Browser("Yahoo!").Page("Yahoo! Mail - The best").WebEdit("login").Set “xxx”<br /><br />或者我们也可以调用一些方法，获取改对象在运行时的对象名，如：<br /><br />Browser("Yahoo!").Page("Yahoo! Mail - The best").WebEdit("login").GetROProperty(“name”)<br /><br />然而，我们可以发觉到，上面的例子在处理对象时，对象已经存在于对象库里，因此我们可以应用这个对象的逻辑名。实际使用中，情况往往并非如此简单，我们经常会遇到很多在页面上动态产生的对象，换而言之，对象库里没有这些对象，我们也无从引用。因此我们必须采用其他的技术来完成这类操作，这也就是我们需要讲解的Descriptive Programming。<br /><br />为了满足上面提到的动态对象的处理问题，QTP允许用户通过将对象属性编码到测试脚本里来动态识别对象，这就是我们通常意义下称为的Descriptive Programming。通过这种方式，我们可以指示QTP不通过引用对象库和对象名来对实际对象进行操作。具体操作中，我们只需要为QTP提供对象的一组属性和值，这样QTP就可以来识别相应的对象并对其进行操作。这相当于，告诉QTP要识别对象的一些关键特征，根据这些特征QTP就可以一一匹配然后识别出来这个对象。<br /><br />而且，更为重要的是，通过这种Descriptive Programming的方式，还可以让QTP识别具有某些相同属性的对象。我们先来举个例子来看一下：我们假设当前的Windows系统中打开了若干的Yahoo主页面（多于一个），现在我们要关闭所有的正在浏览Yahoo主页面的浏览器。<br /><br />对于上面那个例子来说，我们先看一个简单一点的情况，假设只有且仅有一个Yahoo主页面：那么我们可以用下面的方法来<br /><br />Window("Text:=Yahoo! - Microsoft Internet Explorer").Close<br /><br />我们可以看到语句里我们要查找的对象是Window窗口标题为“Yahoo! - Microsoft Internet Explorer”，然后把它关闭，具体的语法说明我们稍后为解释。但是上面的语句仅仅适合前面提到的条件“只有且仅有一个Yahoo主页面”，如果有多个同样的窗口就会出错，原因是通过语句可以匹配到多个对象，而QTP不知道应该对哪个对象进行关闭动作。我们需要进一步的缩小匹配范围：<br /><br />Dim i<br /><br />i = 0<br /><br />while (Window("Text:="Yahoo!" - Microsoft Internet Explorer", "index:="&amp;i).exist)<br /><br />Window("Text:=Yahoo! - Microsoft Internet Explorer", "index:="&amp;i).close<br /><br />i = i +1<br /><br />wend<br /><br />这里我们可以看到，对于具有相同属性的对象，我们可以通过index参数来对其进行区别，第一个对象为index=0，第二个为index=1等等，依次类推。当然我们还可以通过CreationTime和Location参数来定位对象，这里就不详细叙述了。<br /><br />通过上面的例子，我们对Descriptive Programming有一个基本了解了，下面我们详细讲解一下Descriptive Programming：在具体实现中，我们有两种类型的Descriptive Programming方法。可以列出直接在测试语句中描述对象的属性和值的集合；或者向Description 对象中添加属性和值的集合，然后在语句中输入Description 对象的名称。下面我们分别举例介绍。<br /><br /> <br /><br />2、直接在语句中输入编程描述<br /><br />通过多个指定描述对象的property:=value对，可以直接在语句中描述对象，这是最直接有效的方法。<br /><br />常规语法为：<br /><br />TestObject("PropertyName1:=PropertyValue1", "..." , "PropertyNameX:="PropertyValueX""} <br /><br />TestObject - 测试对象的类。<br /><br />PropertyName:=PropertyValue - 测试对象的属性及其值。各个property:="value" 对之间应用逗号和引号分开。<br /><br />例如：以下语句指定Mercury Tours 页面中名为author且索引值为3 的WebEdit 测试对象。当测试运行时，QTP 将查找具有匹配属性值的WebEdit 对象，并输入文本jojo。<br /><br />Browser("Mercury Tours").Page("Mercury Tours").WebEdit("Name:="Author"", "Index:="3"").Set "Mark Twain" <br /><br />我们也可以从从描述中的特定位置（从Page 对象描述开始）开始使用Descriptive Programming。<br /><br />Browser("Mercury Tours").Page("Title:="Mercury" Tours").WebEdit("Name:="Author"", "Index:="3"").Set "jojo" <br /><br />此外，如果我们希望在在一个测试或组件中多次使用相同的Descriptive Programming，则可以将创建的对象赋值给变量，这样使用会方便很多。<br /><br />例如：我们需要完成下面一系列操作<br /><br />Window("Text:=HyperSna").WinButton("Caption:=日期").Click<br /><br />Window("Text:=HyperSna").WinButton("Caption:=时间").Click<br /><br />Window("Text:=HyperSna").WinButton("Caption:=确定").Click<br /><br />那么，为了方便其见，我们可以将Window("Text:=HyperSna")赋值到一个变量，然后再使用，参见下面的代码：<br /><br />Set WinHyper = Window("Text:="HyperSna"") <br /><br />WinHyper.WinButton("Caption:=日期").Click<br /><br />WinHyper.WinButton("Caption:=时间").Click<br /><br />WinHyper.WinButton("Caption:=确定").Click<br /><br />如果使用了VBScript里面的With语句，还可以简化为以下代码：<br /><br />With Window("Text:="HyperSna"") <br /><br />.WinButton("Caption:=日期").Click <br /><br />.WinButton("Caption:=时间").Click<br /><br />.WinButton("Caption:=确定").Click<br /><br />End With <br /><br />下面我们来看一个更为详细的例子，在QTP产品缺省安装里面自带了一个网上订机票的示例称为Mercury Tour，我们看一下在订票过程中何时需要用Descriptive Programming。<br /><br />首先登入系统后，如果需要订票，就要先搜索航班，此时系统要求输入订票乘客的数量，假设我们在第一次录制脚本时选择了1个Passenger，并成功完成订票。然后，我们需要参数化乘客数量来测试订票系统，我们会发现回放会失败。原因在于，不同的乘客的数量导致在订票时需要输入每个乘客的姓名，而录制时，只输入了一个乘客的姓名。而乘客姓名的输入框是随着乘客数量的变化而动态生成的，我们不可能从对象库里得到没有录制的对象，因此必须使用Descriptive Programming。<br /><br /> <br /> <br />  <br /> <br /><br /><br />在录制单个乘客时，我们得到的录制语句是：<br /><br />Browser("Welcome: Mercury Tours").Page("Book a Flight: Mercury").WebEdit("passFirst0").Set "Michael"<br /><br />Browser("Welcome: Mercury Tours").Page("Book a Flight: Mercury").WebEdit("passLast0").Set "Wang"<br /><br />显然WebEdit("passFirst0")和WebEdit("passLast0")是录制时产生的对象并存放到对象库里的。通过对象库，我们可以看到对象的属性如下<br /><br /> <br /> <br />  <br /> <br /><br /><br />系统对于发生多个FirstName时，命名规则是passFirst0，passFirst1…依次类推。因此只要通过简单的Descriptive Programming就可以完成动态FirstName与LastName的识别工作。这里我们假设参数化的乘客数已经赋值给intPassNum，下面是脚本中的关键语句：<br /><br />counter = 0<br /><br />For i = 0 to (intPassNum)<br /><br />Browser("Find a Flight:").Page("Book a Flight:").WebEdit("name:="passFirst""&amp;i).Set "Michael"<br /><br />Browser("Find a Flight:").Page("Book a Flight:").WebEdit("name:="passLast""&amp;i).Set "Wang"<br /><br />counter = counter + 1<br /><br />Next<br /><br /> <br /><br />3、使用description对象<br /><br />使用Description 对象可以返回包含一组Property 对象的Properties 集合对象。Property 对象由属性名和值组成。然后，可以在语句中指定用返回的Properties 集合代替对象名。（每个property 对象都包含一个属性名和值）。<br /><br />要创建Properties 集合，可以使用以下语法输入Description.Create 语句：<br /><br />Set MyDescription = Description.Create() <br /><br />创建Properties 对象（例如，以上示例中的MyDescription）后，就可以输入语句，以便在运行会话期间在Properties 对象中添加、编辑、删除或检索属性和值。这样，就可以在运行会话期间，使用动态方法确定哪个属性以及多少个属性应包含在对象描述中。<br /><br />在Properties 集合中填充一组Property 对象（属性和值）后，可以在测试语句中指定用Properties 对象代替对象名。<br /><br />例如，假设我们需要完成以下一个操作：<br /><br />Window("Error").WinButton("text:=OK", "index:="1"").Click<br /><br />我们可以通过Description对象来实现同样的功能，参加下面的代码：<br /><br />Set MyDescription = Description.Create()<br /><br />MyDescription("text").Value = "OK"<br /><br />MyDescription("index").Value = 1<br /><br />Window("Error").WinButton(MyDescription).Click<br /><br />Set MyDescription = Nothing<br /><br /> <br /><br />【小结】以上是对QTP中有关处理动态对象中的Descriptive Programming的简单介绍，希望对大家能够有所帮助，就总体而言，如果能够熟练掌握Descriptive Programming，那么有很多实际中的问题就可以迎刃而解。当然Descriptive Programming只是QTP中的一个功能，QTP在实际功能测试中还有很多强大的功能，作为QTP学习的一个系列有机会我会一一介绍。 </td>
						</tr>
				</tbody>
		</table><img src ="http://www.cnitblog.com/tilan/aggbug/19638.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2006-11-27 16:11 <a href="http://www.cnitblog.com/tilan/articles/19638.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Loadrunner性能测试的一个实例</title><link>http://www.cnitblog.com/tilan/articles/19486.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Wed, 22 Nov 2006 06:43:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/19486.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/19486.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/19486.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/19486.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/19486.html</trackback:ping><description><![CDATA[随着测试越来越重要，其中的性能测试也受到越来越多的关注。比较普遍的性能测试工具是Loadrunner7.51，但是很多人对此性能工具不是很熟悉。本人也是总结心得体会，将做过的性能测试实例以饷大家，希望对各位做测试的朋友有所帮助。<br />该方案是针对某公司试题库的性能测试。该试题库是用来对公司内部员工培训结果的一个考核。试题库在公司内部web服务器上，假设开设50个账号和密码可供50个考生同时参加考试。要求，每台机器只能由一个用户使用，每个用户只能使用各自不同的账号登录考试系统，做完题目后，要求提交考试结果，若在制定的时间内不提交，则系统强制提交考试结果。<br />但是，一般测试部门不可能有50台机器同时进行测试的。所以，可以借Loadrunner7.51模拟IP地址，修改脚本来协助测试。但是，为了保证测试结果，建议搜罗公司中所有可用的机器进行复测，因为有时候是不可以完全信赖工具的。<br />现场测试环境<br />硬件：50台PC机，Web服务器<br />软件：Loadrunner7.0，Win2000，IE5.0和IE6.0<br />人员：质控部2人，执行现场测试<br />项目部22人，提供现场环境<br />技术部各1人，提供技术支持<br />测试要求<br />50个用户拥有独立IP地址，不同的用户及密码登录，试题完成后各自同时提交。<br />测试内容<br />50个用户以不同的用户名和密码登录试题库。试题完成后，提交考试结果。测试考试结果是否能正常提交以及正确评分。<br />测试方案<br />1、 完全20台实际的PC机进行现场测试。<br />（1） 准备工作，并做计划。第一轮测试执行三遍，设定用户考试内容全部同时提交，第一遍全部使用IE5.0，第二遍10台使用IE5.0，10台使用IE6.0，第三遍全部使用IE6.0<br />（2） At 9：00 ，20个用户同时登录系统<br />（3） At 9：05 ，20个用户同时全部提交<br />（4） 分别记录第一轮测试（三遍）的结果<br />（5） 第二轮测试准备工作，设定15个用户考试内容同时提交，另外5个用户延时5分钟提交，全部使用IE5.0<br />（6） At 9：15 ，20个用户同时登录系统<br />（7） At 9：20 ，15个用户同时提交<br />（8） At 9：25 ，剩余5个用户同时提交<br />（9） 记录第二轮测试结果<br />（10） 第三轮测试准备工作，设定15个用户考试内容同时提交，另外5个用户延时5分钟提交，全部使用IE6.0<br />（11） At 9：15 ，20个用户同时登录系统<br />（12） At 9：20 ，15个用户同时提交<br />（13） At 9：25 ，剩余5个用户同时提交<br />（14） 记录第三轮测试结果<br />（15） 第四轮测试准备工作，设定15个用户考试内容同时提交，另外5个用户延时5分钟提交，正常提交用户使用IE5.0，延时提交用户使用IE6.0<br />（16） At 9：15 ，20个用户同时登录系统<br />（17） At 9：20 ，15个用户同时提交<br />（18） At 9：25 ，剩余5个用户同时提交<br />（19） 记录第四轮测试结果<br />（20） 第五轮测试准备工作，设定15个用户考试内容同时提交，另外5个用户延时5分钟提交，正常提交用户使用IE6.0，延时提交用户使用IE5.0<br />（21） At 9：15 ，20个用户同时登录系统<br />（22） At 9：20 ，15个用户同时提交<br />（23） At 9：25 ，剩余5个用户同时提交<br />（24） 记录第五轮测试结果<br />（25） 第六轮测试准备工作，设定15个用户考试内容同时提交，另外5个用户延时5分钟提交，正常提交用户其中10个使用IE5.0，5个使用IE6.0，延时提交用户使用IE5.0<br />（26） At 9：15 ，20个用户同时登录系统<br />（27） At 9：20 ，15个用户同时提交<br />（28） At 9：25 ，剩余5个用户同时提交<br />（29） 记录第六轮测试结果<br />（30） 第七轮测试准备工作，设定10个用户考试内容同时提交，另外10个用户分两次分别延时5分钟、15提交<br />（31） At 9：35 ，20个用户同时登录系统<br />（32） At 9：40 ，10个用户同时提交<br />（33） At 9：45 ，剩余的其中5个用户同时提交<br />（34） At 9：55 ，剩余的5个用户同时提交<br />（35） 记录第七轮测试结果，参见第二轮测试－第六轮测试过程分别对IE5.0和IE6.0的情况进行测试<br />（36） 第八轮测试准备工作，设定其中10个用户不提交，由系统强行提交<br />（37） At 10：10 ，20个用户同时登录系统<br />（38） At 10：15 ，10个用户同时提交<br />（39） 其余用户的内容由系统强行提交<br />（40） 记录第八轮测试结果，参见第二轮测试－第六轮测试过程分别对IE5.0和IE6.0的情况进行测试<br />（41） 第九轮测试准备工作，设定其中10个用户同时提交，5个用户延时5分钟提交，其余用户由系统强行提交<br />（42） At 10：25 ，20个用户同时登录系统<br />（43） At 10：30 ，10个用户同时提交<br />（44） At 10：35 ，剩余的其中5个用户同时提交<br />（45） 剩余5个用户系统强制提交<br />（46） 记录第九轮测试结果，参见第二轮测试－第六轮测试过程分别对IE5.0和IE6.0的情况进行测试<br />2、 模拟20个用户进行测试。其中，10台是PC机，另外10台机器的IP地址是Loadrunner模拟出来的。<br />（1） 在10台实际的PC机中抽取其中一台虚拟10个IP地址，包括自身的IP地址，该机器上共11个IP地址，这11个IP地址只能全部使用IE5.0或者全部使用IE6.0<br />（2） 其余9台实际的PC机分别由9个人操作，另外一台机器由一位质控部人员操作<br />（3） 对于异常情况，延时提交和强制提交全部由实际的机器来模拟<br />（4） 其余过程参见1<br />3、 模拟20个用户进行测试。其中，5台是PC机，另外15台机器的IP地址是用Loadrunner模拟出来的。<br />（1） 在5台实际的PC机中抽取其中一台虚拟15个IP地址，包括自身的IP地址，该机器上共16个IP地址，这16个IP地址只能全部使用IE5.0或者全部使用IE6.0<br />（2） 其余4台实际的PC机分别由4个人操作，另外一台机器由一位质控部人员操作<br />（3） 对于异常情况，延时提交和强制提交全部由实际的机器来模拟<br />（4） 其余过程参见1<br />4、 模拟35个用户进行测试。其中，20台是PC机，另外15台机器的IP地址是用Loadrunner模拟出来的。<br />（1） 在20台实际的PC机中抽取其中两台分别虚拟7个、8个IP地址，这17个IP地址只能全部使用IE5.0或者全部使用IE6.0<br />（2） 其余18台实际的PC机分别由18个人操作，另外两台机器由两位质控部人员操作<br />（3） 对于异常情况，延时提交和强制提交全部由实际的机器来模拟<br />（4） 其余过程参见1<br />5、 模拟50台用户进行测试。其中，20台是PC机，另外30台机器的IP地址是用分别用两台实际的PC机模拟出来的。记录测试结果。<br />（1） 在20台实际的PC机中抽取其中两台分别虚拟15个IP地址，这32个IP地址只能全部使用IE5.0或者全部使用IE6.0<br />（2） 其余18台实际的PC机分别由18个人操作，另外两台机器由两位质控部人员操作<br />（3） 对于异常情况，延时提交和强制提交全部由实际的机器来模拟<br />（4） 其余过程参见1<br />6、 对5中所述情况重复测试两次。<br />7、 为了保证结果的正确性，完全50台实际的PC机进行现场测试。过程参见1<br />测试过程<br />注：该测试过程针对虚拟IP地址情况。<br />1、 一台PC机上创建15个虚拟的IP地址。首先，启动IP Wizard，如下：开始程序－&gt;Loadrunner－&gt;Tools－&gt;IP Wizard<br />点击“Add”，添加你计划虚拟的IP地址。但是注意不能添加已经被占用的IP地址。<br />2、 启动Virtual User Generator，并录制脚本，由于50个用户的账号和密码各不相同，所以，要修改脚本，设置参数。我是录制了一个脚本，复制了49份，在每个脚本中手工修改了各自不同的地方。<br />3、 启动Loadrunner Controller，先将刚才保存的脚本添加进来。然后点击“Scenario”菜单，激活其中的“Enable IP Spoofer”。<br />4、 点击屏幕右方的“Generators”，添加已经建立的IP，然后connect建立连接。<br />5、对连接起来的不同用户（IP地址）分配不同的脚本，在Controller中的“design”中，点击“Load Generators”其中，每个脚本有一个用户执行。<br />6、 执行Scenario。<img src ="http://www.cnitblog.com/tilan/aggbug/19486.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2006-11-22 14:43 <a href="http://www.cnitblog.com/tilan/articles/19486.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>脚本自动化测试 </title><link>http://www.cnitblog.com/tilan/articles/sam.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Mon, 20 Nov 2006 08:14:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/sam.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/19362.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/sam.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/19362.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/19362.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 性能：软件测试的重中之重																																																																										  																				　　性能测试在软件的质量保证中起着重要的作用，它包括的测试内容丰富多样。中国软件评测中心将性能测试概括为三个方面：应用在客户端性...&nbsp;&nbsp;<a href='http://www.cnitblog.com/tilan/articles/sam.html'>阅读全文</a><img src ="http://www.cnitblog.com/tilan/aggbug/19362.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2006-11-20 16:14 <a href="http://www.cnitblog.com/tilan/articles/sam.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WinRunner的工作流程 </title><link>http://www.cnitblog.com/tilan/articles/19361.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Mon, 20 Nov 2006 08:13:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/19361.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/19361.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/19361.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/19361.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/19361.html</trackback:ping><description><![CDATA[
		<div class="postText">
				<p>WinRunner是一种用于检验应用程序能否如期运行的企业级软件功能测试工具。通过自动捕获、检测和模拟用户交互操作，WinRunner能识别出绝大多数软件功能缺陷，从而确保那些跨越了多个功能点和数据库的应用程序在发布时尽量不出现功能性故障。</p>
				<p>WinRunner 的特点在于: 与传统的手工测试相比，它能快速、批量地完成功能点测试; 能针对相同测试脚本，执行相同的动作，从而消除人工测试所带来的理解上的误差; 此外，它还能重复执行相同动作，测试工作中最枯燥的部分可交由机器完成; 它支持程序风格的测试脚本，一个高素质的测试工程师能借助它完成流程极为复杂的测试，通过使用通配符、宏、条件语句、循环语句等，还能较好地完成测试脚本的重用; 它针对于大多数编程语言和Windows技术，提供了较好的集成、支持环境，这对基于Windows平台的应用程序实施功能测试而言带来了极大的便利。</p>
				<p>WinRunner的工作流程大致可以分为以下六个步骤:</p>
				<p>1．识别应用程序的GUI</p>
				<p>在WinRunner 中，我们可以使用GUI Spy来识别各种GUI对象，识别后，WinRunner会将其存储到GUI Map File中。它提供两种GUI Map File模式: Global GUI Map File和GUI Map File per Test。其最大区别是后者对每个测试脚本产生一个GUI文件，它能自动建立、存储、加载，推荐初学者选用这种模式。但是，这种模式不易于描述对象的改变，其效率比较低，因此对于一个有经验的测试人员来说前者不失为一种更好的选择，它只产生一个共享的GUI文件，这使得测试脚本更容易维护，且效率更高。</p>
				<p>2．建立测试脚本</p>
				<p>在建立测试脚本时，一般先进行录制，然后在录制形成的脚本中手工加入需要的TSL（与C语言类似的测试脚本语言）。录制脚本有两种模式: Context Sensitive和Analog，选择依据主要在于是否对鼠标轨迹进行模拟，在需要回放时一般选用Analog。在录制过程中这两种模式可以通过F2键相互切换。</p>
				<p>只要看看现代软件的规模和功能点数就可以明白，功能测试早已跨越了单靠手工敲敲键盘、点点鼠标就可以完成的阶段。而性能测试则是控制系统性能的有效手段，在软件的能力验证、能力规划、性能调优、缺陷修复等方面都发挥着重要作用。</p>
				<p>3．对测试脚本除错(debug)</p>
				<p>在WinRunner中有专门一个Debug Toolbar用于测试脚本除错。可以使用step、pause、breakpoint等来控制和跟踪测试脚本和查看各种变量值。</p>
				<p>4．在新版应用程序执行测试脚本</p>
				<p>当应用程序有新版本发布时，我们会对应用程序的各种功能包括新增功能进行测试，这时当然不可能再来重新录制和编写所有的测试脚本。我们可以使用已有的脚本，批量运行这些测试脚本测试旧的功能点是否正常工作。可以使用一个call命令来加载各测试脚本。还可在call命令中加各种TSL脚本来增加批量能力。</p>
				<p>5．分析测试结果</p>
				<p>分析测试结果在整个测试过程中最重要，通过分析可以发现应用程序的各种功能性缺陷。当运行完某个测试脚本后，会产生一个测试报告，从这个测试报告中我们能发现应用程序的功能性缺陷，能看到实际结果和期望结果之间的差异，以及在测试过程中产生的各类对话框等。</p>
				<p>6．回报缺陷（defect）</p>
				<p>在分析完测试报告后，按照测试流程要回报应用程序的各种缺陷，然后将这些缺陷发给指定人，以便进行修改和维护。</p>
				<p>性能测试的三大步骤</p>
				<p>第一步 准备和组织是性能测试过程的第一步，在这个阶段，需要明确性能测试的目标和需求，并组织起合适的人员，制订性能测试计划。</p>
				<p>一般来说，性能测试的应用领域分为能力验证、能力规划、性能调优和缺陷修复四个方面。其中能力验证表明测试的目的是验证系统能力是否达到预期的性能标准; 能力规划是要考察系统的可扩展性; 性能调优则是为了找到系统的性能瓶颈，为性能调优提供依据; 缺陷修复是为了找出系统中存在的并发等方面的缺陷。</p>
				<p>明确目标也就是要把性能测试的目的归到相应的应用领域，而确定需求则是要更详细地确定性能测试的基准。对产品的性能测试需求的来源是软件需求、设计文档或是用户备忘录等设计和需求相关的文档。当然，并非所有的性能测试需求都在这些文档中以明确的方式标识出来，此时就需要根据不十分明确的文档描述进行进一步的细化。我们的经验是在文档评审时高度关注所有与性能相关的描述，例如“要求操作响应时间小于……”、“要求……能够快速……”、“要求……能够支持……用户访问”、“要求……能快速稳定运行”等，然后进行进一步的细化，从而作为测试的依据。</p>
				<p>性能测试涉及的设备、环境、技术、工具较多，性能测试人员的组织也必须兼顾这些方面。一个性能测试组最好包括系统工程师（负责测试环境搭建、服务器和应用服务器的配置）、网络工程师（负责网络环境的维护和验证）、性能分析工程师（负责测试计划的拟定，对性能测试结果进行分析，给出性能测试报告）、自动化工程师（负责测试脚本的编写和测试工具实施）、数据库工程师（负责对数据库层进行性能问题定位）。在条件允许的情况下，还可以包括开发工程师和客户代表，辅助对性能测试结果进行分析和确认。</p>
				<p>性能测试计划是用来指导性能测试过程的主要文档，在测试计划中除了要写明本次测试的测试目标、测试需求外，还需要在测试计划中给出明确的测试退出条件和测试的时间和资源计划。</p>
				<p>第二步 第二步测试设计，也是性能测试的主要内容。测试设计一般基于测试场景进行，一个测试场景就是一个用户的实际使用系统的剖面。</p>
				<p>在性能测试过程中，明确每个场景的参与者人数、比例和具体行为是非常重要的，这些都是构成性能测试脚本的基础。根据经验，可以从应用服务器的日志中分析用户行为。例如，对于一个OA系统，我们从日志中分析出在上午9:00～9:30时段内有200个查看邮件页面的page view，且查看时间基本集中在前10分钟; 而在9:00～9:30时间段内对BUG显示页面的查看量是300个page view，对页面的访问基本平均分配在整个时间段，则我们可以建立两个脚本，前一个脚本模拟查看邮件操作（脚本1），后一个脚本模拟查看BUG操作（脚本 2），考虑运行15分钟的测试场景，则只需在前5分钟运行脚本1，在整个过程中运行脚本2，通过调整think time使得page view达到实际的数值即可。</p>
				<p>当然，并不是每个不同的用户应用剖面都需要作为测试场景来设计，在多数情况下，可以通过对测试场景出现的几率、重要性、风险等进行分析，从而最终确定需要设计的测试场景。明确了场景之后，根据性能测试应用领域的不同，可以采用不同的性能测试方法来达到性能测试的目标。另外需要提醒的是，性能测试设计还应该包括测试环境、测试数据等的设计，因为影响系统性能的因素很多，保持测试过程中环境和数据的可控性是非常重要的。</p>
				<p>第三步 第三步性能测试结果分析，是性能测试过程中最困难，也是最重要的步骤。它需要分析人员对测试结果中的各项数据有准确的认识，明确各指标之间的关系。如果各项数据指标间没有明显联系，在多数情况下需要综合考虑各种因素，才能得出最终结论。</p>
				<p>根据经验，在性能测试过程中最容易发生的问题是数据库访问层问题、应用服务器配置问题以及网络问题。因此建议一般按照“从简至繁”的原则，先排除网络问题，其次对应用服务器配置进行分析，然后在数据库访问层进行性能分析，重点是索引、数据库Cache、死锁等问题的分析。在确认所有这些因素都不是性能瓶颈的情况下，才对代码进行分析和检查，找出导致性能问题的因素。</p>
				<p>只要看看现代软件的规模和功能点数就可以明白，功能测试早已跨越了单靠手工敲敲键盘、点点鼠标就可以完成的阶段。而性能测试则是控制系统性能的有效手段，在软件的能力验证、能力规划、性能调优、缺陷修复等方面都发挥着重要作用。</p>
		</div>
<img src ="http://www.cnitblog.com/tilan/aggbug/19361.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2006-11-20 16:13 <a href="http://www.cnitblog.com/tilan/articles/19361.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Winrunner经验总结 </title><link>http://www.cnitblog.com/tilan/articles/19360.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Mon, 20 Nov 2006 08:12:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/19360.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/19360.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/19360.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/19360.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/19360.html</trackback:ping><description><![CDATA[
		<div class="postText">
				<p> 1.1 脚本录制规范：<br />基本原则是录制脚本要分开、gui文件要合并、批调用回放验证、可移植回放验证。<br />1.1.1 录制脚本要分开：<br />脚本太大，不仅不利于以后的维护，并且会导致WinRunner的不可预测的错误产生（具体可以参考WinRunner 的Readme文档）。录制时，可以根据测试用例的流程，拆分为几个小流程，对每个小流程分别录制成不同的脚本。<br />1.1.2 gui文件要合并：<br />首先，要在系统参数中，设置gui的录制模式为“Global GUI Map File<br />录制过程中，WinRunner会自动产生gui文件，一个测试用例要确保生成一个公用gui文件。用一个gui文件主要是为了以后gui对象的维护，脚本回放时gui对象的查找。但是由于我们的测试用例是分开录制的，每个小流程录制时都会产生一个gui临时文件，因此录制完脚本后要把临时gui文件合并到该测试用例的公用gui文件中。但是也要注意，开始新的录制前，一定要先手工加载测试用例的公用gui文件。<br />如果划分的子流程超过20个，则按每20个子流程录制一个gui文件的方式。Gui文件太大，会影响WinRunner的回放效率。<br />1.1.3 批调用回放验证：<br />为了提高脚本的正确性，每录制完成一个子流程后，都要恢复数据库，其他初始环境进行回放，以近早发现脚本错误。<br />单个测试用例脚本录制完成后，要专门写一个主脚本，进行各子脚本的主次调用处理，然后恢复数据库和其他初始环境进行回放，以验证整个脚本是否可以正确回放。<br />1.1.4 可移植回放验证：<br />由于WinRunner 工具的限制，在本机回放成功后，如果把脚本移植到其他机器上，往往无法成功。这其中既有自己编写的脚本问题，又有WinRunner录制自动生成的脚本问题。<br />自己编写脚本问题：往往是编写的可移植性较差，如加载gui文件时用的是绝对地址，如gui_load(“c:\\aa\\aa.gui”)，这样的脚本换到其他机器必然出错。<br />WinRunner录制自动生成的脚本问题： WinRunner的录制脚本往往和机器的环境有关，如果换了其他机器环境，往往回放不成功，这就需要手工修改脚本。<br />因此，可移植性回放是非常必要的。<br />1.1.5 脚本中使用的ODBC数据源名称统一命名为WR。<br />1.1.6 录入中文数据时统一使用简体。<br />1.1.7 数据表列名称规定<br />录入数据驱动的脚本时，数据表列名称统一采用英文，使用PB数据窗口中列对象的名称。数据表列名称下的第一行用中文对英文列名称做注释，使用PB数据窗口中列对象的中文标签，这一行不作为有效的录入数据。与数据表相关的循环语句请修改脚本从数据表的第二行开始读取数据。典型的例子是将数据驱动脚本中For循环的第一个表达式改为table_Row = 2。<br />1.1.8 脚本成功回放判定规定<br />一个子测试录制完成后，一定要及时回放测试，直到测试报告显示测试结果为OK，且子测试明细报告中没有红色的出错提示。如果是回放主测试，回放成功的标准是：主测试的结果报告显示为OK，同时所有子测试的结果报告也为OK,且子测试明细报告中没有红色的出错提示。<br />1.1.9 WinRuner主脚本中关于设置系统日期时间设置的规定，以保证脚本所描述的业务过程按业务逻辑在时间上有序。<br />因为脚本回放与脚本录制时的系统日期时间不一致，会导致与系统时间关系密切的测试脚本回放时失败。<br />为了消除时间差导致的回放错误,要求每一个测试用例的主测试在第一个子测试前加上date_set_system_date(年,月,日,时,分,秒)函数,以修改本地机器的日期时间等于这个主测试在接力式验收回放成功执行后的日期时间.这样再次回放时系统的日期时间就和上一次成功回放时的日期时间一致。</p>
				<p>1.2 测试脚本存放规范：<br />各子测试脚本必须放到同一目录下，即环境目录下的Script目录下。这样便于批调用时引用。<br />1.3 Gui文件的存放：<br />Gui 文件，必须和测试脚本放到同一目录下，即环境目录下的Script目录下。<br />1.4 WinRunner使用规范：<br />（1） 必须写上清楚的注释：编写测试脚本，要进行详细的标注，每测试一小段，就要写一段备注，以便于将来修改，格式可以参考如下：<br />   功能描述：描述脚本的功能<br />   前置条件：该脚本在满足什么条件下才可以被执行<br />   步骤描述：描述脚本录制的动作<br />   检查点描述：描述作了对什么的检查，检查条件。<br />   录入人：录制人<br />   录入时间：<br />   备注：<br />（2） gui文件的加载保存：<br />每次开始测试用例的录制脚本前，如果该测试用例已经存在gui文件，一定要手工打开gui文件，再开始录制。如果不想手工打开，可以写段自动加载gui的脚本，每次录制前运行一下该脚本。录入脚本后，要注意保存GUI文件，如果测试用例已经存在gui文件，一定要把临时的gui文件合并到该用例的公用gui文件中，然后保存。<br />（3） 如果机器数据较慢，或者网络较慢、或者数据库运行较慢，需要把等待打开窗口的时间设长。或者在脚本中插入同步点来处理。<br />（4） WinRunner不支持Fomular One，目前不可以用wr测试Fomular One<br />使用WinRunner录制时不可以切换不同输入法录制，仅可以用一种输入法。 <br />（5） WinRunner 对shift 键无法纪录，需要特殊处理 ，可以加入如下处理 <br />obj_type "dw_1.fslipbugno","&lt;kShift_L&gt;-";（告诉WinRunner按下Shift键）<br />中间是选择行的脚本<br />obj_type ("dw_1.FBugNo","&lt;kShift_L&gt;+";（告诉WinRunner释放Shift键）<br />（6） 保证录制的脚本干净性：<br />在录制过程中，不可避免的要进行其他动作，如打开邮件、打开非录制程序等，这些动作也会被WinRunner录制下来，这些动作会严重影响测试脚本的回放（除非作这些动作前停止录制）。<br />因此，为了保证脚本的干净，在WinRunner的参数中进行如下设置：设置Recode 的“Selected Applications” 为要录制的程序。 <br />（7） 录制脚本时，不允许同时打开两个运行程序（指进行wr测试的程序）<br />（8） 变量的声明：WinRunner有auto \public \static \extern 四个类型的变量作用域声明，其中public为默认的类型。由于public 是全局的，只要在一个脚本中声明了，在任何其他脚本都可以引用，这就带来一个问题，如果其他的脚本修改了这个public 变量的值，将会引发问题。因此变量声明时必须明确的加上类型（auto \public \static \extern），public 的一般不要使用，推荐使用static \auto 。<br />2. 异常处理规范：<br />在录制或者编写测试脚本时，必须进行异常的错误处理。以提高程序的错误检查能力。<br />2.1 函数异常检测：<br />对于一些常用函数，必须进行函数执行异常的处理。至少进行如下函数的异常检测：et_window、win_activate、menu_select_item、ddt_open。<br />发现异常后，要终止程序的执行，并发邮件通知相关人员。<br />2.2 返回值规范：<br />模块、函数的返回值约定如下，0 表示成功 ，其他失败。<br />对于一些函数的返回值，需要进行判断处理：<br />（1） 每一个call语句都应该检查它的返回值是否为0, 如果不为0则报错退出。<br />所有GUI检查点、数据库检查点都应做返回值检查。如果不为0则报错退出。 </p>
		</div>
<img src ="http://www.cnitblog.com/tilan/aggbug/19360.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2006-11-20 16:12 <a href="http://www.cnitblog.com/tilan/articles/19360.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>RUP测试过程实践之测试需求与测试用例</title><link>http://www.cnitblog.com/tilan/articles/19358.html</link><dc:creator>Joinclass Inc</dc:creator><author>Joinclass Inc</author><pubDate>Mon, 20 Nov 2006 08:09:00 GMT</pubDate><guid>http://www.cnitblog.com/tilan/articles/19358.html</guid><wfw:comment>http://www.cnitblog.com/tilan/comments/19358.html</wfw:comment><comments>http://www.cnitblog.com/tilan/articles/19358.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/tilan/comments/commentRss/19358.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/tilan/services/trackbacks/19358.html</trackback:ping><description><![CDATA[
		<div class="postText">
				<p>RUP（Rational Unified Process ，Ratinaol 统一过程）是rational公司提出的一套软件开发过程，目前最新的版本是2003。RUP的最大特点就是它提供了一套完整的软件开发过程框架，任何人或组织都可以根据自己的需要来对这个过程进行裁剪，并根据自身需要进行调整后使其成为个性化的过程。读者可以参考网络上流传的《RUP2000中文版》。</p>
				<p>（Rational以及 Rational Unified Process 均系 Rational Software Corporation 在美国和其他国家的商标或注册商标。）</p>
				<p>        有句老话说：万事开头难。说的是在做事情的时候，通常都是一开始觉得非常困难，但是只要上了道，入了门，就会越来越容易、越来越顺了。写文章也是如此。不过笔者这里说的开头难并不是不会写文章，而是专指不会写文章的开头部分。过去看到过的很多小说，无论是言情的或者武侠的，都会拿很长的篇幅出来作为“引子”，或者叫“楔子”，用来交待一些同小说相关的信息。而一部小说是否能够吸引读者，这部分内容也起了很大的作用。不过，笔者作为一个技术工作者，写的大多数都是技术文章，一般来说文章的内容、结构都是一早就想明白的，唯独这个开头，实在不知如何写起。不过想想也罢，既然不擅长这个，那就努力把内容写的详细、易懂一些，尽量让读者不会有上当的感觉吧。</p>
				<p> </p>
				<p>       软件测试作为一个独立的职位或者说行业，并不是软件业的新生事物，但的确是随着最近两年一些新的思想注入国内软件行业（比如敏捷开发过程、测试驱动开发等），才得以红火起来的——这一点，从相关书籍的出版和销售就可以看得出来，从事软件测试工作的人也渐渐多了起来。但是也因为是刚刚起步，同时国内大多数软件公司都还处在中小型开发团队甚至作坊式开发的层次，不可能提供太多的测试职位，想找到一些高水平并且富有经验的测试人员更是难上加难。这最终也就导致了国内大多数测试从业者都处在“初级阶段”这样一个结果。</p>
				<p>       笔者长期活跃在国内的几个比较知名的测试论坛，发现大家希望讨论的问题主要可以分为两种：一种是对于一些测试工作具体操作方法的提问，一种是对于测试工具使用的提问。总体看来，更多的问题集中在了后者。这似乎已经成为了国内软件业的通病，无论是开发还是测试，总希望可以通过某个工具或者语言来一劳永逸的实现某个理想。如果真的希望工具可以改变一切，那么这种愿望总是会落空的。而前者，大多是因为进入了一些刚刚开始重视软件测试的中小型软件公司，而公司的开发团队中负责软件测试的可能只有一两个对软件测试一知半解的新手，当公司需要开展某些方面的测试工作时，缺少这部分相关经验的朋友变选择了通过网络求助。</p>
				<p>       测试工具的应用，的确可以提高工作效率，而对于测试工具方面的提问，本来也是无可厚非的，但是在笔者的实践中，如果希望提高一个团队的工作效率和改善工作效果，关注于过程和方法要远远好于关注工具。测试工具的学习、引入和使用，本身就是一个需要消耗大量资源的过程，而且对于工具的选择和引入工具时机的选择也是非常关键的，如果负责这项工作的并不是一位在软件行业沉浸多年，有着丰富测试经验并熟知开发过程的资深人士，那么开发团队将为此承担巨大的风险。即使成功的引入了测试工具，工具本身可以带来的效率的提高也不是在短期内可以体现的。</p>
				<p>       在这里，笔者希望刚刚或者正在准备组建测试团队的软件公司在考虑测试流程的搭建和测试工具引入时，不要给刚刚进入测试行业的朋友太多压力，因为这两项工作都不仅仅同软件测试本身相关，同时也会涉及到项目管理、开发过程方面的内容。轻易的做出一个决定只会对将来在团队中测试工作的开展带来不利的影响。</p>
				<p>       在这篇文章中，笔者不打算对测试工具方面的问题提出任何建议，而将对网络上大家关注的测试过程和测试方法方面给出一些具有实际参考价值的经验。</p>
				<p>       测试工作应该什么时候开始？</p>
				<p>测试用例是不是一定要写？如果写，应该详细到什么程度才会比较好用又容易维护？</p>
				<p>       什么样的测试用例才是好的测试用例？</p>
				<p>       测试用例如何覆盖测试需求？测试需求和测试用例的关系是什么？</p>
				<p>       怎么样保证测试需求的整理和测试用例的设计不会浪费太多的人力或其他资源？</p>
				<p>       ……</p>
				<p>       这些问题可谓是老生常谈了，在论坛上、MSN上，或者邮件中，也经常会有朋友问到笔者一些这方面的问题。相信不管是测试新手，还是从事测试工作有一段时间的朋友，都会在工作中不得不经常的要考虑，这些问题到底有没有一个相对明确的答案呢？</p>
				<p>       相信看到这里，已经有些朋友在想：这些问题也不是很难啊，在RUP对测试过程的描述中都已经说的很明白了啊。软件测试工作必须要通过计划测试、设计测试、实现测试、执行测试、评估测试几个阶段来完成。其中计划测试阶段需要制定测试计划、整理测试需求；设计测试阶段要设计测试用例和测试过程，要保证测试用例完全覆盖测试需求；实现测试阶段要根据测试用例实现具体的自动化脚本或者手工的操作步骤；执行测试阶段则通过自动化测试工具或人手工来执行那些自动化或手工脚本；最后的评估阶段则要对软件的质量和测试工作自身的质量做出一个客观的评价。RUP中还有详细的工作指南和文档模板呢！</p>
				<p>       对，上面所说的这些都没有错，RUP中对于软件测试过程的描述要比笔者上面这段文字详细也生动得多。但是，我们同时也可以看到，RUP中描述到的，更多的是关注于过程的管理，或者更准确的说，RUP是在为我们提供一个大的方向，是一个稳定的、具有指导作用的框架，而不是一些具体的、涉及到操作细节的方法。这也是为什么很多朋友通读了RUP中关于软件测试的部分，但是一旦实际应用仍然找不准方向的原因。笔者今天希望同大家讨论的，则恰恰是这样一些在实践RUP测试过程时，从实际工作中总结出来的工作方法和经验。</p>
				<p>对于测试过程方面的规范和一些基本概念，RUP中已经讲的很详细了，笔者在此也就不再赘述，有需要的读者请参照RUP中的相关部分。本文中所关注的内容包括：</p>
				<p>1.       在计划测试时，如何确定测试工作的范围和如何整理测试需求；</p>
				<p>2.       设计测试用例时，应该如何把握测试用例的粒度；</p>
				<p>3.       如何平衡测试用例的可用性和可维护性；</p>
				<p>4.       如何通过逆向的测试数据分析方法来保证测试用例的有效性和减少测试工作中资源的浪费；</p>
				<p>5.       一个简单的但有实际意义的例子将展示如何将笔者的方法应用到测试过程中。</p>
				<p> </p>
				<p>这里要事先声明一下，笔者工作三年来，不管是开发还是测试，工作内容始终是围绕着信息管理系统相关业务展开的，而对于测试工作，也一直局限于在系统测试阶段通过手工方法和简单的利用一些测试工具特性进行黑盒测试。因此，在本文下面描述的内容中，难免受到客观环境和笔者个人经验的影响。也正因为如此，笔者不保证本文中方法和观点适合于所有组织和个人的软件开发过程。只是希望能够借此为大家提供一种思路，帮助更多人进行个性化的RUP测试过程实践，共同提高软件测试行业的水平。</p>
				<p>另外，本文中使用到的例子，均为笔者的一些假设，如果侵害到任何第三方组织或个人的利益，实属巧合，请通过E-Mail通知笔者，笔者将在今后再次发布本文时做出相应的调整。</p>
				<p> </p>
				<p>       如何确定测试工作的范围？</p>
				<p>       </p>
				<p>       对于一个存在生命周期的软件产品来说，它的开发和测试往往都不是一次性的，因为随着新的需求的出现，以及对原有版本的改进，新的版本会不断的发布（即使对于一些以客户定制方式运作的项目，在开发过程中以及发布后的维护期内，也会产生众多的内部版本）。随着版本的迭代，我们的测试工作也会一直继续下去。而在每一次迭代时，可能在整个工作阶段的开始就受到一些因素的影响，比如市场需求、既定的发布时间、并发的工作导致的资源紧张等等，使我们不得不考虑对软件质量要求的适度，最终使得我们在每个阶段的测试工作的要求或者说所涉及到的内容有可能是不同的。这种变化，最终将会影响到测试需求的确定。</p>
				<p>       那么到底该如何确定每次迭代是测试工作的范围呢？</p>
				<p>在笔者的实践中，通常把测试工作范围的确定，等价的认为是软件需求的确定。</p>
				<p>       不过现在有一个很实际的问题是这样：软件需求在开发过程中不断发生变化，有时候到了后期还会有新的需求添加进来，还有些需求在交付内部测试版本之后又发现原来的需求本身就存在缺陷，之后再次返工，在软件最终发布之前，怎么可能确定的下来呢。啊，这些都是让我们的开发人员和测试人员极其头痛的事情。到底应该怎样在频繁变更的需求中确定哪些部分是我们在某个阶段要测试的内容呢？或者说通过什么样的方法可以改善我们上面提到的那些问题呢？</p>
				<p>一个实际的做法就是实现软件需求的版本化控制。</p>
				<p>既然说到了这里，就不免要说些题外话。笔者一直都认为软件需求是开发工作和测试工作在制定计划、开展工作时所共同参照的源头和依据，而我们只有在源头上控制好，才能保证下面工作的平稳开展。</p>
				<p>如果希望某个阶段工作的进度和内容可以明确的定义下来，就必须要考虑软件需求的版本化控制。这里所提到的“软件需求的版本化控制”，是指在一个软件产品的生命周期中，当要进行一个新版本的迭代时，要尽早的确定这个版本中将要实现的需求，并同上个版本做出比较，哪些内容是新增的，哪些内容是被调整过的。在该阶段工作开始之初的工作会议上，明确的向所有需要了解软件需求的涉众传达这部分信息。而如果在该版本的开发过程中不断的出现需求变更的情况，则应该根据市场策略、已公布的发布时间、客户需求、实现的代价、难易程度以及对现有工作的影响等方面，对需求进行适度划分，严格定义当前版本中需要实现的需求，而其他部分，则作为未来版本的软件需求进行考虑。</p>
				<p>如果有的朋友认为上面的内容还是太理论化，需要一个更实际的、可操作的方法。那么只能说，对于需求的变更，以及因为需求变更而引起的设计的变更，必须要早发现，早讨论，早决定，早调整。这可能更多的要依靠一个团队中相关负责人员的主动工作来保证，而不是依靠一个明确的方法。</p>
				<p>注意，这里的一个关键是，对于软件需求，同样需要严格按照版本进行管理，或者说使</p>
				<p>用“基线”进行管理。</p>
				<p>   如何整理测试需求？</p>
				<p>   一旦当前阶段测试工作的范围确定下来，我们就可以开始考虑测试需求的整理——也就</p>
				<p>是明确的定义现阶段要“测什么”。测试需求的确定将为我们制定进度时间表、分配资源以及如何确定某个阶段测试工作是否完成提供一个可供衡量的标准。当然，还有更重要的一点，已被确定的测试需求是我们进行测试用例设计和考虑测试覆盖的依据。</p>
				<p>整理测试需求的第一步，就是要“测试需求”。</p>
				<p>测试需求？对，不知道您是否想到，这里的“测试需求”中的“测试”是一个动词，指</p>
				<p>的是对软件需求本身的检查。</p>
				<p>       啊？这不是已经超出了测试工作的范围了吗？测试人员不是应该只关心软件的实现同需求是否相符吗？这样对测试人员要求未免太高了。——这是笔者过去同一些朋友谈到测试人员必须对需求进行检查时听到的一些不同的声音。</p>
				<p>       在这里，首先要明确一个问题，就是软件测试的工作到底做什么？</p>
				<p>       在《软件测试》（ Ron Patton〔美〕，中文版由机械工业出版社出版，这本书是测试新手入门的经典教材）一书的第10页，有一个明确而简洁的定义：软件测试员的目标是找到软件缺陷，尽可能早一些，并确保其得以修复。</p>
				<p>       瞧！这里说要“尽可能早”的“找到软件缺陷”。那这“尽可能早”要早到什么时候呢？</p>
				<p>       不知道大家对《软件工程》这本书还有什么印象。至少在笔者看过的多个不同版本的软件工程方面的书中，对于软件缺陷都会有一段类似的描述：缺陷发现的越早，则修复这个缺陷的代价就越小，在需求、设计、编码、测试、发布等不同的阶段，发现缺陷后修复的代价都会比在前一个阶段修复的代价提高10倍（参见下图）。这样看来，上面问题的答案自然就变成了“秃子头上的虱子”：从需求阶段开始！从“测试需求”开始！</p>
				<p>       注意，笔者这里的观点并不是说可以取消团队中的“需求评审会议”，这里并不存在冲突。笔者所希望讲述的，是测试人员应该如何看待软件需求，而并不是把“需求评审会议”所承担的责任揽到自己身上。</p>
				<p>    在论坛上也偶尔看到有的朋友问：如何测试需求呢？每次看到这样的提问，笔者内心就禁不住的一阵激动，因为一直以来，讨论这方面问题的朋友的确少之又少。在笔者的实际工作中，对软件需求的检查包括两个方面的内容。</p>
				<p>      一是对软件需求正确性的检查，也就是要保证需求文档中所描述的内容是真实可靠的。在进行这部分工作时，不要迷信所谓的“都是用户提出的真实的需求”，因为我们必须考虑，提出这些需求的涉众，是否真的可以正确的描述自己的需求？我们的需求人员是否真的可以正确的理解用户的需求？有没有一些被用户认为在业务处理上是理所当然、极其平常的事情，而没有作为需求提出来？有没有一些被用户认为他们过去使用的软件已经提供了相应的功能，所以认为我们也应当提供，而没有提出来的？关于这个问题，也曾经有朋友提过不同的看法，认为这样对测试人员的要求太高了——既要熟悉需求人员的工作，又要熟悉软件所涉及的行业的业务。但笔者还是固执的认为，作为测试人员，还是需要对软件产品所涉及的行业的业务有一个全面的、深入的了解——当然，这不是对一个刚刚入门的测试者的要求，但是如果想称为一个优秀的测试者，是难免要付出这部分努力的。</p>
				<p>       二是要保证软件需求的可测试性。对于“可测试性”，笔者的概念是：对于一条软件需求或者一个需要实现的特性，必须存在一个可以明确预知的结果，并且可以通过设计一个可以重复的过程来对这个明确的结果进行验证。说的具体一点，就是要保证所有的需要实现的需求都是可以用某种方法来明确的判断是否符合需求文档中的描述。如果对于某条需求或某个特性，无法通过一个明确的方法来进行验证，或者无法预知它的结果，那么就意味着这条需求的描述存在缺陷，应该请需求人员对需求文档进行修改或补充——我们有理由相信，如果作为测试人员对需求无法产生准确的理解，那么开发人员也同样无法对同一条需求产生准确的理解。对于一条确定的软件需求理解的二义性，是在不规范的开发过程中导致返工的一个主要原因。如果认为有必要，那应该在“需求评审会议”上确认所有涉众对需求的理解是一致的。</p>
				<p>当然，对于如何提高软件需求的质量，在网络上或者已经出版的书刊中都已经有了很多</p>
				<p>更加具体、实用的方法，如果有兴趣，大家也可以找来参考。不过，如果您是一位测试者，那么上面这部分内容对您仍然是非常有用的。相信您只要在工作中进行尝试，慢慢的体会，一定会发现这种方法给您带来的好处。</p>
				<p>    现在当前的测试工作范围已经确定，相应版本的软件需求也通过了评审，我们就可以在</p>
				<p>这个已经确定的范围内进行测试需求的整理。我们手头上可以参考的东西，通常会有软件需求规约（以下简称SRS）和用例（以下简称UC）——当然，也可能是一份包含UC的SRS。通过对SRS和UC的阅读，我们可以从文档对特性和业务流程的描述中获得对软件所涉及的业务的一个基本的认识。比如用户在处理实际业务时都要作些什么，多个业务之间的先后顺序是怎样的，用户在处理业务是对于哪些地方有特别的要求，等等。这部分规则，将成为我们的测试需求中最基本的一部分。</p>
				<p>       至于测试需求的表现形式，笔者认为大家都可以根据自己的需要进行设计，而没有必要把思路限制在到底使用表格方式还是使用文本方式，只要把握一个原则就行了：在一条测试需求中，用容易理解的自然语言，明确的描述一项需要测试的内容。对于多项测试内容，应尽可能的剥离开来，保证一条测试需求只包含一项测试内容。</p>
				<p>       另外，大家也可能注意到了，在软件开发过程的这个阶段，通常是没有用户界面（以下简称UI）可供参考的——虽然RUP中对于需求阶段的工作描述包括了UI设计的部分，但很多时候在这个阶段还是无法提供一个确定的UI的——也就是说我们这时获得的测试需求，将是完全基于业务的，而并不包括基于UI的那部分规则，是同软件的最终具体实现相独立的。</p>
				<p>       随着开发工作的继续，开发部门的架构设计文档和详细设计文档也将陆续提交，这时候，我们可以根据设计文档来对已有的测试需求进行增补。注意，这里我们对于设计文档中提到的内容要有选择的采用，只有同SRS或UC中已经定义的部分相符的内容，才可以用来调整我们的测试需求。而同软件需求不相符的部分，则需要同设计人员和需求人员一起讨论，确定下以哪一方作为基准，决定是否需要调整软件需求，然后对测试需求进行相应的增补或者调整。比如对于一些算法，需要考虑设计文档中定义的，同系统实现相关的那些计算公式，是否同软件需求中描述的算法表达的是否是同一个意思？而对于一些约束或者业务规则，设计文档中描述的是否同需求中的相应部分一致？</p>
				<p>呵呵，看完上面这部分内容，恐怕又有一部分朋友晕倒在地了，而没有晕倒的那部分朋友也要提出异议：啊？！你这不是又包含了对开发人员所作的设计工作的检查吗？！刚刚让我们检查需求，现在又让我们检查设计，真的把我们当成全才了！</p>
				<p>没办法，为了让软件交到我们手上的时候只包含尽量少的缺陷，大家只能再辛苦一下了。我们的工作不应当仅仅限制在软件交付后尽力找到存在的缺陷，而更应该努力及早发现软件缺陷出现的苗头，尽量预防缺陷的出现。</p>
				<p>虽然并不是说在所有的团队中都应该由测试人员承担“测试需求”和“测试设计”的工作，但是测试人员对这些工作起到的作用，是其他团队中的其他角色所无法替代的。</p>
				<p>      开发部门完成编码实现工作，提交供内部测试的应用程序时，测试人员手头上应该已经准备好了绝大部分测试用例和测试数据，测试部门将开始执行测试。通常在我们执行测试的过程中，即使我们已经从“通过测试”和“失败测试”两个不同的角度准备了非常充分的测试用例和测试数据，但总是有些缺陷的出现是出乎我们意料的，或者说是已有的测试需求和测试用例未能覆盖的。那么，对于这部分缺陷，也应当添加到测试需求中，并设计相应的测试用例，以便于下次版本迭代时进行参考。</p>
				<p>OK，相信说到这里，各位看客也应该可以理解我的观点了：对于一个长期发展的团队或者持续开发的产品，它的所有东西都是要不断积累的、不断迭代的。无论对于软件需求还是测试需求，不仅仅是在一个版本的开发过程中，在不同的阶段进行迭代，在产品的整个生命周期中的不同版本间，也是不断迭代和积累的。</p>
				<p>     关于测试用例</p>
				<p>     什么时候开始设计测试用例？</p>
				<p>测试用例该怎么写？</p>
				<p>什么时候算是完成了测试用例的设计工作？</p>
				<p>     上面几条可以算是网络上测试用例设计方面最热的问题，而且每隔一段时间就会被不同的人重新提起。提问的有刚刚进入测试行业的朋友，也有工作一段时间后重新陷入迷茫的“老手”。这几个问题看似简单，可是要想回答的让大家都感到满意，还真是不容易。这样的高难度，笔者也不敢有太多的奢望，还是把自己的经验写出来，希望对大家有些参考价值吧。</p>
				<p>测试用例是为特定目标开发的测试输入、执行条件和预期结果的集合。这些特定目标可以是：验证一个特定的程序路径或核实是否符合特定需求。——这是RUP中关于测试用例的定义。而在实际工作中，对于测试用例的设计和选择，是考察一个测试人员工作能力和经验的最好方法。</p>
				<p>     如果您像笔者前面说的那样，已经在工作中开展了测试需求的整理工作，那么测试用例的设计工作就会变成一件自然而然的事情了。如果您在需求阶段就开始了对测试需求的整理，那么当这部分测试需求整理完后，就可以开始相应测试用例的设计了。而随着开发工作的继续，在测试需求被不断的增补、调整后，也应该添加或修改相应的测试用例，以保证测试用例的有效性。这里笔者要特别强调一点：测试用例的完成并非是一劳永逸的，因为测试用例是来源于测试需求，而测试需求的来源包括了软件需求、系统设计、详细设计，甚至包括了软件发布后，在软件产品生命周期结束前发现的所有软件缺陷。来源的多元化注定了测试需求是非常容易发生变化的。一旦测试需求发生变化，则测试用例必须重新维护。</p>
				<p>      如果您对于软件开发的迭代方法比较熟悉，那么就可以对测试用例的设计采用同样的方法。而最终的结果，是您的团队将逐渐拥有越来越全面细致的测试需求和测试用例库，测试人员越来越多的精力，可以放到对测试过程的考虑和测试用例的选择方面。</p>
				<p>      至少在笔者的实践中，这种方法虽然前期需要相对大量的投入，但随着时间的迁移，在没有使用自动化测试工具的情况下，同样大大提高了每个测试人员单位时间内测试工作的效率。</p>
				<p>      关于设计测试用例的方法，无论是在已经出版的专业测试书籍还是网络上的专业测试论坛中，都已经有了很多非常好的文章来专门讲解，笔者也不打算占用太多篇幅重新引用，大家如果有这方面需要，通过网络都可以很容易的找到这些资料。在这里，笔者只是想简单的评论一下很多初学者对这些方法容易产生的误解。</p>
				<p>       相信对于任何一个测试人员来说，等价类划分法和边界分析法都是最早接触，也是最基本、最容易使用的测试用例设计方法。很多朋友也都知道先使用等价类划分法划分出等价类，然后使用边界分析法确定测试需要的边界值。但是很多朋友也提到，在工作了一段时间后，发现这两中方法所能应用的地方越来越少，难道这两种方法真的只能应用在检查编辑框输入类型和输入长度的时候吗？当然不是。对于一些刚刚接触测试工作的朋友提出的这个问题，笔者认为现在市面上的很多测试书籍都要承担很大的责任。比如很多书中，在讲到测试用例设计时，都不约而同的使用同一个例子——Windows计算器程序。通常是告诉你对于计算器有一个允许的输入范围（比如允许输入一个大于0小于等于100的整数），然后要求设计相应的包含合法数据和不合法数据的测试用例。当然，仅仅是这样一条简单的描述，我们已经可以设计出很多测试用例和测试数据了，比如对于输入范围的考虑，对于输入数据类型的考虑，对于输入长度的考虑等等。但是在我们的实际工作中，很多时候看到的并不是这样过于简单的软件需求描述，很多时候这些内容都是隐含在一些算法或业务规则中的。</p>
				<p>我们现在举个例子来看一下：</p>
				<p>“双倍余额递减法是在不考虑固定资产残值的情况下，以平均年限法折旧率（不扣残值）的两倍作为折旧率，乘以每期期初固定资产折余价值求得每期折旧额的一种快速折旧的方法。<br />　　　年折旧率=2÷预计使用年限×100%<br />　　　月折旧率=年折旧率÷12<br />　　　月折旧额=期初固定资产账面净值×月折旧率<br />　　为了保证固定资产使用年限终了时账面净值与预计净残值相等，在该固定资产折旧年限到期的前两年，将固定资产净值扣除预计净残值后的余额平均摊销。”</p>
				<p>上面的内容是我国现行财务制度中关于固定资产折旧的一种方法——双倍余额递减法——的具体算法，大家可以在任何一本会计书中找到这部分内容以及一些相应的例子，不过我们这里并不关心固定资产的折旧到底是怎么一回事。笔者想知道的是大家在看完上面的描述后是否已经发现，我们在设计测试用例时，对于准备进行折旧的固定资产，至少应该包括预计折旧年限小于两年、等于两年和大于两年三种不同的类型。这也应该算是一个等价类划分法和边界分析法的应用吧。</p>
				<p>实际上，制约我们更好的使用这些测试方法来进行测试用例设计的，并不是方法的应用范围不够宽广，而是因为如果我们不能对这些同实际业务相关的具体算法或业务规则进行深入的分析，就不可能挖掘出深层的测试需求，那么这两种方法的应用也就很有限了。这也是笔者在前面一再强调加深对软件需求了解的原因。</p>
				<p>对于网络上也有讨论的另外两种方法——错误推测法和因果图法，则分别因为可靠性较差和操作相对复杂而并没有得到广泛的应用。</p>
				<p>   如何划分测试用例的粒度？</p>
				<p>    我们是不太可能在一个测试用例包含所有测试需求的，因为众多的功能以及不同的路径</p>
				<p>组合将使这样一个测试用例像巨无霸一般，完全不具有可操作性。——除非您的软件所包含的功能真的又少又简单，不过如果真的有这么一个软件，恐怕也没有测试和发布的必要了。</p>
				<p>       当然，这也并不是要您走向另一个极端，为需求中定义的每个特性或功能都提供一个甚至多个测试用例。这里的关键，是要寻找一个合适的度。</p>
				<p>笔者推荐的方法是：关注有效功能。</p>
				<p>       有效功能：就是指在被测应用所涉及的实际业务中，当用户在手工状态下进行工作时，整个业务流程中对用户来说，具有实际意义那些功能。这个功能的特征是当我们把这个功能单独从计算机软件还原到用户的原始手工状态时，它的完成可以作为用户实际业务的一个阶段性结束的标志，而不是一旦从这个业务流程中独立出来就失去了意义。而该业务完成后，可以为其他用户或业务提供所需要的信息。</p>
				<p>      这里区分“有效功能”的关键有如下两个：</p>
				<p>       1. 这个功能是可以还原到用户原始的手工业务流程中去的。我们的计算机和软件，都是为了帮助用户解决手工业务中一些烦琐和低效的问题，而提出的一些忠实于原始工作方法或略有变通的解决方案，并不是要改变用户全部的业务流程。所以，应该从用户实际业务的角度来判断功能是否有效。</p>
				<p>       2. 这个功能是否可以标志着用户实际业务的一个阶段性结束？并且这项业务完成之后，被完成的业务实体是否可以交付给其他用户或业务以供完成下面的工作？ </p>
				<p>为了方便理解，我们可以先看一下下面的例子。</p>
				<p>拿我们常见的财务软件来说，当添加一张会计凭证时，通常是需要填写会计科目，在使用计算机完成工作时，我们可以利用软件的功能，从很多备选科目中选择一个自己需要的科目，或者通过科目代码来输入科目。这项功能很有可能会作为一个特性要求出现在软件需求规格说明书中，那么这个科目的选择或输入是不是一个有效功能呢？让我们试着用上面规则来衡量一下。</p>
				<p>首先，这个功能在用户手工业务处理过程中是存在的，不同的是这项功能是在用户填写凭证时，在自己的大脑中完成的——用户会根据需要，在自己记忆的科目中选择合适的填写上去，这项功能节省了用户在记忆大量会计科目时付出的额外劳动。我们可以认为这个功能是为用户原来的工作提供了一种简便的、变通的方法。</p>
				<p>那么这项功能的完成对于用户来说意味着什么呢？我们从上面的描述中可以看到，用户希望软件提供的是可以添加一张完整的凭证这样的功能，而不仅仅是方便填写会计科目。填写会计科目只是用户在添加凭证时的一个步骤，单独把这个功能提取出来对用户来说没有任何实际意义。对于业务流程下游的用户，需要的也不仅仅只是一个会计科目的信息，而是一张包含了会计科目以及其他会计信息的完整的会计凭证，否则就无法进行下面的工作。这样看来，这个功能并不是一个有效的功能，我们可以把它最为需要测试的特性在测试需求中进行描述，却不应该作为一个单独的测试用例出现在我们的测试用例集中。而我们在测试用例中真正关注的，应该是添加会计凭证这个具有实际意义的功能。</p>
				<p>   另外，我们还需要关注如何将多个相互之间存在依赖关系的功能区分为单个的有效功能。例如，现在有A、B、C三个功能，其中B功能的开始必须依赖于A功能的完成，而且A功能如果出现不同的完成状态，B功能也会做出不同的反应；C功能对B功能的依赖也是如此。那么这时候，我们是否应当将三个相互依赖的功能包含在一个测试用例中呢？这样的做法也不是不可以，但是我们也可以先判断一下，这三个功能是否都是有效功能（您可以使用前面提到的方法来试着评判一下）？如果A、B、C都是独立的有效功能，那么我们可以从上面的描述中发现，它们之间存在的依赖性，可以理解为是一种状态或者说数据的依赖性。后一个功能关心的，是前一个功能最终提供给它的是什么样的“输入”，而不是前一个功能到底作了些什么。这样看来，我们完全可以将它们分别包含在几个独立的测试用例中，而在每个测试用例的开始，把不同的输入作为不同前置条件来描述。</p>
				<p>     测试用例是否应该包含所有的细节？</p>
				<p>     这是在网络上听到诉苦最多的又一个热点问题：公司要求按照一个严格的规范来开展测试工作，必须书写所有的测试用例文档，要求文档的书写一定要具体，并在执行测试时要参考测试用例文档来进行。如果测试用例文档写的过于简略，则会被领导斥为偷懒。但是，如果文档中的对操作步骤描述的过于具体，像下面这样：</p>
				<p> </p>
				<p>01.   在“用户名”项中输入“user”；</p>
				<p>02.   在“密码”项中输入“password”；</p>
				<p>03.   点击“确定”按钮。</p>
				<p>这样的描述方式表面看起来可操作性似乎是增强了，任何人拿到这个文档都可以充当测</p>
				<p>试人员，检查一下这个功能是否存在缺陷。但是我们不要忘记，在开发过程中，变更的存在是必然的。一旦需求、设计或者应用程序中的某些细节发生了变化，比如“用户名”变成了“操作员”，“密码”变成了“口令”，“确定”变成了“登录”，或者输入项所接受的数据类型发生了变化，那么同这部分内容相关的所有的测试用例都需要修改。否则，我们凭什么可以保证这些描述不同的测试用例说的是同一样东西？如果我们只有这么一个测试用例，也许一切都不是问题，但是对于一个业务复杂、功能完整的系统，如果按照这样的方法描述测试用例，最终要么产生大量的测试用例文档，要么产生过长的单个文档。无论是那一种，如果发生了类似于上面说的变化，维护文档都将变成一次地狱式的体验。</p>
				<p>这也是为什么在网络上频频出现的这个问题，而且每次出现都会受到测试同行们的关注的原因。那么这个问题应该任何解决呢？测试用例是不是把所有的流程写出来就可以了呢？如何在减少测试用例文档中包含过多琐碎的细节的同时保证测试用例的可操作性呢？又有什么方法可以提高我们维护测试用例文档的效率呢？</p>
				<p>笔者的建议是：关注“测试思想”而不是关注操作步骤。</p>
				<p>要理解这个问题，首先要弄明白测试用例的作用。</p>
				<p>就像用例一样，测试用例并不是用来描述具体的实现的，而是着重描述处理问题的思路——对于一项明确的测试内容进行测试的思路。作为测试用例的设计人员，如何理解基本流和备选流？如何深入分析并找到所有需要覆盖的路径和需要检查的特性？我们在测试用例中应该用容易理解的自然语言清晰的来描述我们将要如何进行测试，而不是简单的把在应用程序上如何操作的烦琐的步骤记录下来。把测试用例设计当成填写具体操作步骤的表格是人们对测试用例最大的误解。</p>
				<p>传统的测试用例文档编写有两种方式。</p>
				<p>一种是填写操作步骤列表：将在软件上进行的操作步骤一步一步详细的记录下来，包括所有被操作的项目和相应的值。</p>
				<p>另一种是填写测试矩阵：将被操作项作为矩阵中的一个字段，而矩阵中的一条条记录，则是这些字段的值。</p>
				<p>网络上对于这两种方式孰优孰劣的争论，将大家错误的引导向了两个极端：要么采用A，要么采用B。而大家却忽视了一点，对于工作方法的争论，本质上同工具的争论并不是一回事（例如曾经的VC、BCB之挣）。如果不同的方法各有优势，我们完全可以通过变通的方法，把优势的部分组合在一起来使用。</p>
				<p>操作步骤列表的优势在于对基本流和备选流进行分析后，它可以清晰的描述您的测试思路。而测试矩阵则更适合于用来存放测试数据，特别是那些需要人工赋予一个确定的值的特性。</p>
				<p>下面，我们来看一个例子，当然，这个例子同样是杜撰的。</p>
				<p> </p>
				<p>需求名称：用户登录安全验证</p>
				<p>需求描述：用户登录安全验证是为了保证所有登录到系统中的用户，都是由系统管理员预先在系统中设定的。使用系统中不存在的用户名，或者用户名输入正确，但密码输入错误情况，都无法登录到系统中。当用户使用了不存在的用户名或错误的密码时，系统应分别给出适当的提示。如果用户连续三次无法使用正确的用户名和密码登录到系统，则系统应给出适当的提示，并退出当前程序。如果用户使用正确的用户名和密码登录到系统，则退出界面，转到系统主界面。对于用户登录界面和程序主界面，请参考相应的UI设计文档。</p>
				<p> </p>
				<p>测试需求：</p>
				<p>01.   检查能否使用正确的用户名和密码登录到系统；</p>
				<p>02.   检查能否使用错误的用户名或密码登录到系统；</p>
				<p>03.   检查使用错误的用户名和密码登录失败超过三次，是否会自动退出当前程序。</p>
				<p> </p>
				<p>测试用例：</p>
				<p>序号<br /> 操作过程描述<br /> <br />1<br /> 输入用户名。<br /> <br />2<br /> 输入密码。<br /> <br />3<br /> 确认登录。<br /> <br />序号<br /> 用户名<br /> 密码<br /> 预期结果<br /> <br />1<br /> 正确的用户名<br /> 正确的密码<br /> 登录到系统并转到系统主界面<br /> <br />2<br /> 正确的用户名<br /> 错误的密码<br /> 无法登录到系统并提示密码错误<br /> <br />3<br /> 错误的用户名<br /> 正确的密码<br /> 无法登录到系统并提示用户名错误<br /> <br />4<br /> 错误的用户名<br /> 错误的密码<br /> 无法登录到系统并退出当前程序<br /> <br />5<br /> 空用户名<br /> ……<br /> ……<br /> 这个例子并不是按照RUP提供的标准模板编写的，它的目的只是要为大家展示，用前面所讲的方法，整理出来的测试需求和设计完成的测试用例到底是个什么样子。所以省略了很多细节，不过大家在实际编写测试用例文档的时候，可以根据自己的需要把相应的内容添加上去。同时，也可以在用户名和密码两个字段中填写准备使用的具体数据。</p>
				<p>相信大家已经看到，在我们的例子中，测试需求同测试用例之间并非是一一对应的关系因为一条测试需求未必是明确的对应到一个有效功能的（其实测试需求本身同软件需求和用例之间也未必是一一对应的）。而我们的测试用例所关注的，应该是一个有效功能。不过您不用担心，这种情况并不会增加您管理测试需求和测试用例的成本，现在市面上提供的测试工具中已经有些是专门用来维护软件需求、测试需求同测试用例之间的关系的，并且它们提供的强大的视图功能还可以让您很容易的查看到测试用例对测试需求的覆盖情况。</p>
				<p>对于例子中的测试用例文档，已经被分成了两个部分，一部分是描述了测试用例执行者所应遵循的操作过程，一部分则是在操作中需要使用到的测试数据。这样做的原因是在我们的实际工作中，尤其是在进行功能测试时，很多时候都是使用雷同的操作过程和不同的测试数据来进行的。而使用上面的方法，可以不用再对原本在多个用例中重复出现的操作过程再次描述，而可以把更多的精力放到测试数据的设计和准备上。这样作带来的副产品，就是提高了测试用例的可维护性。</p>
				<p>怎么？还有人对笔者的观点持怀疑态度？那好吧，那么我们来尝试着证明一下。</p>
				<p>我们的邮递员要在5个城市内奔波，并且每个城市都有些邮件需要投递，他需要找到可以一次走遍5个城市的所有路线。这听起来似乎并不是太复杂，利用我们已有的数学知识，很容易就可以得到答案。但是对于我们要测试的内容，通常都会包含更多复杂的规则。</p>
				<p>例如，我们有三个文本框，每个文本框每次都只能输入一个英文大写字母，允许输入的值只包括：A、B、C三个字母，当三个文本框输入不同的值的时候，我们不知道会发生什么，也不知道它们之间是否会互相影响，所以需要您来设计可以覆盖所有输入情况的测试用例来测试它。</p>
				<p>瞧，这很简单不是吗？如果我们希望每个测试用例在执行时一旦出现缺陷都可以很快的找到导致缺陷的原因，那么最好的办法就是每个测试用例只包括一个同其他测试用例不同的输入值。那么可供我们输入的值都有哪些呢？嗯，对于每个文本框，都至少有A、B、C三种已经声明的不同的值，另外，我们还要考虑当文本框为空、输入空格、输入非英文字符以及输入A、B、C之外的英文字符的情况。那么按照上面的方法，我们会有多少测试用例呢？答案是343个。这只是一个很简单的例子，我们工作中遇到的软件的业务规则和特性决不会比这少的，那会有多少个测试用例呢？God knows. 不过至少有一点可以肯定，我们无法在原有业务规则发生变化时高效的、无差错的维护完343个测试用例。</p>
				<p>但是如果使用我们前面所描述的方法，对于操作过程的改变，您只需要重新维护一次，而对测试数据的维护，也同样是非常简单的，而且并不会因为连续大量修改时出现的错误导致测试用例本身出现歧意。</p>
				<p> </p>
				<p>在将主要精力从“设计”操作步骤转移到设计测试数据之后，我们还将从这种方法中获得更大的益处——通过“逆向测试数据分析”来提高测试工作的整体效率。</p>
				<p>这种“逆向测试数据分析”的方法，是假设软件中存在多个互相依赖的功能，而且这些功能中包含在“依赖链”最末端，并且不再被其他功能依赖的功能。</p>
				<p>在我们准备测试数据时，首先从这个“依赖链”最末端的功能开始，分析这个功能会对不同的输入产生哪些不同的结果。然后将所有的输入进行整理，分清哪些输入是来源于其前一个功能的输出。之后，对该功能的上一个功能进行同样的分析，整理出所有的输入和输出，但是这个功能的输出至少应该包含“依赖链”最末端功能接收到的全部输入。</p>
				<p>继续按照这样的思路循环向上，直到到达“依赖链”开始端的功能。</p>
				<p>不知道您在工作中有没有遇到这样的情况：在对那些“依赖链”上的功能进行测试时，一开始并没有严格的规范测试数据的使用，结果前一个功能测试时产生的数据根本无法在下面的工作中被很好的利用起来，反而因为大量无效数据增加了后面功能的测试难度。最终不得不对每一个功能重新准备测试数据。大量的时间，浪费在了这些重复而低效的劳动上。</p>
				<p> </p>
				<p>当然，如果希望可以进一步提高某个阶段测试工作的效率，还可以考虑应用“设计测试过程”的方法。这里所说的测试过程，指的是我们在执行测试时所设定的执行测试用例的先后顺序。之所以这样作，是因为可以充分的利用不同功能之间的耦合性，尽量通过一次操作来检查尽量多的内容，从而降低已完成工作的无效性或低效性，最终提高某个阶段的整体工作效率。不过，这项工作同样要求操作者必须对被测的系统所涉及的所有业务以及这些业务之间的关系都非常熟悉才行。</p>
				<p> </p>
				<p>如果您正被测试工作的低效问题所困扰，那么建议您尝试一下上面的方法，希望会对您的工作有所帮助。</p>
				<p> </p>
				<p>如何评价测试用例的好坏？</p>
				<p> </p>
				<p>这部分内容的出现，完全是因为不久前同几个朋友的一次讨论。当时大家都认为对于一个测试用例好坏的评价，无外乎两个标准：是否可以发现尚未发现的软件缺陷？是否可以覆盖全部的测试需求？但是后来发现这两个标准对于一些问题是处理不了的。例如，对于一个质量非常好的软件产品，存在的软件缺陷异乎寻常的少，测试用例设计人员准备了大量的测试用例，已经完全覆盖了测试需求，但是只有很少一部分测试用例在执行时发现了缺陷，而其他用例都顺利通过了。那么是否就可以认为顺利通过的那部分测试用例不好呢？</p>
				<p>对于这个问题，笔者认为不管是测试用例是否可以发现尚未发现的缺陷，还是测试用例对测试需求的覆盖度，都是用来评估测试设计人员工作能力和经验的标准，而对于如何评价测试用例的优劣，应该还有其他标准。当然，在不同的团队中可能存在不同的标准，但下面两条应该是适合于任何团队的。</p>
				<p>1.易用性。对于一个即熟悉测试工作，又熟悉被测应用的测试人员，应当可以花费</p>
				<p>很少的时间就可以理解测试用例中表达的测试思路，并可以很快的执行完这个测试用例。</p>
				<p>2.易维护性。当开发过程中的某些因素影响了测试需求，测试用例的作者或其他测试设</p>
				<p>计人员，应该可以花费很少的时间就完成定位并维护所有相关测试用例的工作。</p>
				<p> </p>
				<p>       一些题外话</p>
				<p> </p>
				<p>曾经有朋友问：如果测试用例同软件的具体实现互相独立，怎么保证测试用例的可操作性呢？怎么保证任何一个人都可以一拿到测试用例就可以直接上机执行测试呢？笔者的回答是：尽量不要让这种事情发生。</p>
				<p>首先，笔者一直不赞同那种让“任何人”都可以充当测试人员，按照手中测试用例执行测试的做法。因为对于被测应用的全面了解和熟悉，是作为一个测试人员最基本的要求——在前面的文字中对于软件需求的熟悉也多次被强调。我们无法预知让一个对软件以及软件所涉及的实际业务不够熟悉的人，依靠一份他同样不熟悉的操作步骤列表来执行测试会有什么样的结果。但是有一点可以明确，这就好像让一个没有医学背景的人，仅仅依靠一本七年制本硕连读的《内科学》教材来为患者检查是否患有心脏病，最终结果是患者承担了全部的风险。</p>
				<p>其次，测试用例的本来目的是为了描述我们的“测试思想”——也就是“怎样测”，而是否可以熟练的操作被测应用，并不是在测试用例这个“对象”中所要考虑和保证的，应当剥离出来，作为独立的部分进行处理。而问题的关键，在于如何保证拿到测试用例的人有足够的能力和经验来执行测试，这完全可以通过公司内部对软件及软件所涉及的实际业务的培训，或者软件的操作手册。总之，还是尽量不要随意的加入“任何人”到测试工作中吧。</p>
		</div>
<img src ="http://www.cnitblog.com/tilan/aggbug/19358.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/tilan/" target="_blank">Joinclass Inc</a> 2006-11-20 16:09 <a href="http://www.cnitblog.com/tilan/articles/19358.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>