component-scanbase-package="org.springside.examples.miniweb"/>
2.在Servicebean中用@Transcational定义事务。
3.struts2相关
使用conventionplugin,通过在struts.xml中定义扫描web包,搜索所有*..web..*包中的类作为action.
action对象和jsp全部按照默认的目录结构和命名规则进行对应,可以在action对象中通过conventionannotation重新特殊配置。
SpringSide3.0的Java编码规范
明:
本规范分为不同的级别,默认级别为必须遵循级别,而(II)为建议级别,非强制执行。
1.格式与命名规范(FormatingandNamingConventions)
1.最重要:
不用死记硬背,直接使用Eclipse的自动格式化功能。
2.换行:
每行120字符以上--因为现在屏幕已大为宽广。
3.括号:
if,for,while语句全部使用括号包围。
4.命名规则:
不允许使用汉语拼音命名
避免使用下划线(静态变量除外)
接口尽量采用"able","ible",or"er",如Runnable命名,尽量不采用首字母为I或加上IF后缀的命名方式,如IBookDao,BookDaoIF。
(II)
2.注释规范(DocumentConvertions)
2.1注释类型
1.JAVADOC注释
/***....**/
2.失效代码注释
由/**...**/界定,标准的C-Style的注释。
专用于注释已失效的代码。
3.代码细节注释
由//界定,专用于注释代码细节。
注意:
即使有多行注释也仍然使用//,以便与用/**/注释的失效代码分开。
2.2注释的格式
1.注释中的第一个句子要以(英文)句号、问号或者感叹号结束。
Javadoc生成工具会将注释中的第一个句子放在方法汇总表和索引中。
2.为了在JavaDoc和IDE中能快速链接跳转到相关联的类与方法,尽量多的使用@seexxx.MyClass,@seexx.MyClass#find(String)。
3.Class必须以@author声明作者,体现代码责任。
但不需要声明@version与@date,由版本管理系统保留此信息。
(II)
4.标识(javakeyword,class/method/field/argument名,Constants)在注释中第一次出现时以{@linkxxx.Myclass}注解以便JavaDoc与IDE中可以链接。
(II)
2.3注释的内容
1.可精简的注释内容
注释中的每一个单词都要有其不可缺少的意义,注释里不写"@paramname-名字"这样的废话。
如果该注释是废话,连同标签删掉它,而不是自动生成一堆空的标签,如空的@paramname,空的@return。
2.推荐的注释内容
对于调用复杂的API尽量提供代码示例。
(II)
对于已知的Bug需要声明,//TODO或//FIXME声明:
未做/有Bug的代码。
(II)
Null规约:
如果方法允许Null作为参数,或者允许返回值为Null,必须在JavaDoc中说明。
否则方法的调用者不允许使用Null作为参数,并认为返回值是NullSafe(不会返回NULL)。
3.编程规范(ProgrammingConventions)
3.1基本规范
1.当API会面对不可知的调用者时,方法需要对输入参数进行校验,如不符合则抛出IllegalArgumentException,建议使用Spring的Assert系列函数。
2.因为System.out.println(),e.printStackTrace()仅把信息显示在控制台,因此不允许使用,必须使用logger打印并记录信息。
3.在数组中的元素(如String[1]),如果不再使用需要设为NULL,否则会内存泄漏。
因此直接用Collections类而不要使用数组。
4.在不需要封闭修改的时候,尽量使用protected而不是private,方便子类重载。
5.变量,参数和返回值定义尽量基于接口而不是具体实现类,如Mapmap=newHashMap();
6.用double而不是Float,因为float会容易出现小数点后N位的误差。
3.2异常处理
1.重新抛出的异常必须保留原来的异常,即thrownewNewException("message",e);而不能写成thrownewNewException("message")。
2.在所有异常被捕获且没有重新抛出的地方必须写日志。
--TODO
3.如果属于正常异常的空异常处理块必须注释说明原因,否则不允许空的catch块。
3.3JDK5.0规范
1.重载方法必须使用@Override,可避免父类方法改变时导致重载函数失效。
2.不需要关心的warning信息用@SuppressWarnings("unused"),@SuppressWarnings("unchecked"),@SuppressWarnings("serial")注释。
技术参考手册
1.总述
∙架构风格简述
∙目录结构描述
2. 基础框架
∙Spring:
SpringFramework
∙Database:
ORM-Hibernate,Jdbc-SpringJdbcTemplate, 数据库-H2、MySQL、Oracle,数据库连接池-DBCP
∙Web:
MVC-Struts2,View-JSP2、Taglib、UrlRewrite,Javascript-JQuery、DojoBase,CSS-YUICSSFramework
∙基础类库:
日志-Slf4j,Log4j,Utils工具类
3 企业服务
∙Web服务:
WebService-JAX-WS2、CXF,REST-JAX-RS、Jersey,HttpClient
∙安全:
SpringSecurity,验证码-JCaptcha,Utils-散列、签名、加密
∙缓存:
Cache总述,Memcached,EhCache
∙定时任务:
Quartz,JDKScheduledThreadPoolExecutor
∙JMS:
ActiveMQ+SpringJMS
∙JMX:
SpringJMX
∙Email:
SpringEmail
∙报表:
FlashChart-AmCharts,Excel-POI
∙数据格式:
XML-JAXB2,Dom4j,JSON-Jackson
∙应用服务器:
应用服务器总述,Jetty,JSW+Jetty运行环境
4.架构质量
∙架构质量:
GracefulShutdown
∙管理工具:
Monitor-HypericHQ
∙性能调优:
Web2.0页面优化, Profile工具-VisualVM、Yorkit,SQL监控工具-P6Spy
Test
1.资料与概述
∙Java测试资料(江南白衣博物馆)
∙Spring2.5集成测试资料(江南白衣博物馆)
测试用例分三类:
一类是单元测试,测试每一个Class的功能,尽量使用EasyMock/JMockit,Mock掉所有依赖类,隔绝其他类对本类的影响(除了DAO层)。
二类是功能测试,测试子系统对用户故事的实现,为保证测试速度,一般使用Jetty,H2数据库这些嵌入式的底层,GUI部分一般使用Selenium,对依赖的外系统一般也会采用Dummy/Stub/嵌入式版本等形式。
三类是集成测试,测试各子系统集成的效果,一般是最基本最基本的少量用例的自动化测试,配合手工测试进行。
2.选型
2.1JUnit3.8vsJUnit4.5
Spring3.0已经取消JUnit3支持,@Before式的标签使得继承重载关系可以更加的灵活。
2.2EasyMock vsJMockitvsJMock&Others
比较过EasyMock和JMock觉得还是EasyMock要好用一些,但是EasyMock对静态方法没办法,这时候要JMockit出场,另外写Stub而不是Mock的时候,也是JMockit好用。
2.3Selenium
Web集成工具中,Selenium是最好用的了,特别是最新版Selenium2.0,将传统的FireFox/IEDriver与运行速度超快的HtmlUnit,统一在WebDriver的API下可随意切换非常好用。
但Anyway,维护GUI测试用例的成本还是很高的,最好还是配合手工测试,不要想着什么都自动化测试。
2.4Spring的测试框架
像DAO层测试这种需要连接实际数据库及其他需要建立ApplicationContext的情况,Spring提供了较方便的初始化并缓存ApplicationContext,注入以及测试事务自动回滚的功能。
2.5其他
∙测试代码覆盖率工具,Sonar里用C字头的,而开发人员自己用Emma,因为它有Eclipse的插件EclEmma
。
∙DBUnit:
测试数据的初始化与清理。
Unittest
3.1单元测试概况
JUnit4中@BeforeClass是只执行一次的静态函数,@Before是每个测试方法都执行一次的函数(小心测试父类与子类的准备函数名不要都叫before,setup,一不小心就互相覆盖了)
@Ignore("xxx")可以暂时不执行类/方法并说明原因(Sonar会对@Ignore的用例进行监控,所以暂时Skip用例时尽量使用@Ignore,以便日后恢复)。
可以继承Assert,免得那堆静态导入那堆校验函数。
对待测对象的私有变量,私有函数可以用ReflectionUtils的反射函数直接调用,如ReflectionUtils.setFieldValue(userManager,"userDao",mockUserDao);
另外,Spring还为Web相关的测试提供了MockHttpRequest等一大堆stub类,SpringSide也提供了一个可能会用到的WebTestUtils,SpringWebApplicationContext初始化到ServletContext,将MockRequest/Response放入Struts2的ServletActionContext.
3.2Mock
Mock对单元测试是如此重要,EasyMock们也不再要求基于接口编程了.
另外,虽然EasyMock提供了createNiceMock()这样的简便方法,但尽量还是不要用,太不可控了.
在必要情况下可以在设定函数参数时用上isA()这样的功能,如果函数有多个参数,需要都使用匹配。
比如userDao.save(Longid,Useruser);如果想灵活第2个参数,可以写成:
mockUserDao.save(EasyMock.eq(1L),EasyMock.isA(User.class));
3.3使用ApplicationContext的测试
严格说使用ApplicationContext的测试不是完全的单元测试,按Spring的说法是集成测试。
Spring2.5的依赖测试用例支持ApplicationContext依赖注入,事务自动回滚等功能(也可设置不回滚),详见Spring2.5集成测试资料。
因为Spring的类名一贯清晰但超长,而且不继承于Assert,因此基于它的代码作了小小的改造:
∙SpringContextTestCase:
等于AbstractJUnit4SpringContextTests加上Assert函数。
∙SpringTxTestCase:
在SpringContextTest的基础上,支持事务回滚,支持基于jdbcTemplate的数据库操作常用函数,和Assert函数。
注意测试时要使用dao的flush()函数,因为Hibernate只有事务提交时才会执行SQL,为了验证你的ORM正确性,必须常常执行flush强制hibernate执行SQL。
不过只要不执行提交,sql执行的结果不会影响测试数据库的实际数据。
可在applicationContext-test.properties定义与applicationContext.properties不一样的测试环境参数。
注意Spring对于相同applicationContext-*xml数组配置的applicationContext,默认是会被cache起来,在所有TestCase中使用的。
这造成了太多的混乱,在SpringContextTestCase使用使用@DirtiesContext强迫放弃Cache功能。
3.4Assert方法
Junit4下不再有继承TestCase基类后,那些assert方法如果要staticimport会变得麻烦,还是继承一下Assert类算了。
3.5测试数据
FunctionalTest
3.1概述
功能测试以用户故事为线索编写,描述子系统的功能,与单元测试针对类的覆盖率而编写明显不同。
多变的GUI的测试编写与维护都有一定成本,慎重决定手工还是自动,特别是一些不那么重要的用例。
但非GUI的部分如WebService,就可以尽量的多写了。
3.2Jetty+H2的嵌入式功能测试环境
如果要启动半天的应用服务器和数据库,显然不适合,而嵌入式的Jetty与H2启动飞快且想关就关,是功能测试的必须。
如果你坚持用"真正"的应用服务器与数据库,我可以打赌按着这个风格,你的功能测试很快就会突破15分钟的总运行时间,然后总是有用例失败没人修复,然后成为一个摆设。
SpringSide提供了JettyUtils可以很方便的启动Jetty服务器。
用一个测试用的web.xml指向测试用的applicationContext-test.xml再指向测试用的Mock和Embed们。
H2服务用一个嵌入式的JDBCURL即可,注意DB_CLOSE_DELAY=-1,另外需要编写一个ant命令,将mysql/oracle的真正sql粗转为H2的SQL,在applicationContext-test.xml中运行初始化。
3.3Selenium功能测试
Selenium是我在公司实际项目中坚持下来的Web自动测试工具。
Selenium2.0很好的同时支持了速度飞快的HtmlUnit与实际的IE/Firefox,如果持续集成用的服务器不方便启动浏览器,还有一个RemoteDriver远程连到一台Windows的服务器上面跑,SpringSide提供了SeleniumUtil封装了分析属性文件切换这几种Driver的能力。
但Selenium2.0目前的API反倒不如1.0丰富,所以SeleniumUtils对最缺失的最常用函数进行了重新封装。
Selenium用例的维护成本非常高,因此相比其他的测试用例,需要把测试代码写的更加漂亮,需要有良好的封装重用,良好的可读性,稳健的不受其他用例执行结果影响的用例设计,最后页面代码本身也要有可测试性,添加适当的ID方便selenium定位元素,而这一切的反面教材,就是用例中充满了靠SeleniumIDE记录的XPath路径(/tr[3]/td[1]),难读,且脆弱。
Selenium2.0的资料:
∙官方UserGuide
∙官方博客
,每周收集很多文章。
3.4 分组执行测试
TestNG的Groups效果,可以控制只运行某些Group的用例,比如有些用例执行起来很慢,而且重要程度不高,可以放到晚上的nightly-build再去执行,使用方法如下:
1.在测试用例的方法上定义Groups,如@Groups("nightly"),
2.为TestCase设置@RunWith(GroupsTestRunner.class)
3.用-Dtest.groups=daily,nightly定义会执行的group.
4.如果方法上没有定义Groups,则全部执行。
如果-D没有定义test.groups,也是全部执行。
5.如果类的所有方法均不执行,则类的@BeforeClass标注的方法也不执行。
详见GroupsTestRunnerTest
3.5DBUnit,数据准备类与测试用例间数据解耦
当测试用例多起来以后,如果防止用例间执行结果的互相影响(这个用例跑完之后会影响另一个用例的结果值),降低用例对基础数据的依赖非常重要(增加或修改基础数据不会造成一大堆用例跑不过)。
因为使用H2嵌入式数据库,表结构的初始化sql在applicationContext-test.xml中定义,这是Spring3.0新提供的功能。
测试数据尽量在用例中创建,使用相应的数据准备类如UserData.java,使用了SpringSide提供了DataUtils工具方法尽量随机的产生数据,比如随机生成数字,随机从备选List出取出若干个元素等。
有些基本数据也可以用DBUnit来载入,预先定义在src/test/resources/*-data.xml.可以定义多套数据.
另外平时开发调试时,也可以用Ant来调用DBUnit(Maven的DBUnit插件不支持调用多个xml文件)来记录和载入基础数据,详见用bin的db-init.bat与db-export.bat。
JUnit执行用例的顺序不可控,因此规定,
∙纯单元测试不访问数据库
∙访问数据库的集成测试用Spring的事务测试基类强制Rollback
∙使用DBUnit的