﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-Tin's Blog-随笔分类-开源</title><link>http://www.blogjava.net/iamtin/category/16715.html</link><description>You are coming a long way, baby~Thinking, feeling, memory...</description><language>zh-cn</language><lastBuildDate>Thu, 29 Nov 2007 02:50:25 GMT</lastBuildDate><pubDate>Thu, 29 Nov 2007 02:50:25 GMT</pubDate><ttl>60</ttl><item><title>Re:架构考量-选择的难度</title><link>http://www.blogjava.net/iamtin/archive/2007/11/28/reply_architecture_debate_of_haokanbu.html</link><dc:creator>Tin</dc:creator><author>Tin</author><pubDate>Wed, 28 Nov 2007 14:39:00 GMT</pubDate><guid>http://www.blogjava.net/iamtin/archive/2007/11/28/reply_architecture_debate_of_haokanbu.html</guid><wfw:comment>http://www.blogjava.net/iamtin/comments/163835.html</wfw:comment><comments>http://www.blogjava.net/iamtin/archive/2007/11/28/reply_architecture_debate_of_haokanbu.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/iamtin/comments/commentRss/163835.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iamtin/services/trackbacks/163835.html</trackback:ping><description><![CDATA[在中文网织年会上和啄木鸟老大HD讨论了一下好看簿的架构问题，而后老黄写了一个blog entry：<br />
<a title="架构考量-选择的难度" href="http://blog.opensource.org.cn/hdcola/2007/11/post-8.html">架构考量-选择的难度</a><br />
里面谈到了架构一个高支撑能力的Web 2.0应用需要考虑的架构选型问题，对我很有帮助。我也回复一下他的建议：<br />
<br />
非常不好意思，今天检查google reader才发现HD老大记录了这个谈话。而我都没有在blog里面记录这个事情。不过和HD老大的谈话回来我还是仔细消化了一下。关于交换机的事情我已经反思了，后来在切换服务器的时候的确发现了百兆和千兆的区别，rsync在百兆网络下的确造成了我们的切换宕计时间变长。当时我们停止服务15分钟，如果是千兆网络估计5分钟以内就可以了，所以如HD所说，我们也许应该选择HW的千兆。<br />
关于文件服务的问题，我想目前的关键还是需要看看是否有热点数据。不过对于网站来说，由于首页和离首页深度比较近的页面被访问的可能性要明显的高，所以如果使用squid做反向代理肯定可以减轻静态文件服务的压力。但是问题也在这里，一定要流量对静态文件有压力的时候再加Squid。<br />
其实本次切换的主要问题是将动态服务与静态服务分开。因为没有选择纯磁盘阵列用光纤或者iSCSI的方式挂在到动态服务器（因为原先的2950充当了文件服务器），所以为了不浪费计算资源我们将动态服务器（8G内存，Raid1和15k rpm硬盘）和静态服务器（8G内存，Raid5和750G X 6的7200 rpm硬盘）分开处理，这样动态服务器跑Django，静态服务器跑Lighttpd。他们之间只需要一个读写的通讯，因为是内部通讯，所以用http是没有意义的。用NFS可能是最直接的方法。用SAN或者iSCSI的方式其实也是可行的，前者是成本问题，而后者是浪费计算资源的问题，所以我们自然的按HD的意思上了NFSv4。<br />
然后又引出MogileFS的问题。其实这是个大文件存储的真谛问题。如果数据量达到一定程度，单个节点不可以承受的时候，那么我们只能选择数据分片，可以时髦的叫做shard，如google做的map reduce的GFS。或者干脆就自己写个简单的数据索引，然后路由分区一下，这个概念就是MogileFS。MogileFS就是利用多个有自己的计算资源的静态服务器来分区存储并管理它们的一个准分布式文件系统（因为MogileFS不支持随机访问，只是整存整取，所以说是准文件系统），它已经能解决我们Web 2.0应用的问题了，Flickr也是这么干的&#8230;&#8230;选用它或者自己做是个看起来和做起来都挺简单的问题，只是它比什么都不需要改变的NFS还是稍微麻烦一点。所以这个作为未来的一种被选方案。其实呼应一下HD在方案分析里面说的应付流量压力的目标，MogileFS只是用来解决存储压力的一个方式。<br />
关于FS，我最近也作了Research，发现这还真是一个坑呀，非常大的坑。XFS、JFS、nb的ZFS都是好方案，但是大文件系统还要考虑分区表格式，MBR已经成了限制，用GPT吧你还不好引导（因为如果你都是大硬盘的话，单弄一个小的上MBR引导，其它再分GPT，势必要浪费一块硬盘，非常不划算），然后LVM解决引导问题吧用起来还不踏实（毕竟它的条带化不是硬件的Raid那样可靠），然后你又需要去对比那几个FS，反正头大。最后还是硬着头皮上了XFS。<br />
我觉得架构考量就像HD所说的，你有无数选择，这些选择造成了噪音，然后在你四处碰壁的时候，你可能选择了第一个可以用的方案去实施。而实际上你会很快发现更好的方案&#8230;&#8230;架构的重构代价是可怕的&#8230;&#8230;所以有了更好的方案可能也不会实施，或者要很久以后再实施。所以，这个经验是需要年头的，也许，也许，很多的方案都让被实施者称为了学徒练手的冬瓜，脑袋上的伤口只有冬瓜自己知道。虽然我作为学徒&#8230;&#8230;看着也疼。我发誓，下次我一定做到更好！<br />
<br />
相关的好看簿故事，我把好看簿服务器升级的过程用照片故事的形式记录下来了，欢迎大家参观：<br />
<a onclick="return top.js.OpenExtLink(window,event,this)" href="http://www.haokanbu.com/story/2991/" target="_blank">http://www.haokanbu.com/story<wbr>/2991/</a><br />
<br />
还有关于中国网志2007的记录<br />
<a onclick="return top.js.OpenExtLink(window,event,this)" href="http://www.haokanbu.com/story/3022/" target="_blank">http://www.haokanbu.com/story<wbr>/3022/</a><br />
<br />
<img src ="http://www.blogjava.net/iamtin/aggbug/163835.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/iamtin/" target="_blank">Tin</a> 2007-11-28 22:39 <a href="http://www.blogjava.net/iamtin/archive/2007/11/28/reply_architecture_debate_of_haokanbu.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>大型Java Web项目的架构和部署调优问题</title><link>http://www.blogjava.net/iamtin/archive/2007/09/17/java_web_architecture_and_performance_turnning.html</link><dc:creator>Tin</dc:creator><author>Tin</author><pubDate>Mon, 17 Sep 2007 14:48:00 GMT</pubDate><guid>http://www.blogjava.net/iamtin/archive/2007/09/17/java_web_architecture_and_performance_turnning.html</guid><wfw:comment>http://www.blogjava.net/iamtin/comments/146003.html</wfw:comment><comments>http://www.blogjava.net/iamtin/archive/2007/09/17/java_web_architecture_and_performance_turnning.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/iamtin/comments/commentRss/146003.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iamtin/services/trackbacks/146003.html</trackback:ping><description><![CDATA[<img height="44" alt="" src="http://www.infoq.com/styles/cn/i/logo.gif" width="140" border="0" /> 本文已经发表于InfoQ中文站，（<a href="http://www.infoq.com/cn/news/2007/09/java_web_architecture_turnning">大型Java Web项目的架构和部署问题</a>）<br />
<style>
blockquote {background:#eee;font-size:12px;}
</style>
<p>一位ID是jackson1225的网友在javaeye询问了<a title="一个大型Web系统的架构和部署选型问题" href="http://www.javaeye.com/topic/117564?page=1" target="_blank">一个大型Web系统的架构和部署选型问题</a>，希望能提高现有的基于Java的Web应用的服务能力。由于架构模式和部署调优一直是Java社区的热门话题，这个问题引发了很多热心网友的讨论，其中一些意见对其它大型Web项目也有很好的指导意义。在讨论之初jackson1225这样描述了当前的应用的架构和部署方案：</p>
<blockquote>
<p>目前系统架构如下:</p>
<ol>
    <li>web层采用struts+tomcat实现，整个系统采用20多台web服务器，其负载均衡采用硬件F5来实现；
    <li>中间层采用无状态会话Bean+DAO+helper类来实现，共3台weblogic服务器，部署有多个EJB，其负载均衡也采用F5来实现；
    <li>数据库层的操作是自己写的通用类实现的，两台ORACLE数据库服务器，分别存放用户信息和业务数据；一台SQL SERVER数据库，是第三方的业务数据信息； </li>
</ol>
<p>web层调用EJB远程接口来访问中间件层。web层首先通过一个XML配置文件中配置的EJB接口信息来调用相应的EJB远程接口；</p>
<p>该系统中一次操作涉及到两个ORACLE库以及一个SQL SERVER库的访问和操作，即有三个数据库连接，在一个事务中完成。</p>
</blockquote>
<p>这样的架构其实很多公司都在使用，因为Struts和Tomcat分别是最流行的Java Web MVC框架和Servlet容器，而F5公司的负载均衡是横向扩展常见的解决方案（例如配置session sticky方案）。由于这个系统中有跨数据源的事务，所以使用Weblogic Server EJB容器和支持两阶段提交的数据库驱动就可以保证跨数据源的事物完整性（当然，容器管理的分布式事务并非是唯一和最优的解决方案）。</p>
<p>但是随着Rod Johnson重量级的著作《J2EE Development without EJB》和其中的Spring框架的流行，轻量级框架和轻量级容器的概念已经深入人心。所以对于jackson1225提出的这个场景，大多数网友都提出了置疑，认为这个系统滥用了技术，完全是在浪费钱。网友们大都认为SLSB（无状态会话Bean）完全没有必要出现在这个场景中，认为SLSB通过远程接口访问本地资源会有很大的性能开销，这种观点也是Rod johnson在without EJB中批判EJB 2.x中的一大反模式。</p>
<p>由于JavaEE是一个以模式见长的解决方案，模式和架构在JavaEE中占有很重要的地位，所以很多业内专家也都警惕&#8220;反模式（Anti-patterns）&#8221;的出现。对于上面所述的方案是否是反模式，jackson1225马上站出来申辩：</p>
<blockquote>
<p>我们项目就是把EJB作为一个Facade，只是提供给WEB层调用的远程接口，而且只用了无状态会话Bean，所以性能上还可以的。</p>
</blockquote>
<p>这个解释很快得到了一些网友的认可，但是大家很快意识到架构的好坏决定于是否能够满足用户的需求，davexin（可能是jackson1225的同事）描述了这个系统的用户和并发情况：</p>
<blockquote>
<p>现在有用户4000万，马上要和另一个公司的会员系统合并，加起来一共有9000万用户。数据量单表中有一亿条以上的数据。这是基本的情况，其实我觉得现在的架构还是可以的，现在支持的并发大概5000并发用户左右，接下来会进行系统改造，目标支持1万个并发用户。</p>
</blockquote>
<p>具体的并发量公布后又有网友置疑这个数据，认为这个系统的Servlet容器支持的并发数太小，怀疑是否配置不够优化。davexin又补充了该项目的服务器配置：</p>
<blockquote>
<p>系统前端tomcat都是用的刀片，配置在2G内存，cpu大概在2.0G，每台机器也就支持250-400个并发，再多的话，就会相应时间非常的常，超过20秒，失去了意义 ，所以我们才得出这样的结论的。</p>
</blockquote>
<p>一位ID是cauherk的网友提出了比较中肯的意见，他没有从Web容器单纯的并发支持能力上提出改进方案，而是提出了对于类似的应用的<a title="一些通用的改进提示" href="http://www.javaeye.com/topic/117564?page=4#368432" target="_blank">一些通用的改进提示</a>，这里摘要一下：</p>
<blockquote>
<ol>
    <li>数据库压力问题
    <p>可以按照业务、区域等等特性对数据库进行配置，可以考虑分库、使用rac、分区、分表等等策略，确保数据库能正常的进行交易。</p>
    <li>事务问题
    <p>要在两个数据库中操作，那么必须考虑到分布式事务。你应该仔细的设计你的系统，来避免使用分布式事务，以避免分布式事务带来更多的数据库压力和其它问题。推荐你采用延迟提交的策略(并不保证数据的完整)，来避免分布式事务的问题，毕竟commit失败的几率很低。</p>
    <li>web的优化
    <p>将静态、图片独立使用不同的服务器，对于常态的静态文件，采用E-TAG或者客户端缓存， google很多就是这样干的。对于热点的功能，考虑使用完全装载到内存，保证绝对的响应速度，对于需要频繁访问的热点数据，采用集中缓存(多个可以采用负载均衡)，减轻数据库的压力。</p>
    <p>对于几乎除二进制文件，都应该在L4上配置基于硬件的压缩方案，减少网络的流量。提高用户使用的感知。</p>
    <li>网络问题
    <p>可以考虑采用镜像、多路网络接入、基于DNS的负载均衡。如果有足够的投资，可以采用CDN(内容分发网)，减轻你的服务器压力。</p>
    </li>
</ol>
</blockquote>
<p>cauherk的这个分析比较到位，其中ETags的方案是最近的一个热点，InfoQ的&#8220;<a title="使用ETags减少Web应用带宽和负载" href="http://www.infoq.com/cn/articles/etags" target="_blank">使用ETags减少Web应用带宽和负载</a>&#8221;里面对这种方案有很详细的介绍。一般以数据库为中心的Web应用的性能瓶颈都在数据库上，所以cauherk把数据库和事务问题放到了前两位来讨论。但是davexin解释在所讨论的这个项目中数据库并非瓶颈：</p>
<blockquote>
<p>我们的压力不在数据库层，在web层和F5。 当高峰的时候 ，F5也被点死了，就是每秒点击超过30万，web动态部分根本承受不了。根据我们程序记录，20台web最多承受5000个并发，如果再多，tomcat就不响应了。就像死了一样。</p>
</blockquote>
<p>这个回复让接下来的讨论都集中于Web容器的性能优化，但是<a title="JavaEye站长robbin发表了自己的意见" href="http://www.javaeye.com/topic/117564?page=5#369868" target="_blank">JavaEye站长robbin发表了自己的意见</a>，将话题引回了这个项目的架构本身：</p>
<blockquote>
<p><strong>performance tuning最重要的就是定位瓶颈在哪里，以及瓶颈是怎么产生的。</strong></p>
<p><strong>我的推测是瓶颈还是出在EJB远程方法调用上！</strong></p>
<p>tomcat上面的java应用要通过EJB远程方法调用，来访问weblogic上面的无状态SessionBean，这样的远程方法调用一般都在100ms~500ms级别，或者更多。而如果没有远程方法调用，即使大量采用spring的动态反射，一次完整的web请求处理在本地JVM内部的完成时间一般也不过20ms而已。一次web请求需要过长的执行时间，就会导致servlet线程被占用更多的时间，从而无法及时响应更多的后续请求。</p>
<p>如果这个推测是成立的话，那么我的建议就是既然你没有用到分布式事务，那么就干脆去掉EJB。weblogic也可以全部撤掉，业务层使用spring取代EJB，不要搞分布式架构，在每个tomcat实例上面部署一个完整的分层结构。</p>
<p>另外在高并发情况下，apache处理静态资源也很耗内存和CPU，可以考虑用轻量级web server如lighttpd/litespeed/nginx取代之。</p>
</blockquote>
<p>robbin的推断得到了网友们的支持，davexin也认同robbin的看法，但是他解释说<a title="公司认为放弃SLSB存在风险" href="http://www.javaeye.com/topic/117564?page=6#370089" target="_blank">公司认为放弃SLSB存在风险</a>，所以公司倾向于通过将Tomcat替换为Weblogic Server 10来提升系统的用户支撑能力。<a title="robbin则马上批评了这种做法" href="http://www.javaeye.com/topic/117564?page=6#370107" target="_blank">robbin则马上批评了这种做法</a>：</p>
<blockquote>
<p>坦白说我还从来没有听说过大规模互联网应用使用EJB的先例。为什么大规模互联网应用不能用EJB，其实就是因为EJB性能太差，用了EJB几乎必然出现性能障碍。</p>
<p>web容器的性能说到底无非就是Servlet线程调度能力而已，Tomcat不像WebLogic那样附加n多管理功能，跑得快很正常。对比测试一下WebLogic的数据库连接池和C3P0连接池的性能也会发现类似的结论，C3P0可要比WebLogic的连接池快好几倍了。这不是说WebLogic性能不好，只不过weblogic要实现更多的功能，所以在单一的速度方面就会牺牲很多东西。</p>
<p>以我的经验来判断，使用tomcat5.5以上的版本，配置apr支持，进行必要的tuning，使用BEA JRockit JVM的话，在你们目前的刀片上面，支撑500个并发完全是可以做到的。结合你们目前20个刀片的硬件，那么达到1万并发是没问题的。当然这样做的前提是必须扔掉EJB，并置web层和业务层在同一个JVM内部。</p>
</blockquote>
<p>接下来robbin还针对davexin对话题中的应用分别在tomcat和weblogic上的测试数据进行了分析：</p>
<blockquote>引用：
<blockquote>
<p>2。1台weblogic10 Express（相当于1台tomcat，用于发布jsp应用）加1台weblogic10（发布ejb应用），能支持1000个并发用户......<br />
......<br />
4。1台tomcat4.1加1台weblogic8，只能支持350个并发用户，tomcat就连结超时，说明此种结构瓶颈在tomcat。 </p>
</blockquote>
<p>这说明瓶颈还不在EJB远程调用上，但是问题已经逐渐清楚了。为什么weblogic充当web容器发起远程EJB调用的时候可以支撑1000个并发，但是tomcat只能到350个？只有两个可能的原因：</p>
<p>
<ol>
    <li>你的tomcat没有配置好，严重影响了性能表现
    <li>tomcat和weblogic之间的接口出了问题 </li>
</ol>
<p>&nbsp;</p>
</blockquote>
<p>接着springside项目发起者江南白衣也提出了一个总体的优化指导：</p>
<blockquote>
<p>1.基础配置优化</p>
<p>tomcat 6？ tomcat参数调优?<br />
JRockit JVM? JVM参数调优？<br />
Apache+Squid 处理静态内容？ </p>
<p>2.业务层优化</p>
<p>部分功能本地化，而不调remote session bean?<br />
异步提交操作,JMS？<br />
cache热点数据？ </p>
<p>3.展示层优化</p>
<p>动态页面发布为静态页面？<br />
Cache部分动态页面内容？ </p>
</blockquote>
<p>davexin在调整了Tomcat配置后应验了robbin对tomcat配置问题的质疑，davexin这样描述经过配置优化以后的测试结果：</p>
<blockquote>
<p>经过测试，并发人数是可以达到像robbin所说的一样，能够在600人左右，如果压到并发700人，就有15%左右的失败，虽然在调整上面参数之后，并发人数上去了，但是在同样的时间内所完成的事务数量下降了10%左右，并且响应时间延迟了1秒左右，但从整体上来说，牺牲一点事务吞吐量和响应时间，并发人数能够提高500，觉得还是值得的。</p>
</blockquote>
<p>至此这个话题有了一个比较好的结果。这个话题并非完全针对一个具体的项目才有意义，更重要的是在分析和讨论问题的过程中网友们解决问题的思路，尤其是cauherk、robbin、江南白衣等几位网友提出的意见可以让广大Java Web项目开发者了解到中、大型项目所需要考虑的架构和部署所需要考虑的关键问题，也消除了很多人对轻量Servlet容器与EJB容器性能的一些误解。</p>
<p>在讨论中还有一些小插曲，如davexin和江南白衣讨论了<a title="JRocket的实时（Realtime）版本是否可以提升Servlet容器的相应能力" href="http://www.javaeye.com/topic/117564?page=8#371197" target="_blank">JRocket的实时（Realtime）版本是否可以提升Servlet容器的相应能力</a>，答案是不可以。还有ID为mfc42d的网友从Servlet容器的并发支持能力引申到了<a title="Java的线程调度能力和NIO对Servelet容器的意义" href="http://www.javaeye.com/topic/117564?page=8#377459" target="_blank">Java的线程调度能力和NIO对Servelet容器的意义</a>，他推荐了自己的两篇不错的blog&#8220;<a title="java的线程实现" href="http://blogger.org.cn/blog/more.asp?name=hongrui&amp;id=25175" target="_blank">java的线程实现</a>&#8221;和&#8220;<a title="java进程使用的最大内存的数值" href="http://blogger.org.cn/blog/more.asp?name=hongrui&amp;id=23973" target="_blank">java进程使用的最大内存的数值</a>&#8221;，blog文章里面从JVM源码级别分析了Java的线程支持能力，面临JVM性能调优问题的网友可以认真阅读一下。</p>
<img src ="http://www.blogjava.net/iamtin/aggbug/146003.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/iamtin/" target="_blank">Tin</a> 2007-09-17 22:48 <a href="http://www.blogjava.net/iamtin/archive/2007/09/17/java_web_architecture_and_performance_turnning.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>与时俱进的轻量级Web服务器</title><link>http://www.blogjava.net/iamtin/archive/2007/08/02/light-web-servers.html</link><dc:creator>Tin</dc:creator><author>Tin</author><pubDate>Thu, 02 Aug 2007 02:10:00 GMT</pubDate><guid>http://www.blogjava.net/iamtin/archive/2007/08/02/light-web-servers.html</guid><wfw:comment>http://www.blogjava.net/iamtin/comments/133926.html</wfw:comment><comments>http://www.blogjava.net/iamtin/archive/2007/08/02/light-web-servers.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/iamtin/comments/commentRss/133926.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iamtin/services/trackbacks/133926.html</trackback:ping><description><![CDATA[本文已经发表于InfoQ中文站点（http://www.infoq.com/cn/news/2007/07/light-web-servers）<br><br>
<p>IBM developerWorks网站上最近发布了一则Cameron Laird的<a href="http://www.ibm.com/developerworks/cn/web/wa-ltwebserv/index.html/?ca=dgr-cn-infoq">关于轻量级Web服务器的文章</a>，
里面列举了很多的轻型的Web服务器实现和它们的特点，Cameron还从自己的经验出发总结了评价Web服务器的一些指标。这篇文章目的在于扩展我们在
Web应用部署时的思路，让我们重新思考Web应用的架构和部署方案。众多的轻量级Web服务器其实见证了动态脚本语言实现Web应用的火爆，给实现
Web应用提供了更多解决方案。</p>
<p>轻量Web服务器这个概念关注&#8220;轻巧性&#8221;，这意味着简单、易于安装、流线化、要求低和健壮。这种&#8220;轻巧&#8221;主要是相对于目前市场占有率占优的
Apache和IIS而言的，轻量Web服务器应该更小更简单，并且它们至少要有一些性能／特性超过这两个产品（这样它们才可能分得市场份额）。
Cameron这样对比了&#8220;轻量&#8221;相比&#8220;重量&#8221;的<a href="http://www.ibm.com/developerworks/cn/web/wa-ltwebserv/index.html/?ca=dgr-cn-infoq">一些优势</a>：</p>
<blockquote style="background: #eeeeee none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; font-style: italic;">轻量级Web服务器可以适用于市场领头产品和其他&#8220;重量级&#8221;服务器无法胜任的情况。例如，整个服务器可以打包在一个文件中。这意
味着开发人员可以方便地携带生产环境所需的所有工具。即使在生产服务器上运行的是
Apache，也仍然可以在宾馆的房间里，借助只需数秒钟就可以安装完毕的轻量级Web服务器以尝试新想法。而且，由于轻量级Web服务器要求很低，因此
可以在那些无法负担IIS的主机上顺畅地运行。</blockquote>
<p>我们关注一下目前的Web服务器占有率情况，Netcraft在它2007年7月的<a href="http://news.netcraft.com/archives/web_server_survey.html">Web服务器调查</a>中的服务器占有率数据如下：</p>
<table border="1" cellspacing="0">
    <tbody>
        <tr>
            <th>开发者</th>
            <th>2007年6月</th>
            <th>百分比</th>
            <th>2007年7月</th>
            <th>百分比</th>
            <th>变更率</th>
        </tr>
        <tr align="right">
            <td align="left">Apache</td>
            <td>65588298</td>
            <td>53.76</td>
            <td>66144734</td>
            <td>52.65</td>
            <td>-1.11</td>
        </tr>
        <tr align="right">
            <td align="left">Microsoft</td>
            <td>38836030</td>
            <td>31.83</td>
            <td>41257913</td>
            <td>32.84</td>
            <td>1.01</td>
        </tr>
        <tr align="right">
            <td align="left">Google</td>
            <td>4872765</td>
            <td>3.99</td>
            <td>5465538</td>
            <td>4.35</td>
            <td>0.36</td>
        </tr>
        <tr align="right">
            <td align="left">Sun</td>
            <td>2273173</td>
            <td>1.86</td>
            <td>2245493</td>
            <td>1.79</td>
            <td>-0.07</td>
        </tr>
        <tr align="right">
            <td align="left">lighttpd</td>
            <td>1470930</td>
            <td>1.21</td>
            <td>1471779</td>
            <td>1.17</td>
            <td>-0.04</td>
        </tr>
        <tr align="right">
            <td align="left">Zeus</td>
            <td>480698</td>
            <td>0.39</td>
            <td>463449</td>
            <td>0.37</td>
            <td>-0.02</td>
        </tr>
    </tbody>
</table>
<p>其中Apache占有率最高，它是公认的稳定、性能优良、开发者活跃的开源软件产品。而Microsoft则受益于Windows平台内置的PWS
和IIS的优势及.NET平台的市场占优率，占有第二的位置。Sun则是由于历史问题，它的iPlanet、SunONE和一并计算的Netscape-
Communications产品还能跻身前4。后面的lighttpd则是轻量型Web容器的代表，已经超过了老牌的商业Web服务器Zeus
（ServerWatch给出了一个<a href="http://www.serverwatch.com/stypes/servers/index.php/17191__r">lighttpd市场占有率上升的分析</a>），主要因为一些AJAX项目和Ruby on Rails（以下简称RoR）的流行对它的广泛部署起了推波助澜的作用。</p>
<p>轻量Web服务器除了lighttpd还有mongrel也经常被提及，主要因为它们是RoR项目的两种主要部署方案。JavaEye的创始人<a href="http://robbin.javaeye.com/">Robbin Fan</a>曾经在它的blog中对比过RoR的这<a href="http://robbin.javaeye.com/blog/98658">两种部署方案</a>：</p>
<blockquote style="background: #eeeeee none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; font-style: italic;">（RoR项目）用fcgi方式还是http方式，我个人觉得区别不大，关键还是看应用的场合，一般而言，推荐的搭配是lighttpd＋fcgi 或者nginx＋mongrel，而Apache因为性能差距，而不被推荐。</blockquote>
<p>lighttpd+fcgi是大量使用脚本语言编写的网站的首选部署方案，Robbin Fan在同一篇文章中阐述了他选择lighttp部署JavaEye的理由：</p>
<blockquote style="background: #eeeeee none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; font-style: italic;"> JavaEye为什么用lighttpd＋fcgi呢？原因如下：
<p>1) lighttpd发展了好几年了，市场占有率也相当高，是一个经过实践检验的server，它的文档也很全；</p>
<p>2) JavaEye的Ruby进程和Web Server在一台机器上面跑，通过unix socket使用fcgi协议通讯可以避免tcp的网络开销，其通讯速度比使用tcp socket使用http协议通讯要快一些。</p>
</blockquote>
<p>Robbin选择lighttpd的主要原因是性能好于Apache。并且Apache目前的fastcgi模块有些bug，而对于像RoR这样的项目fastcgi是一种很好的部署方式，所以Apache就因此失去了这块份额。最近InfoQ报道过的<a href="http://www.infoq.com/cn/rubyworks">RubyWorks</a>提
供的RoR工作栈中选择了Haproxy+mongrel的方式，这也是前面引用的Robbin所说的另外一种部署方案。mongrel本身可以跑
Ruby进程，同时也是一个http服务器，它可以兼顾动态和静态Web服务，配合Haproxy做负载均衡就可以支持大并发量的Web应用，所以它越来
越流行了。</p>
可见轻量级Web服务器由于性能／特性上的一些优势，开始逐渐瓜分Apache、IIS所没有照顾到的一些新兴的市场分额。那么如何去评价一个Web服务器呢？Cameron给出了如下的<a href="http://www.ibm.com/developerworks/cn/web/wa-ltwebserv/index.html/?ca=dgr-cn-infoq">一些重要指标</a>：  <blockquote style="background: #eeeeee none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; font-style: italic;">
<li><span style="font-weight: bold;">性能：</span>对请求作出响应的速度有多快？</li>
<li><span style="font-weight: bold;">可伸缩性：</span>当很多用户同时访问它时，服务器还能继续可靠地运行吗？</li>
<li><span style="font-weight: bold;">安全性：</span>服务器是否只执行它应该执行的操作。它在认证用户和加密传输方面提供了怎样的支持？它的使用是否使附近的应用程序或主机变得更易受攻击？</li>
<li><span style="font-weight: bold;">可靠性：</span>服务器的失效模式和故障发生率如何？</li>
<li><span style="font-weight: bold;">标准遵从性：</span>服务器遵从相关的 RFC 吗？</li>
<li><span style="font-weight: bold;">灵活性：</span>是否可以对服务器进行调优，以支持较重的请求负载、需要计算的动态页面或者代价不菲的认证等等？</li>
<li><span style="font-weight: bold;">平台需求：</span>该服务器可用于哪些平台？它是否有特定的硬件需求？</li>
<li><span style="font-weight: bold;">易管理性：</span>服务器是否易于设置和维护？它是否与日志记录、审计、成本计算等组织标准兼容？</li>
</blockquote>  目前越来越多的轻型Web服务器开始在上面的一个或着多个方面向Apache和IIS提出了挑战，因为很难有一个Web服务器可以做到面面俱到。我们可以从Cameron提供的一份列表里面看到一些选用轻量级Web服务器的<a href="http://www.ibm.com/developerworks/cn/web/wa-ltwebserv/index.html/?ca=dgr-cn-infoq">成功案例</a>：   <blockquote style="background: #eeeeee none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; font-style: italic;">
<li>YouTube依靠lighttpd快速交付归档的内容，例如视频；</li>
<li>cdServe运行 &#8220;German Woodworking Machinery and Tools&#8221; CD；</li>
<li>LiteSpeed宣扬它在
twitter、www.funnyoride.com、www.airliners.com、WordPress.com、
fanfiction.com、SlashGear、www.forumactif.com 和其他著名Web 站点上担任的角色；</li>
<li>OpenSUSE、RubyOnRails、MarkaBoo和其他一些著名站点依赖于Mongrel；</li>
<li>demon.net、bluelight.com、mtv.com、The Drudge Report、garfield.com等站点则使用thttpd；</li>
</blockquote>
<p>上面的例子中有一些使用RoR的网站的例子，Cameron指出不仅是网站可以使用常规以外的其他编程语言。&#8220;不常见&#8221;语言还可以被用来实现轻量
Web服务器，例如Erlang、Java、Lisp、Lua、Perl、Python和Tcl。用这些语言实现的轻量级Web服务器不一定只是在性能／
特性上超过Apache和IIS，它们可以提供例如容易嵌入、体积轻小这样的特性来吸引开发者的使用。Cameron给出了使用&#8220;不常见&#8221;语言编写轻量级
Web服务器的原因：</p>
<blockquote style="background: #eeeeee none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; font-style: italic;">
<li>教学：使用轻量级Web服务器来制定一个重要、但是并不太大的目标。这是获得使用某种语言的经验的好方法。</li>
<li>虽然用C编写的轻量级Web服务器大小为10-50KB，更高级的语言有100KB到数MB的运行时，但整个 Web 服务器的源文件可能只占几千个字节。这种Web服务器占用的空间很小，因此比Apache更易于与技术伙伴共享。</li>
<li>更高级的语言可以使实验更吸引人 —— 例如，添加一个新的HTTP/1.1特性可能只需几行源代码。这些轻量级服务器是非常方便的实验材料。</li>
<li>将HTTP服务器添加到已有的、用高级语言编写的应用程序中只需增加几行源代码。</li>
<p>如前所述，不同的轻量级Web服务器有着不同的优点，它们或多或少独立于编程语言。所有轻量级Web服务器都比Apache更小、更易于配置。与
Apache相比，有些轻量级 Web
服务器更快，有些则快得多。有些则强调安全性、重负载下的从容性、可扩展性或者内存占有量。在任何情况下，都可以以一种不适用于 Apache
的方式彻底地理解这些服务器。</p>
</blockquote>
<p>这些理由从另外一个方面说明了轻量级Web服务器的优势，Cameron还提供了一长串的轻量级Web服务器的<a href="http://www.ibm.com/developerworks/cn/web/wa-ltwebserv/index.html/?ca=dgr-cn-infoq">列表和简介</a>，感兴趣的读者可以认真阅读，从中寻找到您感兴趣的实现。轻量级Web服务器不只是Apache、IIS的竞争者，也是很好的合作者（例如我们经常可以见到关于mongrel与Apache<a href="http://robbin.javaeye.com/blog/43290">配合使用的文章</a>），现在我们还可以看到很多服务器协作部署的例子，各取所长应该是最佳的选择，所以我们更应该从现在就开始拓宽眼界，寻找我们所需要的。</p>
<p>最后，推荐对Web服务器感兴趣的读者可以使用Netcraft提供的<a href="http://news.netcraft.com/">Webserver Search</a>的服务器查询功能来探索你感兴趣的网站的服务器，Webserver Search可以报告搜索的url对应的服务器的操作系统和Web服务器类型，是设计部署方案的一个很好参考。</p>
<br><br><img src ="http://www.blogjava.net/iamtin/aggbug/133926.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/iamtin/" target="_blank">Tin</a> 2007-08-02 10:10 <a href="http://www.blogjava.net/iamtin/archive/2007/08/02/light-web-servers.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于InfoQ的“评论：C#正变得越来越臃肿”的感想</title><link>http://www.blogjava.net/iamtin/archive/2007/07/31/133581.html</link><dc:creator>Tin</dc:creator><author>Tin</author><pubDate>Tue, 31 Jul 2007 07:41:00 GMT</pubDate><guid>http://www.blogjava.net/iamtin/archive/2007/07/31/133581.html</guid><wfw:comment>http://www.blogjava.net/iamtin/comments/133581.html</wfw:comment><comments>http://www.blogjava.net/iamtin/archive/2007/07/31/133581.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/iamtin/comments/commentRss/133581.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iamtin/services/trackbacks/133581.html</trackback:ping><description><![CDATA[有幸在InfoQ的饭局里面认识了王翔，他对.Net和MS技术的确有非常深的造诣。今天看到他的一篇评论：<a href="http://www.infoq.com/cn/news/2007/07/csharp-getting-plump">&#8220;C#正变得越来越臃肿&#8221;</a><br>发表了一些感想：<br><br>先进与成熟的确是矛盾，但是现在的新技术成熟的都比较快，可能是人接受新事物的速度提高了吧。<br>Haskell这样的语言是函数式编程的代表，更多的需要从头开始。所以国外学计算机理论首选Haskell，很多老外抱怨过上学的时候这个东西学的头疼，但是后来他们也都表示获益匪浅。我们的计算机教育是本末倒置，所以我们这些程序员觉得他们晦涩难懂。但是看到Erlang这样的语言，在未来多核环境下的前途，我们还是会动摇的。<br>LINQ的确不错，但是又是M$一言堂。统一数据访问模型是非常好的想法，MS总能后发制人，但是闭门造车很容易被人家超过。现在我们看到LINQ很先进，但是等MS的讲师把它推到实践的第一线的时候，别的开发平台也会有类似的产品出现了。而且，根据标准，查询XML用JQuery，在各种语言里面查询关系数据库也都有众多ORM实现。所以LINQ的想法虽然很好，但是对于其他语言／平台来说却没有非常迫切的需求去实现类似的技术。<br><br>关于修改Java JVM的话题不是最紧才有的，下一步会怎样很难说。CLS这个技术不足为奇，其实虚拟机本身就是平台／语言无关的东西，我们已经看到了JRuby、XRuby、Jython和现在的Java Script Engine这样的东西，Java已经在平台化了，这个大家都不会放慢脚步。<br><br>关于C#和Java的痼疾，我推荐Bruce Tate的《超越Java》，里面的观点同样适用于C#。<br><br>他的原文引用如下：<br>
<div style="background: #eeeeee none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; font-style: italic;">
<p>C# 2.0发布的时候，我们回头看Java，总认为这个语言怎么发展得这么慢？但当C#发展到3.0的时候，它也<a href="http://www.theserverside.net/news/thread.tss?thread_id=46268">开始显示出臃肿之态</a>了，这是否会也会带来什么连锁效应呢？</p>
<p>6年前，我是个Java的拥护者，当时C#还是1.0版，我经常和师傅争论Java如何比C#好，于是他给我一个回答：&#8220;我们的COM比Java早
了近5年，所以我们更成熟；我们的.NET比Java晚了5年，所以更先进&#8221;。虽然这么比较有&#8220;偷换概念&#8221;的感觉，但现在想想其实有另一层意思——&#8220;成熟
与先进&#8221;的矛盾。</p>
<p>Lisp、Haskell、Scheme这些语言也都可以被称之为&#8220;伟大&#8221;，但为什么很少有人去学呢？因为需要用太多的东西&#8220;充斥&#8221;我们的大脑后才
可以使用。Java和C#之所以可以快速地被普遍接受，一个很重要的原因就是因为它们的简单与清爽。但当明年春天C#
3.0发布的时候会怎么样呢？虽然你可以将WCF、WF、WCS和WPF视为.NET的外挂，不予理会，但LINQ是个不好回避的内容，因为它在处理数据
访问（关系型的、非关系型的）方面有比较明显的优势，所以即便你个人排斥它，其他还是会有很多人用。最后很可能成为这样一种局面：参与到一个项目组，自己
只能从事一些表层业务开发，因为下层的公共封装机制都是用LINQ编写的，况且还有Enterprise Library这个&#8220;样板工程&#8221;在后面催着。</p>
<p>可以这么说，C#越来越臃肿是个必然的趋势，作为.NET语言的&#8220;主力&#8221;，随着新的开发架构的出现，C#的复杂性还会增加，同时很可能导致革新特性越出越慢，毕竟牵扯的内容多了，作为&#8220;主力&#8221;除了要考虑语言特性间的协作外，还要充分考虑处理效率。</p>
<p>不过比起&#8220;一条道跑到黑&#8221;的Java而言，.NET平台有个优势——CLS（Common Language
Specification，公共语言规范）。相信Java的设计者不太愿意，也不敢随便为了一个&#8220;快速走红&#8221;但还没有2年时间市场考验的技术趋势就去修
改Java编译器；.NET不同，&#8220;C#红旗不倒的同时，.NET平台可以彩旗飘飘&#8221;，比如Spec#就是个例子，为了避免null对于软件的影响，.
NET家族诞生了<a href="http://research.microsoft.com/specsharp/">Spec#</a>，目的就是通过非null这个前提，提高数据验证、异常处理、堆栈管理的能力，利于开发者提供更高质量的软件；<a href="http://research.microsoft.com/fsharp/fsharp.aspx">F#</a>也是，虽然C#是强类型的，但动态语言式的开发一样可以基于这个&#8220;小兄弟&#8221;开发，加上它和其他.NET语言前辈基于同一个CLR环境，所以功能毫不逊色。</p>
<p>综上所述，C#臃肿是不可避免的，而且很可能会像Visual
C++一样，因为语言的复杂性，导致C#开发人员技术能力的两极分化。但同时，借助试验性.NET语言的支持，即便需要集成新的特性，也不会像某些语言一
样从头开始。依靠试验性语言的积累，相信从MSDN中查看C#这些新语法的时候，可以少见一些标着&#8220;[Obsolete]&#8221;的内容。</p>
&nbsp;</div><img src ="http://www.blogjava.net/iamtin/aggbug/133581.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/iamtin/" target="_blank">Tin</a> 2007-07-31 15:41 <a href="http://www.blogjava.net/iamtin/archive/2007/07/31/133581.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java交互管理工具——SecureJSH发布</title><link>http://www.blogjava.net/iamtin/archive/2007/07/27/java-securejsh-publish.html</link><dc:creator>Tin</dc:creator><author>Tin</author><pubDate>Fri, 27 Jul 2007 01:56:00 GMT</pubDate><guid>http://www.blogjava.net/iamtin/archive/2007/07/27/java-securejsh-publish.html</guid><wfw:comment>http://www.blogjava.net/iamtin/comments/132698.html</wfw:comment><comments>http://www.blogjava.net/iamtin/archive/2007/07/27/java-securejsh-publish.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/iamtin/comments/commentRss/132698.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iamtin/services/trackbacks/132698.html</trackback:ping><description><![CDATA[<p>本文已经发布于InfoQ中文站（http://www.infoq.com/cn/news/2007/07/java-securejsh-publish），感谢Complystill为我们贡献了SJSH这个项目。<br></p>
<p>JavaEye上活跃的<a href="http://complystill.javaeye.com/">开发者Complystill（歆渊）</a>最近发布了自己的开源<a href="http://www.javaeye.com/topic/100212">SecureJSH项目</a>，提供了一个通过SSH交互进行Java应用开发或者管理的工具。</p>
<p>在项目的介绍中可以得知，SecureJSH与Ptyhon里面的ipython或者Ruby里面的irb非常相似。它们都允许交互式运行语言的代
码，以方便跟踪或者调试应用。但是，Java与Ruby、Python不同，后者是动态脚本语言，它们天生具有解释执行的特点（注意：当然Python支
持预编译，Ruby也将在YARV中开始支持，这里指它们的解释执行状态）。我们常见的Python和Ruby发行版本基本上都包括自己的解释器（这也是
它们的核心组件），但是Java是一种需要中间编译过程的语言，默认情况下它无法直接解释运行，也没有相应的解释器。</p>
<p>那么SecureJSH是如何实现的呢？读者首先会想到JSR-223，这个API可以自己扩展脚本语言支持，比如rhino是
Javascript解释引擎。但是使用它难以实现交互操作，因为它必须输入一个相对完整的脚本才可以运行，这样会丧失一部分交互性。SecureJSH
实际上是使用了JDK 6.0的新特性Java Compiler
API（JSR-199），它提供了一组API来让程序可以动态地访问Java编译器的接口，这样就可以使用Java编译器动态检查代码语法或者动态根据
Java源码生成可以执行的字节码。这种方式与ASM的编程直接生成字节码不同，它能直接将Java源码转换为字节码，XRuby的主力开发者郑晔（网名
dreamhead）在他的Blog中<a href="http://www.infoq.com/cn/news/2007/07/java-securejsh-publish" dreamhead.blogbus.com="" logs="">这样对比了两种方案</a>：</p>
<blockquote style="background: #eeeeee none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">之前，刚刚<a href="http://dreamhead.blogbus.com/logs/2006/12/4007513.html">在Blog中提到ASM</a>，
里面的代码生成工作是通过直接写 字节码完成的。现在有了Compiler
API，可以考虑生成代码以Java源码的形式完成，然后，通过调用Compiler
API对源码进行动态编译，这样，可以达到同直接写字节码类似的作用。使用Compiler
API，肯定不如直接生成字节码来得高效，但对于不了解JVM指令的人来说这也许是一种解决方案。</blockquote>
<p>可见JSR-199不是最高效的字节码生成方案，但是更方便使用。Java Compiler
API不是为了取代ASM这样的方案的，它的本意是以编程的方式实现实时编译及信息反馈。Java目前的主要架构师之一Peter von der
Ah&#233;曾经在他的Blog对谁需要使用Java Compiler API这个问题做了<a href="http://blogs.sun.com/ahe/entry/java_compiler_api_who">如下解释</a>：</p>
<blockquote style="background: #eeeeee none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">99%的Java开发者都不需要了解Java Compiler
API。只有少数的开发者会直接应用这个API。但是IDE、Java
EE应用程序服务器、Maven或者Ant还有测试框架的开发者却不一样，他们有一个共同点，就死需要调用编译器将Java源码转换为类文件（他们是这个
API的潜在用户）。</blockquote>
<p>可见JSR-199的产生主要是面向热部署或者增量编译这样的场合，但是SecureJSH的产生扩展了Java Compiler API的应用场景，同时也增强了Java和JVM的交互性。Complystill这样介绍了<a href="https://sjsh.dev.java.net/">SecureJSH的应用场景和需求</a>：</p>
<blockquote style="background: #eeeeee none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">SecureJSH允许Java编写的服务器端应用程序为管理员、客户、开发者和客户端服务提供一个安全shell，这里可以交互性地让Java语言逐句运行。SecureJSH需要JDK 6.0或者JRE 6.0加JAVAC（在classpath中）来运行。</blockquote>   <a href="https://sjsh.dev.java.net/">SecureJSH的官方首页</a>这样描述了它的主要特性：
<blockquote style="background: #eeeeee none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">
<ul>
    <li><strong>安全：</strong>SecureJSH在服务器端实现了RFC-4251，SSH 2.0协议，支持公钥认证，这种方式方便安全（不需要每次输入密码）。</li>
    <li><strong>交互式执行：</strong>传
    统的方式下，在运行Java源代码之前你必须将它们编译为字节码。但是使用SecureJSH，编译的过程是透明完成的，所以你只需要随意输入一些
    Java表达式（就可以运行）。这意味着你可以使用你书写应用程序时完全相同的语法，与最新的Java语言规范同步。你可以在你的Java项目源码和
    SecureJSH终端里面拷贝＆粘贴任何代码，都没有问题。</li>
    <li><strong>智能命令识别，UNIX Shell风格：</strong>不
    像JSR-223（Java Scripting
    Engin，Java脚本引擎）对Java语言的脚本的支持，在（Java脚本引擎）里面你必须将Java类的全部代码输入后才可以执行，
    secureJSH更加智能和人性化，如果你输入了不完整的Java表达式，它会自动提示你进行多行的输入，然后将这些表达式包装到一个预先定义的类结构
    中来执行。它是一个真正的Shell。</li>
    <li><strong>没有相互干扰，最小化资源消耗：</strong>SecureJSH没有需要储存在JVM范围的静态资源，每一个实例只消耗很少量的资源（基于NIO实现，所有的SSH通讯都由一个线程处理）。你可以按照你的想法在一个JVM里面运行任意多个shell服务，包括Java应用程序服务器的JVM。</li>
