??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲A∨精品一区二区三区,国产精品亚洲二区在线,国产精品亚洲午夜一区二区三区 http://www.tkk7.com/justuszhang2009/zh-cnMon, 12 May 2025 11:15:43 GMTMon, 12 May 2025 11:15:43 GMT60Struts2+Spring+Hibernate整合的例?/title><link>http://www.tkk7.com/justuszhang2009/archive/2011/11/27/364925.html</link><dc:creator>张益?/dc:creator><author>张益?/author><pubDate>Sun, 27 Nov 2011 09:27:00 GMT</pubDate><guid>http://www.tkk7.com/justuszhang2009/archive/2011/11/27/364925.html</guid><wfw:comment>http://www.tkk7.com/justuszhang2009/comments/364925.html</wfw:comment><comments>http://www.tkk7.com/justuszhang2009/archive/2011/11/27/364925.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.tkk7.com/justuszhang2009/comments/commentRss/364925.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/justuszhang2009/services/trackbacks/364925.html</trackback:ping><description><![CDATA[ <p>自从6月䆾写过一些博客之后,有将q?个月没写博客了,或者由于工作繁忙,或者由于懒于书W,又或者最q没有研I技术上的东西,Ҏ无从写v。虽然从事项目管理工作,但深知没有技术根底,理好一个IT目谈何Ҏ。难得近期各目C正轨Q有炚w心回忆一下技术方面的东西Q那拿ssh开刀吧,谁叫它是最行的J2EE框架l合呢?br /><br />׃近3个小时终于把一个ssh整合的例子做完,感叹不如当年勇啊Q虽说经验丰富了很多Q但是实打实地编码工作,可真不是靠吹牛吹出来的,到处都存在问题,需要花旉一一解决。好了,废话说Q下面列一下用到的一些技术以及注意点Qؓ了避免误ghQ或致h懒惰Q这里就不将所有代码一一列出Q只是脓一些关键的代码Dc?br /><br />用到的技术如下:<br />1QMySqlQ在本机上能跑的最数据库?br />2QHibernate3Q有了注解功能后Q感觉比Hibernate2方便多了<br />3QSpring3<br />4QStruts2<br />5QJunit4Q用于测试service的方?br />6QLog4j<br />7Q需要的jar包如下,<br /><img border="0" alt="" src="http://www.tkk7.com/images/blogjava_net/justuszhang2009/jar包库.png" width="819" height="576" /></p><p><br /><br />1、MySql<br />    q个׃多说了,安装q程非常单。创Z个数据库QtestQ用grant语句创徏用户testQ密码testQ创Z张表QACCOUNT?br />2、Hibernate3<br />    1Q创Z个domain对象QAccountQ和表ACCOUNT对应Q在上面加注解@Entity @Table(name="ACCOUNT")Q这样就省去了些hbm文g<br />    2Q创建AccountDaoQ实现增删改查功能;<br />3、spring3<br />    1Q创建spring配置文gQspring.xmlQ定义datasourceQsessionFactory{;<br />    2Q创建AccountServiceQ实C务逻辑Q调用AccountDaoQ?br />4、Struts2<br />    1Q创建web.xmlQ将spring.xml攑օContextConfigLocationQ?br />    2Q创建struts.xmlQ定义package和action及蟩转;<br />    3Q创建LoginActionc,从页面获取用户名和密码,调用AccountService的用于验证方?br /><br />ȝQ在做这个例子的q程中,出现很多问题Q很大一部分都是来自于jar包的~失和冲H,以下几点是比较难于发现的Q?br />  1QSpringframework的jar包版本不一_会出现很奇怪的问题Q?br />  2Q缺?span style="color: red;">struts2-spring-plugin</span>-2.2.3的jar包,会导致spring的bean无法实例化成功,L获取到nullQ?br />  3Qjavaee.jar和servlet-api.jar的冲H,个h感觉后者是前者的_版,在Tomcat容器的lib目录下存在,会和工程中的lib冲突Q解x案是把Tomcat下的servlet-api.jar换成javaee.jarQ?br />  4Q如果想通过标记的方式来注入beanQ必dspring配置文g中,d以下代码Q?br /><span style="color: red;">       <context:annotation-config /></span><br /><span style="color: red;">       <context:component-scan base-package="com.glen" /></span><br /><br />另外Q还有两个问题未解决Q望能h帮之Q?/p> <div>  1Q两表关联,PrimaryKeyJoinColumn不v作用Q只能插数据C表,不能数据插入关联表Q?/div> <div>  2Qmysql数据库,插入中文时报错,</div> <div> <div style="color: rgb(0, 0, 128);">[2011/11/27 11:30:45:045 CST] ERROR org.hibernate.util.JDBCExceptionReporter:(JDBCExceptionReporter.java:101): Incorrect string value: '\xE5\xBC\xA0\xE7\x9B\x8A...' for column 'chinese_name' at row 1</div> <div style="color: rgb(0, 0, 128);">[2011/11/27 11:30:46:046 CST] ERROR org.hibernate.event.def.AbstractFlushingEventListener:(AbstractFlushingEventListener.java:324): Could not synchronize database state with session</div> <div style="color: rgb(0, 0, 128);">org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update</div></div> <p> </p> <img src ="http://www.tkk7.com/justuszhang2009/aggbug/364925.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/justuszhang2009/" target="_blank">张益?/a> 2011-11-27 17:27 <a href="http://www.tkk7.com/justuszhang2009/archive/2011/11/27/364925.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>谈pȝ架构Q一Q?/title><link>http://www.tkk7.com/justuszhang2009/archive/2011/06/26/353014.html</link><dc:creator>张益?/dc:creator><author>张益?/author><pubDate>Sun, 26 Jun 2011 00:16:00 GMT</pubDate><guid>http://www.tkk7.com/justuszhang2009/archive/2011/06/26/353014.html</guid><wfw:comment>http://www.tkk7.com/justuszhang2009/comments/353014.html</wfw:comment><comments>http://www.tkk7.com/justuszhang2009/archive/2011/06/26/353014.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/justuszhang2009/comments/commentRss/353014.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/justuszhang2009/services/trackbacks/353014.html</trackback:ping><description><![CDATA[<p>目前正在实施的一个项目,׃pȝ架构l组长突然离职,使我有幸代理了一D|间的pȝ架构l组长,但我主要负责pȝ架构l的日常理工作Q在技术层面涉入不深,q也是我比较遗憾的地斏V最q被人问到如何设计一个系l架构才能支撑高q发的要求时Q我哑口了,因ؓ我只知道用的什么系l架构,但真的没有去ȝq用这个架构的原因Q今天有I稍微整理了一下思AQ浅地谈一下?br /><br />先说一下我对系l架构的认识Q这是我在和一个资qpȝ架构师交谈时所吸收的,架构臛_可以分成三种层面的架构:pȝ架构、Y件架构、应用架构。系l架构是最高层面的一个架构,可以独立于Y件架构(用什么技术框架来搭徏Q和应用架构Q实现的什么业务需求)而存在。一个系l架构师应该考虑的是Q根据系l的非功能性需求(讉K量、ƈ发量、扩展性要求等Q,来选择使用什么样的硬件、操作系l、数据库、中间g、编E语a?br /><br />׃没有太多pȝ架构的经验,q次先说到q里Q之后会单聊聊我所熟知的Y件架构和应用架构?/p> <img src ="http://www.tkk7.com/justuszhang2009/aggbug/353014.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/justuszhang2009/" target="_blank">张益?/a> 2011-06-26 08:16 <a href="http://www.tkk7.com/justuszhang2009/archive/2011/06/26/353014.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【{】单元测试利?JUnit 4http://www.tkk7.com/justuszhang2009/archive/2011/06/24/352430.html张益?/dc:creator>张益?/author>Fri, 24 Jun 2011 05:06:00 GMThttp://www.tkk7.com/justuszhang2009/archive/2011/06/24/352430.htmlhttp://www.tkk7.com/justuszhang2009/comments/352430.htmlhttp://www.tkk7.com/justuszhang2009/archive/2011/06/24/352430.html#Feedback0http://www.tkk7.com/justuszhang2009/comments/commentRss/352430.htmlhttp://www.tkk7.com/justuszhang2009/services/trackbacks/352430.html引言

毋庸|疑Q程序员要对自己~写的代码负责,您不仅要保证它能通过~译Q正常地q行Q而且要满需求和设计预期的效果。单元测试正是验证代码行为是否满预期的有效手段之一。但不可否认Q做试是g很枯燥无的事情Q而一遍又一遍的试则更是让人生畏的工作。幸q的是,单元试工具 JUnit 使这一切变得简单艺术v来?/p>

