??xml version="1.0" encoding="utf-8" standalone="yes"?> 译自Q?a >http://www.theserverside.com/blogs/showblog.tss?id=Unitized 把上面提到的考虑在一P意味着单元试是测试整个代码中最低层ơ的部分Q每一个部分是和其它部分隔ȝ。测试和~码是同一个h完成的?br />q种方式的测试正是“我”所说的“low hanging fruit”[可轻易实现的目标 (easy targets)]。它可以捕获的问题Q也是可以扑ֈ不符合单元测试的要求的单独的函数或者类?/p> 单元试是一个好事,提供了对于自׃码正性的有h值的反馈。但是“Keep in mind" 它只能得到“low hanging fruit”。在设计上,单元试被期望“简单的”、“作为系l中独立的小部分”。因些,在它的本质上Q与生俱来的Q,单元试没有考虑pȝ的“组合”,它只考虑独立的部分。单元测试从不检查一个系l中内部的联l,从不查他们是如何捆绑在一L?/p> Ҏ“我”的l验Q系l中如何联络和如何捆l在一h是系l的复杂度所在?br />正是q种“连接”定义了你的设计Q如果在一个够高的层ơ上考虑Q这U联pȝ臛_以理解ؓpȝ的架构?br />信息是如何在不同的Y件层上和不同的组件之间的动实实在在的定义了一个应用?br />由此看来Q单元测试是不会试一个应用的q些斚w的。单元测试忽略了信息是如何在不同的层和不同的lg之间动的,忽略了类和对象在一个大的架构和设计中如何相互关联和l合在一L?br />q就意味着单元试只能在独立的代码片断中捕L单的错误Q但是对pȝ的整体的设计或者机构Say nothing?br />设计和架构限定了你的pȝ的性能Q内存用,“端到端”的正确性。[用户的输入,到Server处理所使用的,到最后的q回的整个\径]。所以这些是如何q行联系的显CZpȝ的行为,q且正是在这个范围中存在着the toughest bug ?problemsQ要惌一切OKQ程序员们也要在q个地方苦干不止?br />~写隔离的独立组件是Ҏ的,把他们粘合在一h困难的。单元测试只在隔ȝ在独立的部分上作判断Q而不是在整体上?/p> 使系l中的一个组件的动作正确相当来说是hg高的zd。独立的~写一个系l的lg不是计算机编E的困难的部分,M一个个体的的lg都是Ҏ~写的。在开发中最隄部分来自于如何把所有的lg捆绑在一起工作。单元测试可以验证每一个你~写的独立组件是不是按照你所想的那样工作Q但是它不能查更复杂的“wiring?-“wiring”正是我们的设计Q开发和调试l大部分工数所在?/p> 从上看来Q单元测试不会指出“端到端”的处理是否正常Q不会关心性能Q不会关心内存的使用Q不会关心可用性,不会兛_代码是否正是用户惌的。它也不会捕获多U程的bugQ或者错误的理解了外部API或者子pȝ的用等{。这些ƈ不意味着单元试是不好的或者应该避免的Q它只是说明单元试只会l你一个有限的回报。设x们作为开发h员,我们没有无限的资源去开发我们的代码Q我们不得不聪明的决定我们要把我们的_֊攑֜那里。我们不得不l常的折衷和军_怎样做有最好的效果?/p> 在“我”参加的所有开发中。单元测试覆盖了l大部分的代码,但是在以下的斚w的努力还差得很远Q?br />1。应用程序设计的本n。你应该p更多的时间在你的设计上,采用一UP代的Q真实地方式而不是花费在单元试上,因ؓ一个好的设计得到的回报比Q何数量的单元试都多?br />2。集成测试(Integration TestQ。集成测试的试特征是基于“端到端”的。通过它的设计可以证明你的独立的组件可以工作在一赗通过一个集成测试,你可以更信赖你的pȝ按照“端到端”的方式工作Q而不是一些独立的对象?br />3。功能测试和回归试QFunctional Test&Regression TestQ。系l不是开发h员想的那P而是用户期望它是什么样子。更q一步,回归试当新的特性被q加或者底层的代码被改变时Q验证高U别的功能的正确性没有被改变?br />4。非功能试QNon-function Test)。在可接受的q行需求下Q代码作为整体被q行Q请求在可接受的旉范围内被处理。sever不会因ؓ?个用戯求就会memory紧张。等{?/p> 做以上的东西会比单元试隑־多。但是在同样的投入下会得到更多的回报?/p>
]]>
考虑一下单元测试的目的和原则:
1。尽量小_度的“单元”被试?br />2。测试在于其它模块隔d情况下独立地完成?br />3。Mocking在隔ȝ斚w作出了强化?br />4。代码和试都是同一个h完成的?/p>
今天在完成一个功能的?/span>候,使用?/span>ServiceLocate模式Q?/span>
?/span>q这个模式,在程序中可以自由的加?/span>其他?/span>员实?/span>的功能模?/span>
具体的做法:
1Q定义标准的?/span>?/span>接口?/span>
2Q定?/span>描述实现?/span>?/span>接口?/span>xml文g?/span>
3Q程?/span>?/span>?/span>?/span>xml文gQ?/span>Class.newInstance()?/span>例化具体的服务对象?/span>
4Q徏立一个特定服?/span>和特定服务实?/span>?/span>对应?/span>HashMap?/span>象。完成注册Q?/span>?/span>
5Q主E序中根据具体的?/span>?/span>?/span>HashMap中取得具体的?/span>?/span>q?/span>行服?/span>?/span>
q?/span>个方?/span>q?/span>?/span>?/span>Q可以完成基?/span>Interface?/span>开?/span>要求Q利?/span>Test和程序的拓展性?/span>
有新的要求出?/span>后,只需要添?/span>xml中的元素和具体的实现c?/span>可以了?/span>
接下来,l箋惟뀂又发现?/span>一?/span>问题Q?/span>
1Q?/span>xml是和E序一?/span>?/span>布的Q如果用?/span>随意?/span>?/span>了。很?/span>?/span>E序会崩?/span>?/span>
解决ҎQ?/span>xml攑֜jar包中Q?/span>getClass().getResourceAsStream(String name)
自己?/span>载进来。用?/span>完全不知道具体的情况?/span>
2Q如果把xml攑֜?/span>jar包中“藏h”,实际上原?/span>?/span>来的动态扩展的Ҏ,
也就没有?/span>?/span>?/span>?/span>了。如何解军_
l细xQ?/span>q?/span>?/span>问题?/span>关键在于Q所有的?/span>务实?/span>?/span>象的?/span>建和注册都是?/span>
LE序中?/span>q?/span>xml来完成的。如果可以把q?/span>个注册和?/span>例化?/span>q?/span>E从LE序
中分d来,?/span>q每个服务实?/span>?/span>象自?/span>注册来完成,?/span>?/span>?/span>是真正的可拓展的?/span>
如果需要完成新的功能,只需要把新的?/span>务对?/span>Class?/span>布,重新q行LE序׃实现?/span>的功能。(看v来就?/span>Eclipse一?/span>Q?/span>
q?/span>真是一个不?/span>的想法,但是?/span>?/span>做呢Q?/span>
看看Eclipse如何做的?/span>
http://www.eclipse.org/articles/Article-Plug-in-architecture/plugin_architecture.html
首先要有一?/span>?/span>定的plugin deploy?/span>?/span>Q?/span>q样ȝ序才知道从哪里加?/span>?/span>
要有一?/span>plugin.xml文g描述q?/span>?/span>plugin.q?/span>着文g中有属性:class="foo.bar.Plugin">
看上d?/span>?/span>原来做的方式一?/span>啊。但是它是如何把q?/span>个目?/span>下的plugin都加?/span>的呢Q?/span>
Q?/span>我没有看q?/span>Eclipse的源?/span>Q不知道他是?/span>?/span>写的Q?/span>
再想惻I?/span>?/span>主要要解决的问题是不?/span>q?/span>L架程序注册服务实?/span>Q?/span>
应该由服?/span>E序自己注册上来?/span>按照q?/span>个思\Q我x?/span>U?/span>解决Ҏ?/span>
1Q服?/span>接口dregisterService Ҏ?/span>
* ?/span>jar?/span>METATINFO文g中定义类名?/span>
* 从特定的?/span>?/span>?/span>?/span>?/span>jar/class文g?/span>
* ?/span>q?/span>URLClassLoader.newInstance()?/span>?/span>
* ?/span>?/span>后把ServiceLoader?/span>?/span>参数出入 service.registerSevice()?/span>
* service?/span>象完成自q注册?/span>
2Q服?/span>dstatic?/span>?/span>端在c?/span>?/span>?/span>例化?/span>?/span>候自?/span>完成注册?/span>
* ?/span>?/span>之前和上一个方法一?/span>?/span>
* ?/span>SeviceLoader?/span>?/span>实现为单?/span>的模式。提供静?/span>的注册方法?/span>
* ?/span>servie?/span>象中实现如下的代?/span>D完成自?/span>注册?/span>
static
{
ServiceLoader.registerService(new service());
}
q样看来ȝOK了吧?/span>
自己上都费劲。{到这里会好一些吧Q?/p>
回头把东襉K搬过来?/p>