</ul>
</blockquote>
<p>作为一个开源项目，SecureJSH使用了ganymed的纯Java实现的SSH 2.0库，并使用Java
NIO编写了网络服务，代码质量很高。据Comply
Still介绍，SecureJSH最初是为内存数据库TOB设计的，为这个面向对象数据库提供交互访问的接口，但是后来作者发现它可以被应用在很多场
合，所以单独开源发布。作为Java开发者，您可以从<a href="https:///" sjsh.dev.java.net="" servlets="" projectdocumentlist="">这里下载源码</a>从中学习SSH 2.0、NIO网络服务、Java Compiler API的使用方法，相信一定会有所收获。</p><img src ="http://www.blogjava.net/iamtin/aggbug/132698.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/iamtin/" target="_blank">Tin</a> 2007-07-27 09:56 <a href="http://www.blogjava.net/iamtin/archive/2007/07/27/java-securejsh-publish.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>争论又起，RIA的未来在哪里？</title><link>http://www.blogjava.net/iamtin/archive/2007/07/18/dhh-debates-ria-future.html</link><dc:creator>Tin</dc:creator><author>Tin</author><pubDate>Wed, 18 Jul 2007 06:28:00 GMT</pubDate><guid>http://www.blogjava.net/iamtin/archive/2007/07/18/dhh-debates-ria-future.html</guid><wfw:comment>http://www.blogjava.net/iamtin/comments/131063.html</wfw:comment><comments>http://www.blogjava.net/iamtin/archive/2007/07/18/dhh-debates-ria-future.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/iamtin/comments/commentRss/131063.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iamtin/services/trackbacks/131063.html</trackback:ping><description><![CDATA[<p>本文已经发表于InfoQ（<a title=争论又起，RIA的未来在哪里？ href="http://www.infoq.com/cn/news/2007/07/dhh-debates-ria-future">http://www.infoq.com/cn/news/2007/07/dhh-debates-ria-future</a>）<br><br>David Heinemeier Hansson（以下简称DHH，Ruby on Rails作者）在最近的一篇Blog&#8220;<a href="http://www.37signals.com/svn/posts/487-what-if-i-actually-like-html-css-and-javascript"><u><font color=#0000ff>如果我真的喜欢HTML、CSS和Javascript，那又怎么了？</font></u></a>&#8221;（What if I actually like HTML, CSS, and JavaScript?）中阐述了他对RIA未来的一种看法。他认为目前在三大Web标准规范下的HTML、CSS和Javascript是一套足够强大的工具箱，这些技术提供给开发人员的功能并没有影响到Web应用的发展，并且随着像<a href="http://www.getfirebug.com/"><u><font color=#0000ff>Firebug</font></u></a>和其他优秀Javascript库的支持下，Web程序员的日常开发工作已经非常惬意了。DHH表示：</p>
<blockquote><span style="BACKGROUND-COLOR: #c0c0c0">从用户体验的角度来说，我们甚至还没有发挥出HTML的全部潜力。</span></blockquote>
<p>本篇Blog引起了众多网友的评论，大部分人都认同DHH的观点。大部分开发者认为基于标准的Web开发还大有潜力可挖，通过加强设计者与开发者的联系，产品的用户体验可以得到很大的提升。目前大部分Web应用还不能令人满意，但是这个问题并不完全归咎于浏览器的非标准实现，更多的是因为设计和开发者本身对技术的掌握还不到位。DHH认为不能假设用新的（基于插件的）RIA技术开发出了非常令人惊奇的应用，就认为这些更&#8220;先进&#8221;和&#8220;富&#8221;的技术会取代我们正在使用的HTML、CSS和Javascript等。相反，DHH认为对这些技术的过度鼓吹都是废话。但回复的网友中也有一些人认为这是DHH对于RIA技术革命的不友好表现，例如Flexible Rails的作者Peter Armstrong就认为Flex结合Rails可以带来更好的用户体验。而后，DHH也很快出来澄清说他只是向那些无视HTML、CSS和Javascript的技术狂热者表示反对，而Rails是非常欢迎其它RIA技术作为补充的。</p>
<p>在国内技术社区，Ajax方面的专家（<a href="http://ajaxcn.org/space/start"><u><font color=#0000ff>Ajaxcn网站</font></u></a>站长）李锟针对DHH的这篇博客也发起了<a href="http://www.javaeye.com/topic/95739?page=1"><u><font color=#0000ff>讨论</font></u></a>。讨论中李锟认为基于标准的HTML、CSS和Javascript在RIA的未来发展中还将扮演主力的地位，引出许多针锋相对的观点讨论。最后大家基本上一致认为基于标准和模式进行基于HTML、CSS和Javascript的开发在目前还没有成为技术瓶颈，这些技术在未来还有很多潜力。李锟很好地总结了开发者目前面临的问题，现在看到了技术局限是因为对它的了解，而其它新兴RIA技术是否会成为主流还要等它们充分暴露问题以后再说。</p>
<blockquote style="BACKGROUND-COLOR: #c0c0c0">Apple的iPhone也将Mobile Ajax作为他们首先支持的一种开发技术，这也不是偶然的。我觉得我们应该看到技术本身的局限，也应该看到技术未来发展的趋势。我们之所以对基于Web标准的技术局限看的这么清楚，也是因为对这些技术我们已经有了大量的实践。而其他的RIA技术目前尚未得到大量的实践，它们描绘的美好蓝图能否实现还未可知，它们存在哪些局限还没有充分暴露出来。</blockquote>
<p>这里李锟引用发布于<a href="http://www.infoq.com/cn/news/2007/06/mobileajax"><u><font color=#0000ff>InfoQ中文站上的这条新闻</font></u></a>，其实表明了基于标准的Ajax有可能被作为另外一种可行的技术手段，在以前被认为是插件型RIA天下的受限环境中被重新认可。这就是说现在的新兴RIA技术（如<a href="http://www.infoq.com/cn/apollo"><u><font color=#0000ff>Apollo</font></u></a>、<a href="http://www.infoq.com/cn/silverlight"><u><font color=#0000ff>Silverlight</font></u></a>等）并不一定会以Ajax杀手的形式出现，而是作为Ajax的补充，所以RIA的未来似乎更加扑朔迷离。而作为Ajax开发者，这是一条好消息，证明现在正在使用的HTML、CSS和Javascript工具箱并没有过时，不需要在恐慌中去学习新的RIA技术，而应该坦然地喜爱你正在使用的技术，就像DHH和李锟这些Web开发者一样。</p>
<p>最后，关于最近在RIA界非常火的离线存储技术（如<a href="http://gears.google.com/"><u><font color=#0000ff>Google Gears</font></u></a>、<a href="http://ajaxian.com/archives/audible-ajax-episode-21-dojo-offline-on-google-gears"><u><font color=#0000ff>Dojo Offline</font></u></a>等），DHH也写了一篇有趣的<a href="http://www.37signals.com/svn/posts/347-youre-not-on-a-fucking-plane-and-if-you-are-it-doesnt-matter"><u><font color=#0000ff>Blog</font></u></a>，有兴趣的读者也可以一并阅读。</p>
<img src ="http://www.blogjava.net/iamtin/aggbug/131063.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/iamtin/" target="_blank">Tin</a> 2007-07-18 14:28 <a href="http://www.blogjava.net/iamtin/archive/2007/07/18/dhh-debates-ria-future.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[翻译]使用测试分类(test categorization)进行敏捷构建</title><link>http://www.blogjava.net/iamtin/archive/2006/12/01/84700.html</link><dc:creator>Tin</dc:creator><author>Tin</author><pubDate>Thu, 30 Nov 2006 16:30:00 GMT</pubDate><guid>http://www.blogjava.net/iamtin/archive/2006/12/01/84700.html</guid><wfw:comment>http://www.blogjava.net/iamtin/comments/84700.html</wfw:comment><comments>http://www.blogjava.net/iamtin/archive/2006/12/01/84700.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/iamtin/comments/commentRss/84700.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iamtin/services/trackbacks/84700.html</trackback:ping><description><![CDATA[
		<p>
				<font size="1">本文翻译自IBM DeveloperWorks上的一篇文章，该文讲述了测试分类(test categorization)的概念，本身这个概念很简单，但是却实际的解决我们常见的问题，在我们的测试庞大到一定地步的时候，测试的运行时间过长，维护成本很高，我们如何能够保证持续集成(CI)的正常运行？那就是通过测试分类。所以我翻译了这片文章，希望对大家有所帮助。<br /><br />原文：<a href="http://www-128.ibm.com/developerworks/java/library/j-cq10316/" target="_blank"><font size="2"><span style="COLOR: #999999">In pursuit of code quality: </span>Use test categorization for agile builds</font></a><br />原文作者：Andrew Glover is president of <a href="http://www.stelligent.com/"><font color="#5c81a7">Stelligent Incorporated</font></a>, which helps companies address software quality with effective developer testing strategies and continuous integration techniques that enable teams to monitor code quality early and often. Check out <a href="http://www.thediscoblog.com/publications/"><font color="#5c81a7">Andy's blog</font></a> for a list of his publications.<br /><br />大家都同意开发人员的测试很重要，但是为什么要花这么长的时间运行测试呢？这个月，Andrew Glover将给我们讲述对于系统来说需要保证运行的三类测试，并且告诉你如何根据分类整理和运行测试。结果将会奇迹般的减少build的时间，即使是面对当今庞大的测试集。<br /></font>
				<font size="1">如果不太难过的话，假想一下你是一个2002年初刚刚建立的公司的开发人员。在淘金热潮中，你和你的同事已经决定使用最流行最强大的Java API来开发一个庞大的数据驱动的Web应用程序。你可你的管理团队坚定的信仰敏捷过程。从第一天开始，就使用JUnit编写测试，并且通过Ant build脚本尽可能频繁的运行它们。最后，你们还会使用cron（*nix下的一个定时运行脚本的任务）来进行nightly build。再然后，某些人可能会下在CruiseControl然后把测试写成套件，然后在每次check-in时执行（持续集成）。<br /></font>
				<font size="1">现在回到今天。<br /></font>
				<font size="1">经过了前几年的磨练，你的公司已经开发了数量巨大的代码，当然也有同样庞大的JUnit测试。一年前所有的事情都运转良好，当你的测试套件有超过2000个测试，人们开始注意到build过程可能要执行三个小时以上。几个月以前，你停止通过代码提交来处罚持续集成（CI）运行单元测试，因为CI服务器会因此过渡繁忙。你改为进行nightly测试（每日测试），第二天早上开发人员可能会头疼测试为何失败。<br /></font>
				<font size="1">最近，测试套件似乎很难在晚上运行一次以上了——这是为什么呢？它们永远运行不完！没有人会用几个小时的时间来等待确认代码运行是正常的（或不正常）。所以，整个的测试会在晚上运行，对么？<br /></font>
				<font size="1">因为你如此频繁的运行测试，他们总是充满了问题。（译者注：你会开始怀疑是不是测试也出了问题，是否想测试你的测试？）从而，你和你的团队开始怀疑单元测试的价值：如果代码质量并不那么重要，为什么我们要承受这种痛苦？假如你可以用敏捷的方法运行它们的话，你们完全同意这是单元测试的基本价值。</font>
		</p>
		<p>
				<strong>尝试测试分类（test categorization）</strong>
		</p>
		<p>
				<font size="1">你需要的是一个让你的build转变到更敏捷状态的策略。你需要一种解决方案来允许你在一天内多次运行测试，让那些已经需要三个小时完成的测试回到原先的状态。<br /></font>
				<font size="1">在你尝试使用这个策略让你的测试套件恢复原形之前，思考一下“单元测试”的基本概念可能会有所帮助。“我家有一只动物”和“我喜欢汽车”这样的陈述不是非常明确，所以，不幸的是，“我们编写单元测试”也不明确。现在，但愿测试泛指一切。<br /></font>
				<font size="1">思考前面的两个关于动物和汽车的陈述：它们产生了很多疑问。例如，你家里有什么动物？是猫、蜥蜴还是熊？“我家有一只熊”与“我家有一只猫”完全不同。同样的，“我喜欢汽车”对于与汽车销售商交谈时没有帮助。你喜欢哪种车：运动车、卡车或者大货车？不同的答案会将你引入不同的路径。<br /></font>
				<font size="1">同样，对于开发人员进行测试，根绝测试类型分类是有所帮助的。这样做更加精确，能够允许你的团队以不同的频度运行不同类型的测试。分类是避免恼人的运行所有“单元测试”的三小时build的关键方法。<br /></font>
		</p>
		<p>
				<font size="1">
						<hr />
						<br />
				</font>
				<font size="3">
						<strong>三种分类</strong>
				</font>
		</p>
		<p>
		</p>
		<p>
		</p>
		<p>
				<font size="1">形象的将你的测试套件整理为三层，每一层代表开发人员进行的不同类型的测试，它们是根据运行时间的长短划分的。如图1所示，每一层将花费更多的总build时间，无论是运行时间还是编写它们所需的时间。</font>
		</p>
		<p>
				<font size="1">
						<strong>图1 测试分类的三层<br /><img src="http://www-128.ibm.com/developerworks/java/library/j-cq10316/testcats.gif" /><br /><br /></strong>
				</font>
		</p>
		<p>
				<font size="1">最下面一层测试运行时间最短，如你所想，他们也是最容易写的。他们也覆盖最少量的代码。顶层是有高层次的测试组成，它们检测应用程序的很大一部分。这些测试相对难写，同时也需要更多时间来执行。中间一层测试介于两个极端之间。<br />这三个分类如下：<br /></font>
		</p>
		<ul>
				<li>
						<strong>
								<font size="1">单元测试</font>
						</strong>
				</li>
				<li>
						<strong>
								<font size="1">组件测试</font>
						</strong>
				</li>
				<li>
						<strong>
								<font size="1">系统测试</font>
						</strong>
				</li>
		</ul>
		<font size="1">让我们分别的考察它们。</font>
		<p>
		</p>
		<p>
				<strong>
						<font size="4">1、单元测试</font>
				</strong>
		</p>
		<p>
				<font size="1">单元测试隔离的确认一个或者多个对象。单元测试不处理数据库、文件系统或者任何可能带来测试不能保证长期可运行的因素；顺序上，测试可以从（项目）第一天就开始写。事实上，这就是JUnit的设计目标。单元测试的隔离概念是在很多mock对象库隔离特定对象的外在依赖的基础上的。进一步说，单元测试可以在实际代码编写前就开始写——也就是测试先行开发TDD的概念。<br /></font>
				<font size="1">单元测试一般容易编写，因为他们不依靠于系统依赖，并且他们运行迅速。不好的方面是，单独的单元测试只能提供有限的代码覆盖度。单元测试的价值在于允许开发者在最低的依赖程度下保证对象的质量。<br /></font>
				<font size="1">因为单元测试运行迅速容易编写，一个代码库应该有很多单元测试且尽量频繁的运行它们。你应该在每次build的时候运行它们，不管是在你的机器或者一个CI环境（以为这你应该在每次向SCM系统chech in之前运行它们）。</font>
		</p>
		<p>
				<font size="4">
						<strong>2、组件测试</strong>
				</font>
		</p>
		<p>
				<font size="1">组件测试保证多个对象的交互，但是它们突破了代码隔离的概念。因为组件测试处理多层架构，他们经常要处理数据库、文件系统、网络元素等。而且组件测试一般很难在（项目）前编写，所以将它们加入到一个实际的测试先行/测试驱动的场景中是个很大的挑战。<br /></font>
				<font size="1">组件测试编写要花多一些时间，因为他们比单元测试要棘手。从另一个方面来看，他们能够提供比单元测试更高的代码覆盖率因为它们的宽工作范围。它们运行耗时更多，所以它们会极大地拖长你们的总测试耗时。<br /></font>
				<font size="1">一个宿主框架可能减少测试庞大架构组建的挑战难度。DbUnit就是一个这种框架的完美例子。DbUnit是编写依赖于数据库的测试容易，它能够处理复杂的数据库状态准备工作。<br /></font>
				<font size="1">当测试引起build时间延长，你基本上可以确定那就是大组的组件测试造成的。因为这些测试比单元测试运行时间更长，你可能发现你不能总是运行它们。因此，它让CI环境至少以小时为间隔执行它们。你一应该要求每个开发者在check in前在本机环境运行这些代码。</font>
		</p>
		<p>
				<font size="4">
						<strong>3、系统测试</strong>
				</font>
		</p>
		<p>
				<font size="1">系统测试从端到端保证软件应用。因此，他们提出了高度的架构复杂性：整个应用必须在进行系统测试时运行。如果是一个Web应用程序，你需要访问数据库，从Web服务器、（应用程序）容器、任何相关的配置都要配合系统测试的运行。系统测试总是在软件开发周期的最后阶段撰写的。<br /></font>
				<font size="1">系统测试对于编写人员是个挑战，并且实际往往花费比较长的时间。另一方面，他们提供更好的催款理由，也就是说，他们提供了系统架构级的代码覆盖率。<br /></font>
				<font size="1">系统测试与功能测试非常相近。区别在于它们不是一个假扮用户，用户是虚拟的。就像组件测试一样，很多框架都是来帮助这类测试的。例如，jWebUnit通过模拟一个浏览器提供了测试Web应用程序的基础设施。<br /></font>
		</p>
		<p style="BORDER-RIGHT: #666 2px dotted; PADDING-RIGHT: 10px; BORDER-TOP: #666 2px dotted; PADDING-LEFT: 10px; FONT-SIZE: 12px; BACKGROUND: #ccc; PADDING-BOTTOM: 10px; BORDER-LEFT: #666 2px dotted; PADDING-TOP: 10px; BORDER-BOTTOM: #666 2px dotted">
				<b>什么是接受测试？</b>
				<br />接受测试与功能测试类似，不同点在于，理想情况下，客户或者最终用户来编写接受测试。与功能测试类似，接受测试按照最终用户的行为测试。一个备受关注的接受测试框架是Selenium，它使用浏览器来测试Web应用程序。Selenium可以在build过程中自动运行，就像JUnit测试一样。但是Selenium是一个新的平台：他不一定使用JUnit，方式也不太一样。（Selenium RC就没有这个问题了）</p>
		<p style="BORDER-RIGHT: #666 2px dotted; PADDING-RIGHT: 10px; BORDER-TOP: #666 2px dotted; PADDING-LEFT: 10px; FONT-SIZE: 12px; BACKGROUND: #ccc; PADDING-BOTTOM: 10px; BORDER-LEFT: #666 2px dotted; PADDING-TOP: 10px; BORDER-BOTTOM: #666 2px dotted">
				<b>我应该使用jWebUnit或者Selenium？</b>
				<br />jWebUnit是一个JUnit扩展框架，设计用来进行系统测试；所以，它需要你自己写这些测试。Selenium是一个优秀的接受测试和功能测试工具，不同于jWebUnit，它允许非程序员编写测试。理想状态下，你的团队可以同时使用两种工具来确认应用程序的功能。</p>
		<p style="BORDER-RIGHT: #666 2px dotted; PADDING-RIGHT: 10px; BORDER-TOP: #666 2px dotted; PADDING-LEFT: 10px; FONT-SIZE: 12px; BACKGROUND: #ccc; PADDING-BOTTOM: 10px; BORDER-LEFT: #666 2px dotted; PADDING-TOP: 10px; BORDER-BOTTOM: #666 2px dotted">
				<b>使用TestNG进行测试分类</b>
				<br />使用TestNG实现测试分类非常容易。使用TestNG的group注释，逻辑上将测试分类就是进行合适的group注释，这非常简单。运行某一分类的测试只需要将group名称传给test runner就可以了，例如通过Ant。</p>
		<p>
				<font size="1">
						<font size="3">
								<strong>实现测试分类</strong>
						</font>
						<br />
						<br />所以，你的单元测试套件实际上是单元测试、组件测试和系统测试的套件。甚至，在你检查所有的测试后发现build需要这么长时间是因为大部分测试都是组件测试。下一个问题是，如何通过JUnit实现测试分类？<br /></font>
				<font size="1">你有很多选择，但是让我们先试验一下最简单的两个： 