JUnit ?Java C֌中知名度最高的单元试工具。它诞生?1997 q_?Erich Gamma ?Kent Beck 共同开发完成。其?Erich Gamma 是经典著作《设计模式:可复用面向对象Y件的基础》一书的作者之一Qƈ?Eclipse 中有很大的A献;Kent Beck 则是一位极限编E(XPQ方面的专家和先驱?/p>

麻雀虽小Q五脏俱全。JUnit 设计的非常小巧,但是功能却非常强大。Martin Fowler 如此评h JUnitQ在软g开发领域,从来没有如此少的代码vC如此重要的作用。它大大化了开发h员执行单元测试的隑ֺQ特别是 JUnit 4 使用 Java 5 中的注解QannotationQɋ试变得更加单?/p>


JUnit 4 初体?/span>

在开始体?JUnit 4 之前Q我们需要以下Y件的支持Q?/p>

  • EclipseQ最为流行的 IDEQ它全面集成?JUnitQƈ从版?3.2 开始支?JUnit 4。当?JUnit q不依赖于Q?IDE。您可以?http://www.eclipse.org/ 上下载最新的 Eclipse 版本?/li>
  • AntQ基?Java 的开源构建工P您可以在 http://ant.apache.org/ 上得到最新的版本和丰富的文档。Eclipse 中已l集成了 AntQ但是在撰写本文ӞEclipse 使用?Ant 版本较低Q必需 1.7 或者以上版本)Q不能很好的支持 JUnit 4?/li>
  • JUnitQ它的官方网站是 http://www.junit.org/。您可以从上面获取关?JUnit 的最新消息。如果您和本文一样在 Eclipse 中?JUnitQ就不必再下载了?

首先为我们的体验新徏一?Java 工程 —— coolJUnit。现在需要做的是Q打开目 coolJUnit 的属性页 -> 选择“Java Build Path”子选项 -> 炚w?#8220;Add Library …”按钮 -> 在弹出的“Add Library”对话框中选择 JUnitQ?a >?1Q,q在下一中选择版本 4.1 后点?#8220;Finish”按钮。这样便?JUnit 引入到当前项目库中了?/p>
?1 为项目添?JUnit ?/strong>
?1 为项目添?JUnit ? src=

h?JDK 的版?/h2>

JUnit 4.1 是基?Java 5 的升U版本,它用了 Tiger 中的很多新特性来化原有的使用方式。正因ؓ如此Q它q不能直接运行在 JDK1.4.x 版本上。如果您需要在 JDK1.4.x 版本使用 JUnit 的话Q请使用 3.8.1 版本?/p>

可以开始编写单元测试了吗?{等……Q您打算把单元测试代码放在什么地方呢Q把它和被测试代码؜在一Pq显然会照成混ؕQ因为单元测试代码是不会出现在最l品中的。徏议您分别为单元测试代码与被测试代码创建单独的目录Qƈ保证试代码和被试代码使用相同的包名。这h保证了代码的分离Q同时还保证了查扄方便。遵照这条原则,我们在项?coolJUnit 根目录下d一个新目录 testsrcQƈ把它加入到项目源代码目录中(加入方式??2Q?/p>
?2 修改目源代码目?/strong>
?2 修改目源代码目? src=

现在我们得到了一?JUnit 的最佛_践:单元试代码和被试代码使用一L包,不同的目录?/p>

一切准备就l,一起开始体验如何?JUnit q行单元试吧。下面的例子来自W者的开发实践:工具c?WordDealUtil 中的静态方?wordFormat4DB 是专用于处理 Java 对象名称向数据库表名转换的方法(您可以在代码注释中可以得到更多详l的内容Q。下面是W一ơ编码完成后大致情ŞQ?/p>
 package com.ai92.cooljunit; 

 import java.util.regex.Matcher; 
 import java.util.regex.Pattern; 

 /** 
 * 对名U、地址{字W串格式的内容进行格式检?
 * 或者格式化的工L
 * 
 * @author Ai92 
 */ 
 public class WordDealUtil { 

	 /** 
	 * ?Java 对象名称Q每个单词的头字母大写)按照
	 * 数据库命名的习惯q行格式?
	 * 格式化后的数据ؓ写字母Qƈ且用下划线分割命名单词
	 * 
	 * 例如QemployeeInfo l过格式化之后变?employee_info 
	 * 
	 * @param name 	 Java 对象名称
	 */ 
	 public static String wordFormat4DB(String name){ 
		 Pattern p = Pattern.compile("[A-Z]"); 
		 Matcher m = p.matcher(name); 
		 StringBuffer sb = new StringBuffer(); 
		
		 while(m.find()){ 
			 m.appendReplacement(sb, "_"+m.group()); 
		 } 
		 return m.appendTail(sb).toString().toLowerCase(); 
	 } 
 } 

它是否能按照预期的效果执行呢Q尝试ؓ它编?JUnit 单元试代码如下Q?/p>
 package com.ai92.cooljunit; 

 import static org.junit.Assert.assertEquals; 
 import org.junit.Test; 

 public class TestWordDealUtil { 
	 // 试 wordFormat4DB 正常q行的情?
	 @Test public void wordFormat4DBNormal(){ 
		 String target = "employeeInfo"; 
		 String result = WordDealUtil.wordFormat4DB(target); 
		
		 assertEquals("employee_info", result); 
	 } 
 } 

很普通的一个类嘛!试c?TestWordDealUtil 之所以?#8220;Test”开_完全是ؓ了更好的区分试cM被测试类。测试方?wordFormat4DBNormal 调用执行被测试方?WordDealUtil.wordFormat4DBQ以判断q行l果是否辑ֈ设计预期的效果。需要注意的是,试Ҏ wordFormat4DBNormal 需要按照一定的规范书写Q?/p>

  1. 试Ҏ必须使用注解 org.junit.Test 修饰?/li>
  2. 试Ҏ必须使用 public void 修饰Q而且不能带有M参数?

试Ҏ中要处理的字W串?#8220;employeeInfo”Q按照设计目的,处理后的l果应该?#8220;employee_info”。assertEquals 是由 JUnit 提供的一pd判断试l果是否正确的静态断aҎQ位于类 org.junit.Assert 中)之一Q我们用它执行结?result 和预期?#8220;employee_info”q行比较Q来判断试是否成功?/p>

看看q行l果如何。在试cM点击右键Q在弹出菜单中选择 Run As JUnit Test。运行结果如 下图所C:


?3 JUnit q行成功界面
?3 JUnit q行成功界面

l色的进度条提示我们Q测试运行通过了。但现在宣布代码通过了单元测试还为时q早。记住:您的单元试代码不是用来证明您是对的Q而是Z证明您没有错。因此单元测试的范围要全面,比如对边界倹{正常倹{错误值得试Q对代码可能出现的问题要全面预测Q而这也正是需求分析、详l设计环节中要考虑的。显Ӟ我们的测试才刚刚开始,l箋补充一些对Ҏ情况的测试:

 public class TestWordDealUtil { 
	……
	 // 试 null 时的处理情况
	 @Test public void wordFormat4DBNull(){ 
		 String target = null; 
		 String result = WordDealUtil.wordFormat4DB(target); 
		
		 assertNull(result); 
	 } 
	
	 // 试I字W串的处理情?
	 @Test public void wordFormat4DBEmpty(){ 
		 String target = ""; 
		 String result = WordDealUtil.wordFormat4DB(target); 
		
		 assertEquals("", result); 
	 } 

	 // 试当首字母大写时的情况
	 @Test public void wordFormat4DBegin(){ 
		 String target = "EmployeeInfo"; 
		 String result = WordDealUtil.wordFormat4DB(target); 
		
		 assertEquals("employee_info", result); 
	 } 
	
	 // 试当尾字母为大写时的情?
	 @Test public void wordFormat4DBEnd(){ 
		 String target = "employeeInfoA"; 
		 String result = WordDealUtil.wordFormat4DB(target); 
		
		 assertEquals("employee_info_a", result); 
	 } 
	
	 // 试多个相连字母大写时的情况
	 @Test public void wordFormat4DBTogether(){ 
		 String target = "employeeAInfo"; 
		 String result = WordDealUtil.wordFormat4DB(target); 
		
		 assertEquals("employee_a_info", result); 
	 } 
 } 

再次q行试。很遗憾QJUnit q行界面提示我们有两个测试情冉|通过试Q?a >?4Q?#8212;—当首字母大写时得到的处理l果与预期的有偏差,造成试p|QfailureQ;而当试?null 的处理结果时Q则直接抛出了异?#8212;—试错误QerrorQ。显Ӟ被测试代码中q没有对首字母大写和 null q两U特D情况进行处理,修改如下Q?/p>
 // 修改后的Ҏ wordFormat4DB 
 /** 
	 * ?Java 对象名称Q每个单词的头字母大写)按照
	 * 数据库命名的习惯q行格式?
	 * 格式化后的数据ؓ写字母Qƈ且用下划线分割命名单词
	 * 如果参数 name ?nullQ则q回 null 
	 * 
	 * 例如QemployeeInfo l过格式化之后变?employee_info 
	 * 
	 * @param name Java 对象名称
	 */ 
	 public static String wordFormat4DB(String name){ 
		
		 if(name == null){ 
			 return null; 
		 } 
		
		 Pattern p = Pattern.compile("[A-Z]"); 
		 Matcher m = p.matcher(name); 
		 StringBuffer sb = new StringBuffer(); 
		
		 while(m.find()){ 
			 if(m.start() != 0) 
				 m.appendReplacement(sb, ("_"+m.group()).toLowerCase()); 
		 } 
		 return m.appendTail(sb).toString().toLowerCase(); 
	 } 


?4 JUnit q行p|界面
?4 JUnit q行p|界面

JUnit 测试失败的情况分ؓ两种Qfailure ?error。Failure 一般由单元试使用的断aҎ判断p|引vQ它表示在测试点发现了问题;?error 则是׃码异常引Pq是试目的之外的发玎ͼ它可能生于试代码本n的错误(试代码也是代码Q同h法保证完全没有缺PQ也可能是被试代码中的一个隐藏的 bug?/p>

L讎ͼ

L记这一?JUnit 最佛_践:试M可能的错误。单元测试不是用来证明您是对的,而是Z证明您没有错?/p>

啊哈Q再ơ运行测试,l条又重现眼前。通过?WordDealUtil.wordFormat4DB 比较全面的单元测试,现在的代码已l比较稳定,可以作ؓ API 的一部分提供l其它模块用了?/p>

不知不觉中我们已l?JUnit 漂亮的完成了一ơ单元测试。可以体会到 JUnit 是多么轻量Q多么简单,Ҏ不需要花心思去研究Q这可以把更多的注意力攑֜更有意义的事情上——~写完整全面的单元测试?/p>


JUnit 深入

当然QJUnit 提供的功能决不仅仅如此简单,在接下来的内容中Q我们会看到 JUnit 中很多有用的Ҏ,掌握它们Ҏ灉|的编写单元测试代码非常有帮助?/p>

Fixture

何谓 Fixture Q它是指在执行一个或者多个测试方法时需要的一pd公共资源或者数据,例如试环境Q测试数据等{。在~写单元试的过E中Q您会发现在大部分的试Ҏ在进行真正的试之前都需要做大量的铺?#8212;—计准?Fixture 而忙。这些铺垫过E占据的代码往往比真正测试的代码多得多,而且q个比率随着试的复杂程度的增加而递增。当多个试Ҏ都需要做同样的铺垫时Q重复代码的“坏味?#8221;便在试代码中I漫开来。这?#8220;坏味?#8221;会弄脏您的代码,q会因ؓ疏忽造成错误Q应该用一些手D|栚w它?/p>

JUnit 专门提供了设|公?Fixture 的方法,同一试cM的所有测试方法都可以q它来初始?Fixture 和注销 Fixture。和~写 JUnit 试Ҏ一P公共 Fixture 的设|也很简单,您只需要:

  1. 使用注解 org,junit.Before 修饰用于初始?Fixture 的方法?/li>
  2. 使用注解 org.junit.After 修饰用于注销 Fixture 的方法?/li>
  3. 保证q两U方法都使用 public void 修饰Q而且不能带有M参数?

遵@上面的三条原则,~写出的代码大体是这个样子:

 // 初始?Fixture Ҏ
 @Before public void init(){ …… } 

 // 注销 Fixture Ҏ
 @After public void destroy(){ …… } 

q样Q在每一个测试方法执行之前,JUnit 会保?init Ҏ已经提前初始化测试环境,而当此测试方法执行完毕之后,JUnit 又会调用 destroy Ҏ注销试环境。注意是每一个测试方法的执行都会触发对公?Fixture 的设|,也就是说使用注解 Before 或?After 修饰的公?Fixture 讄Ҏ是方法别的Q?a >?5Q。这样便可以保证各个独立的测试之间互不干扎ͼ以免其它试代码修改试环境或者测试数据媄响到其它试代码的准性?/p>
?5 ҎU别 Fixture 执行C意?/strong>
?5 ҎU别 Fixture 执行C意? src=

可是Q这U?Fixture 讄方式q是引来了批评,因ؓ它效率低下,特别是在讄 Fixture 非常耗时的情况下Q例如设|数据库链接Q。而且对于不会发生变化的测试环境或者测试数据来_是不会媄响到试Ҏ的执行结果的Q也没有必要针Ҏ一个测试方法重新设|一?Fixture。因此在 JUnit 4 中引入了cȝ别的 Fixture 讄ҎQ编写规范如下:

  1. 使用注解 org,junit.BeforeClass 修饰用于初始?Fixture 的方法?/li>
  2. 使用注解 org.junit.AfterClass 修饰用于注销 Fixture 的方法?/li>
  3. 保证q两U方法都使用 public static void 修饰Q而且不能带有M参数?

cȝ别的 Fixture 仅会在测试类中所有测试方法执行之前执行初始化Qƈ在全部测试方法测试完毕之后执行注销ҎQ?a >?6Q。代码范本如下:

 // cȝ?Fixture 初始化方?
 @BeforeClass public static void dbInit(){ …… } 
	
 // cȝ?Fixture 注销Ҏ
	 @AfterClass public static void dbClose(){ …… } 


?6 cȝ?Fixture 执行C意?/strong>
?6 cȝ?Fixture 执行C意? src=

异常以及旉试

注解 org.junit.Test 中有两个非常有用的参敎ͼexpected ?timeout。参?expected 代表试Ҏ期望抛出指定的异常,如果q行试q没有抛个异常,?JUnit 会认个测试没有通过。这为验证被试Ҏ在错误的情况下是否会抛出预定的异常提供了便利。D例来_Ҏ supportDBChecker 用于查用户用的数据库版本是否在pȝ的支持的范围之内Q如果用户用了不被支持的数据库版本Q则会抛行时异常 UnsupportedDBVersionException。测试方?supportDBChecker 在数据库版本不支持时是否会抛出指定异常的单元试Ҏ大体如下Q?/p>
 @Test(expected=UnsupportedDBVersionException.class) 
	 public void unsupportedDBCheck(){ 
		……
 } 

注解 org.junit.Test 的另一个参?timeoutQ指定被试Ҏ被允许运行的最长时间应该是多少Q如果测试方法运行时间超q了指定的毫U数Q则 JUnit 认ؓ试p|。这个参数对于性能试有一定的帮助。例如,如果解析一份自定义?XML 文档p了多?1 U的旉Q就需要重新考虑 XML l构的设计,那单元测试方法可以这h写:

 @Test(timeout=1000) 
	 public void selfXMLReader(){ 
		……
 } 

忽略试Ҏ

JUnit 提供注解 org.junit.Ignore 用于暂时忽略某个试ҎQ因为有时候由于测试环境受限,q不能保证每一个测试方法都能正运行。例如下面的代码便表C由于没有了数据库链接,提示 JUnit 忽略试Ҏ unsupportedDBCheckQ?/p>
 @ Ignore(“db is down”) 
 @Test(expected=UnsupportedDBVersionException.class) 
	 public void unsupportedDBCheck(){ 
		……
 } 

但是一定要心。注?org.junit.Ignore 只能用于暂时的忽略测试,如果需要永q忽略这些测试,一定要认被测试代码不再需要这些测试方法,以免忽略必要的测试点?/p>

试q行?/span>

又一个新概念出现?#8212;—试q行器,JUnit 中所有的试Ҏ都是由它负责执行的。JUnit 为单元测试提供了默认的测试运行器Q但 JUnit q没有限制您必须使用默认的运行器。相反,您不仅可以定制自qq行器(所有的q行器都l承?org.junit.runner.RunnerQ,而且q可以ؓ每一个测试类指定使用某个具体的运行器。指定方法也很简单,使用注解 org.junit.runner.RunWith 在测试类上显式的声明要用的q行器即可:

 @RunWith(CustomTestRunner.class) 
 public class TestWordDealUtil { 
……
 } 

显而易见,如果试cL有显式的声明使用哪一个测试运行器QJUnit 会启动默认的试q行器执行测试类Q比如上面提及的单元试代码Q。一般情况下Q默认测试运行器可以应对l大多数的单元测试要求;当?JUnit 提供的一些高U特性(例如卛_介绍的两个特性)或者针对特D需求定?JUnit 试方式Ӟ昑ּ的声明测试运行器必不可了?/p>

试套g

在实际项目中Q随着目q度的开展,单元试cM来多Q可是直到现在我们还只会一个一个的单独q行试c,q在实际目实践中肯定是不可行的。ؓ了解册个问题,JUnit 提供了一U批量运行测试类的方法,叫做试套g。这P每次需要验证系l功能正性时Q只执行一个或几个试套g便可以了。测试套件的写法非常单,您只需要遵循以下规则:

  1. 创徏一个空cM为测试套件的入口?/li>
  2. 使用注解 org.junit.runner.RunWith ?org.junit.runners.Suite.SuiteClasses 修饰q个I类?/li>
  3. ?org.junit.runners.Suite 作ؓ参数传入注解 RunWithQ以提示 JUnit 为此cM用套件运行器执行?/li>
  4. 需要放入此试套g的测试类l成数组作ؓ注解 SuiteClasses 的参数?/li>
  5. 保证q个I类使用 public 修饰Q而且存在公开的不带有M参数的构造函数?
 package com.ai92.cooljunit; 

 import org.junit.runner.RunWith; 
 import org.junit.runners.Suite; 
……

 /** 
 * 扚w试 工具?中测试类
 * @author Ai92 
 */ 
 @RunWith(Suite.class) 
 @Suite.SuiteClasses({TestWordDealUtil.class}) 
 public class RunAllUtilTestsSuite { 
 } 

上例代码中,我们前文提到的试c?TestWordDealUtil 攑օ了测试套?RunAllUtilTestsSuite 中,?Eclipse 中运行测试套Ӟ可以看到试c?TestWordDealUtil 被调用执行了。测试套件中不仅可以包含基本的测试类Q而且可以包含其它的测试套Ӟq样可以很方便的分层理不同模块的单元测试代码。但是,您一定要保证试套g之间没有循环包含关系Q否则无的循环׃出现在您的面?#8230;…?/p>

参数化测?/span>

回顾一下我们在节“JUnit 初体?/a>”中D的实例。ؓ了保证单元测试的严}性,我们模拟了不同类型的字符串来试Ҏ的处理能力,为此我们~写大量的单元测试方法。可是这些测试方法都是大同小异:代码l构都是相同的,不同的仅仅是试数据和期望倹{有没有更好的方法将试Ҏ中相同的代码l构提取出来Q提高代码的重用度,减少复制_脓代码的烦|在以前的 JUnit 版本上,q没有好的解x法,而现在您可以使用 JUnit 提供的参数化试方式应对q个问题?/p>

参数化测试的~写E微有点ȝQ当然这是相对于 JUnit 中其它特性而言Q:

  1. 为准备用参数化试的测试类指定Ҏ的运行器 org.junit.runners.Parameterized?/li>
  2. 为测试类声明几个变量Q分别用于存放期望值和试所用数据?/li>
  3. 为测试类声明一个用注?org.junit.runners.Parameterized.Parameters 修饰的,q回gؓ java.util.Collection 的公共静态方法,q在此方法中初始化所有需要测试的参数寏V?/li>
  4. 为测试类声明一个带有参数的公共构造函敎ͼq在其中为第二个环节中声明的几个变量赋倹{?/li>
  5. ~写试ҎQ用定义的变量作ؓ参数q行试?

我们按照q个标准Q重新改造一番我们的单元试代码Q?/p>
package com.ai92.cooljunit; 

import static org.junit.Assert.assertEquals; 
import java.util.Arrays; 
import java.util.Collection; 

import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.junit.runners.Parameterized; 
import org.junit.runners.Parameterized.Parameters; 

@RunWith(Parameterized.class) 
public class TestWordDealUtilWithParam { 

        private String expected; 
    
        private String target; 
    
        @Parameters 
        public static Collection words(){ 
            return Arrays.asList(new Object[][]{ 
                {"employee_info", "employeeInfo"},      // 试一般的处理情况
                {null, null},                           // 试 null 时的处理情况
                {"", ""},                               // 试I字W串时的处理情况
                {"employee_info", "EmployeeInfo"},      // 试当首字母大写时的情况
                {"employee_info_a", "employeeInfoA"},   // 试当尾字母为大写时的情?
                {"employee_a_info", "employeeAInfo"}    // 试多个相连字母大写时的情况
            }); 
        } 
    
         /** 
         * 参数化测试必ȝ构造函?
         * @param expected     期望的测试结果,对应参数集中的第一个参?
         * @param target     试数据Q对应参数集中的W二个参?
         */ 
        public TestWordDealUtilWithParam(String expected , String target){ 
            this.expected = expected; 
            this.target = target; 
        } 
    
         /** 
         * 试?Java 对象名称到数据库名称的{?
         */ 
        @Test public void wordFormat4DB(){ 
            assertEquals(expected, WordDealUtil.wordFormat4DB(target)); 
        } 
} 

很明显,代码瘦n了。在静态方?words 中,我们使用二维数组来构建测试所需要的参数列表Q其中每个数l中的元素的攄序q没有什么要求,只要和构造函C的顺序保持一致就可以了。现在如果再增加一U测试情况,只需要在静态方?words 中添加相应的数组卛_Q不再需要复制粘贴出一个新的方法出来了?/p>


JUnit ?Ant

随着目的进展,目的规模在不断的膨胀Qؓ了保证项目的质量Q有计划的执行全面的单元试是非常有必要的。但单靠 JUnit 提供的测试套件很难胜任这工作,因ؓ目中单元测试类的个数在不停的增加,试套g却无法动态的识别新加入的单元试c,需要手动修Ҏ试套Ӟq是一个很Ҏ遗忘得步骤,E有疏忽׃影响全面单元试的覆盖率?/p>

当然解决的方法有多种多样Q其中将 JUnit 与构建利?Ant l合使用可以很简单的解决q个问题。Ant —— 备受赞誉?Java 构徏工具。它凭借出色的易用性、^台无x以及对目自动试和自动部|的支持Q成Z多项目构E中不可或缺的独立工Pq已l成Z实上的标准。Ant 内置了对 JUnit 的支持,它提供了两个 TaskQjunit ?junitreportQ分别用于执?JUnit 单元试和生成测试结果报告。用这两个 Task ~写构徏脚本Q可以很单的完成每次全面单元试的Q务?/p>

不过Q在使用 Ant q行 JUnit 之前Q您需要稍作一些配|。打开 Eclipse 首选项界面Q选择 Ant -> Runtime 首选项Q见 ?7Q,?JUnit 4.1 ?JAR 文gd?Classpath Tab 中?Global Entries 讄w。记得检查一?Ant Home Entries 讄中?Ant 版本是否?1.7.0 之上Q如果不是请替换为最新版本的 Ant JAR 文g?/p>
?7 Ant Runtime 首选项
?7 Ant Runtime 首选项

剩下的工作就是要~写 Ant 构徏脚本 build.xml。虽然这个过E稍嫌繁琐,但这是一件一x逸的事情。现在我们就把前面编写的试用例都放|到 Ant 构徏脚本中执行,为项?coolJUnit 的构本添加一下内容:

 <?xml version="1.0"?> 
 <!-- ============================================= 
     auto unittest task    
     ai92                                                                
     ========================================== --> 
 <project name="auto unittest task" default="junit and report" basedir="."> 

		 <property name="output folder" value="bin"/> 

		 <property name="src folder" value="src"/> 
	
		 <property name="test folder" value="testsrc"/> 
	
		 <property name="report folder" value="report" /> 

		 <!-- - - - - - - - - - - - - - - - - - 
          target: test report folder init                      
         - - - - - - - - - - - - - - - - - --> 
		 <target name="test init"> 
			 <mkdir dir="${report folder}"/> 
		 </target> 
	
		 <!-- - - - - - - - - - - - - - - - - - 
          target: compile                      
         - - - - - - - - - - - - - - - - - --> 
		 <target name="compile"> 
			 <javac srcdir="${src folder}" destdir="${output folder}" /> 
			 <echo>compilation complete!</echo> 
		 </target> 

		 <!-- - - - - - - - - - - - - - - - - - 
          target: compile test cases                      
         - - - - - - - - - - - - - - - - - --> 
		 <target name="test compile" depends="test init"> 
			 <javac srcdir="${test folder}" destdir="${output folder}" /> 
			 <echo>test compilation complete!</echo> 
		 </target> 
	
		 <target name="all compile" depends="compile, test compile"> 
		 </target> 
	
		 <!-- ======================================== 
          target: auto test all test case and output report file                      
      	 ===================================== --> 
		 <target name="junit and report" depends="all compile"> 
			 <junit printsummary="on" fork="true" showoutput="true"> 
				 <classpath> 
					 <fileset dir="lib" includes="**/*.jar"/> 
					 <pathelement path="${output folder}"/> 
				 </classpath> 
				 <formatter type="xml" /> 
				 <batchtest todir="${report folder}"> 
					 <fileset dir="${output folder}"> 
						 <include name="**/Test*.*" /> 
					 </fileset> 
				 </batchtest> 
			 </junit> 
			 <junitreport todir="${report folder}"> 
				 <fileset dir="${report folder}"> 
					 <include name="TEST-*.xml" /> 
				 </fileset> 
				 <report format="frames" todir="${report folder}" /> 
			 </junitreport> 
		 </target> 
 </project> 

Target junit report ?Ant 构徏脚本中的核心内容Q其?target 都是为它的执行提供前期服务。Task junit 会寻找输出目录下所有命名以“Test”开头的 class 文gQƈ执行它们。紧接着 Task junitreport 会将执行l果生成 HTML 格式的测试报告(?8Q放|在“report folder”下?/p>

为整个项目的单元试cȝ定一U命名风根{不仅是Z区分cd的考虑Q这?Ant 扚w执行单元试也非常有帮助Q比如前面例子中的测试类都已“Test”打头Q而测试套件则?#8220;Suite”l尾{等?/p>
?8 junitreport 生成的测试报?/strong>
?8 junitreport 生成的测试报? src=

现在执行一ơ全面的单元试变得非常单了Q只需要运行一?Ant 构徏脚本Q就可以走完所有流E,q能得到一份详的试报告。您可以?Ant 在线手册中获得上面提及的每一?Ant 内置 task 的用细节?/p>


ȝ

随着来多的开发h员开始认同ƈ接受极限~程QXPQ的思想Q单元测试的作用在Y件工E中变得来重要。本文旨在将最新的单元试工具 JUnit 4 介绍l您Q以及如何结?IDE Eclipse 和构建工?Ant 创徏自动化单元测试方案。ƈ且还期望您能够通过本文“感染”一些好的单元测试意识,因ؓ JUnit 本n仅仅是一份工兯已Q它的真正优势来自于它的思想和技术?/p>

]]>
【{】持l集成工?/title><link>http://www.tkk7.com/justuszhang2009/archive/2011/06/24/352182.html</link><dc:creator>张益?/dc:creator><author>张益?/author><pubDate>Fri, 24 Jun 2011 05:06:00 GMT</pubDate><guid>http://www.tkk7.com/justuszhang2009/archive/2011/06/24/352182.html</guid><wfw:comment>http://www.tkk7.com/justuszhang2009/comments/352182.html</wfw:comment><comments>http://www.tkk7.com/justuszhang2009/archive/2011/06/24/352182.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/justuszhang2009/comments/commentRss/352182.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/justuszhang2009/services/trackbacks/352182.html</trackback:ping><description><![CDATA[<table class="seyle4" border="0" cellspacing="0" cellpadding="0" width="100%"> <tbody> <tr> <td class="content9" valign="middle"><strong></strong></td></tr> <tr> <td> <div align="right"><span id="ugaoasq" class="textbox-label">[ 2009-12-23 9:25:00 | By: <span id="wymgmoo" class="style3">王v?/span> ]</span></div></td></tr></tbody></table> <table border="0" cellspacing="0" cellpadding="0" width="100%"> <tbody> <tr> <td height="3"> </td></tr></tbody></table> <table style="table-layout: fixed" border="0" cellspacing="0" cellpadding="0" width="100%" align="center"> <tbody> <tr> <td><span id="ykmiaow" class="oblog_text"><span id="ob_logd41613"> <div style="text-align: center; margin: 0px 10px 5px 0px; width: 45px; display: inline;background: url(http://www.tkk7.com/Images/digg.gif) no-repeat left top; float: right; height: 55px" class="digg_list"> <div style="padding-bottom: 11px; line-height: 1; padding-left: 0px; width: 45px; padding-right: 0px; font-family: tahoma,Arial,Helvetica,sans-serif; color: #333; font-size: 18px; font-weight: 600; padding-top: 10px" class="digg_number">0</div> <div style="padding-bottom: 0px; line-height: 1; padding-left: 6px; padding-right: 0px; letter-spacing: 6px; padding-top: 3px" class="digg_submit"><a style="line-height: 1; font-size: 12px" href="javascript:void(null)">推荐</a></div></div></span> <p>引言</p> <p>Thomas Carlyle_“人类是用工L动物。没有工PZ么都不是Q有了工P人无所不能?#8221;金融家们创造了复杂的金融工Pq利用这些工具制造了财富话Q制造了著名的跨国公司,也制造了世界范围的危机。Y件精׃Z让自q工作效率更高Q有更多旉d惛_的事Q也创造了各式各样的工兗持l集成已l不是一个新概念Q在q个概念发展的十多年_出现了支持这一概念的众多工兗这些工Ll合使用Qؓ软g开发提供了强大的支持?/p> <p>持箋集成工具的分cd功能</p> <p>一般来_持箋集成工具可以分成两大c:自动化构建工具和构徏计划安排工具?/p> <p>自动化构建工hq样一些基本功能:代码~译、组件打包、程序执行和文g操作。编译源代码是构建的主要工作之一Qؓ了提高效率,~译应该Ҏ相应的源代码是否发生改变而有条g地执行。组件打包是编译的l果和其他需要包含的文gl织在一P形成可以部v的组件。构建工具应该知道何旉要重新打包。程序执行是指构建工兯够在它支持的q_上,调用所有提供命令行接口的程序。构建工具应该支持创建、拷贝、删除文件和目录{操作?/p> <p>某些自动化构建工兯有一些扩展功能:执行开发者测试、版本控制工具集成、文档集成、部|功能、代码品质分析、支持扩展、多q_构徏、加速构建。虽然构建工具可以通过命o行执行的方式来集成构建工具和试工具Q但如果它提供更直接的集成方式,开发者就更省力。同P如果构徏工具能够直接与版本控制工具集成,开发者也会觉得更方便。文档集成是指构建工兯够自动从源代码中抽取q生成API文档。构建工兯可以打包好的组件自动部|到目标试环境中去。构建工具一般通过一些第三方插gQ支持对代码品质q行分析。而提供插件接口,是构建工具实现可扩展性的通用方式。如果您开发的软g需要在多个q_上构建ƈ试Q那么构建工具对多^台的支持׃带来极大的方ѝ对于较大的代码集,一ơ构建可能需要好几个时Q这为持l集成带来了一些挑战。有的构建工h持加速构建,卛_多个构徏服务器的多个处理器上q行分布式构建?/p> <p>常见的自动化构徏工具包括Ant、NAnt、MSBuild、make、Maven、Rake{?/p> <p>构徏计划安排工具有这样一些基本功能:构徏执行、版本控刉成、构建工具集成、提供反馈、ؓ构徏打上标签。构划安排工L核心功能是在特定时间执行自动化的构建,q可以通过轮询版本控制库、计划驱动或事g通知{方式来实现。大部分构徏计划安排工具都支持大多数行的版本控制系l,也支持大多数行的构建工兗构划安排工兯支持通过电子邮g提供反馈信息Q有一些工具可以通过x消息、手机短信或其他讑֤来提供反馈。大多数构徏计划安排工具会提供某U类型的升序计数Q作为构建版本的标签?/p> <p>某些构徏计划安排工具q有一些扩展功能:支持目间依赖关pR提供用L面、制品发布、安全。如果项目间存在依赖关系Q您可能希望在被依赖的项目重新构建时Q重新构Z赖于它的目。设计良好的用户界面会在工作时ؓ您节U时间。制品发布是指除了得到可部v的组件之外,一些成熟的某些构徏计划安排工具可以文档、测试结果、品质分析结构和其他量指标数据格式化,便于查看。有一些工h供了w䆾认证和授权等安全斚w的功能,允许您指定谁能查看结果和修改配置?/p> <p>常见的构划安排工具包括AnthillPro、Continuum、CruiseControl、CruiseControl.NET、Draco.NET、Luntbuild、Hudson{?/p> <p>下面介绍两个颇具代表性的工具QAnt和Hudson?/p> <p>Ant</p> <p>Ant是Java构徏工具的事实标准,一般徏议,不论目团队成员使用哪种集成开发环境,目都要有一个可以脱IDE执行的Ant脚本。Ant采用插g式的设计l构Q通过不同的插件来实现各种dQ其d分类如表1所C?/p> <p>Archive Tasks<br /> 打包解包dQ支持的格式包括QBZip2、Cab、Ear、GZip、Jar、Rpm、Tar、War、Zip?br /> <br />Audit/Coverage Tasks<br /> JDependdQ调用JDepend实现代码静态分析,针对每个Java包生成设计品质指标数据?br /> <br />Compile Tasks<br /> ~译dQ实现对Java、JSP、NetRexx{源文g的编译?br /> <br />Deployment Tasks<br /> 部vdQ实现在JavaEE服务器上热部|Ӏ?br /> <br />Documentation Tasks<br /> 文档生成dQ生成javadoc文档、Apache Stylebook文档?br /> <br />EJB Tasks<br /> EJBdQ提供对1.x?.x的EJB的支持,q支持不同供应商的应用服务器?br /> <br />Execution Tasks<br /> 执行dQ包括对子项目调用Ant、调用同一脚本中的另一个target、执行系l提供的命o行程序、执行JavaE序、暂停和q行同步执行{功能?br /> <br />File Tasks<br /> 文gdQ实现对文g和目录的操作?br /> <br />Java2 Extensions Tasks<br /> Java2 扩展信息dQ对jar包中的版本、供应商{扩展信息进行检查和操作?br /> <br />Logging Tasks<br /> 日志dQ将构徏q程事g记录到文件中?br /> <br />Mail Tasks<br /> 邮gdQ发送SMTP邮g?br /> <br />Miscellaneous Tasks<br /> 其他dQ各U或怼用到的小dQ例如播放wav文g?br /> <br />.NET Tasks<br /> .NETdQ支持执?NETE序、执行NUnit试、调用NAnt、调用MSBuild、调用WiX工具?br /> <br />Pre-process Tasks<br /> 预处理Q务,实现~译之前的一些预处理。例如调用ANTLR、JavaCC、Native2Ascii{程序?br /> <br />Property Tasks<br /> 属性Q务,对脚本中的属性变量进行判断和操作?br /> <br />Remote Tasks<br /> q程dQ支持FTP、Rexec、Scp、SSH和Telnet?br /> <br />SCM Tasks<br /> SCMdQ支持各U配|管理(版本控制QYӞ包括CVS、ClearCase、Continuus、Visual SourceSafe、Perforce、PVCS、SourceOffSite和StarTeam?br /> <br />Testing Tasks<br /> 试dQ支持执行JUnit试?br /> <br />?. Antd分类</p> <p>以上介绍的只是Ant发行版所带的一些Q务。由于Ant采用的是插gl构Q所以开发者可以开发自己需要的AntdQ支持各U工P如FindBugs、TestNG{其他代码检查工具和试工具。早期的Ant没有很好的依赖关pL持,后来则通过Ivy弥补了这一~点?/p> <p>关键是Ant为我们提供了一个跨q_的Java构徏工具Qؓ持箋集成提供了根本的支持。对于Java开发者来_如果不想采用AntQ也可以考虑采用Maven?/p> <p>Hudson</p> <p>Hudson是一个开放源代码的CI服务器,受到世界各地各种规模和类型的开发团队的Ƣ迎。关键是因ؓ它非常易于安装和使用Q提供了灉|的配|方式和复杂的功能,同时支持Java目和非Java目Q由强大的HudsonC֌提供技术支持?/p> <p>而言之,Hudson不仅仅是一个CI服务器,它的可扩展架构它不仅是一个构建管理系l,也成Z个通用的开发生命周期管理系l,让开发者能够完成提升基Uѝ打标签、执行工作流、根据依赖关p追t变更、监视ƈ囄试l果、查看代码覆盖率和违反编码标准的情况{Q务?/p> <p>Hudson是最z跃Q成长最快的开源社Z一Q目前每周下载达4000ơ,有超q?万个在工作的安装实例。它的开发者超q?60人,贡献的工作量过137人年Q目前已发布了超q?00个发行版本。Hudson实际上是现在世界上最受欢q的开源CI服务器?/p> <p>?是Apache软g基金会运行Hudson的屏q截图,您可以在<a >http://wiki.hudson-ci.org/display/HUDSON/Meet+Hudson</a> 看到更多Hudson的用案例?/p> <p>?. Apacheq行的Hudson</p> <p>Huddon的主要优点包括:</p> <p>易于安装。只要执?#8220;java –jar hudson.war”Q或者将hudson.war部v到应用服务器上就可以了,不需要其他的安装工作Q也不需要徏立数据库?<br />易于配置。所有东襉K通过Web GUI界面来配|,不需要手工修改XML文g?<br />支持分布式构建。Hudson支持构建和试负蝲分布到多台机器上Q图2是Apache采用Hudson的分布式构徏功能?<br />支持环境配置矩阵。Hudson支持在不同的环境配置下执行相同的dQ例如不同的JDK版本、不同的操作pȝ、不同的数据库。执行的l果可以汇d一赗?<br />支持JUnit/TestNG试报告。测试的l果可以分标{ֈ出、汇总,q与历史信息一同显C。历史趋势可以显C在图中?<br />q踪依赖关系。Hudsonq踪记录哪次构徏生成了哪些jarQ某ơ构Z用了哪些版本的jarQ即使这些jar包来自于外部也可以?</p> <p>?. Hudson支持的分布式构徏</p> <p>Hudson通过大量的插件来实现其丰富的功能Q这些插件大致可以分Z下几c:</p> <p>SCM。Hudson~省支持CVS和SubversionQ通过安装插g支持Accurev、Bitkeeper、ClearCase、Git、Mercurial、Perforce、StarTeam、Synergy{?<br />构徏触发器。可以通过IRC、Ivy、Jabber、Join、Locks and Latches、Navigator来触发执行构建?<br />构徏工具。缺省支持Ant、Maven、shell s和Windows 批处理命令,通过安装插g支持batch tasks、Gant、Gradle、Grails、Groovy、Jython、Kundo、MSBuild、Phing、Powershell、Python、Rake、Ruby、SCons、SCTMExecutor,Selenium{?<br />构徏包装。对构徏的方式进行一些控Ӟ如ƈ发同步、启停虚拟机{。包括Hudson Centralized Job Action、Hudson Distributed Workspace Clean、Locks and Latches、M2 Extra Steps、M2 Release、Release、VMware、Xvnc、Zen Timestamp{?<br />构徏通知。缺省支持电子邮仉知Q通过插g支持Campfire、Google Calendar、HudsonTracker (RSS feeds)、IRC、Jabber、Nabaztag、SameTime、Status Monitor、The new Emailer、TuxDroid、Twitter{?<br />Slave启动和控制。缺省支持JNLP和命令行Q通过插g支持SSH?<br />构徏报告。缺省支持JUnit、javadoc和FindBugsQ通过插g支持CCCC、Checkstyle、Clover、DRY、Emma、Gallio、Gnat、Grinder、Japaex、JavaNCS、JavaTest Report、MSTest、N Cover、NUint、Plot、PMD、PureCoverage、Ruby metrics、Selenium AES、Selenium hq、Serenitec、SLOCCount、Task Scanner、Testability Explorer、Violations、Warnings、WebTest Presenter{。图3是Sonar生成的项目报告的样例?<br />集群理/分布式构建。支持DistFork、Hadoop、PXE、Selenium、Swarm{?<br />制品上传。支持FTP-Publisher、java.net uploader、SCP,SFEE、SVN{?<br />w䆾认证和用L理。支持操作审计追t、LDAP、MySQL认证{?</p> <p>?. Sonar Dashboard</p> <p>l束?/p> <p>工欲善其事,必先利其器。h是工Ld。A fool with a tool is still a foolQ傻子拿着工具q是dQ。h们L在学习工兗用工兗创造更好的工具Q以期提高工作的效率和品质。h要有智慧Q工兯先进?br /></p></span></td></tr></tbody></table> <img src ="http://www.tkk7.com/justuszhang2009/aggbug/352182.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/justuszhang2009/" target="_blank">张益?/a> 2011-06-24 13:06 <a href="http://www.tkk7.com/justuszhang2009/archive/2011/06/24/352182.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>spring和CXF集成来实现webserviceshttp://www.tkk7.com/justuszhang2009/archive/2011/06/24/352944.html张益?/dc:creator>张益?/author>Fri, 24 Jun 2011 05:05:00 GMThttp://www.tkk7.com/justuszhang2009/archive/2011/06/24/352944.htmlhttp://www.tkk7.com/justuszhang2009/comments/352944.htmlhttp://www.tkk7.com/justuszhang2009/archive/2011/06/24/352944.html#Feedback0http://www.tkk7.com/justuszhang2009/comments/commentRss/352944.htmlhttp://www.tkk7.com/justuszhang2009/services/trackbacks/352944.html阅读全文

]]>
mybatis扚w更新的问?/title><link>http://www.tkk7.com/justuszhang2009/archive/2011/06/21/352698.html</link><dc:creator>张益?/dc:creator><author>张益?/author><pubDate>Mon, 20 Jun 2011 23:19:00 GMT</pubDate><guid>http://www.tkk7.com/justuszhang2009/archive/2011/06/21/352698.html</guid><wfw:comment>http://www.tkk7.com/justuszhang2009/comments/352698.html</wfw:comment><comments>http://www.tkk7.com/justuszhang2009/archive/2011/06/21/352698.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.tkk7.com/justuszhang2009/comments/commentRss/352698.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/justuszhang2009/services/trackbacks/352698.html</trackback:ping><description><![CDATA[<p>一、问题描q?br />场景描述Q有q样一个serviceҎQ调用了两个dao中的Ҏ。第一个方法按照传入的id扚w更新用户名。第二个daoҎ无数据库操作Q仅仅抛Z个RuntimeException. <br />q个serviceҎ通过xml配置由spring事务理的?br />两个DAOcM分别有SqlSessionTemplatecd的属性templateQ用IOC的方式注入的?br /> public void batchUpdate() {<br />  String username="newname59";</p> <p>  List<Integer> idList=Arrays.asList(10000,10001);<br />  userDao.batchUpdateUsername(username, idList);<br />  testDao.testException();<br />  userDao.batchUpdateUserage(55, idList);<br />  testDao.testNormal(); <br /> }<br />当userDao及testDao中注入的是ExcutorType.Simplecd的templateӞ扚w更新用户名的操作会回滚?br />当userDao及testDao中注入的是ExcutorType.Batchcd的templateӞ扚w更新用户名的操作未回滚?/p> <p>l过查数据库日志Q发现第二种情况的数据库执行序列如下Q?br />1 set autocommit = 0<br />2 rollback<br />3 update t_user set username="newname59" where id = '10000'<br />4 update t_user set username="newname59" where id = '10001'<br />5 set autocommit = 1<br />更新操作在回滚之后执行,故回滚失败?/p> <p>调试源代码发现有如下序列Q?br />AbstractPlatformTransactionManager <br /> processRollback Q) --> triggerAfterCompletion() --> invokeAfterCompletion()<br />--> <br />TransactionSynchronizationUtils <br /> invokeAfterCompletion() <br />--> <br />SqlSessionUtils<br />    afterCompletion()<br />--><br />DefaultSqlSession<br /> close()<br />--><br />BaseExecutor<br /> close() --> rollback() --> flushStatement()<br />--><br />BatchExecutor<br /> doFlushStatements()<br />q时执行了sql语句?br /> <br />单来_抛出异常Qspring事务回滚Q清理资源关闭sqlSession.<br />mybatis关闭sqlsession,关闭前先flushStatementsQ执行未执行的sql语句Q然后再rollback.<br />但是q个rollbackҎ里判断connection是受事务理的,׃执行M操作?br /> <br /> public void rollback(boolean required) throws SQLException {<br />    if (!closed) {<br />      try {<br />        clearLocalCache();<br />        flushStatements();<br />      } finally {<br />        if (required) {<br />          transaction.rollback();<br />        }<br />      }<br />    }<br />  } </p> <p>   public void rollback() throws SQLException {<br />        if (!this.isConnectionTransactional) {<br />            if (this.logger.isDebugEnabled()) {<br />                this.logger.debug("Rolling back JDBC Connection [" + this.connection + "]");<br />            }<br />            this.connection.rollback();<br />        }<br />    }<br /> <br />二、解军_法:<br /> 1、在自己的应用程序中写个拦截器。在执行完executor的close()之后Q由q个拦截器再执行一遍connection.rollback()Q但从代码的可读性来看,会非常的差?br /> 2、修改mybatis的bug。修改BaseExecutor的rollback()<br /> public void rollback(boolean required) throws SQLException {<br />    if (!closed) {<br />      try {<br />        clearLocalCache();<br />  if (!required) { <br />   flushStatements();<br />  }<br />      } finally {<br />        if (required) {<br />          transaction.rollback();<br />        }<br />      }<br />    }<br />  } <br /><br />不知道大家有没有到q类似的问题Q又是通过什么方案解决的呢?</p> <img src ="http://www.tkk7.com/justuszhang2009/aggbug/352698.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/justuszhang2009/" target="_blank">张益?/a> 2011-06-21 07:19 <a href="http://www.tkk7.com/justuszhang2009/archive/2011/06/21/352698.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>spring 3 和mybatis 3集成Qƈ用junit4q行试http://www.tkk7.com/justuszhang2009/archive/2011/06/19/352618.html张益?/dc:creator>张益?/author>Sun, 19 Jun 2011 07:31:00 GMThttp://www.tkk7.com/justuszhang2009/archive/2011/06/19/352618.htmlhttp://www.tkk7.com/justuszhang2009/comments/352618.htmlhttp://www.tkk7.com/justuszhang2009/archive/2011/06/19/352618.html#Feedback5http://www.tkk7.com/justuszhang2009/comments/commentRss/352618.htmlhttp://www.tkk7.com/justuszhang2009/services/trackbacks/352618.html阅读全文

]]>
如何Ȁ励团?/title><link>http://www.tkk7.com/justuszhang2009/archive/2011/06/16/352451.html</link><dc:creator>张益?/dc:creator><author>张益?/author><pubDate>Thu, 16 Jun 2011 09:57:00 GMT</pubDate><guid>http://www.tkk7.com/justuszhang2009/archive/2011/06/16/352451.html</guid><wfw:comment>http://www.tkk7.com/justuszhang2009/comments/352451.html</wfw:comment><comments>http://www.tkk7.com/justuszhang2009/archive/2011/06/16/352451.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/justuszhang2009/comments/commentRss/352451.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/justuszhang2009/services/trackbacks/352451.html</trackback:ping><description><![CDATA[在谈到项目经理最重要的品质时Q经怼谈到一个h的leadershipQ一个优U的项目经理应该可以轻易激励项目团队的士气Q即便在很困隄情况下也能按时按质完成项目?br /><br />但是一个h有没有leadership不是靠喊口号喊出来的Q也不是看那张脸是不是象leaderQ我觉得是从一个h的言行n教中反映出来的。我喜欢和一些非常senior的PM、Director谈论一个成功的目l理是怎么LQ下面是令我印象最深刻的片D,是关于如何激励项目团队的Q不得不佩服此h的才qԌ<br /><br />一、描l宏伟蓝图?br />      在项目启动之初,在开目l的kick off meetingӞ目l理说出以下q段话:“Hi 各位Q大安非常q运Q能加入到这个项目中来,q个目是全上v最大的一个项目,是由上v市场亲自宣布启动的,q个目的成功上U将会媄响全上v2000万h的生zR做完这个项目,每个人都会得到很大的提升Q就不会再有什么难得倒你们的目了?#8221;<br /><br />二、故意羃短工期?br />     在描l完目的宏伟蓝图之后,拉上目l的核心人员q行W二轮的Ȁ励,假设客户或者老板l项目经理的期限?个月完成Q那告诉目l成员的时候,p目的周期只?个月Q问大家有没有信心完成,׃目实在太大Q大家肯定会?#8220;不可能完成!”Q项目经理接着_“大家加一下a嘛!”Q?#8220;q是无法完成Q?#8221;Q?#8220;l大家加钱呢Q?#8221;Q?#8220;有点困难Q?#8221;Q项目经理这时说Q?#8220;既然大家都说无法完成Q我跟客户再沟通沟通,争取多给一个月旉Q这h没有问题Q?#8221;Q大家这时候就跟减了便宜一P会齐声说“可以Q?#8221;。因此如果真能在4个月内完成,那么你还能提?个月完成目Q你q个目l理q不是成功的目l理吗? <img src ="http://www.tkk7.com/justuszhang2009/aggbug/352451.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/justuszhang2009/" target="_blank">张益?/a> 2011-06-16 17:57 <a href="http://www.tkk7.com/justuszhang2009/archive/2011/06/16/352451.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>持箋集成工具Sonar的用(二)http://www.tkk7.com/justuszhang2009/archive/2011/06/14/352280.html张益?/dc:creator>张益?/author>Tue, 14 Jun 2011 09:02:00 GMThttp://www.tkk7.com/justuszhang2009/archive/2011/06/14/352280.htmlhttp://www.tkk7.com/justuszhang2009/comments/352280.htmlhttp://www.tkk7.com/justuszhang2009/archive/2011/06/14/352280.html#Feedback0http://www.tkk7.com/justuszhang2009/comments/commentRss/352280.htmlhttp://www.tkk7.com/justuszhang2009/services/trackbacks/352280.html 
目前来说QSonar和Ant的集成没有做到Sonar和Maven的集成这么好Q因此在使用q程中需要多写一些脚本。我们下面来介绍一下用步骤吧Q?br />  1、下载Sonarq解压到M目录Q注意目录中不允许有中文Q?br />  2、点击bin\windows-x86-32\StartSonar.bat启动SonarQ?br />  3、下载一个ant插gQsonar-ant-task-1.1.jarQƈ存放到某个\径,ant脚本需要访问这个文件?br />  4、编写一个ant脚本Q如下:

<?xml version="1.0" encoding="UTF-8" ?>

<project name="framework-client" default="sonar" basedir=".">
  
 <property name="project.name" value="framework-client"/>
 <property name="src.dir" value="${basedir}/src/main/java" />
 <property name="lib.dir" value="${basedir}/lib"/>
 
   <!-- Out-of-the-box those parameters are optional -->
   <!-- EXAMPLE FOR MYSQL    
   <property name="sonar.jdbc.url"
        value="jdbc:mysql://localhost:3306/sonar?useUnicode=true&amp;characterEncoding=utf8" />
   <property name="sonar.jdbc.driverClassName" value="com.mysql.jdbc.Driver" />
   <property name="sonar.jdbc.username" value="sonar" />
   <property name="sonar.jdbc.password" value="sonar" />
   -->

   <!-- SERVER ON A REMOTE HOST -->
   <!--
   <property key="sonar.host.url" value="http://myserver:1234" />
   -->
 
   <!-- Define the Sonar task if this hasn't been done in a common script -->
   <taskdef uri="antlib:org.sonar.ant" resource="org/sonar/ant/antlib.xml">
     <classpath>
       <pathelement location="${lib.dir}/sonar-ant-task-1.1.jar"/>
     </classpath>
   </taskdef>
  
   <!-- Add the target -->
   <target name="sonar">
     <!-- list of mandatories Sonar properties -->
     <property name="sonar.sources" value="${src.dir}" />
    <property name="sonar.projectKey" value="org.example:${project.name}" />

     <!-- list of optional Sonar properties -->
    <!--
     <property key="sonar.projectName" value="this value overrides the name defined in Ant root node" />
     <property key="sonar.binaries" value="list of directories which contain for example the Java bytecode" />
     <property key="sonar.tests" value="list of test source directories separated by a comma" />
     <property key="sonar.libraries" value="list of paths to libraries separated by a comma (These libraries are for example used by the Sonar Findbugs plugin)" />
    -->
    
     <sonar:sonar key="${sonar.projectKey}" version="0.9" xmlns:sonar="antlib:org.sonar.ant"/>

    </target>
</project>

  5、运行ant脚本Q看到build successfully的提C后Q就可以讉KQ?a href="http://localhost:9000/">http://localhost:9000/来查看代码质量审查结果了?br />
上述是用Sonar和ant最单的步骤Q用了Sonar自带的嵌入式数据库DerbyQ以及standalone的应用服务器Q当然也支持使用其它数据库,比如QmysqlQ只要修改一下sonar.properties的配|文Ӟ以及在ant脚本中配|一下连接数据库的方式。另外也可以使用tomcat、jboss{应用服务器来发布Sonar应用Q只要运行一下Sonar自带的一个脚本:build-war.bat可以了Q这里不再详q?br />



]]>
持箋集成工具Sonar的用(一Q?/title><link>http://www.tkk7.com/justuszhang2009/archive/2011/06/13/352176.html</link><dc:creator>张益?/dc:creator><author>张益?/author><pubDate>Mon, 13 Jun 2011 03:42:00 GMT</pubDate><guid>http://www.tkk7.com/justuszhang2009/archive/2011/06/13/352176.html</guid><wfw:comment>http://www.tkk7.com/justuszhang2009/comments/352176.html</wfw:comment><comments>http://www.tkk7.com/justuszhang2009/archive/2011/06/13/352176.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.tkk7.com/justuszhang2009/comments/commentRss/352176.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/justuszhang2009/services/trackbacks/352176.html</trackback:ping><description><![CDATA[最q由于工作需要,接触CSonarQ用它的出发点是因为它能统计代码注释率Q而且支持drill downQ可以依ơ看到工E、包、类的注释率?br /><br />但Sonar作ؓ一个很不错的持l集成工P它的功能源不止于此,<span lang="EN-US"><strong>sonar</strong></span> 可以持箋Q自动地l计q分析Y仉目的相关质量数据Q例如单元测试的通过率,覆盖率,代码的复杂度Q代码的行数Q代码注释率{等Q用于评估和度量软g目质量?br /><br />我的Sonar的第一个应用,是Sonar和maven的配合用,Sonar对Maven支持的比较好Q网站上对于q两者结合用的文章也非常多Q因此如何用Sonar和maven来分析项目质量,在这边就不细说了Q可以参考官方的|站Q?a >http://docs.codehaus.org/display/SONAR/Use+Sonar</a>。这边主要说一下大致的步骤Q以及在具体使用中碰到的几个问题。Sonar的用真的非常简单,大概包括以下几步,<br /><br /> 1、到官方|站下蝲<span lang="EN-US">Sonar</span> 的压~包Q解压到L目录Q但是一定要注意Q?strong style="color: red">目录中不允许有中?/strong>Q不然启动Sonar后,讉KQ?a href="http://localhost:9000">http://localhost:9000</a>q回的界面会报错?br /> 2、启动Sonar应用Q可以直接点击bin/windows-x86-32目录下的StartSonar.batQ启动过E可能要1分多钟,误心{待Q这里Sonar有一点不好的是,弹出的console中不打印M信息?br /> 3、进入你的工E目录(当前目录下面有pom.xml文gQ,q行Qmvn clean install  sonar:sonarQ看到build successfully之后Q就可以讉KQ?a href="http://localhost:9000/">http://localhost:9000</a>来分析你的工E的代码质量了?br /><br />q里要说明的是,在执行maven命oӞ后台会报一些ؕ码方面的错误Q是׃java代码中出C文字W串的问题造成的。可以通过以下方式解决Q在<properties>中添?strong>Q?lt;project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></strong>Q这是我试过的唯一的解x案,在网上还提到两种解决ҎQ但都不用? <img src ="http://www.tkk7.com/justuszhang2009/aggbug/352176.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/justuszhang2009/" target="_blank">张益?/a> 2011-06-13 11:42 <a href="http://www.tkk7.com/justuszhang2009/archive/2011/06/13/352176.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://www.tkk7.com/" title="亚洲av成人片在线观看">亚洲av成人片在线观看</a> <div class="friend-links"> </div> </div> </footer> վ֩ģ壺 <a href="http://kt4444.com" target="_blank">ƷĻ߹ۿ</a>| <a href="http://xjscr.com" target="_blank">ëƬaëƬѲ100</a>| <a href="http://szwangzhongwang.com" target="_blank">Ůڵվ</a>| <a href="http://xsjxp.com" target="_blank">ɫWWW߹ۿ</a>| <a href="http://wwwabxx.com" target="_blank">鶹ƷƵ</a>| <a href="http://yy9977.com" target="_blank">޾Ʒҹ߹ۿ</a>| <a href="http://513109.com" target="_blank">ֳִִֺƵ</a>| <a href="http://yw5168.com" target="_blank">ۺʮ</a>| <a href="http://kutuwo.com" target="_blank">ŷƵ</a>| <a href="http://139699.com" target="_blank">޾Ʒ߾ƷƵ</a>| <a href="http://yw835.com" target="_blank">ŮѹۿƬ</a>| <a href="http://69ct.com" target="_blank">aһ</a>| <a href="http://maomi90.com" target="_blank">ؼƬѿ</a>| <a href="http://laxdz.com" target="_blank">һѵӰ</a>| <a href="http://kkjk123.com" target="_blank">þ޹ŷ޾Ʒһ</a>| <a href="http://118762.com" target="_blank">벻Ļϵ</a>| <a href="http://gisdn.com" target="_blank">޳aƬ߹ۿ</a>| <a href="http://ziniurj.com" target="_blank">ҹһëƬ</a>| <a href="http://mosason.com" target="_blank">ҹҹҹҹƵ</a>| <a href="http://qqcao7.com" target="_blank">޳aƬ߹ۿձ</a>| <a href="http://snbbearing.com" target="_blank">Ļѹۿ</a>| <a href="http://pecbj.com" target="_blank">˳С˵վɫ</a>| <a href="http://lyaa60.com" target="_blank">޵һƷպ߲</a>| <a href="http://pecbj.com" target="_blank">¾þƵ</a>| <a href="http://see01.com" target="_blank">AVպAV̾ </a>| <a href="http://4794d.com" target="_blank">ۺר</a>| <a href="http://gkhnf.com" target="_blank">ձѹۿ</a>| <a href="http://sjzbosite.com" target="_blank">һƵ </a>| <a href="http://6609929.com" target="_blank">պŷһѹۿ</a>| <a href="http://51xinshiji.com" target="_blank">Ļ뱬</a>| <a href="http://bbby6.com" target="_blank">޾ƷNVþþþþþþþ</a>| <a href="http://haiwaizhuyun.com" target="_blank">AVվ</a>| <a href="http://ulihix.com" target="_blank">þþƷ99Ʒ</a>| <a href="http://240842.com" target="_blank">ѹۿƷ</a>| <a href="http://jjwgzx.com" target="_blank">þþþþһƷƷѿ</a>| <a href="http://gzltchem.com" target="_blank">ۺavһ</a>| <a href="http://527352.com" target="_blank">鸣ۺĻһƵ1 </a>| <a href="http://zjpcyh.com" target="_blank">Ƭ91Ʒѹۿ</a>| <a href="http://scbangde.com" target="_blank">AVһ</a>| <a href="http://sjzbosite.com" target="_blank">AרAV</a>| <a href="http://653349.com" target="_blank">ŮƵƵȫƵ</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>