<ul><li>根据需要的分类创建不同的JUnit套件（suite）文件
</li><li>对于不同类型的测试创建不同的目录</li></ul><p></p><p><font size="3"><strong>创建不同的套件</strong></font></p><p><font size="1">你可以使用JUnit的TestSuite类（它也是一种Test）定义一组同类测试的集合。你要创建一个TestSuite的实例并添加相关的测试类到test方法中。你可以在TestSuite实例中通过定义一个叫做suite()的public static方法告诉JUnit这个套件包括哪些测试。所有包括的测试将会一次全部执行。因此你可以通过创建TestSuite来实现测试分类，一个单元测试的TestSuite、一个组件测试的TestSuite，有一个系统测试的TestSuite。<br /></font><font size="1">例如清单1的类中的suite()方法创建了一个包含所有组建测试的TestSuite。注意这个类不是非常符合JUnit规范。他既没有继承TestCase，也没有任何测试的定义。但是JUnit会自动发现suite()方法并且运行它返回的所有测试类。</font></p><p><font size="1"><strong>清单1 单元测试的TestSuite<br /></strong></font></p><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">package</span><span style="COLOR: #000000"> test.org.acme.widget;<br /><br /></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> junit.framework.Test;<br /></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> junit.framework.TestSuite;<br /></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> test.org.acme.widget.</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">;<br /><br /></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> ComponentTestSuite {<br /><br /> </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> main(String[] args) {<br />  junit.textui.TestRunner.run(ComponentTestSuite.suite());<br /> }<br /><br /> </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> Test suite(){<br />  TestSuite suite </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> TestSuite();<br />  suite.addTestSuite(DefaultSpringWidgetDAOImplTest.</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">);<br />  suite.addTestSuite(WidgetDAOImplLoadTest.</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">);<br />  <img src="http://www.blogjava.net/images/dot.gif" /><br />  suite.addTestSuite(WidgetReportTest.</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">);<br />  </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> suite;<br /> }<br />}<br /></span></div><p><br /></p></font>
				<font size="1">定义TestSuite的过程需要你察看你当前的所有测试并将它们加入到相应的类里面（例如，所有的单元测试加入到UnitTestSuite）。这也就意味着你在相应的分类里面创建了新的测试，你必须编程式的将它们添加到合适的TestSuite中，当然还需要重新编译它们。<br /></font>
				<font size="1">运行单独的TestSuite需要单独的Ant任务来运行正确的测试组。你可以定义一个component-test任务来执行ComponentTtestSuite，就像清单2中的样子：</font>
		</p>
		<p>
				<font size="1">
						<strong>清单2 运行组建测试的一个Ant任务</strong>
						<br />
				</font>
		</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">target </span>
				<span style="COLOR: #ff0000">name</span>
				<span style="COLOR: #0000ff">="component-test"</span>
				<span style="COLOR: #ff0000"> <br />           if</span>
				<span style="COLOR: #0000ff">="Junit.present"</span>
				<span style="COLOR: #ff0000"> <br />           depends</span>
				<span style="COLOR: #0000ff">="junit-present,compile-tests"</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br /> </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">mkdir </span>
				<span style="COLOR: #ff0000">dir</span>
				<span style="COLOR: #0000ff">="${testreportdir}"</span>
				<span style="COLOR: #0000ff">/&gt;</span>
				<span style="COLOR: #000000">   <br /> </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">junit </span>
				<span style="COLOR: #ff0000">dir</span>
				<span style="COLOR: #0000ff">="./"</span>
				<span style="COLOR: #ff0000"> failureproperty</span>
				<span style="COLOR: #0000ff">="test.failure"</span>
				<span style="COLOR: #ff0000"> <br />             printSummary</span>
				<span style="COLOR: #0000ff">="yes"</span>
				<span style="COLOR: #ff0000"> <br />             fork</span>
				<span style="COLOR: #0000ff">="true"</span>
				<span style="COLOR: #ff0000"> haltonerror</span>
				<span style="COLOR: #0000ff">="true"</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />   </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">sysproperty </span>
				<span style="COLOR: #ff0000">key</span>
				<span style="COLOR: #0000ff">="basedir"</span>
				<span style="COLOR: #ff0000"> value</span>
				<span style="COLOR: #0000ff">="."</span>
				<span style="COLOR: #0000ff">/&gt;</span>
				<span style="COLOR: #000000">     <br />   </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">formatter </span>
				<span style="COLOR: #ff0000">type</span>
				<span style="COLOR: #0000ff">="xml"</span>
				<span style="COLOR: #0000ff">/&gt;</span>
				<span style="COLOR: #000000">      <br />   </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">formatter </span>
				<span style="COLOR: #ff0000">usefile</span>
				<span style="COLOR: #0000ff">="false"</span>
				<span style="COLOR: #ff0000"> type</span>
				<span style="COLOR: #0000ff">="plain"</span>
				<span style="COLOR: #0000ff">/&gt;</span>
				<span style="COLOR: #000000">     <br />   </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">classpath</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />    </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">path </span>
				<span style="COLOR: #ff0000">refid</span>
				<span style="COLOR: #0000ff">="build.classpath"</span>
				<span style="COLOR: #0000ff">/&gt;</span>
				<span style="COLOR: #000000">       <br />    </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">pathelement </span>
				<span style="COLOR: #ff0000">path</span>
				<span style="COLOR: #0000ff">="${testclassesdir}"</span>
				<span style="COLOR: #0000ff">/&gt;</span>
				<span style="COLOR: #000000">        <br />    </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">pathelement </span>
				<span style="COLOR: #ff0000">path</span>
				<span style="COLOR: #0000ff">="${classesdir}"</span>
				<span style="COLOR: #0000ff">/&gt;</span>
				<span style="COLOR: #000000">      <br />   </span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">classpath</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />   </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">batchtest </span>
				<span style="COLOR: #ff0000">todir</span>
				<span style="COLOR: #0000ff">="${testreportdir}"</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />    </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">fileset </span>
				<span style="COLOR: #ff0000">dir</span>
				<span style="COLOR: #0000ff">="test"</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />     </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">include </span>
				<span style="COLOR: #ff0000">name</span>
				<span style="COLOR: #0000ff">="**/ComponentTestSuite.java"</span>
				<span style="COLOR: #0000ff">/&gt;</span>
				<span style="COLOR: #000000">                 <br />    </span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">fileset</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />   </span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">batchtest</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br /> </span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">junit</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">target</span>
				<span style="COLOR: #0000ff">&gt;</span>
		</div>
		<p>
				<font size="1">理想情况下，你还需要一个触发单元测试的任务和系统测试的任务。最后，还有希望运行所有测试的情况，你需要创建第四个任务来运行其它三个任务，就像清单3里面那样：</font>
		</p>
		<p>
				<font size="1">
						<strong>清单3 运行所有测试的任务</strong>
						<br />
				</font>
		</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">target </span>
				<span style="COLOR: #ff0000">name</span>
				<span style="COLOR: #0000ff">="test-all"</span>
				<span style="COLOR: #ff0000"> depends</span>
				<span style="COLOR: #0000ff">="unit-test,component-test,system-test"</span>
				<span style="COLOR: #0000ff">/&gt;</span>
		</div>
		<p>
				<font size="1">创建单独的TestSuite是一个迅速实现测试分类的解决方案。缺点是这个方法需要你创建新的测试，你必须编成式的将它们添加到合适的TestSuite里面，这可能有点痛苦。给每个测试类型创建单独的目录可能是一种更加有弹性的方法，它允许你添加新的测试分类但无需重新编译。<br /><hr /></font>
		</p>
		<p>
				<font size="3">
						<strong>创建单独的目录</strong>
				</font>
		</p>
		<p>
				<font size="1">我发现最简单的通过JUnit实现测试分类的方法是逻辑上将不同类型的测试放到不同的目录中。使用这个方法，所有的单元测试都放在unit目录，所有的组建测试都放在component目录，等等。<br /></font>
				<font size="1">例如，在test目录中保存着所有未分类的测试，你可以创建三个新的子目录，就像清单4中那样：</font>
		</p>
		<p>
				<font size="1">
						<strong>清单4 实现测试分类的目录结构</strong>
						<br />
				</font>
		</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #000000">acme-proj/<br />       test/<br />          unit/<br />          component/<br />          system/ <br />          conf/<br /></span>
		</div>
		<p>
				<font size="1">运行这些测试，你需要定义至少四个Ant任务：一个给单元测试，另外的给组建测试，还有系统测试。第四个任务是一个方便运行其它三个测试类型的任务（就像清单3种展示的那种方式）。<br /></font>
				<font size="1">JUnit任务就像清单2中的形式。区别在哪里呢，只是在任务的batchtest这个地方。这次，fileset指向的是一个指定的目录，就像清单5种的样子，他指向了unit目录：<br /><br /></font>
				<font size="1">
						<strong>清单5 JUnit任务中的batchtest方面，用来运行所有单元测试</strong>
				</font>
		</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">batchtest </span>
				<span style="COLOR: #ff0000">todir</span>
				<span style="COLOR: #0000ff">="${testreportdir}"</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /> </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">fileset </span>
				<span style="COLOR: #ff0000">dir</span>
				<span style="COLOR: #0000ff">="test/unit"</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000"> <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />  </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">include </span>
				<span style="COLOR: #ff0000">name</span>
				<span style="COLOR: #0000ff">="**/**Test.java"</span>
				<span style="COLOR: #0000ff">/&gt;</span>
				<span style="COLOR: #000000">       <br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /> </span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">fileset</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">batchtest</span>
				<span style="COLOR: #0000ff">&gt;</span>
		</div>
		<p>
				<font size="1">注意这个任务运行test/unit目录下的所有测试，当创建了新的单元测试（或者其它分类的其它测试），你只需要把它们放到这个目录里面就可以了！这比添加一行到TestSuite中并重新编译它要方便多了。<br /><hr /></font>
		</p>
		<p>
				<font size="4">
						<strong>问题解决了！</strong>
				</font>
		</p>
		<p>
				<font size="1">回到最初的场景，我认为你和你的团队会决定使用单独的目录这种弹性的解决方案来解决你们的build时间过长的问题。这个任务最难的一个方面是检查和分清测试类型。你重构你的Ant build文件创建四个新的任务（三个单独的测试分类还有一个运行它们三个）。甚至，你修改CuiresControl只在check-in的时候运行单元测试，而组建测试按小时运行。更进一步的检查后，系统测试也可以几个小时运行一次，也许你会创建一个新的任务来同时运行组建测试和系统测试。</font>
		</p>
		<p>
				<font size="1">最后的结果是每天测试运行很多次，你的团队可以快速的发现集成错误——一般在几个小时内。</font>
		</p>
		<p>
				<font size="1">创建敏捷构建不是为了赶时髦，它实际上是保证代码质量的重要因素。测试运行的更加频繁，开发人员的测试的价值就能直接转化为钱。并且，希望你们的公司能够在2006取得广泛的成功！</font>
		</p>
		<p>
				<font size="1">
						<font size="3">
								<strong>资源<br /><font size="1">Learn<br /></font></strong>
						</font>
				</font>
		</p>
		<ul>
				<li>
						<font size="1">"</font>
						<a href="http://www.ibm.com/developerworks/web/library/wa-selenium-ajax/">
								<font color="#5c81a7" size="1">Automate acceptance tests with Selenium</font>
						</a>
						<font size="1">" (Christian Hellsten, developerWorks, December 2005): Architects, developers, and testers learn how to use the Selenium testing tools to automate acceptance tests.</font>
				</li>
				<li>
						<font size="1">"</font>
						<a href="http://www.onjava.com/pub/a/onjava/2004/01/21/dbunit.html">
								<font color="#5c81a7" size="1">Effective Unit Testing with DbUnit</font>
						</a>
						<font size="1">" (Andrew Glover, OnJava, January 2004): Introduces database-dependent testing with DbUnit.</font>
				</li>
				<li>
						<font size="1">"</font>
						<a href="http://www.ibm.com/developerworks/java/library/j-junit4.html">
								<font color="#5c81a7" size="1">An early look at JUnit 4</font>
						</a>
						<font size="1">" (Elliotte Harold, developerWorks, September 2005): Obsessive code tester Elliotte Harold takes JUnit 4 out for a spin.</font>
				</li>
				<li>
						<font size="1">"</font>
						<a href="http://www.ibm.com/developerworks/java/library/j-cq09266.html">
								<font color="#5c81a7" size="1">Repeatable system tests</font>
						</a>
						<font size="1">" (Andrew Glover, developerWorks, September 2006): Andrew Glover introduces Cargo, an open source framework that automates container management in a generic fashion.</font>
				</li>
				<li>
						<font size="1">"</font>
						<a href="http://www.ibm.com/developerworks/java/library/j-jwebunit/">
								<font color="#5c81a7" size="1">Create test cases for Web applications</font>
						</a>
						<font size="1">" (Amit Tuli, developerWorks, May 2005): Software engineer Amit Tuli introduces jWebUnit.</font>
				</li>
				<li>
						<font size="1">"</font>
						<a href="http://www.ibm.com/developerworks/java/library/j-cq08296/">
								<font color="#5c81a7">
										<font size="1">
												<i>In pursuit of code quality</i>: JUnit 4 vs. TestNG</font>
								</font>
						</a>
						<font size="1">" (Andrew Glover, developerWorks, April 2006): Has JUnit 4 rendered TestNG obsolete? Find out why not.</font>
				</li>
				<li>
						<a href="http://www.ibm.com/developerworks/views/java/libraryview.jsp?search_by=code+quality:">
								<font color="#996699">
										<font size="1">
												<i>In pursuit of code quality</i> series</font>
								</font>
						</a>
						<font size="1"> (Andrew Glover, developerWorks): Learn more about code metrics, test frameworks, and writing quality-focused code.</font>
				</li>
				<li>
						<a href="http://www.ibm.com/developerworks/java/">
								<font color="#5c81a7" size="1">developerWorks</font>
						</a>
						<font size="1">: Hundreds of articles about every aspect of Java programming.</font>
				</li>
		</ul>
		<p>
				<font size="1">
						<b>Get products and technologies</b>
						<br />
				</font>
		</p>
		<ul>
				<li>
						<a href="http://www.junit.org/">
								<font color="#5c81a7" size="1">Download JUnit</font>
						</a>
						<font size="1">: Find out what's new with JUnit 4.</font>
				</li>
				<li>
						<a href="http://www.testng.org/">
								<font color="#5c81a7" size="1">Download TestNG</font>
						</a>
						<font size="1">: Another powerful testing framework.</font>
				</li>
		</ul>
		<p>
				<font size="1">
						<b>Discuss</b>
						<br />
				</font>
		</p>
		<ul>
				<li>
						<a href="http://www.ibm.com/developerworks/forums/dw_forum.jsp?forum=812&amp;cat=10">
								<font color="#5c81a7" size="1">Participate in the discussion forum</font>
						</a>
						<font size="1">.</font>
				</li>
				<li>
						<a href="http://www.ibm.com/developerworks/forums/dw_forum.jsp?forum=812&amp;cat=10">
								<font color="#5c81a7" size="1">Discussion forum: Improve your code quality</font>
						</a>
						<font size="1">: Andrew shares his expertise as a consultant focused on improving code quality.</font>
				</li>
		</ul>
<img src ="http://www.blogjava.net/iamtin/aggbug/84700.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/iamtin/" target="_blank">Tin</a> 2006-12-01 00:30 <a href="http://www.blogjava.net/iamtin/archive/2006/12/01/84700.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在JUnit中多个testCase只执行一次setup和tearDown的方法</title><link>http://www.blogjava.net/iamtin/archive/2006/11/17/81802.html</link><dc:creator>Tin</dc:creator><author>Tin</author><pubDate>Fri, 17 Nov 2006 09:29:00 GMT</pubDate><guid>http://www.blogjava.net/iamtin/archive/2006/11/17/81802.html</guid><wfw:comment>http://www.blogjava.net/iamtin/comments/81802.html</wfw:comment><comments>http://www.blogjava.net/iamtin/archive/2006/11/17/81802.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/iamtin/comments/commentRss/81802.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iamtin/services/trackbacks/81802.html</trackback:ping><description><![CDATA[这个问题出现在这种情况，你的每个testCase都需要使用某一种初始化比较耗时的对象（资源），举例如数据库连接、Spring Context。我们遇到的问题是Selenium测试中开启和关闭浏览器，如果一个test启动关闭（我们的程序还需要登录和注销），这样测试的时间会拖的很长，给持续集成带来了困难。<br />所以，我们需要在每组不会冲突的test中间共享一个浏览器窗口，这样也就需要一个全局的setUp和tearDown。问题是JUnit 3.8.1里面的setUp和tearDown是在每个test之前和之后运行的，如果在里面初始化和关闭浏览器就会造成上面所说的问题。要解决它，就产生了如下3种思路：<br />1、升级，使用JUnit4<br />JUnit4从TestNG里面吸取了两个注释：@BeforeClass和@AfterClass<br />用它们注释过的方法就会只初始化一次，完全符合我们的需求。<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img id="Codehighlighter1_56_678_Open_Image" onclick="this.style.display='none'; Codehighlighter1_56_678_Open_Text.style.display='none'; Codehighlighter1_56_678_Closed_Image.style.display='inline'; Codehighlighter1_56_678_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" /><img id="Codehighlighter1_56_678_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_56_678_Closed_Text.style.display='none'; Codehighlighter1_56_678_Open_Image.style.display='inline'; Codehighlighter1_56_678_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" /><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> SeleniumTestCase </span><span style="COLOR: #0000ff">extends</span><span style="COLOR: #000000"> SeleneseTestCase4 </span><span id="Codehighlighter1_56_678_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_56_678_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">protected</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">final</span><span style="COLOR: #000000"> Log log </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> LogFactory.getLog(SeleniumTestCase.</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">protected</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> Selenium selenium </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">null</span><span style="COLOR: #000000">;<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img id="Codehighlighter1_191_267_Open_Image" onclick="this.style.display='none'; Codehighlighter1_191_267_Open_Text.style.display='none'; Codehighlighter1_191_267_Closed_Image.style.display='inline'; Codehighlighter1_191_267_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_191_267_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_191_267_Closed_Text.style.display='none'; Codehighlighter1_191_267_Open_Image.style.display='inline'; Codehighlighter1_191_267_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span id="Codehighlighter1_191_267_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/** */</span><span id="Codehighlighter1_191_267_Open_Text"><span style="COLOR: #008000">/**</span><span style="COLOR: #008000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />     * 包含了登录的代码，保证在一个测试内部只执行一次开启浏览器并登录操作<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />     * </span><span style="COLOR: #808080">@throws</span><span style="COLOR: #008000"> Exception<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />     </span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    @BeforeClass<br /><img id="Codehighlighter1_342_461_Open_Image" onclick="this.style.display='none'; Codehighlighter1_342_461_Open_Text.style.display='none'; Codehighlighter1_342_461_Closed_Image.style.display='inline'; Codehighlighter1_342_461_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_342_461_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_342_461_Closed_Text.style.display='none'; Codehighlighter1_342_461_Open_Image.style.display='inline'; Codehighlighter1_342_461_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> startSelenium() </span><span style="COLOR: #0000ff">throws</span><span style="COLOR: #000000"> Exception </span><span id="Codehighlighter1_342_461_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_342_461_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        log.debug(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Starting Selenium<img src="http://www.blogjava.net/images/dot.gif" /></span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        selenium </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> SeleniumSession.getCurrentSession().getSelenium();<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" /><br /><img id="Codehighlighter1_468_530_Open_Image" onclick="this.style.display='none'; Codehighlighter1_468_530_Open_Text.style.display='none'; Codehighlighter1_468_530_Closed_Image.style.display='inline'; Codehighlighter1_468_530_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_468_530_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_468_530_Closed_Text.style.display='none'; Codehighlighter1_468_530_Open_Image.style.display='inline'; Codehighlighter1_468_530_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span id="Codehighlighter1_468_530_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/** */</span><span id="Codehighlighter1_468_530_Open_Text"><span style="COLOR: #008000">/**</span><span style="COLOR: #008000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />     * 在该类包含的所有测试结束之后关闭浏览器<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />     * </span><span style="COLOR: #808080">@throws</span><span style="COLOR: #008000"> Exception<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />     </span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    @AfterClass<br /><img id="Codehighlighter1_603_676_Open_Image" onclick="this.style.display='none'; Codehighlighter1_603_676_Open_Text.style.display='none'; Codehighlighter1_603_676_Closed_Image.style.display='inline'; Codehighlighter1_603_676_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" /><img id="Codehighlighter1_603_676_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_603_676_Closed_Text.style.display='none'; Codehighlighter1_603_676_Open_Image.style.display='inline'; Codehighlighter1_603_676_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> stopSelenium() </span><span style="COLOR: #0000ff">throws</span><span style="COLOR: #000000"> Exception </span><span id="Codehighlighter1_603_676_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/images/dot.gif" /></span><span id="Codehighlighter1_603_676_Open_Text"><span style="COLOR: #000000">{<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        log.debug(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Stoping Selenium<img src="http://www.blogjava.net/images/dot.gif" /></span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br /><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />        selenium.stop();<br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" />    }</span></span><span style="COLOR: #000000"><br /><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span></span></div>这个里面的selenium = SeleniumSession.getCurrentSession().getSelenium();其实是个singleton，第一次open new，后来就直接返回selenium的instance（具体参考其它文章）。<br />这样做非常舒服，因为完全不是Trick，而是新的feature，用起来踏实。这样，这个类的所有@Test就会公用一个selenium打开的浏览器了。<br />那么缺点是什么呢？缺点是放到CI环境的时候如果使用我们习惯的Ant写执行脚本的话必须将Ant升级到1.7Beta3，因为Ant 1.6.5的Junit task不支持JUnit4……当然升级并不会带来代码的变化，但是问题在于Ant 1.7还是Beta，而且JUnit4需要JDK5的Annotation，你的PM估计要撇嘴了<img height="19" src="http://www.blogjava.net/Emoticons/74_74.gif" width="19" border="0" /><br /><br />2、JVM级别钩子法<br />因为JVM支持关闭时执行制定代码的钩子，而static代码会在类初始化时执行，再加上Ant调用的是类似命令行的java命令，实际上每一个测试运行在一个完整的JVM启动关闭周期里面，所以也就产生了这种解决方案。<br />这个方案来自<a href="http://wiki.javascud.org/display/SEL/selenium+resources+selenium+tips+2+taowen" target="_blank">taowen同学的两则Selenium经验</a>。<br />代码我恢复了一下，大概是这样：<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">abstract</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> SomeTestCase </span><span style="COLOR: #0000ff">extends</span><span style="COLOR: #000000"> TestCase {<br /><br />  </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> {<br />    </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> perform the "global" set up logic<br />    </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">这里的代码会在类初始化时执行，所以相当于BeforeClass</span><span style="COLOR: #008000"><br /></span><span style="COLOR: #000000">    log.debug(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Starting Selenium<img src="http://www.blogjava.net/images/dot.gif" /></span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br />        selenium </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> SeleniumSession.getCurrentSession().getSelenium();<br /><br />    </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> and now register the shutdown hook for tear down logic<br />    </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">将一个匿名方法写到这里，就相当于AfterClass</span><span style="COLOR: #008000"><br /></span><span style="COLOR: #000000">    Runtime.getRuntime().addShutdownHook(<br />       </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> Thread(){<br />           </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> run() {<br />             log.debug(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Stoping Selenium<img src="http://www.blogjava.net/images/dot.gif" /></span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br />             selenium.stop();<br />           }<br />       }<br />     );<br />  }<br /><br />}</span></div><br />这个方法挺酷的，我认为完全可以被称作“奇技淫巧”。缺点就是，有点不好看。<br /><br />3、还有别的方法，这个来自Selenium网站，似乎是不错的中庸方案。<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> junit.framework.</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">;<br /></span><span style="COLOR: #0000ff">import</span><span style="COLOR: #000000"> junit.extensions.TestSetup;<br /><br /></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> AllTestsOneTimeSetup {<br /><br />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> Test suite() {<br /><br />        TestSuite suite </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> TestSuite();<br /><br />        suite.addTest(SomeTest.suite());<br />        suite.addTest(AnotherTest.suite());<br /><br />        TestSetup wrapper </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> TestSetup(suite) {<br /><br />            </span><span style="COLOR: #0000ff">protected</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> setUp() {<br />                oneTimeSetUp();<br />            }<br /><br />            </span><span style="COLOR: #0000ff">protected</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> tearDown() {<br />                oneTimeTearDown();<br />            }<br />        };<br /><br />        </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> wrapper;<br />    }<br /><br />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> oneTimeSetUp() {<br />        </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> one-time initialization code</span><span style="COLOR: #008000"><br /></span><span style="COLOR: #000000">    }<br /><br />    </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> oneTimeTearDown() {<br />        </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> one-time cleanup code</span><span style="COLOR: #008000"><br /></span><span style="COLOR: #000000">    }<br />}<br /><br /></span></div><br /><p>这个好像是比较正统的方案，不好意思我并没有试验，但是看起来这的确可能是限定用JDK 1.4或JUnit 3.8.1的最佳解决方案。欢迎尝试。相关的连接参考这里：<a href="http://www.cs.wm.edu/~noonan/junit/doc/faq/faq.htm#organize_3">http://www.cs.wm.edu/~noonan/junit/doc/faq/faq.htm#organize_3</a> </p><img src ="http://www.blogjava.net/iamtin/aggbug/81802.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/iamtin/" target="_blank">Tin</a> 2006-11-17 17:29 <a href="http://www.blogjava.net/iamtin/archive/2006/11/17/81802.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Selenium Remote Control 0.9.0发布</title><link>http://www.blogjava.net/iamtin/archive/2006/11/15/81284.html</link><dc:creator>Tin</dc:creator><author>Tin</author><pubDate>Wed, 15 Nov 2006 07:57:00 GMT</pubDate><guid>http://www.blogjava.net/iamtin/archive/2006/11/15/81284.html</guid><wfw:comment>http://www.blogjava.net/iamtin/comments/81284.html</wfw:comment><comments>http://www.blogjava.net/iamtin/archive/2006/11/15/81284.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/iamtin/comments/commentRss/81284.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iamtin/services/trackbacks/81284.html</trackback:ping><description><![CDATA[Selenium Remote Control项目组很高兴的宣布Selenium Remote Control 0.9.0发布。<br />你可以在这里察看：<br /><a href="http://www.openqa.org/selenium-rc/">http://www.openqa.org/selenium-rc/</a><br />也可以在这里下载：<br /><a href="http://www.openqa.org/selenium-rc/download.action">http://www.openqa.org/selenium-rc/download.action</a><br />0.9.0包括很多酷玩意，包括frame支持，多窗口支持（用来测试那些不能够在子frame中运行的应用），一个Konqueror浏览器launcher，新的cookie管理功能，和Firefox 2.0与IE7的支持。还包括一个试验性的在Selenium代理中直接的SSL支持，一个新的实验性的“代理注入（proxy injection）”模式允许我们通过修改HTTP代理来更好的控制我们测试的应用程序。<br />Have Fun！<img src ="http://www.blogjava.net/iamtin/aggbug/81284.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/iamtin/" target="_blank">Tin</a> 2006-11-15 15:57 <a href="http://www.blogjava.net/iamtin/archive/2006/11/15/81284.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Selenium相关资源中文化动员</title><link>http://www.blogjava.net/iamtin/archive/2006/11/13/selenium_chinese_translation_start.html</link><dc:creator>Tin</dc:creator><author>Tin</author><pubDate>Mon, 13 Nov 2006 07:31:00 GMT</pubDate><guid>http://www.blogjava.net/iamtin/archive/2006/11/13/selenium_chinese_translation_start.html</guid><wfw:comment>http://www.blogjava.net/iamtin/comments/80902.html</wfw:comment><comments>http://www.blogjava.net/iamtin/archive/2006/11/13/selenium_chinese_translation_start.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/iamtin/comments/commentRss/80902.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iamtin/services/trackbacks/80902.html</trackback:ping><description><![CDATA[
		<h1>
				<a name="Home-Selenium%E7%9B%B8%E5%85%B3%E8%B5%84%E6%BA%90%E4%B8%AD%E6%96%87%E5%8C%96">
				</a>Selenium相关资源中文化</h1>
		<h3>
				<a name="Home-1.%E5%8A%A8%E6%9C%BA">
				</a>1. 动机</h3>
		<p>springside项目的江南白衣、cac和徐昊、熊杰都多次推广非常Pragmatic的Selenium进行功能测试。而我们的项目中也开始引入Selenium测试，并结合持续集成搭建了一个测试环境，也尝试通过Selenium进行一些浏览器兼容性的测试。期间感觉到Selenium的强大，同时也发现这个项目还不是很成熟，还需要很多改进。但是，对于已经起步的程序员，我们觉得应该提供一个学习的场所，所以决定依靠javascud提供的服务，进行Selenium相关资源的中文化。<br />已经与Openqa的Wiki的负责人Patrick lightbody进行了沟通，他非常支持我们翻译Selenium文档，我们将一边翻译一边将翻译结果转移到OpenQA，这样就能够方便所有使用中文的Selenium用户了，希望大家共同努力！</p>
		<h3>2. 初步计划</h3>
		<p>我们准备从翻译 <span class="nobr"><a title="Visit page outside Confluence" href="http://wiki.openqa.org/dashboard.action" rel="nofollow">Selenium相关wiki <sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" /></sup></a></span> 开始，翻译openqa下面的Selenium、Selenium RemoteControl、Selenium IDE下面的相关文章。顺序应该是偏重SeleniumRemoteControl和Selenium Core部分。<br />而openqa网站下面Selenium和RC的相关教程我们也会选择性的进行翻译。<br />Selenium On Rails如果哪位朋友感兴趣也可以负责（目前还是空的：）。<br /><strong><font color="#006400">欢迎所有对Selenium感兴趣的（翻译的过程就是很好的学习）或者已经使用Selenium的同学积极参加，参加的方式可以是：直接参与翻译，编写原创学习文章并添加到相关资源列表，交流心得并将心得添加到相关资源列表，提供使用的视频片断，推荐好的Selenium文章进入翻译计划，提出你自己的意见。以上方式都非常欢迎，可以发信给我进行沟通（iamtin AT gmail.com）。<br />目前我们使用JavaScud的Wiki进行翻译工作，网址如下：<br /></font></strong><a href="http://wiki.javascud.org/display/SEL/Home"><strong><font color="#006400">http://wiki.javascud.org/display/SEL/Home</font></strong></a><br /><strong><font color="#006400">需要帐号请自行注册，然后将注册后的帐号发给我带为申请或者直接向scud（飞云小侠）申请。</font></strong></p>
		<h3>
				<a name="Home-3.%E5%B7%A5%E4%BD%9C%E7%BA%BF%E8%B7%AF%E5%9B%BE%E5%B7%A5%E4%BD%9C%E7%BA%BF%E8%B7%AF%E5%9B%BE">
				</a>3. <a title="工作线路图" href="http://wiki.javascud.org/pages/viewpage.action?pageId=5082">工作线路图 </a></h3>
		<p>按照官方网站的目录进行整理，首先翻译比较有意义/实用的部分。本页将作为文档的索引，同时也作为任务分配的页面。如果某一页的内容被翻译者认领，请将自己的名字和文档的翻译状态注在索引后面，方便统计。状态为（working, complete, reviewd），认领后为working状态，翻译好则complete，其它人看过并审过以后为reviewd。<br />我们首先翻译Selenium的几个About页面，然后开始翻译相应的Wiki部分，然后再补全Documentation、Reference部分，其余部分最后补齐。<br />现在wiki和about的原文文档已经粘贴过来了，请大家有工夫的时候开始翻译，这部分翻译完成后我们将把阶段成果链接到openqa的translation部分去。</p>
		<ul>
				<li>Selenium Core 
<ul><li><a title="Selenium - 关于" href="http://wiki.javascud.org/pages/viewpage.action?pageId=5087">关于 </a></li><li>News 
</li><li>Documentation 
</li><li>Usage 
</li><li>Reference 
</li><li>FAQ 
</li><li>Demos 
</li><li>Wiki 
<ul><li><a title="我应该使用哪种Selenium工具？" href="http://wiki.javascud.org/pages/viewpage.action?pageId=5115">我应该使用哪种Selenium工具？</a></li><li><a title="Selenium Core FAQ" href="http://wiki.javascud.org/display/SEL/Selenium+Core+FAQ">Selenium Core FAQ</a></li><li><a title="Getting Started with Selenium Core" href="http://wiki.javascud.org/display/SEL/Getting+Started+with+Selenium+Core">Getting Started with Selenium Core</a></li><li><a title="Selenium Core Examples" href="http://wiki.javascud.org/display/SEL/Selenium+Core+Examples">Selenium Core Examples</a></li><li><a title="Help With XPath" href="http://wiki.javascud.org/display/SEL/Help+With+XPath">Help With XPath</a></li><li><a title="References and Citations" href="http://wiki.javascud.org/display/SEL/References+and+Citations">What People are Saying About Selenium</a></li><li><a title="Publications and Presentations" href="http://wiki.javascud.org/display/SEL/Publications+and+Presentations">Publications and Presentations</a></li><li><a title="Translated Document" href="http://wiki.javascud.org/display/SEL/Translated+Document">Translated Document</a><font color="red">new!!</font></li><li><a title="Selenium Core API Documentation Standard" href="http://wiki.javascud.org/display/SEL/Selenium+Core+API+Documentation+Standard">Selenium Core API Documentation Standard</a></li><li><a title="Contributed User-Extensions" href="http://wiki.javascud.org/display/SEL/Contributed+User-Extensions">Contributed User-Extensions</a></li></ul></li></ul></li>
				<li>Selenium IDE 
<ul><li><a title="Selenium IDE - 关于" href="http://wiki.javascud.org/pages/viewpage.action?pageId=5097">关于 </a></li><li>News 
</li><li>Recording a test (video) 
</li><li>Documentation 
</li><li>Wiki 
<ul><li><a title="Recording a Test" href="http://wiki.javascud.org/display/SEL/Recording+a+Test">Recording a Test</a></li><li><a title="FAQ" href="http://wiki.javascud.org/display/SEL/FAQ">FAQ</a></li><li><a title="Contributed Extensions and Formats" href="http://wiki.javascud.org/display/SEL/Contributed+Extensions+and+Formats">Contributed Extensions and Formats</a></li><li><a title="Automating Selenium IDE tests" href="http://wiki.javascud.org/display/SEL/Automating+Selenium+IDE+tests">Automating Selenium IDE tests</a></li><li><a title="Writing extensions" href="http://wiki.javascud.org/display/SEL/Writing+extensions">Writing extensions</a></li><li><a title="Adding Custom Format" href="http://wiki.javascud.org/display/SEL/Adding+Custom+Format">Adding Custom Format</a></li><li><a title="Building Selenium IDE" href="http://wiki.javascud.org/display/SEL/Building+Selenium+IDE">Building Selenium IDE</a></li></ul></li></ul></li>
				<li>Selenium RC 
<ul><li><a title="Selenium Remote Control - 关于" href="http://wiki.javascud.org/pages/viewpage.action?pageId=5096">关于 </a></li><li>News 
</li><li>Documentation 
</li><li>Tutorial 
</li><li>Troubleshooting/FAQ 
<ul><li>Java 
</li><li>.NET 
</li><li>Perl 
</li><li>Python 
</li><li>Ruby 
</li><li>Selenese </li></ul></li><li>Server Command Line Options 
</li><li>Developer's Guide 
</li><li><a title="Selenium Remote Control - Wiki" href="http://wiki.javascud.org/display/SEL/Selenium+Remote+Control+-+Wiki">Wiki</a><ul><li><a title="Possible Solution to HTTP AUTH Issues" href="http://wiki.javascud.org/display/SEL/Possible+Solution+to+HTTP+AUTH+Issues">Possible Solution to HTTP AUTH Issues</a></li><li><a title="Release Process" href="http://wiki.javascud.org/display/SEL/Release+Process">Release Process</a></li><li><a title="Selenium-RC and Continuous Integration" href="http://wiki.javascud.org/display/SEL/Selenium-RC+and+Continuous+Integration">Selenium-RC and Continuous Integration</a></li><li><a title="Specifications for Selenium Remote Control Client Driver Protocol" href="http://wiki.javascud.org/display/SEL/Specifications+for+Selenium+Remote+Control+Client+Driver+Protocol">Specifications for Selenium Remote Control Client Driver Protocol</a></li><li><a title="TODO for first Selenium Release" href="http://wiki.javascud.org/display/SEL/TODO+for+first+Selenium+Release">TODO for first Selenium Release</a></li><li><a title="Windows Registry Support" href="http://wiki.javascud.org/display/SEL/Windows+Registry+Support">Windows Registry Support</a></li></ul></li></ul></li>
				<li>Selenium On Rails </li>
		</ul>
		<h3>
				<a name="Home-4.%E7%9B%B8%E5%85%B3%E8%B5%84%E6%BA%90%EF%BC%88%E9%83%A8%E5%88%86%EF%BC%89">
				</a>4. 相关资源（部分）</h3>
		<p>
				<span class="nobr">
						<a title="Visit page outside Confluence" href="/raimundox/archive/2006/08/04/61860.html" rel="nofollow">徐昊(X)的：Selenium Better Pratice <sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" /></sup></a>
				</span>
				<br />
				<span class="nobr">
						<a title="Visit page outside Confluence" href="http://calvin.javaeye.com/blog/27298" rel="nofollow">江南白衣的：Selenium--透明反复推介的集成测试工具(Pragmatic系列) <sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" /></sup></a>
				</span>
				<br />
				<span class="nobr">
						<a title="Visit page outside Confluence" href="http://wiki.javascud.org/display/springs/SeleniumRefrence" rel="nofollow">cac翻译的：selenium参考手册 <sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" /></sup></a>
				</span>
				<br />
				<span class="nobr">
						<a title="Visit page outside Confluence" href="http://wiki.springside.org.cn/display/springside/Selenium" rel="nofollow">SpringSideTeam的Selenium指南 <sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" /></sup></a>
				</span>
				<br />
				<span class="nobr">
						<a title="Visit page outside Confluence" href="http://www-128.ibm.com/developerworks/cn/java/wa-selenium-ajax/" rel="nofollow">IBM的用 Selenium 自动化验收测试 <sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" /></sup></a>
				</span>
				<br />
				<span class="nobr">
						<a title="Visit page outside Confluence" href="http://www.testearly.com/2006/10/04/selenium-using-selenium-ide-selenium-remote-control-and-ant/" rel="nofollow">Fit(table)+RC的方式使用Selenium <sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" /></sup></a>
				</span>
				<br />
				<span class="nobr">
						<a title="Visit page outside Confluence" href="http://wiki.openqa.org/display/SRC/Home" rel="nofollow">OpenQA的Selenium Remote Control Wiki <sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" /></sup></a>
				</span>
				<br />
				<span class="nobr">
						<a title="Visit page outside Confluence" href="http://wiki.openqa.org/display/SEL/Home" rel="nofollow">OpenQA的Selenium Core Wiki <sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" /></sup></a>
				</span>
				<br />
				<span class="nobr">
						<a title="Visit page outside Confluence" href="http://wiki.openqa.org/display/SIDE/Home" rel="nofollow">OpenQA的Selenium IDE Wiki <sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" /></sup></a>
				</span>
				<br />
				<span class="nobr">
						<a title="Visit page outside Confluence" href="http://wiki.openqa.org/display/SOR/Home" rel="nofollow">OpenQA的Selenium Selenium on Rails Wiki <sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" /></sup></a>
				</span>
				<br />
				<span class="nobr">
						<a title="Visit page outside Confluence" href="/Nicholas/archive/2006/11/02/78725.html" rel="nofollow">Nicholas的用Selenium进行功能测试 <sup><img class="rendericon" height="7" alt="" src="http://wiki.javascud.org/images/icons/linkext7.gif" width="7" align="absMiddle" border="0" /></sup></a>
				</span>
				<br />
				<span class="nobr">
						<a title="Visit page outside Confluence" href="/iamtin/archive/2006/10/30/78137.html" rel="nofollow">Tin的Selenium做功能测试的一点讨论</a>
				</span>
		</p>
<img src ="http://www.blogjava.net/iamtin/aggbug/80902.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/iamtin/" target="_blank">Tin</a> 2006-11-13 15:31 <a href="http://www.blogjava.net/iamtin/archive/2006/11/13/selenium_chinese_translation_start.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Selenium做功能测试的一点讨论(061102 update)</title><link>http://www.blogjava.net/iamtin/archive/2006/10/30/78137.html</link><dc:creator>Tin</dc:creator><author>Tin</author><pubDate>Mon, 30 Oct 2006 13:33:00 GMT</pubDate><guid>http://www.blogjava.net/iamtin/archive/2006/10/30/78137.html</guid><wfw:comment>http://www.blogjava.net/iamtin/comments/78137.html</wfw:comment><comments>http://www.blogjava.net/iamtin/archive/2006/10/30/78137.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/iamtin/comments/commentRss/78137.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iamtin/services/trackbacks/78137.html</trackback:ping><description><![CDATA[先后和nemo、limo、raimudox、nicholas讨论：<br />selenium的Remote Control比较适合在需求阶段就撰写（当然Fit方式也可以先于实现写），作为验收的测试。好处是RC对重构支持相对好一些，而且你可以换Agent，也可以做浏览器兼容测试。（但是由于RC的限制，兼容侧试兼容性并不好：）<br />按照raimudox所说RC是更加Pragmatic的实践，更能体现敏捷软件开发的测试先行的特性。功能测试可以说是沟通用户与开发者的最佳契约。<br />Selenium IDE录制script适合作为基线保留（指先实现需求，后录制测试这样的顺序），作为某次重构之前的样本。或者说，如果觉得手写测试脚本太麻烦，而喜欢本末倒置（没有贬义，纯技术上）的人设计的。更现实的说，这很有用，比如一个项目从一半开始敏捷改造，引入功能测试、单元测试，对以后的迭代进行基线的衡量，给新引入的CI（持续集成）一个更有实际意义的测试保障，用Selenium IDE帮助生成一下Script，然后再使用RC或者直接用Core执行一下都是不错的实践。而Fit方式（这里指先于应用实现就写出来的基于html/table的Fit式测试），相对吸引力差一些，因为工作量与RC相仿，重构支持比较差，而且没有DSL风格的封装，读起来相对费解一些。<br />还有，据Nicholas同学实践，Selenium IDE所录制的script在IDE中执行比RC方式兼容性要好，尤其对于跨域的情况，RC很有可能是无法工作的。还有一个问题，就是Selenium实际上是ThoughtWorks和BEA牵头的项目，TW负责Core，目前Core的代码发展的必较快，而RC由BEA负责，发展比较缓慢，所以，有些时候选择也就成为无奈了。<br />061102补充：<br />1、Selenium目前有做不到的地方：例如&lt;input type="file"/&gt;的情况，由于安全问题，浏览器是不允许通过javascript置里面的value的，所以selenium在此时会处于无能为力的情况。比较郁闷。虽然强行修改如Mozzila的安全属性可以办，但那不是好办法。<br />2、对于拥有复杂的Ajax widget的应用测试可能会非常麻烦，因为需要写很多javascript api在测试里面，对重构支持差（如api发生变化修改unit test很麻烦，而且可能出现需要对你的测试进行测试的尴尬情况）。当然对于大部分的ajax应用Selenium都是很好的选择。<br />3、大家都很看好的Remote Control方式发展比较慢，API还不够友好（经常抛出奇怪的异常），Bug还是比较多。所以还需要耐心等待，要多些像我们这样的小白鼠:D<br /><font color="#0000ff">推荐大家看看我的同事nicholas的这篇：</font><a class="singleposttitle" id="viewpost1_TitleUrl" href="/Nicholas/archive/2006/11/02/78725.html"><font color="#0000ff">用 Selenium 进行功能测试</font></a><br /><font color="#a52a2a">浓缩一下：<br />1、何时、何目的来用Selenium选择不同。RC、Fit适合从需求阶段就开始写。而IDE录制则适合后补。<br />2、重构支持。RC重构友好一些。Fit重构不友好。<br />3、IDE目前限定于FF，做跨浏览器RC比较好。但是IDE录制后的代码很方便转为RC方式。<br />4、跨域兼容性问题，IDE解决的比较好。</font><img src ="http://www.blogjava.net/iamtin/aggbug/78137.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/iamtin/" target="_blank">Tin</a> 2006-10-30 21:33 <a href="http://www.blogjava.net/iamtin/archive/2006/10/30/78137.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>