﻿<?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-jinfeng_wang-随笔分类-Thinking</title><link>http://www.blogjava.net/jinfeng_wang/category/699.html</link><description>G-G-S,D-D-U!</description><language>zh-cn</language><lastBuildDate>Thu, 18 Mar 2010 21:39:23 GMT</lastBuildDate><pubDate>Thu, 18 Mar 2010 21:39:23 GMT</pubDate><ttl>60</ttl><item><title>劳动法分析</title><link>http://www.blogjava.net/jinfeng_wang/archive/2010/03/19/315853.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Thu, 18 Mar 2010 16:27:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2010/03/19/315853.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/315853.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2010/03/19/315853.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/315853.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/315853.html</trackback:ping><description><![CDATA[&nbsp;
<p>A)<span style="font-family: 'ＭＳ 明朝'">中</span><span style="font-family: SimSun">华</span><span style="font-family: 'ＭＳ 明朝'">人民共和国</span><span style="font-family: SimSun">劳动</span><span style="font-family: 'ＭＳ 明朝'">合同法</span></p>
<p><a href="http://www.molss.gov.cn/gb/news/2007-06/30/content_184630.htm">http://www.molss.gov.cn/gb/news/2007-06/30/content_184630.htm</a></p>
<p>B)<span style="font-family: 'ＭＳ 明朝'">中</span><span style="font-family: SimSun">华</span><span style="font-family: 'ＭＳ 明朝'">人民共和国</span><span style="font-family: SimSun">劳动</span><span style="font-family: 'ＭＳ 明朝'">合同法</span><span style="font-family: SimSun">实</span><span style="font-family: 'ＭＳ 明朝'">施条例</span><span style="font-family: 'ＭＳ 明朝'">(</span><span style="font-family: SimSun">解释劳动法实施</span><span style="font-family: 'ＭＳ 明朝'">)</span></p>
<p><a href="http://www.gov.cn/flfg/2008-09/19/content_1099500.htm">http://www.gov.cn/flfg/2008-09/19/content_1099500.htm</a></p>
<p>C)<span style="font-family: SimSun">关于确立劳动关系有关事项的通知</span></p>
<p><a href="http://www.law-lib.com/law/law_view.asp?id=92395">http://www.law-lib.com/law/law_view.asp?id=92395</a></p>
<p>D)<span style="font-family: SimSun">上海市女职工劳动保护办法</span></p>
<p><a href="http://www.shanghai.gov.cn/shanghai/node2314/node3124/node3125/node3133/userobject6ai655.html">http://www.shanghai.gov.cn/shanghai/node2314/node3124/node3125/node3133/userobject6ai655.html</a></p>
<p style="margin-left: 36pt; text-indent: -36pt; tab-stops: list 0cm"><span style="font-family: Symbol">&#183;<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong>C)</strong></span><strong><span style="font-family: SimSun">的相关内容：</strong></span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-family: SimSun">用人单位未与劳动者签订劳动合同，<strong><span style="color: red">认定双方存在劳动关系</strong>时可参照下列凭证：</span></span></p>
<p>(<span style="font-family: SimSun">一</span>)<span style="font-family: SimSun">工资支付凭证或记录</span>(<span style="font-family: SimSun">职工工资发放花名册</span>)<span style="font-family: SimSun">、缴纳各项社会保险费的记录；</span></p>
<p>(<span style="font-family: SimSun">二</span>)<span style="font-family: SimSun">用人单位向劳动者发放的<strong><span style="color: red">&#8220;工作证&#8221;、&#8220;服务证&#8221;等能够证明身份的证件</strong>；</span></span></p>
<p style="margin-left: 36pt; text-indent: -36pt; tab-stops: list 0cm"><span style="font-family: Symbol">&#183;<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong>B) </strong></span><strong><span style="font-family: SimSun">的相关内容：</strong></span></p>
<p style="margin-left: 69pt; text-indent: -48pt; tab-stops: list 69.0pt">第六条<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: SimSun">用人单位自用工之日起<span style="color: blue">超过一个月不满一年</span>未与劳动者订立书面劳动合同的，应当依照<span style="color: blue">劳动合同法第八十二条的规定向劳动者每月支付两倍的工资，并与劳动者补订书面劳动合同</span>；劳动者不与用人单位订立书面劳动合同的，用人单位应当书面通知劳动者终止劳动关系，<span style="color: blue">并依照劳动合同法第四十七条的规定支付经济补偿</span>。</span></span><strong><span style="color: red">(1</strong></span><strong><span style="color: red; font-family: SimSun">，相当于给</strong></span><strong><span style="color: red">2</strong></span><strong><span style="color: red; font-family: SimSun">倍工资，</strong></span><strong><span style="color: red">2</strong></span><strong><span style="color: red; font-family: SimSun">，补合同，</strong></span><strong><span style="color: red">3</strong></span><strong><span style="color: red; font-family: SimSun">，如果辞退，再按照有合同补偿）</strong></span></p>
<p style="margin-left: 21pt"><span style="font-family: SimSun">第二十七条　劳动合同法第四十七条规定的<strong><span style="color: red">经济补偿的月工资按照劳动者应得工资计算，包括计时工资或者计件工资以及奖金</strong><span style="color: red">。</span></span></span></p>
<p style="margin-left: 36pt; text-indent: -36pt; tab-stops: list 0cm"><span style="font-family: Symbol">&#183;<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong>A)</strong></span><strong><span style="font-family: SimSun">的相关内容：</strong></span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: SimSun">第四十二条　劳动者有下列情形之一的，用人单位<strong><span style="color: red">不得依照</strong>本法第四十条、第四十一条的规定解除劳动合同：</span></span></p>
<p><strong><span style="color: red">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;</strong></span><strong><span style="color: red; font-family: SimSun">（四）女职工在孕期、产期、哺乳期的</strong></span></p>
<p>&nbsp;<span style="font-family: SimSun">　第四十七条　经济补偿按劳动者在本单位工作的年限，<strong><span style="color: red">每满一年支付一个月工资的标准向劳动者支付。六个月以上不满一年的，按一年计算；</strong>不满六个月的，向劳动者支付半个月工资的经济补偿。</span></span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: SimSun">第八十二条　<strong><span style="color: red">用人单位自用工之日起超过一个月不满一年未与劳动者订立书面劳动合同的，应当向劳动者每月支付二倍的工资。</strong></span></span></p>
<p><strong><span style="color: red">&nbsp;&nbsp;&nbsp; </strong></span><span style="font-family: SimSun">用人单位违反本法规定不与劳动者订立<strong><span style="color: red">无固定期限劳动合同</strong>的，自应当订立无固定期限劳动合同之日起向劳动者每月<strong><span style="color: red">支付二倍的工资</span></strong>。</span></span></p>
<p><strong><span style="color: red">&nbsp;&nbsp;&nbsp;&nbsp; </strong></span><span style="font-family: SimSun">第八十七条　用人<strong><span style="color: red">单位违反本法</strong>规定解除或者终止劳动合同的，应当<strong><span style="color: red">依照本法第四十七条</span></strong>规定的经济补偿<strong><span style="color: red">标准的二倍</span></strong>向劳动者支付赔偿金。</span></span></p>
<p>&nbsp;<span style="font-family: SimSun">第十四条　无固定期限劳动合同，是指用人单位与劳动者约定无确定终止时间的劳动合同。</span></p>
<p>&nbsp;&nbsp;&nbsp; <span style="font-family: SimSun">用人单位与劳动者协商一致，可以订立无固定期限劳动合同。有下列情形之一，劳动者提出或者同意续订、订立劳动合同的，除劳动者提出订立固定期限劳动合同外，应当<strong><span style="color: red">订立无固定期限劳动合同</strong>：</span></span></p>
<p>&nbsp;&nbsp;&nbsp; <span style="font-family: SimSun">（一）劳动者在该用人单位<span style="color: red">连续<strong>工作满十年</strong>的；</span></span></p>
<p>&nbsp;&nbsp;&nbsp; <span style="font-family: SimSun">（二）用人单位初次实行劳动合同制度或者国有企业改制重新订立劳动合同时，劳动者在该用人单位连续工作满十年且距法定退休年龄不足十年的；</span></p>
<p>&nbsp;&nbsp;&nbsp; <span style="font-family: SimSun">（三）<strong><span style="color: red">连续订立二次固定期限劳动合同</strong>，且劳动者没有本法第三十九条和第四十条第一项、第二项规定的情形，续订劳动合同的。</span></span></p>
<p>&nbsp;&nbsp;&nbsp; <span style="font-family: SimSun">用人单位<strong><span style="color: red">自用工之日起满一年不与劳动者订立书面劳动合同的，视为用人单位与劳动者已订立无固定期限劳动合同</strong>。</span></span></p>
<p><strong>&nbsp;</strong></p>
<p style="margin-left: 36pt; text-indent: -36pt; tab-stops: list 0cm"><span style="font-family: Symbol">&#183;<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong>D) </strong></span><strong><span style="font-family: SimSun">的相关内容：</strong></span></p>
<p><span style="font-family: SimSun">第十一条</span><span style="font-family: SimSun">对妊娠期的女职工，<strong><span style="color: red">不应延长其劳动时间</strong>；</span></span></p>
<p><span style="font-family: SimSun">第十四条</span><span style="font-family: SimSun">女职工产假分别按下列情况执行：</span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: SimSun">（一）单胎顺产者，给予<span style="color: red">产假九十天，其中产前休息十五天，产后休息七十五天。</span></span></p>
<p><span style="font-family: SimSun">第十五条</span><span style="font-family: SimSun">女职工生育后，在其婴儿一周岁内应照顾其在每班劳动时间内<span style="color: red">授乳两次（包括人工喂养）。<span style="color: red">每次</span>单胎纯授乳时间为<span style="color: red">三十分钟</span>，亦可将两次授乳时间合并使用。多胞胎生育者，每多生一胎，每次哺乳时间增加三十分钟。</span></span></p>
<p>&nbsp;<span style="font-family: SimSun">第十八条</span><span style="font-family: SimSun">女职工在<span style="color: red">产假期间的工资照发。按本规定享受的<span style="color: red">产前假和哺乳假的工资</span>按本人原工资的<span style="color: red">百分之八十发给</span>。单位增加工资时，女职工按规定享受的产前假、产假、哺乳假，应作出勤对待。</span></span></p>
<p><strong><span style="color: red">&nbsp;&nbsp;&nbsp; </strong></span></p>
<p style="margin-left: 36pt; text-indent: -36pt; tab-stops: list 0cm"><span style="font-family: Symbol">&#183;<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><strong><span style="font-family: SimSun">结论：</span></strong></span></p>
<p style="margin-left: 36pt; text-indent: -27pt; tab-stops: list 36.0pt"><strong><span style="color: red">1）<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></strong><strong><span style="color: red; font-family: SimSun">认定劳动关系：工作证</span></strong></span></p>
<p style="margin-left: 36pt; text-indent: -27pt; tab-stops: list 36.0pt"><strong><span style="color: red">2）<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></strong><strong><span style="color: red; font-family: SimSun">是否签合同</span></strong></span></p>
<p style="margin-left: 36pt; text-indent: -27pt; tab-stops: list 36.0pt"><strong><span style="color: red">3）<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></strong><strong><span style="color: red; font-family: SimSun">如果没签合同，怎么补偿（</span></strong></span><span style="color: red">1</span><span style="color: red; font-family: SimSun">，<strong>相当于给</strong></span><strong><span style="color: red">2</strong></span><strong><span style="color: red; font-family: SimSun">倍工资，</strong></span><strong><span style="color: red">2</strong></span><strong><span style="color: red; font-family: SimSun">，补合同，</strong></span><strong><span style="color: red">3</strong></span><strong><span style="color: red; font-family: SimSun">，如果辞退，再按照有合同补偿）</strong></span></p>
<p style="margin-left: 36pt; text-indent: -27pt; tab-stops: list 36.0pt"><strong><span style="color: red">4）<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></strong><strong><span style="color: red; font-family: SimSun">如果是固定合同，怎么补偿（</span></strong></span><strong><span style="color: red">N+1</strong></span><strong><span style="color: red; font-family: SimSun">）</strong></span></p>
<p style="margin-left: 36pt; text-indent: -27pt; tab-stops: list 36.0pt"><strong><span style="color: red">5）<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></strong><strong><span style="color: red; font-family: SimSun">如果是无期合同，</span></strong></span><strong><span style="color: red">2</strong></span><strong><span style="color: red; font-family: SimSun">倍</strong></span></p>
<p style="margin-left: 36pt; text-indent: -27pt; tab-stops: list 36.0pt"><strong><span style="color: red">6）<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></strong><strong><span style="color: red; font-family: SimSun">孕妇怎么处理？</span></strong></span></p>
<p style="margin-left: 9pt"><span style="background: silver; color: #333333">1</span><span style="background: silver; color: #333333; font-family: SimSun">、公司辞退孕妇的补偿情况标准是怎样？</span></p>
<p style="margin-left: 9pt"><span style="background: silver; color: #333333; font-family: SimSun">答：发放工资到哺乳期满；按工作年限计算经济补偿金。</span></p>
<p style="margin-left: 9pt"><span style="background: silver; color: #333333">2</span><span style="background: silver; color: #333333; font-family: SimSun">、公司是否可以以我的考核和我是孕产妇不能胜任工作为由对我进行降职降级降薪处理？</span></p>
<p style="margin-left: 9pt"><span style="background: silver; color: #333333; font-family: SimSun">答：不可以。</span></p>
<p style="margin-left: 9pt"><span style="background: silver; color: #333333; font-family: SimSun">我们的工资分为基本工资（约占</span><span style="background: silver; color: #333333">1/4)+</span><span style="background: silver; color: #333333; font-family: SimSun">岗位工资</span><span style="background: silver; color: #333333">+</span><span style="background: silver; color: #333333; font-family: SimSun">绩效工资等。是否可能出现只要不降低我的基本工资就是合法的行为？</span></p>
<p style="margin-left: 9pt"><span style="background: silver; color: #333333; font-family: SimSun">答：不合理。工资是包括了岗位工资和绩效工资。</span></p>
<p style="margin-left: 9pt"><span style="background: silver; color: #333333">3</span><span style="background: silver; color: #333333; font-family: SimSun">、如果公司依法破产，我是否有向集团主张赔偿的权利？</span></p>
<p style="margin-left: 9pt"><span style="background: silver; color: #333333; font-family: SimSun">答：破产也可以主张权利，在破产财产中优先演戏偿。</span></p>
<p style="margin-left: 9pt"><span style="background: silver; color: #333333">4</span><span style="background: silver; color: #333333; font-family: SimSun">、如果可能需要诉诸法律，我应该准备哪些方面的举证？</span></p>
<p style="margin-left: 9pt"><span style="background: silver; color: #333333; font-family: SimSun">答：存在劳动关系的证据最重要，此外，工资条、怀孕的证据、结婚证、准生证</span></p>
<p style="margin-left: 9pt"><span style="background: silver; color: #333333; font-family: SimSun">也比较重要。</span><span style="background: silver; color: #333333; font-family: SimSun">（</span><strong><span style="background: silver; color: red; font-family: SimSun">按照劳动法</span></strong><strong><span style="background: silver; color: red">42</span></strong><strong><span style="background: silver; color: red; font-family: SimSun">条，不得解除三期【孕期、产期、哺乳期】妇女。那么如果一定要违反劳动法解除劳动关系，只能按照违反劳动法，按照第八十七条进行二倍赔偿，也就是</span></strong><strong><span style="background: silver; color: red">3</span></strong><strong><span style="background: silver; color: red; font-family: SimSun">倍）</span></strong></p>
<p style="margin-left: 9pt"><strong><span style="font-size: 13.5pt; color: #333333; font-family: 'ＭＳ 明朝'">案例</span></strong><strong><span style="font-size: 13.5pt; color: #333333">:</span></strong></p>
<p style="margin-left: 9pt"><strong><span style="font-size: 13.5pt; color: #333333"><a href="http://www.tianya.cn/publicforum/content/law/1/119373.shtml">http://www.tianya.cn/publicforum/content/law/1/119373.shtml</a> </span></strong></p>
<p style="margin-left: 9pt"><span style="background: silver; font-family: 'ＭＳ 明朝'">案情：</span><span style="background: silver">A</span><span style="background: silver; font-family: 'ＭＳ 明朝'">公司辞退</span><span style="background: silver">B</span><span style="background: silver; font-family: 'ＭＳ 明朝'">孕</span><span style="background: silver; font-family: SimSun">妇</span><span style="background: silver; font-family: 'ＭＳ 明朝'">（不考</span><span style="background: silver; font-family: SimSun">虑</span><span style="background: silver">B</span><span style="background: silver; font-family: 'ＭＳ 明朝'">可能存在的</span><span style="background: silver; font-family: SimSun">过错</span><span style="background: silver; font-family: 'ＭＳ 明朝'">，假</span><span style="background: silver; font-family: SimSun">设</span><span style="background: silver">A</span><span style="background: silver; font-family: 'ＭＳ 明朝'">毫无道理毫无依据的辞退</span><span style="background: silver">B</span><span style="background: silver; font-family: 'ＭＳ 明朝'">孕</span><span style="background: silver; font-family: SimSun">妇</span><span style="background: silver; font-family: 'ＭＳ 明朝'">）。</span></p>
<p style="margin-left: 9pt"><span style="background: silver; font-family: 'ＭＳ 明朝'">　　</span><span style="background: silver; font-family: 'ＭＳ 明朝'">一</span><span style="background: silver; font-family: SimSun">审结</span><span style="background: silver; font-family: 'ＭＳ 明朝'">果：<strong><span style="color: red">判</span></strong></span><strong><span style="background: silver; color: red; font-family: SimSun">赔</span></strong><strong><span style="background: silver; color: red; font-family: 'ＭＳ 明朝'">全</span></strong><strong><span style="background: silver; color: red; font-family: SimSun">额</span></strong><strong><span style="background: silver; color: red; font-family: 'ＭＳ 明朝'">孕期工</span></strong><strong><span style="background: silver; color: red; font-family: SimSun">资</span></strong><strong><span style="background: silver; color: red; font-family: 'ＭＳ 明朝'">、全</span></strong><strong><span style="background: silver; color: red; font-family: SimSun">额产</span></strong><strong><span style="background: silver; color: red; font-family: 'ＭＳ 明朝'">期（</span></strong><strong><span style="background: silver; color: red; font-family: SimSun">晚</span></strong><strong><span style="background: silver; color: red; font-family: 'ＭＳ 明朝'">育</span></strong><strong><span style="background: silver; color: red; font-family: SimSun">还</span></strong><strong><span style="background: silver; color: red; font-family: 'ＭＳ 明朝'">加了</span></strong><strong><span style="background: silver; color: red">15</span></strong><strong><span style="background: silver; color: red; font-family: 'ＭＳ 明朝'">天）工</span></strong><strong><span style="background: silver; color: red; font-family: SimSun">资</span></strong><strong><span style="background: silver; color: red; font-family: 'ＭＳ 明朝'">、</span></strong><strong><span style="background: silver; color: red">75%</span></strong><strong><span style="background: silver; color: red; font-family: 'ＭＳ 明朝'">的哺乳期工</span></strong><strong><span style="background: silver; color: red; font-family: SimSun">资</span></strong><span style="background: silver; font-family: 'ＭＳ 明朝'">，并以入</span><span style="background: silver; font-family: SimSun">职时间</span><span style="background: silver; font-family: 'ＭＳ 明朝'">至三期届</span><span style="background: silver; font-family: SimSun">满为劳动</span><span style="background: silver; font-family: 'ＭＳ 明朝'">合同</span><span style="background: silver; font-family: SimSun">关</span><span style="background: silver; font-family: 'ＭＳ 明朝'">系存</span><span style="background: silver; font-family: SimSun">续</span><span style="background: silver; font-family: 'ＭＳ 明朝'">期</span><span style="background: silver; font-family: SimSun">间计</span><span style="background: silver; font-family: 'ＭＳ 明朝'">算在</span><span style="background: silver; font-family: SimSun">职时间</span><span style="background: silver; font-family: 'ＭＳ 明朝'">，然后以</span><span style="background: silver; font-family: SimSun">该</span><span style="background: silver; font-family: 'ＭＳ 明朝'">在</span><span style="background: silver; font-family: SimSun">职时间</span><span style="background: silver; font-family: 'ＭＳ 明朝'">按照《</span><span style="background: silver; font-family: SimSun">劳动</span><span style="background: silver; font-family: 'ＭＳ 明朝'">合同法》第八十七条判</span><span style="background: silver; font-family: SimSun">赔</span><span style="background: silver; font-family: 'ＭＳ 明朝'">了</span><strong><span style="background: silver; color: red; font-family: SimSun">赔偿</span></strong><strong><span style="background: silver; color: red; font-family: 'ＭＳ 明朝'">金（即合法解除的</span></strong><strong><span style="background: silver; color: red; font-family: SimSun">补偿</span></strong><strong><span style="background: silver; color: red; font-family: 'ＭＳ 明朝'">金的双倍）</span></strong><span style="background: silver; font-family: 'ＭＳ 明朝'">。一</span><span style="background: silver; font-family: SimSun">审</span><span style="background: silver; font-family: 'ＭＳ 明朝'">不是我代理的。</span></p>
<p style="margin-left: 9pt"><span style="background: silver; font-family: 'ＭＳ 明朝'">　　</span><span style="background: silver; font-family: 'ＭＳ 明朝'">二</span><span style="background: silver; font-family: SimSun">审</span><span style="background: silver">A</span><span style="background: silver; font-family: 'ＭＳ 明朝'">公司找到我，我想当然的以</span><span style="background: silver; font-family: SimSun">为</span><span style="background: silver; font-family: 'ＭＳ 明朝'">，按照《</span><span style="background: silver; font-family: SimSun">劳动</span><span style="background: silver; font-family: 'ＭＳ 明朝'">合同法》第八十七条的</span><span style="background: silver; font-family: SimSun">规</span><span style="background: silver; font-family: 'ＭＳ 明朝'">定，</span><span style="background: silver; font-family: SimSun">劳动</span><span style="background: silver; font-family: 'ＭＳ 明朝'">者可以</span><span style="background: silver; font-family: SimSun">选择</span><span style="background: silver; font-family: 'ＭＳ 明朝'">要求</span><span style="background: silver; font-family: SimSun">继续</span><span style="background: silver; font-family: 'ＭＳ 明朝'">履行，不要求</span><span style="background: silver; font-family: SimSun">继续</span><span style="background: silver; font-family: 'ＭＳ 明朝'">履行的，</span><span style="background: silver; font-family: SimSun">应</span><span style="background: silver; font-family: 'ＭＳ 明朝'">当</span><span style="background: silver; font-family: SimSun">仅</span><span style="background: silver; font-family: 'ＭＳ 明朝'">支付双倍</span><span style="background: silver; font-family: SimSun">补偿</span><span style="background: silver; font-family: 'ＭＳ 明朝'">即可，一</span><span style="background: silver; font-family: SimSun">审</span><span style="background: silver; font-family: 'ＭＳ 明朝'">判决属适用法律</span><span style="background: silver; font-family: SimSun">错误</span><span style="background: silver; font-family: 'ＭＳ 明朝'">。</span></p>
<img src ="http://www.blogjava.net/jinfeng_wang/aggbug/315853.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2010-03-19 00:27 <a href="http://www.blogjava.net/jinfeng_wang/archive/2010/03/19/315853.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>创意是什么？创意就在我身边</title><link>http://www.blogjava.net/jinfeng_wang/archive/2007/02/15/100000.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Thu, 15 Feb 2007 13:25:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2007/02/15/100000.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/100000.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2007/02/15/100000.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/100000.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/100000.html</trackback:ping><description><![CDATA[突然想到这个问题，<br /><br />创意就在我们的身边。<br /><br />偶然的进入sohu的blog，<br /><br />看到了sohu  blog提供的音乐盒<br /><br />相当不错的一个结合<br /><br />什么是门户？什么是整合？什么是资源复合？<br /><br />也许我也可以尝试着利用搜索引擎，做一点其它的小创意来。<br /><br />很奇怪的是，sogou的mp3试听里面是用的其他网站的URL连接<br /><br />但是blog里面的mp3 连接好像直接来源于 sohu<br /><br />嘿嘿， sohu不怕官司了？<br /><br /><br />＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝<br />whois :  220.181.26.88<br /><br /><table cellspacing="0" cellpadding="2" border="1"><tbody><tr><td class="t_blue"><font size="2">地址段范围: </font></td><td class="t_blue"><font size="2">220.181.0.0 - 220.181.255.255 </font></td></tr><tr><td class="t_blue"><font size="2">网络名: </font></td><td class="t_blue"><font size="2">CHINANET-IDC-BJ </font></td></tr><tr><td class="t_blue"><font size="2">国家: </font></td><td class="t_blue"><font size="2">CN </font></td></tr><tr><td class="t_blue"><font size="2">单位描述: </font></td><td class="t_blue"><font size="2">CHINANET Beijing province network </font></td></tr><tr><td class="t_blue"><font size="2">单位描述: </font></td><td class="t_blue"><font size="2">China Telecom </font></td></tr><tr><td class="t_blue"><font size="2">单位描述: </font></td><td class="t_blue"><font size="2">No.31,jingrong street </font></td></tr><tr><td class="t_blue"><font size="2">单位描述: </font></td><td class="t_blue"><font size="2">Beijing 100032 </font></td></tr><tr><td class="t_blue"><font size="2">管理联系人: </font></td><td class="t_blue"><font size="2">CH93-AP </font></td></tr><tr><td class="t_blue"><font size="2">技术联系人: </font></td><td class="t_blue"><font size="2">HC55-AP </font></td></tr><tr><td class="t_blue"><font size="2">附注: </font></td><td class="t_blue"><font size="2">hostmaster is not for spam complaint, </font></td></tr><tr><td class="t_blue"><font size="2">附注: </font></td><td class="t_blue"><font size="2">please send spam complaint to anti-spam@ns.chinanet.cn.net </font></td></tr><tr><td class="t_blue"><font size="2">维护方帐号: </font></td><td class="t_blue"><font size="2">MAINT-CHINANET </font></td></tr><tr><td class="t_blue"><font size="2">次级维护者: </font></td><td class="t_blue"><font size="2">MAINT-CHINATELECOM-BJ </font></td></tr><tr><td class="t_blue"><font size="2">地址段状态: </font></td><td class="t_blue"><font size="2">ALLOCATED NON-PORTABLE </font></td></tr><tr><td class="t_blue"><font size="2">更改记录: </font></td><td class="t_blue"><font size="2">hostmaster@ns.chinanet.cn.net 20030620 </font></td></tr><tr><td class="t_blue"><font size="2">更改记录: </font></td><td class="t_blue"><font size="2">hm-changed@apnic.net 20050715 </font></td></tr><tr><td class="t_blue"><font size="2">数据来源: </font></td><td class="t_blue"><font size="2">APNIC </font></td></tr><tr><td class="t_blue"><font size="2"><br /></font></td><td class="t_blue"><font size="2"><br /></font></td></tr><tr><td class="t_blue"><font size="2">联系人: </font></td><td class="t_blue"><font size="2">Chinanet Hostmaster </font></td></tr><tr><td class="t_blue"><font size="2">联系人帐号: </font></td><td class="t_blue"><font size="2">CH93-AP </font></td></tr><tr><td class="t_blue"><font size="2">电子邮件: </font></td><td class="t_blue"><font size="2">anti-spam@ns.chinanet.cn.net </font></td></tr><tr><td class="t_blue"><font size="2">通信地址: </font></td><td class="t_blue"><font size="2">No.31 ,jingrong street,beijing </font></td></tr><tr><td class="t_blue"><font size="2">通信地址: </font></td><td class="t_blue"><font size="2">100032 </font></td></tr><tr><td class="t_blue"><font size="2">电话: </font></td><td class="t_blue"><font size="2">+86-10-58501724 </font></td></tr><tr><td class="t_blue"><font size="2">传真: </font></td><td class="t_blue"><font size="2">+86-10-58501724 </font></td></tr><tr><td class="t_blue"><font size="2">国家: </font></td><td class="t_blue"><font size="2">CN </font></td></tr><tr><td class="t_blue"><font size="2">更改记录: </font></td><td class="t_blue"><font size="2">lqing@chinatelecom.com.cn 20051212 </font></td></tr><tr><td class="t_blue"><font size="2">维护方帐号: </font></td><td class="t_blue"><font size="2">MAINT-CHINANET </font></td></tr><tr><td class="t_blue"><font size="2">数据来源: </font></td><td class="t_blue"><font size="2">APNIC </font></td></tr><tr><td class="t_blue"><font size="2"><br /></font></td><td class="t_blue"><font size="2"><br /></font></td></tr><tr><td class="t_blue"><font size="2">联系人: </font></td><td class="t_blue"><font size="2">Hostmaster of Beijing Telecom corporation CHINA TELECOM </font></td></tr><tr><td class="t_blue"><font size="2">联系人帐号: </font></td><td class="t_blue"><font size="2">HC55-AP </font></td></tr><tr><td class="t_blue"><font size="2">电子邮件: </font></td><td class="t_blue"><font size="2">bjnic@bjtelecom.net </font></td></tr><tr><td class="t_blue"><font size="2">通信地址: </font></td><td class="t_blue"><font size="2">Beijing Telecom </font></td></tr><tr><td class="t_blue"><font size="2">通信地址: </font></td><td class="t_blue"><font size="2">No. 107 XiDan Beidajie, Xicheng District Beijing </font></td></tr><tr><td class="t_blue"><font size="2">电话: </font></td><td class="t_blue"><font size="2">+86-010-58503461 </font></td></tr><tr><td class="t_blue"><font size="2">传真: </font></td><td class="t_blue"><font size="2">+86-010-58503054 </font></td></tr><tr><td class="t_blue"><font size="2">国家: </font></td><td class="t_blue"><font size="2">cn </font></td></tr><tr><td class="t_blue"><font size="2">更改记录: </font></td><td class="t_blue"><font size="2">bjnic@bjtelecom.net 20040115 </font></td></tr><tr><td class="t_blue"><font size="2">维护方帐号: </font></td><td class="t_blue"><font size="2">MAINT-CHINATELECOM-BJ </font></td></tr><tr><td class="t_blue"><font size="2">数据来源: </font></td><td class="t_blue"><font size="2">APNIC </font></td></tr><tr><td class="t_blue"><font size="2"><br /></font></td><td class="t_blue"><font size="2"><br /></font></td></tr><tr><td class="t_blue"><font size="2"><br /></font></td></tr></tbody></table><br /><br /><br /><img src ="http://www.blogjava.net/jinfeng_wang/aggbug/100000.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2007-02-15 21:25 <a href="http://www.blogjava.net/jinfeng_wang/archive/2007/02/15/100000.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>人员、资源、操作及这三者构成的权限控制</title><link>http://www.blogjava.net/jinfeng_wang/archive/2007/02/14/99819.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Wed, 14 Feb 2007 06:53:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2007/02/14/99819.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/99819.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2007/02/14/99819.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/99819.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/99819.html</trackback:ping><description><![CDATA[Web系统因为是面向Internet/Intranet的，所以其安全性比常规的应用程序系统更难以保证。<br /><br />在谈到其安全性的时候，很多的都是从“网络安全”的角度去看待问题，殊不知，堡垒<br />的内部是最最不安全的。对付“黑客攻击”是系统管理员所要面对的问题，而如何更好的<br />加强堡垒内部自身的安全，是在Web程序的设计中就需要考虑的问题。<br /><br />系统管理员所要面对的网络攻击、操作系统 安全不是我所考虑的问题，如何加强Web系统<br />自身的健康是我所最最关心的事情。 <br /><br />从“构造URL”攻击到“注入SQL文”攻击，都是属于过分信任用户输入，而造成的安全问题。<br />这恰恰应该是由应用程序自身加以重视、解决的问题。<br /><br />基于角色的安全控制已经逐渐的被大家逐渐的接受，每个用户被分配为不同的角色，不同的角色<br />具有不同的操作权限。 但是如何划分角色、用户、操作权限，则是需要认真对待的问题。<br /><br />举例：<br />一个MIS系统中，员工有查询工资的权限，但是某个员工是否具有查询其他员工的权限呢？<br /><br />不能深入的追问问题，详细的分辨清楚系统中到底有多少角色、每个用户所在的角色，是不能完成安全控制的。<br /><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: #000000"><br /><font color="#0000ff" size="5"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />btw: 以上的问题，大家不妨在自己的类似系统中自己去检查一下，有此问题的占绝大多数吧。<br /><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />看过此文的，愿意回答“是”“否”的，可以留言， 也当作一个调查吧。</font><br /></span></div><br /><br />上面的这个例子，就是一个很成熟的办公系统中存在的问题。使用客户端script脚本，控制了用户的界面操作，殊不知maxthon就可以解除这个限制。此系统中，用户的请求都被整理为URL（get方式提交），虽然URL中的键值含义并不是很明显，但是还是可以尝试着去攻击，获取秘密。<br /><br />认真的核查用户的输入，利用AOP部署，细密的对用户的输入进行核查，是很有必要的事情。<br /><br />某个人、某个资源、某个操作，这三个要素组织在一起则是：某个人对某个资源进行某项操作<br />实际情况下，许多人、许多资源、对每个资源冰存在着多个操作。<br /><br />将人、资源、操作进行划分，可以得到：<br />具体的某一类人，可以对某些资源，进行某些的操作＝》 这就是具体的某项权限限制。<br />    某一类人，则可以归纳为角色。<br />    对某些资源的某些操作，则可以归纳为工作任务。<br />也就是说，整个系统是“某个角色去完成某些工作任务，而具体的一个帐户属于某个角色，某项工作则具体的是指对某个资源进行某个操作”。<br /><br />相对来说，系统中的人员是最容易辨认的，系统中的资源也是可以在系统的功能调查时分清楚的，系统中的操作则是最复杂、最难分清晰，甚至在系统完成时都会变化的。<br /><br />只有分辨清楚了系统中的人、资源、操作，才能辨别清楚系统中的具体的权限限制。<br /><br />“基于角色的安全控制”这样的提法，只提及了人，未能强调将资源、操作进行规类，这是很不充分的一种提法。<br /><br />在Web系统中，系统在设计的过程中，就分清楚资源，分清楚操作，极大缩小每个页面的功能、提高页面功能的原子性，这也是权限控制对系统设计提出的一项要求。<br /><br />前面提及使用AOP进行权限控制，现在简述一下各部件的功能：<br />   业务模块－－完成具体的对某个资源的操作；<br />   前台页面模块－－ 完成整体页面的整合；<br />   安全控制模块－－实现安全控制功能，完成人员、角色、工作的逻辑判断；<br />   AOP配置整合模块－－粘合安全控制模块和业务模块；<br /><br /><br />在于如何去解决，而是如何去发现。隐藏起来的问题更是危险。<br /><br />而如何发现问题，则完全是一个素质、能力的事情，也许这是下一个话题。<br /><img src ="http://www.blogjava.net/jinfeng_wang/aggbug/99819.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2007-02-14 14:53 <a href="http://www.blogjava.net/jinfeng_wang/archive/2007/02/14/99819.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>应用协议的设计 (zz)</title><link>http://www.blogjava.net/jinfeng_wang/archive/2007/02/13/99737.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Tue, 13 Feb 2007 09:32:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2007/02/13/99737.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/99737.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2007/02/13/99737.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/99737.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/99737.html</trackback:ping><description><![CDATA[
		<a href="http://www.ietf.org/rfc/rfc3117.txt">http://www.ietf.org/rfc/rfc3117.txt</a>
		<br />
		<br />RFC 3117         On the Design of Application Protocols    November 2001<br /><br /><br />Table of Contents<br /><br />   1.  A Problem 19 Years in the Making . . . . . . . . . . . . . . .  3<br />   2.  You can Solve Any Problem... . . . . . . . . . . . . . . . . .  6<br />   3.  Protocol Mechanisms  . . . . . . . . . . . . . . . . . . . . .  8<br />   3.1 Framing  . . . . . . . . . . . . . . . . . . . . . . . . . . .  8<br />   3.2 Encoding . . . . . . . . . . . . . . . . . . . . . . . . . . .  9<br />   3.3 Reporting  . . . . . . . . . . . . . . . . . . . . . . . . . .  9<br />   3.4 Asynchrony . . . . . . . . . . . . . . . . . . . . . . . . . . 10<br />   3.5 Authentication . . . . . . . . . . . . . . . . . . . . . . . . 12<br />   3.6 Privacy  . . . . . . . . . . . . . . . . . . . . . . . . . . . 12<br />   3.7 Let's Recap  . . . . . . . . . . . . . . . . . . . . . . . . . 13<br />   4.  Protocol Properties  . . . . . . . . . . . . . . . . . . . . . 14<br />   4.1 Scalability  . . . . . . . . . . . . . . . . . . . . . . . . . 14<br />   4.2 Efficiency . . . . . . . . . . . . . . . . . . . . . . . . . . 15<br />   4.3 Simplicity . . . . . . . . . . . . . . . . . . . . . . . . . . 15<br />   4.4 Extensibility  . . . . . . . . . . . . . . . . . . . . . . . . 15<br />   4.5 Robustness . . . . . . . . . . . . . . . . . . . . . . . . . . 16<br />   5.  The BXXP Framework . . . . . . . . . . . . . . . . . . . . . . 17<br />   5.1 Framing and Encoding . . . . . . . . . . . . . . . . . . . . . 17<br />   5.2 Reporting  . . . . . . . . . . . . . . . . . . . . . . . . . . 19<br />   5.3 Asynchrony . . . . . . . . . . . . . . . . . . . . . . . . . . 19<br />   5.4 Authentication . . . . . . . . . . . . . . . . . . . . . . . . 21<br />   5.5 Privacy  . . . . . . . . . . . . . . . . . . . . . . . . . . . 21<br />   5.6 Things We Left Out . . . . . . . . . . . . . . . . . . . . . . 21<br />   5.7 From Framework to Protocol . . . . . . . . . . . . . . . . . . 22<br />   6.  BXXP is now BEEP . . . . . . . . . . . . . . . . . . . . . . . 23<br />   7.  Security Considerations  . . . . . . . . . . . . . . . . . . . 23<br />   References . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24<br />   Author's Address . . . . . . . . . . . . . . . . . . . . . . . . . 26<br />   Full Copyright Statement . . . . . . . . . . . . . . . . . . . . . 27<br /><img src ="http://www.blogjava.net/jinfeng_wang/aggbug/99737.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2007-02-13 17:32 <a href="http://www.blogjava.net/jinfeng_wang/archive/2007/02/13/99737.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ADO.NET Connection Status Map</title><link>http://www.blogjava.net/jinfeng_wang/archive/2006/06/03/50173.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Sat, 03 Jun 2006 13:35:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2006/06/03/50173.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/50173.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2006/06/03/50173.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/50173.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/50173.html</trackback:ping><description><![CDATA[
		<img src="http://www.blogjava.net/images/blogjava_net/jinfeng_wang/6626/r_ConnectionStatus.JPG" />
<img src ="http://www.blogjava.net/jinfeng_wang/aggbug/50173.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2006-06-03 21:35 <a href="http://www.blogjava.net/jinfeng_wang/archive/2006/06/03/50173.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Checked Exception VS UnChecked Excetion (续2)</title><link>http://www.blogjava.net/jinfeng_wang/archive/2006/06/03/50170.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Sat, 03 Jun 2006 13:22:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2006/06/03/50170.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/50170.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2006/06/03/50170.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/50170.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/50170.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal">
				<span style="font-family: &quot;ＭＳ 明朝&quot;;" lang="ZH-CN">　　</span>
				<span style="font-family: SimSun;" lang="ZH-CN">假设我的团队正在开发一个库程序，由于某种原因，现在希望能够得到所有最外层</span>
				<span style="" lang="EN-US">API</span>
				<span style="font-family: SimSun;" lang="ZH-CN">所抛出的所有异常的类型、各自的信息、并且能够附上各种异常所出现的原因和解决办法。如果开发过程中内部使用的是</span>
				<span style="" lang="EN-US">Unchecked
Exception</span>
				<span style="font-family: SimSun;" lang="ZH-CN">，那么对于这个任务简直就麻烦了。没办法，开发人员一个个的自我进行检查然后统计吧，但是往往这样的统计总会有漏网之鱼。现在的</span>
				<span style="" lang="EN-US">MSDN</span>
				<span style="font-family: SimSun;" lang="ZH-CN">中的异常信息糟糕的很，最底层的公有库的异常信息内容可能完整一点，但是上层的库的异常信息糟糕的不行，根本不能完整的报全所有出错的可能性。</span>
				<span style="" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="text-indent: 21pt;">
				<span style="font-family: SimSun;" lang="ZH-CN">你可以想象的出，一个库函数的异常信息不完整，对于他的用户来说，是多么不友好的事情。假设</span>
				<span style="" lang="EN-US">MSDN</span>
				<span style="font-family: SimSun;" lang="ZH-CN">中</span>
				<span style="" lang="EN-US">File.Open()</span>
				<span style="font-family: SimSun;" lang="ZH-CN">会抛出</span>
				<span style="" lang="EN-US">IOException</span>
				<span style="font-family: SimSun;" lang="ZH-CN">，你的程序就很难想到很规矩的对</span>
				<span style="" lang="EN-US">IOException</span>
				<span style="font-family: SimSun;" lang="ZH-CN">做了</span>
				<span style="" lang="EN-US">catch</span>
				<span style="font-family: SimSun;" lang="ZH-CN">，然后提示用户检查相应位置的文件是否存在</span>
				<span style="" lang="EN-US">/</span>
				<span style="font-family: SimSun;" lang="ZH-CN">被打开等。别指望</span>
				<span style="" lang="EN-US">MSDN</span>
				<span style="font-family: SimSun;" lang="ZH-CN">的那些信息能够对终端用户有多大的帮助，太多不懂计算机的人在傻呆呆的握着鼠标了。再加上</span>
				<span style="" lang="EN-US">MicroSoft</span>
				<span style="font-family: SimSun;" lang="ZH-CN">的提示信息本身就存在着“答非所问”，“莫名其妙”的事情，用户看到这些情况就更不知道怎么解决问题了。再加上自己的应用程序中会弹出一个个“蹩脚”的运行时错误的错误框，真的不是一个很如意的创作。</span>
				<span style="" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span style="" lang="EN-US">
						<span style=""> </span>
						<span style=""> </span>
						<span style=""> </span>
						<span style=""> </span>
				</span>
				<span style="font-family: SimSun;" lang="ZH-CN">但是，如果使用的是</span>
				<span style="" lang="EN-US">Checked Exception</span>
				<span style="font-family: SimSun;" lang="ZH-CN">，这时候编译器会强迫你的外部接口的异常相当的完整，最起码可以做到比</span>
				<span style="" lang="EN-US">MSDN</span>
				<span style="font-family: SimSun;" lang="ZH-CN">的异常类型齐整。</span>
				<span style="" lang="EN-US">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span style="" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span style="" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span style="" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal">
				<span style="" lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
<img src ="http://www.blogjava.net/jinfeng_wang/aggbug/50170.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2006-06-03 21:22 <a href="http://www.blogjava.net/jinfeng_wang/archive/2006/06/03/50170.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>数据库驱动程序的测试需要注意的问题</title><link>http://www.blogjava.net/jinfeng_wang/archive/2006/05/28/48597.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Sun, 28 May 2006 07:52:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2006/05/28/48597.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/48597.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2006/05/28/48597.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/48597.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/48597.html</trackback:ping><description><![CDATA[
		<div>
				<font face="MS UI Gothic" size="2">
						<font color="#ff0000">1. 不要用TestCase的构造函数初始化Fixture，而要用<br />setUp()和tearDown()方法。</font>
				</font>
		</div>
		<div>
				<font face="MS UI Gothic" size="2">
						<font color="#ff0000">
								<br />
						</font>2. 不要依赖或假定测试运行的顺序，因为JUnit利用<br />Vector保存测试方法。所以不同的平台会按不同的<br />顺序从Vector中取出测试方法。 <br /><br /><font color="#ff0000"></font></font>
		</div>
		<div>
				<font face="MS UI Gothic" size="2">
						<font color="#ff0000">3. 避免编写有副作用的TestCase。例如：如果随后的<br />测试依赖于某些特定的交易数据，就不要提交交易数<br />据。简单的会滚就可以了。</font>
						<br />
				</font>
		</div>
		<div>
				<font face="MS UI Gothic" size="2">
						<font color="#ff0000">
								<br />  对于我们来说，有时是必须要提交，以至于有副作用的。</font>
				</font>
		</div>
		<div>
				<font face="MS UI Gothic" color="#ff0000" size="2">  例如：在执行“插入“后，数据库显然会多出一条数<br />据来。那么必须在随后每个测试自己消除自己的副<br />作用。</font>
		</div>
		<div>
				<font face="MS UI Gothic" color="#ff0000" size="2">  在这里，就是自己“再删除刚插入的数据”。（这时候<br />需要考虑到这个善后的工作不能自己就不能有副作用，</font>
		</div>
		<div>
				<font face="MS UI Gothic" color="#ff0000" size="2">  删除多了其他的数据）。</font>
		</div>
		<div>
				<font face="MS UI Gothic" color="#ff0000" size="2">
				</font> </div>
		<div>
				<font face="MS UI Gothic" color="#ff0000" size="2">  这里的副作用还指“影响到周围环境”，因为我们现<br />在工作的人比较多，所以最好大家的测试服务器能够<br />分开来，</font>
		</div>
		<div>
				<font face="MS UI Gothic" color="#ff0000" size="2"> 例如一个人一个Database实例（可以建得稍微小一<br />点）或者一个人一个数据库，</font>
				<font face="MS UI Gothic" color="#ff0000" size="2">  注意将这些个人之间<br />有区别的内容用常量在每个人自己的所有程序中公<br />用。而不是分布在各个位置。</font>
				<font face="MS UI Gothic" color="#ff0000" size="2">  否则以后要改换测试<br />服务器，所有的程序都需要改动。</font>
		</div>
		<div>
				<font face="MS UI Gothic" color="#ff0000" size="2">
				</font> </div>
		<div>
				<font face="MS UI Gothic" color="#ff0000" size="2">  为了保证测试程序能够很容易的到处执行，请保证<br />大家的数据库服务器的测试数据全部一致。</font>
				<font face="MS UI Gothic" color="#ff0000" size="2"> 否则，<br />就不能做到很容易得拿到FJ也可以很容易的运行，<br />所以需要准备“测试数据集“。</font>
				<font face="MS UI Gothic" color="#ff0000" size="2">包括：Schema ,table ，<br />stored procedure等数据库对象的结构一致，</font>
				<font face="MS UI Gothic" color="#ff0000" size="2"> 还包<br />括数据库的数据内容保持一致。</font>
		</div>
		<font face="MS UI Gothic" size="2">
				<div>
						<br />4. 当继承一个测试类时，记得调用父类的setUp()和<br />tearDown()方法。 </div>
				<div>
						<br />5. 将测试代码和工作代码放在一起，一边同步编译<br />和更新。（使用Ant中有支持junit的task.） </div>
				<div>
						<br />6. 测试类和测试方法应该有一致的命名方案。如在<br />工作类名前加上test从而形成测试类名。 </div>
				<div>
						<font color="#ff0000">可能这里我们需要改动，将函数名和我们的测试用<br />例的编号一致起来。</font>
				</div>
				<div>
						<br />7. 确保测试与时间无关，不要依赖使用过期的数据<br />进行测试。导致在随后的维护过程中很难重现测试。 </div>
				<div>
						<br />8. 如果你编写的软件面向国际市场，编写测试时要<br />考虑国际化的因素。不要仅用母语的Locale进行测试。 </div>
				<div>
						<br />9. 尽可能地利用JUnit提供地assert/fail方法以及<br />异常处理的方法，可以使代码更为简洁。 </div>
				<div> </div>
				<div>
						<font color="#ff0000">这个内容有其关键，assert语句的好坏直接影响<br />到测试的正确性。</font>
						<font color="#ff0000">因为assert就是用于当前测试<br />项的正确性的。</font>
				</div>
				<div>
						<br />10.测试要尽可能地小，执行速度快。 <br /><br /><br />==========<br />1）将所有的数据库的测试数据用ODBC程序自动<br />生成的。 <font face="MS UI Gothic" size="2">用户可以简单的</font><font face="MS UI Gothic" size="2">修改ConnectionString，<br />然后运行程序，就可以创建生成数</font><font face="MS UI Gothic" size="2">据库/数据库<br />表/存储结构</font><font face="MS UI Gothic" size="2">，并且自动插入数据。<br /></font><div><font face="MS UI Gothic" size="2"></font> </div><div><font face="MS UI Gothic" size="2">   2）为了保证多个测试人员的不干扰，建议分别<br />各自单独使用自己的数据</font><font face="MS UI Gothic" size="2">库。否则会因为一个自<br />己的错误，影响别人的工作。</font></div><div><font face="MS UI Gothic" size="2"></font> </div><div><font face="MS UI Gothic" size="2">   3）在自己的程序中，所有涉及环境的内容都用<br />单独放到一个类中，用static</font><font face="MS UI Gothic" size="2">常量共享使用（这样<br />就便于很容易的更换环境再进行测试，做到很容<br />易的移植</font><font face="MS UI Gothic" size="2">测试环境）。</font></div><div><font face="MS UI Gothic" size="2"></font> </div><div><font face="MS UI Gothic" size="2">   4）关于数据库表结构，我建议测试表中含有一<br />个主键，我们在插入数据的时</font><font face="MS UI Gothic" size="2">候，保证测试用例，<br />测试用例程序，测试用例程序中的数据，这三者<br />的编号一</font><font face="MS UI Gothic" size="2">致起来。便于出现问题时，可以排除数据。</font></div></div>
		</font>
<img src ="http://www.blogjava.net/jinfeng_wang/aggbug/48597.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2006-05-28 15:52 <a href="http://www.blogjava.net/jinfeng_wang/archive/2006/05/28/48597.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>数据库驱动程序测试的建议</title><link>http://www.blogjava.net/jinfeng_wang/archive/2006/05/28/48596.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Sun, 28 May 2006 07:32:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2006/05/28/48596.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/48596.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2006/05/28/48596.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/48596.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/48596.html</trackback:ping><description><![CDATA[
		<div>
				<font face="MS UI Gothic" size="2">
						<font color="#ff0000">1. 不要用TestCase的构造函数初始化Fixture，而要用<br />setUp()和tearDown()方法。</font>
				</font>
		</div>
		<div>
				<font face="MS UI Gothic" size="2">
						<font color="#ff0000">
								<br />
						</font>2. 不要依赖或假定测试运行的顺序，因为JUnit利用<br />Vector保存测试方法。所以不同的平台会按不同的<br />顺序从Vector中取出测试方法。 <br /><br /><font color="#ff0000"></font></font>
		</div>
		<div>
				<font face="MS UI Gothic" size="2">
						<font color="#ff0000">3. 避免编写有副作用的TestCase。例如：如果随后的<br />测试依赖于某些特定的交易数据，就不要提交交易<br />数据。简单的会滚就可以了。<br /></font>
						<br />
				</font>
		</div>
		<div>
				<font face="MS UI Gothic" size="2">
						<font color="#ff0000">  对于我们来说，有时是必须要提交，以至于有副作用的。</font>
				</font>
		</div>
		<div>
				<font face="MS UI Gothic" color="#ff0000" size="2">  例如：在执行“插入“后，数据库显然会多出一条数据来。<br />那么必须在随后每个测试自己消除自己的副作用。</font>
		</div>
		<div>
				<font face="MS UI Gothic" color="#ff0000" size="2">  在这里，就是自己“再删除刚插入的数据”。（这时候需要<br />考虑到这个善后的工作不能自己就不能有副作用，</font>
				<font face="MS UI Gothic" color="#ff0000" size="2">  删除<br />多了其他的数据）。</font>
		</div>
		<div>
				<font face="MS UI Gothic" color="#ff0000" size="2">
				</font> </div>
		<div>
				<font face="MS UI Gothic" color="#ff0000" size="2">  这里的副作用还指“影响到周围环境”，因为我们现在工<br />作的人比较多，所以最好大家的测试服务器能够分开来，</font>
		</div>
		<div>
				<font face="MS UI Gothic" color="#ff0000" size="2"> 例如一个人一个Database实例（可以建得稍微小一点）或<br />者一个人一个数据库，</font>
				<font face="MS UI Gothic" color="#ff0000" size="2">  注意将这些个人之间有区别的内<br />容用常量在每个人自己的所有程序中公用。而不是分布在<br />各个位置。</font>
				<font face="MS UI Gothic" color="#ff0000" size="2">  否则以后要改换测试服务器，所有的程序都需<br />要改动。</font>
		</div>
		<div>
				<font face="MS UI Gothic" color="#ff0000" size="2">
				</font> </div>
		<div>
				<font face="MS UI Gothic" color="#ff0000" size="2">  为了保证测试程序能够很容易的到处执行，请保证大家<br />的数据库服务器的测试数据全部一致。</font>
				<font face="MS UI Gothic" color="#ff0000" size="2"> 否则，就不能做到<br />很容易得拿到FJ也可以很容易的运行，所以需要准备“测<br />试数据集“。</font>
				<font face="MS UI Gothic" color="#ff0000" size="2">包括：Schema ,table ，stored procedure等数据<br />库对象的结构一致，</font>
				<font face="MS UI Gothic" color="#ff0000" size="2"> 还包括数据库的数据内容保持一致。</font>
		</div>
		<font face="MS UI Gothic" size="2">
				<div>
						<br />4. 当继承一个测试类时，记得调用父类的setUp()和tearDown()方法。 </div>
				<div>
						<br />5. 将测试代码和工作代码放在一起，一边同步编译和更新。<br />（使用Ant中有支持junit的task.） </div>
				<div>
						<br />6. 测试类和测试方法应该有一致的命名方案。如在工作类<br />名前加上test从而形成测试类名。 </div>
				<div>
						<font color="#ff0000">可能这里我们需要改动，将函数名和我们的测试用例的编号一致起来。</font>
				</div>
				<div>
						<br />7. 确保测试与时间无关，不要依赖使用过期的数据进行测试。<br />导致在随后的维护过程中很难重现测试。 </div>
				<div>
						<br />8. 如果你编写的软件面向国际市场，编写测试时要考虑国际<br />化的因素。不要仅用母语的Locale进行测试。 </div>
				<div>
						<br />9. 尽可能地利用JUnit提供地assert/fail方法以及异常处理的<br />方法，可以使代码更为简洁。 </div>
				<div> </div>
				<div>
						<font color="#ff0000">这个内容有其关键，assert语句的好坏直接影响到测试的正确性。</font>
				</div>
				<div>
						<font color="#ff0000">因为assert就是用于当前测试项的正确性的。</font>
				</div>
				<div>
						<br />10.测试要尽可能地小，执行速度快。 <br /><br />=============<br /> 1）将所有的数据库的测试数据程序自动生成的。 
<div><font face="MS UI Gothic" size="2">用户可以简单的</font><font face="MS UI Gothic" size="2">修改ConnectionString，然后运行程序，<br />就可以创建生成数</font><font face="MS UI Gothic" size="2">据库/数据库表/存储结构</font><font face="MS UI Gothic" size="2">，并且自动<br />插入数据。 <br /></font><font face="MS UI Gothic" size="2"></font></div><div><font face="MS UI Gothic" size="2"><br />   2）为了保证多个测试人员的不干扰，建议分别各自<br />单独使用自己的数据</font><font face="MS UI Gothic" size="2">库。否则会因为一个自己的错误，<br />影响别人的工作。</font></div><div><font face="MS UI Gothic" size="2"></font> </div><div><font face="MS UI Gothic" size="2">   3）在自己的程序中，所有涉及环境的内容都用单独<br />放到一个类中，用static</font><font face="MS UI Gothic" size="2">常量共享使用（这样就便于很<br />容易的更换环境再进行测试，做到很容易的移植</font><font face="MS UI Gothic" size="2">测试<br />环境）。</font></div><div><font face="MS UI Gothic" size="2"></font> </div><div><font face="MS UI Gothic" size="2">   4）关于数据库表结构，我建议测试表中含有一个主键，<br />我们在插入数据的时</font><font face="MS UI Gothic" size="2">候，保证测试用例，测试用例程序，<br />测试用例程序中的数据，这三者的编号一</font><font face="MS UI Gothic" size="2">致起来。便于<br />出现问题时，可以排除数据。</font></div></div>
		</font>
<img src ="http://www.blogjava.net/jinfeng_wang/aggbug/48596.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2006-05-28 15:32 <a href="http://www.blogjava.net/jinfeng_wang/archive/2006/05/28/48596.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>测试、构建和重构(zz)</title><link>http://www.blogjava.net/jinfeng_wang/archive/2006/04/26/43358.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Wed, 26 Apr 2006 08:52:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2006/04/26/43358.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/43358.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2006/04/26/43358.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/43358.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/43358.html</trackback:ping><description><![CDATA[
		<div class="entrylistTitle">测试、构建和重构</div>
		<div class="entrylistDescription">
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl00_TitleUrl" href="http://www.cnblogs.com/confach/archive/2005/06/20/177817.html" target="_blank">NUnit2.0详细使用方法</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl01_TitleUrl" href="http://www.cnblogs.com/excel/archive/2005/06/17/176100.html" target="_blank">重构啊重构</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl02_TitleUrl" href="http://www.cnblogs.com/snowwolf/archive/2004/06/18/16644.html" target="_blank">.Net Code Cover</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl03_TitleUrl" href="http://www.cnblogs.com/william_fire/archive/2004/11/15/63867.html" target="_blank">让代码更具有可测试性</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl04_TitleUrl" href="http://www.cnblogs.com/anf/archive/2005/03/20/122342.html" target="_blank">NMock --- 从零开始</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl05_TitleUrl" href="http://www.cnblogs.com/jiezhi/archive/2005/04/28/146779.html" target="_blank">Unit Test : rules,design and strategy</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl06_TitleUrl" href="http://blog.joycode.com/musicland/archive/2005/04/16/48690.aspx" target="_blank">Concurrent connection limit</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl07_TitleUrl" href="http://www.cnblogs.com/iaxes/articles/121158.html" target="_blank">Log4Net Appender 之 ADONetAppender</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl08_TitleUrl" href="http://www.cnblogs.com/dahuzizyd/archive/2005/03/04/112566.html" target="_blank">Bug管理的流程和几个重点</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl09_TitleUrl" href="http://blog.joycode.com/ghj/articles/44720.aspx" target="_blank">把单元测试代码跟项目代码放在一个工程中</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl10_TitleUrl" href="http://www.cnblogs.com/java_aix/archive/2005/02/10/103717.html" target="_blank">Subversion配置安装教程（三） </a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl11_TitleUrl" href="http://www.cnblogs.com/java_aix/archive/2005/02/09/103500.html" target="_blank">Subversion配置安装教程（二） </a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl12_TitleUrl" href="http://www.cnblogs.com/java_aix/archive/2005/02/08/103399.html" target="_blank">Subversion配置安装教程（一）</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl13_TitleUrl" href="http://www.cnblogs.com/william_fire/articles/102245.html" target="_blank">敏捷（AM）：TDD(Test Driven Development）实践与变化--&gt;TAD（Test Assist Development)</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl14_TitleUrl" href="http://blog.joycode.com/uestc95/archive/2005/01/14/43057.aspx" target="_blank">如何在*.CS文件中加入版本跟踪信息？</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl15_TitleUrl" href="http://www.cnblogs.com/xchunyu/archive/2005/01/12/90425.html" target="_blank">推荐一个关于"架构"的演示文稿(PPT)</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl16_TitleUrl" href="http://blog.joycode.com/oldsidney/archive/2005/01/06/42468.aspx" target="_blank">什麼是 LoadRunner？ </a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl17_TitleUrl" href="http://www.cnblogs.com/dudu/archive/2004/12/18/78838.html" target="_blank">推荐一个不错的VS.NET集成单元测试工具TestDriven.NET</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl18_TitleUrl" href="http://www.cnblogs.com/bigtall/archive/2004/11/24/68126.html" target="_blank">实战dailybuild-cc.net的配置</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl19_TitleUrl" href="http://www.cnblogs.com/netcobra/archive/2004/11/24/68204.html" target="_blank">[翻译] NMock 两分钟教程</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl20_TitleUrl" href="http://www.cnblogs.com/netcobra/archive/2004/11/24/68199.html" target="_blank">[翻译] NMock 简介</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl21_TitleUrl" href="http://www.cnblogs.com/william_fire/archive/2004/11/15/64111.html" target="_blank">测试驱动开的的实例</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl22_TitleUrl" href="http://www.cnblogs.com/William_Fire/archive/2004/11/15/63867.html" target="_blank">让代码更具有可测试性</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl23_TitleUrl" href="http://www.cnblogs.com/rickie/archive/2004/11/08/61311.html" target="_blank">重构（Refactoring）技巧读书笔记 之三 </a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl24_TitleUrl" href="http://pfzhou.cnblogs.com/pvistely/archive/2004/11/11/62600.html" target="_blank">第一次用CVS后的流程小结（其实VSS也一样）</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl25_TitleUrl" href="http://pfzhou.cnblogs.com/airforce1st/archive/2004/10/22/55303.html" target="_blank">我也再补充一个NANT使用注意事项</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl26_TitleUrl" href="http://pfzhou.cnblogs.com/rickie/archive/2004/10/04/48859.aspx" target="_blank">重构（Refactoring）技巧读书笔记 之二</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl27_TitleUrl" href="http://pfzhou.cnblogs.com/rickie/archive/2004/09/25/46577.aspx" target="_blank">重构（Refactoring）技巧读书笔记 之一</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl28_TitleUrl" href="http://blog.csdn.net/ycw/archive/2004/09/05/95076.aspx" target="_blank">Bugzilla简明使用手则</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl29_TitleUrl" href="http://pfzhou.cnblogs.com/ccBoy/archive/2004/08/31/38140.aspx" target="_blank">Daily Build 的链接</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl30_TitleUrl" href="http://pfzhou.cnblogs.com/muddle/archive/2004/04/20/6673.aspx" target="_self">Test-Driven Development In .NET 部分译文</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl31_TitleUrl" href="http://pfzhou.cnblogs.com/feidao/archive/2004/06/19/17050.aspx" target="_blank">有关于Refactor(重构)与Source(源)的比较</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl32_TitleUrl" href="http://pfzhou.cnblogs.com/coolbug/archive/2004/07/26/27367.aspx" target="_blank">终于完成了DailyBuild</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl33_TitleUrl" href="http://pfzhou.cnblogs.com/ccBoy/archive/2004/07/26/27363.aspx" target="_blank">用MSBuild.... DailyBuild和软件开发流程的东东</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl34_TitleUrl" href="http://pfzhou.cnblogs.com/coolbug/archive/2004/07/27/27735.aspx" target="_blank">DailyBuild全攻略</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl35_TitleUrl" href="http://pfzhou.cnblogs.com/unruledboy/archive/2004/08/13/33227.aspx" target="_blank">关于Peer Review、代码评审和测试驱动等</a>
				</h5>
		</div>
		<div class="post">
				<h5>
						<a id="FavoriteList1_Favorites_ctl36_TitleUrl" href="http://pfzhou.cnblogs.com/jobs/archive/2004/08/13/33065.aspx" target="_blank">测试开发驱动实践</a>
				</h5>
		</div>
<img src ="http://www.blogjava.net/jinfeng_wang/aggbug/43358.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2006-04-26 16:52 <a href="http://www.blogjava.net/jinfeng_wang/archive/2006/04/26/43358.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>追求代码质量: 不要被覆盖报告所迷惑(zz)</title><link>http://www.blogjava.net/jinfeng_wang/archive/2006/04/26/43340.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Wed, 26 Apr 2006 08:24:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2006/04/26/43340.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/43340.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2006/04/26/43340.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/43340.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/43340.html</trackback:ping><description><![CDATA[
		<blockquote>测试覆盖工具对单元测试具有重要的意义，但是经常被误用。这个月，Andrew Glover 会在他的新系列 —— <i>追求代码质量</i> 中向您介绍值得参考的专家意见。第一部分深入地介绍覆盖报告中数字的真实含义。然后他会提出您可以尽早并经常地利用覆盖来确保代码质量的三个方法。</blockquote>
		<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
		<!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->
		<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
		<p>您还记得以前大多数开发人员是如何追求代码质量的吗。在那时，有技巧地放置 <code>main()</code> 方法被视为灵活且适当的测试方法。经历了漫长的道路以后，现在自动测试已经成为高质量代码开发的基本保证，对此我很感谢。但是这还不是我所要感谢的全部。Java™ 开发人员现在拥有很多通过代码度量、静态分析等方法来度量代码质量的工具。我们甚至已经设法将重构分类成一系列便利的模式！</p>
		<table cellspacing="0" cellpadding="0" width="40%" align="right" border="0">
				<tbody>
						<tr>
								<td width="10">
										<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" />
								</td>
								<td>
										<table cellspacing="0" cellpadding="5" width="100%" border="1">
												<tbody>
														<tr>
																<td bgcolor="#eeeeee">要获得有关代码质量问题的答案，您可以访问由 Andrew Glover 主持的 <a href="http://www.ibm.com/developerworks/forums/dw_forum.jsp?forum=812&amp;cat=10"><font color="#5c81a7">Code Quality</font></a> 论坛。 </td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>所有的这些新的工具使得确保代码质量比以前简单得多，不过您还需要知道如何使用它们。在这个系列中，我将重点阐述有关保证代码质量的一些有时看上去有点神秘的东西。除了带您一起熟悉有关代码质量保证的众多工具和技术之外，我还将为您说明：</p>
		<ul>
				<li>定义并有效度量最影响质量的代码方面。 
</li>
				<li>设定质量保证目标并照此规划您的开发过程。 
</li>
				<li>确定哪个代码质量工具和技术可以满足您的需要。 
</li>
				<li>实现最佳实践（清除不好的），使确保代码质量<i>及早并经常地</i> 成为开发实践中轻松且有效的方面。 </li>
		</ul>
		<p>在这个月，我将首先看看 Java 开发人员中最流行也是最容易的质量保证工具包：测试覆盖度量。</p>
		<p>
				<a name="N1008B">
						<span class="atitle">
								<font face="Arial" size="4">谨防上当</font>
						</span>
				</a>
		</p>
		<p>这是一个晚上鏖战后的早晨，大家都站在饮水机边上。开发人员和管理人员们了解到一些经过良好测试的类可以达到超过 90% 的覆盖率，正在高兴地互换着 NFL 风格的点心。团队的集体信心空前高涨。从远处可以听到 “放任地重构吧” 的声音，似乎缺陷已成为遥远的记忆，响应性也已微不足道。但是一个很小的反对声在说：</p>
		<p>
				<i>女士们，先生们，不要被覆盖报告所愚弄</i>。</p>
		<p>现在，不要误解我的意思：并不是说使用测试覆盖工具是愚蠢的。对单元测试范例，它是很重要的。不过更重要的是您如何理解所得到的信息。许多开发团队会在这儿犯第一个错。</p>
		<p>高覆盖率只是表示执行了很多的代码，并不意味着这些代码被<i>很好地</i> 执行。如果您关注的是代码的质量，就必须精确地理解测试覆盖工具能做什么，不能做什么。然后您才能知道如何使用这些工具去获取有用的信息。而不是像许多开发人员那样，只是满足于高覆盖率。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N100A2">
						<span class="atitle">
								<font face="Arial" size="4">测试覆盖度量</font>
						</span>
				</a>
		</p>
		<p>测试覆盖工具通常可以很容易地添加到确定的单元测试过程中，而且结果可靠。下载一个可用的工具，对您的 Ant 和 Maven 构建脚本作一些小的改动，您和您的同事就有了在饮水机边上谈论的一种新报告：<i>测试覆盖报告</i>。当 <code>foo</code> 和 <code>bar</code> 这样的程序包令人惊奇地显示<i>高</i> 覆盖率时，您可以得到不小的安慰。如果您相信至少您的部分代码可以保证是 “没有 BUG” 的，您会觉得很安心。但是这样做是一个错误。</p>
		<p>存在不同类型的覆盖度量，但是绝大多数的工具会关注<i>行覆盖</i>，也叫做<i>语句覆盖</i>。此外，有些工具会报告<i>分支覆盖</i>。通过用一个测试工具执行代码库并捕获整个测试过程中与被 “触及” 的代码对应的数据，就可以获得测试覆盖度量。然后这些数据被合成为覆盖报告。在 Java 世界中，这个测试工具通常是 JUnit 以及名为 Cobertura、Emma 或 Clover 等的覆盖工具。</p>
		<p>
				<i>行覆盖</i>只是指出代码的哪些行被执行。如果一个方法有 10 行代码，其中的 8 行在测试中被执行，那么这个方法的行覆盖率是 80%。这个过程在总体层次上也工作得很好：如果一个类有 100 行代码，其中的 45 行被触及，那么这个类的行覆盖率就是 45%。同样，如果一个代码库包含 10000 个非注释性的代码行，在特定的测试运行中有 3500 行被执行，那么这段代码的行覆盖率就是 35%。</p>
		<p>报告<i>分支覆盖</i> 的工具试图度量决策点（比如包含逻辑 <code>AND</code> 或 <code>OR</code> 的条件块）的覆盖率。与行覆盖一样，如果在特定方法中有两个分支，并且两个分支在测试中都被覆盖，那么您可以说这个方法有 100% 的分支覆盖率。</p>
		<p>问题是，这些度量有什么用？很明显，很容易获得所有这些信息，不过您需要知道如何使用它们。一些例子可以阐明我的观点。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N100DB">
						<span class="atitle">
								<font face="Arial" size="4">代码覆盖在活动</font>
						</span>
				</a>
		</p>
		<p>我在清单 1 中创建了一个简单的类以具体表述类层次的概念。一个给定的类可以有一连串的父类，例如 <code>Vector</code>，它的父类是 <code>AbstractList</code>，<code>AbstractList</code> 的父类又是 <code>AbstractCollection</code>，<code>AbstractCollection</code> 的父类又是 <code>Object</code>：</p>
		<br />
		<a name="code1">
				<b>清单 1. 表现类层次的类</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">package com.vanward.adana.hierarchy;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class Hierarchy {
  private Collection classes;
  private Class baseClass;

  public Hierarchy() {
    super();
    this.classes = new ArrayList();
  }

  public void addClass(final Class clzz){
    this.classes.add(clzz);
  }
  /**
   * @return an array of class names as Strings
   */
  public String[] getHierarchyClassNames(){
    final String[] names = new String[this.classes.size()];        
    int x = 0;
    for(Iterator iter = this.classes.iterator(); iter.hasNext();){
       Class clzz = (Class)iter.next();
       names[x++] = clzz.getName();
    }        
    return names;
  }

  public Class getBaseClass() {
    return baseClass;
  }

  public void setBaseClass(final Class baseClass) {
    this.baseClass = baseClass;
  }
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>正如您看到的，清单 1 中的 <code>Hierarchy</code> 类具有一个 <code>baseClass</code> 实例以及它的父类的集合。清单 2 中的 <code>HierarchyBuilder</code> 通过两个复制 <code>buildHierarchy</code> 的重载的 <code>static</code> 方法创建了 <code>Hierarchy</code> 类。</p>
		<br />
		<a name="code2">
				<b>清单 2. 类层次生成器</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">package com.vanward.adana.hierarchy;

public class HierarchyBuilder {  

  private HierarchyBuilder() {
    super();		
  }

  public static Hierarchy buildHierarchy(final String clzzName) 
    throws ClassNotFoundException{
      final Class clzz = Class.forName(clzzName, false, 
          HierarchyBuilder.class.getClassLoader());        
      return buildHierarchy(clzz);
  }

  public static Hierarchy buildHierarchy(Class clzz){
    if(clzz == null){
      throw new RuntimeException("Class parameter can not be null");
    }

    final Hierarchy hier = new Hierarchy();
    hier.setBaseClass(clzz);

    final Class superclass = clzz.getSuperclass();

    if(superclass != 
      null &amp;&amp; superclass.getName().equals("java.lang.Object")){
       return hier; 
    }else{      
       while((clzz.getSuperclass() != null) &amp;&amp; 
          (!clzz.getSuperclass().getName().equals("java.lang.Object"))){
             clzz = clzz.getSuperclass();
             hier.addClass(clzz);
       }	        
       return hier;
    }
  }      
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<font face="Lucida Console">
												<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
												<br />
												<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
										</font>
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<font face="Lucida Console">
												<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
												<br />
										</font>
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<font face="Lucida Console">
																				<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																				<br />
																		</font>
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1012B">
						<span class="atitle">
								<font face="Arial" size="4">现在是测试时间！</font>
						</span>
				</a>
		</p>
		<p>有关测试覆盖的文章怎么能缺少测试案例呢？在清单 3 中，我定义了一个简单的有三个测试案例的 JUnit 测试类，它将试图执行 <code>Hierarchy</code> 类和 <code>HierarchyBuilder</code> 类：</p>
		<br />
		<a name="code3">
				<b>清单 3. 测试 HierarchyBuilder！</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">package test.com.vanward.adana.hierarchy;

import com.vanward.adana.hierarchy.Hierarchy;
import com.vanward.adana.hierarchy.HierarchyBuilder;
import junit.framework.TestCase;

public class HierarchyBuilderTest extends TestCase {
  
  public void testBuildHierarchyValueNotNull() {        
     Hierarchy hier = HierarchyBuilder.buildHierarchy(HierarchyBuilderTest.class);
     assertNotNull("object was null", hier);
  }

  public void testBuildHierarchyName() {        
     Hierarchy hier = HierarchyBuilder.buildHierarchy(HierarchyBuilderTest.class);
     assertEquals("should be junit.framework.Assert", 
       "junit.framework.Assert", 
         hier.getHierarchyClassNames()[1]);      
  }

  public void testBuildHierarchyNameAgain() {        
     Hierarchy hier = HierarchyBuilder.buildHierarchy(HierarchyBuilderTest.class);
     assertEquals("should be junit.framework.TestCase", 
       "junit.framework.TestCase", 
         hier.getHierarchyClassNames()[0]);      
  }
 
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>因为我是一个狂热的测试人员，我自然希望运行一些覆盖测试。对于 Java 开发人员可用的代码覆盖工具中，我比较喜欢用 Cobertura，因为它的报告很友好。而且，Corbertura 是开放源码项目，它派生出了 JCoverage 项目的前身。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10149">
						<span class="atitle">
								<font face="Arial" size="4">Cobertura 的报告</font>
						</span>
				</a>
		</p>
		<p>运行 Cobertura 这样的工具和运行您的 JUnit 测试一样简单，只是有一个用专门逻辑在测试时检查代码以报告覆盖率的中间步骤（这都是通过工具的 Ant 任务或 Maven 的目标完成的）。</p>
		<p>正如您在图 1 中看到的，<code>HierarchyBuilder</code> 的覆盖报告说明部分代码<i>没有</i> 被执行。事实上，Cobertura 认为 <code>HierarchyBuilder</code> 的行覆盖率为 59%，分支覆盖率为 75%。</p>
		<br />
		<a name="N10162">
				<b>图 1. Cobertura 的报告</b>
		</a>
		<br />
		<img height="718" alt="" src="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/coverage-01-1.gif" width="572" border="0" />
		<br />
		<p>这样看来，我的第一次覆盖测试是失败的。首先，带有 <code>String</code> 参数的 <code>buildHierarchy()</code> 方法根本没有被测试。其次，另一个 <code>buildHierarchy()</code> 方法中的两个条件都没有被执行。有趣的是，所要关注的正是第二个没有被执行的 <code>if</code> 块。</p>
		<p>因为我所需要做的只是增加一些测试案例，所以我并不担心这一点。一旦我到达了所关注的区域，我就可以很好地完成工作。注意我这儿的逻辑：我使用测试报告来了解什么<i>没有</i> 被测试。现在我已经可以选择使用这些数据来增强测试或者继续工作。在本例中，我准备增强我的测试，因为我还有一些重要的区域未覆盖。</p>
		<p>
				<a name="N1018A">
						<span class="smalltitle">
								<strong>
										<font face="Arial">Cobertura：第二轮</font>
								</strong>
						</span>
				</a>
		</p>
		<p>清单 4 是一个更新过的 JUnit 测试案例，增加了一些附加测试案例，以试图完全执行 <code>HierarchyBuilder</code>： </p>
		<br />
		<a name="code4">
				<b>清单 4. 更新过的 JUnit 测试案例</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">package test.com.vanward.adana.hierarchy;

import com.vanward.adana.hierarchy.Hierarchy;
import com.vanward.adana.hierarchy.HierarchyBuilder;
import junit.framework.TestCase;

public class HierarchyBuilderTest extends TestCase {
  
  public void testBuildHierarchyValueNotNull() {        
     Hierarchy hier = HierarchyBuilder.buildHierarchy(HierarchyBuilderTest.class);
     assertNotNull("object was null", hier);
  }

  public void testBuildHierarchyName() {        
     Hierarchy hier = HierarchyBuilder.buildHierarchy(HierarchyBuilderTest.class);
     assertEquals("should be junit.framework.Assert", 
       "junit.framework.Assert", 
         hier.getHierarchyClassNames()[1]);      
  }

  public void testBuildHierarchyNameAgain() { zo       
     Hierarchy hier = HierarchyBuilder.buildHierarchy(HierarchyBuilderTest.class);
     assertEquals("should be junit.framework.TestCase", 
       "junit.framework.TestCase", 
         hier.getHierarchyClassNames()[0]);      
  }

  public void testBuildHierarchySize() {        
     Hierarchy hier = HierarchyBuilder.buildHierarchy(HierarchyBuilderTest.class);
     assertEquals("should be 2", 2, hier.getHierarchyClassNames().length);
  }

  public void testBuildHierarchyStrNotNull() throws Exception{
    Hierarchy hier = 
       HierarchyBuilder.
       buildHierarchy("test.com.vanward.adana.hierarchy.HierarchyBuilderTest");
    assertNotNull("object was null", hier);
  }

  public void testBuildHierarchyStrName() throws Exception{        
    Hierarchy hier = 
       HierarchyBuilder.
       buildHierarchy("test.com.vanward.adana.hierarchy.HierarchyBuilderTest");
    assertEquals("should be junit.framework.Assert", 
      "junit.framework.Assert",
        hier.getHierarchyClassNames()[1]);
  }

  public void testBuildHierarchyStrNameAgain() throws Exception{
    Hierarchy hier = 
       HierarchyBuilder.
       buildHierarchy("test.com.vanward.adana.hierarchy.HierarchyBuilderTest");
    assertEquals("should be junit.framework.TestCase", 
      "junit.framework.TestCase",
        hier.getHierarchyClassNames()[0]);      
  }

  public void testBuildHierarchyStrSize() throws Exception{        
     Hierarchy hier = 
        HierarchyBuilder.
        buildHierarchy("test.com.vanward.adana.hierarchy.HierarchyBuilderTest");
     assertEquals("should be 2", 2, hier.getHierarchyClassNames().length);        
  }

  public void testBuildHierarchyWithNull() {
     try{
       Class clzz = null;
       HierarchyBuilder.buildHierarchy(clzz);
       fail("RuntimeException not thrown");
     }catch(RuntimeException e){}
  }
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>当我使用新的测试案例再次执行测试覆盖过程时，我得到了如图 2 所示的更加完整的报告。现在，我覆盖了未测试的 <code>buildHierarchy()</code> 方法，也处理了另一个 <code>buildHierarchy()</code> 方法中的两个 <code>if</code> 块。然而，因为 <code>HierarchyBuilder</code> 的构造器是 <code>private</code> 类型的，所以我不能通过我的测试类测试它（我也不关心）。因此，我的行覆盖率仍然只有 88%。</p>
		<br />
		<a name="N101BA">
				<b>图 2. 谁说没有第二次机会</b>
		</a>
		<br />
		<img height="709" alt="" src="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/coverage-01.gif" width="569" border="0" />
		<br />
		<p>正如您看到的，使用一个代码覆盖工具<i>可以</i> 揭露重要的没有相应测试案例的代码。重要的事情是，在阅读报告（<i>特别</i> 是覆盖率高的）时需要小心，它们也许隐含危险的信息。让我们看看两个例子，看看在高覆盖率后面隐藏着什么。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N101D2">
						<span class="atitle">
								<font face="Arial" size="4">条件带来的麻烦</font>
						</span>
				</a>
		</p>
		<p>正如您已经知道的，代码中的许多变量可能有多种状态；此外，条件的存在使得执行有多条路径。在留意这些问题之后，我将在清单 5 中定义一个极其简单只有一个方法的类：</p>
		<br />
		<a name="code5">
				<b>清单 5.您能看出下面的缺陷吗？ </b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">package com.vanward.coverage.example01;

public class PathCoverage {

  public String pathExample(boolean condition){
    String value = null;
    if(condition){
      value = " " + condition + " ";
    }
    return value.trim();
  }
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>您是否发现了清单 5 中有一个隐藏的缺陷呢？如果没有，不要担心，我会在清单 6 中写一个测试案例来执行 <code>pathExample()</code> 方法并确保它正确地工作： </p>
		<br />
		<a name="code1">
				<b>清单 6. JUnit 来救援！ </b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">package test.com.vanward.coverage.example01;

import junit.framework.TestCase;
import com.vanward.coverage.example01.PathCoverage;

public class PathCoverageTest extends TestCase {

  public final void testPathExample() {
    PathCoverage clzzUnderTst = new PathCoverage();
    String value = clzzUnderTst.pathExample(true);
    assertEquals("should be true", "true", value);
  }
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>我的测试案例正确运行，我的神奇的代码覆盖报告（如下面图 3 所示）使我看上去像个超级明星，测试覆盖率达到了 100%！</p>
		<br />
		<a name="#figure3">
				<b>图 3. 覆盖率明星 </b>
		</a>
		<br />
		<img height="399" alt="" src="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/coverage-ex01.gif" width="515" border="0" />
		<br />
		<p>我想现在应该到饮水机边上去说了，但是等等，我不是怀疑代码中有什么缺陷呢？认真检查清单 5 会发现，如果 <code>condition</code> 为 <code>false</code>，那么第 13 行确实会抛出 <code>NullPointerException</code>。<i>Yeesh</i>，这儿发生了什么？</p>
		<p>这表明行覆盖的确不能很好地指示测试的有效性。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N1021F">
						<span class="atitle">
								<font face="Arial" size="4">路径的恐怖</font>
						</span>
				</a>
		</p>
		<p>在清单 7 中，我定义了另一个包含 <i>indirect</i> 的简单例子，它仍然有不能容忍的缺陷。请注意 <code>branchIt()</code> 方法中 <code>if</code> 条件的后半部分。（<code>HiddenObject</code> 类将在清单 8 中定义。）</p>
		<br />
		<a name="code1">
				<b>清单 7. 这个代码足够简单</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">package com.vanward.coverage.example02;

import com.acme.someotherpackage.HiddenObject;

public class AnotherBranchCoverage {
   
  public void branchIt(int value){
    if((value &gt; 100) || (HiddenObject.doWork() == 0)){
      this.dontDoIt();
    }else{
      this.doIt();
    }
  }                             

  private void dontDoIt(){
    //don't do something...
  }

  private void doIt(){
    //do something!
  }   
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>呀！清单 8 中的 <code>HiddenObject</code> 是<i>有害的</i>。与清单 7 中一样，调用 <code>doWork()</code> 方法会导致 <code>RuntimeException</code>：</p>
		<br />
		<a name="code1">
				<b>清单 8. 上半部分！ </b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">package com.acme.someotherpackage.HiddenObject;

public class HiddenObject {

  public static int doWork(){
    //return 1;
    throw new RuntimeException("surprise!");
  }
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>但是我的确可以通过一个良好的测试捕获这个异常！在清单 9 中，我编写了另一个好的测试，以图挽回我的超级明星光环：</p>
		<br />
		<a name="code1">
				<b>清单 9. 使用 JUnit 规避风险</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1">
				<tbody>
						<tr>
								<td>
										<pre>
												<code class="section">
														<font face="Lucida Console">package test.com.vanward.coverage.example02;

import junit.framework.TestCase;
import com.vanward.coverage.example02.AnotherBranchCoverage;

public class AnotherBranchCoverageTest extends TestCase {
    
  public final void testBranchIt() {
    AnotherBranchCoverage clzzUnderTst = new AnotherBranchCoverage();
    clzzUnderTst.branchIt(101);
  }    
}
</font>
												</code>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>您对这个测试案例有什么想法？您也许会写出更多的测试案例，但是请设想一下清单 7 中不确定的条件有不止一个的缩短操作会如何。设想如果前半部分中的逻辑比简单的 <code>int</code> 比较更复杂，那么<i>您</i> 需要写多少测试案例才能满意？</p>
		<p>
				<a name="N10274">
						<span class="smalltitle">
								<strong>
										<font face="Arial">仅仅给我数字</font>
								</strong>
						</span>
				</a>
		</p>
		<p>现在，对清单 7、8、9 的测试覆盖率的分析结果不再会使您感到惊讶。在图 4 的报告中显示我达到了 75% 的行覆盖率和 100% 的分支覆盖率。最重要的是，我执行了第 10 行！</p>
		<br />
		<a name="N1027F">
				<b>图 4.愚弄的报酬</b>
		</a>
		<br />
		<img height="497" alt="" src="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/coverage-ex02.gif" width="528" border="0" />
		<br />
		<p>从第一印象看，这让我骄傲。但是这个报告有什么误导吗？只是粗略地看一看报告中的数字，会导致您相信代码是经过<i>良好测试的</i>。基于这一点，您也许会认为出现缺陷的风险很低。这个报告并不能帮助您确定 <code>or</code> 缩短操作的后半部分是一个定时炸弹！</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10298">
						<span class="atitle">
								<font face="Arial" size="4">质量测试</font>
						</span>
				</a>
		</p>
		<p>我不止一次地说：您可以（而且应该）使用测试覆盖工具作为您的测试过程的一部分。但是<i>不要被覆盖报告所愚弄</i>。关于覆盖报告您需要了解的主要事情是，覆盖报告最好用来检查哪些代码<i>没有经过</i> 充分的测试。当您检查覆盖报告时，找出较低的值，并了解为什么特定的代码没有经过充分的测试。知道这些以后，开发人员、管理人员以及 QA 专业人员就可以在真正需要的地方使用测试覆盖工具。通常有下列三种情况：</p>
		<ul>
				<li>估计修改已有代码所需的时间 
</li>
				<li>评估代码质量 
</li>
				<li>评定功能测试 </li>
		</ul>
		<p>现在我可以断定对测试覆盖报告的一些使用方法会将您引入歧途，下面这些最佳实践可以使得测试覆盖报告可以真正为您所用。</p>
		<p>
				<a name="N102B6">
						<span class="smalltitle">
								<strong>
										<font face="Arial">1. 估计修改已有代码所需的时间</font>
								</strong>
						</span>
				</a>
		</p>
		<p>对一个开发团队而言，针对代码编写测试案例自然可以增加集体的信心。与没有相应测试案例的代码相比，经过测试的代码更容易重构、维护和增强。测试案例因为暗示了代码在测试工作中是<i>如何</i> 工作的，所以还可以充当内行的文档。此外，如果被测试的代码发生改变，测试案例通常也会作相应的改变，这与诸如注释和 Javadoc 这样的静态代码文档不同。</p>
		<p>在另一方面，没有经过相应测试的代码更难于理解和<i>安全地</i> 修改。因此，知道代码有没有被测试，并看看实际的测试覆盖数值，可以让开发人员和管理人员更准确地预知修改已有代码所需的时间。</p>
		<p>再次回到饮水机边上，可以更好地阐明我的观点。</p>
		<blockquote>市场部的 Linda：“我们想让系统在用户完成一笔交易时做 <i>x</i> 工作。这需要多长时间。我们的用户需要尽快实现这一功能。” <br /><br />管理人员 Jeff：“让我看看，这个代码是 Joe 在几个月前编写的，需要对业务层和 UI 做一些变动。Mary 也许可以在两天内完成这项工作。” <br /><br />Linda：“Joe？他是谁？” <br /><br />Jeff：“哦，Joe，因为他不知道自己在干什么，所以被我解雇了。” </blockquote>
		<p>情况似乎有点不妙，不是吗？尽管如此，Jeff 还是将任务分配给了 Mary，Mary 也认为能够在两天内完成工作 —— 确切地说，在看到代码之前她是这么认为的。</p>
		<blockquote>Mary：“Joe 写这些代码时是不是<i>睡着了</i>？这是我所见过的最差的代码。我甚至不能确认这是 Java 代码。除非推倒重来，要不我根本没法修改。” </blockquote>
		<p>情况对 “饮水机” 团队不妙，不是吗？但是我们假设，如果在这个不幸的事件的当初，Jeff 和 Mary 就拥有一份测试报告，那么情况会如何呢？当 Linda 要求实现新功能时，Jeff 做的第一件事就是检查以前生成的覆盖报告。注意到需要改动的软件包几乎没有被覆盖，然后他就会与 Mary 商量。</p>
		<blockquote>Jeff：“Joe 编写的这个代码很差，绝大多数没经过测试。您认为要支持 Linda 所说的功能需要多长时间？” <br /><br />Mary：“这个代码很混乱。我甚至都不想看到它。为什么不让 Mark 来做呢？” <br /><br />Jeff：“因为 Mark 不编写测试，刚被我解雇了。我需要您测试这个代码并作一些改动。告诉我您需要多长时间。” <br /><br />Mary：“我至少需要两天编写测试，然后我会重构这个代码，增加新的功能。我想总共需要四天吧。” </blockquote>
		<p>正如他们所说的，知识的力量是强大的。开发人员可以在试图修改代码<i>之前</i> 使用覆盖报告来检查代码质量。同样，管理人员可以使用覆盖数据更好地估计开发人员实际所需的时间。</p>
		<p>
				<a name="N102F8">
						<span class="smalltitle">
								<strong>
										<font face="Arial">2. 评估代码质量</font>
								</strong>
						</span>
				</a>
		</p>
		<p>开发人员的测试可以降低代码中存在缺陷的风险，因此现在很多开发团队在新开发和更改代码的同时需要编写单元测试。然而正如前面所提到的 Mark 一样，并不总是在编码的同时进行单元测试，因而会导致低质量代码的出现。</p>
		<p>监控覆盖报告可以帮助开发团队迅速找出不断增长的<i>没有</i> 相应测试的代码。例如，在一周开始时运行覆盖报告，显示项目中一个关键的软件包的覆盖率是 70%。如果几天后，覆盖率下降到了 60%，那么您可以推断：</p>
		<ul>
				<li>软件包的代码行增加了，但是没有为新代码编写相应的测试（或者是新增加的测试不能有效地覆盖新代码）。<br /><br /></li>
				<li>删除了测试案例。<br /><br /></li>
				<li>上述两种情况都发生了。 </li>
		</ul>
		<p>能够监控事情的发展，无疑是件好事。定期地查阅报告使得设定目标（例如获得覆盖率、维护代码行的测试案例的比例等）并监控事情的发展变得更为容易。如果您发现测试没有如期编写，您可以提前采取一些行动，例如对开发人员进行培训、指导或帮助。与其让用户 “在使用中” 发现程序缺陷（这些缺陷本应该在几个月前通过简单的测试暴露出来），或者等到管理人员发现没有编写单元测试时再感到惊讶（和愤怒），还不如采取一些预防性的措施。</p>
		<p>使用覆盖报告来确保正确的测试是一项伟大的实践。关键是要训练有素地完成这项工作。例如，使每晚生成并查阅覆盖报告成为<i>连续累计</i> 过程的一部分。</p>
		<p>
				<a name="N10320">
						<span class="smalltitle">
								<strong>
										<font face="Arial">3. 评定功能测试</font>
								</strong>
						</span>
				</a>
		</p>
		<p>假设覆盖报告在指出<i>没有经过</i> 足够测试的代码部分方面非常有效，那么质量保证人员可以使用这些数据来评定与功能测试有关的关注区域。让我们回到 “饮水机” 团队来看看 QA 的负责人 Drew 是如何评价 Joe 的代码的：</p>
		<blockquote>Drew 对 Jeff 说：“我们为下一个版本编写了测试案例，我们注意到很多代码没有被覆盖。那好像是与股票交易有关的代码。” <br /><br />Jeff：“哦，我们在这个领域有好些问题。如果我是一个赌徒的话，我会对这个功能区域给予特别的关注。Mary 正在对这个应用程序做一些其他的修改 —— 她在编写单元测试方面做得很好，但是这个代码也太差了点。” <br /><br />Drew：“是的，我正在确定工作的资源和级别，看上去我没必要那么担心了，我估计我们的团队会对股票交易模块引起足够的关注。” </blockquote>
		<p>知识再次显示了其强大的力量。与其他软件生命周期中的风险承担者（例如 QA）配合，您可以利用覆盖报告所提供的信息来降低风险。在上面的场景中，也许 Jeff 可以为 Drew 的团队提供一个早期的不包含 Mary 的所有修改的版本。不过无论如何，Drew 的团队都应该关注应用程序的股票交易方面，与其他具有相应单元测试的代码相比，这个地方似乎存在更大的缺陷风险。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" />
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-cq01316/#main">
																				<b>
																						<font color="#996699">回页首</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<p>
				<a name="N10338">
						<span class="atitle">
								<font face="Arial" size="4">测试有什么好处</font>
						</span>
				</a>
		</p>
		<p>对单元测试范例而言，测试覆盖度量工具是一个有点奇怪的组成部分。对于一个已存在的有益的过程，覆盖度量可以增加其深度和精度。然而，您应该仔细地阅读代码覆盖报告。单独的高覆盖率并不能确保代码的质量。对于减少缺陷，代码的高覆盖并不是必要条件，尽管高覆盖的代码的确<i>更少</i> 有缺陷。</p>
		<p>测试覆盖度量的窍门是使用覆盖报告找出<i>未经</i> 测试的代码，分别在微观和宏观两个级别。通过从顶层开始分析您的代码库，以及分析单个类的覆盖，可以促进深入的覆盖测试。一旦您能够综合这些原则，您和您的组织就可以在真正需要的地方使用覆盖度量工具，例如估计一个项目所需的时间，持续监控代码质量以及促进与 QA 的协作。</p>
		<br />
<img src ="http://www.blogjava.net/jinfeng_wang/aggbug/43340.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2006-04-26 16:24 <a href="http://www.blogjava.net/jinfeng_wang/archive/2006/04/26/43340.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>工作流之大局势</title><link>http://www.blogjava.net/jinfeng_wang/archive/2005/06/07/5655.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Tue, 07 Jun 2005 04:51:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2005/06/07/5655.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/5655.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2005/06/07/5655.html#Feedback</comments><slash:comments>23</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/5655.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/5655.html</trackback:ping><description><![CDATA[转自： <A href="http://blog.csdn.net/hongbo781202/archive/2004/09/26/117271.aspx" target=_blank><FONT color=#333399>http://blog.csdn.net/hongbo781202/archive/2004/09/26/117271.aspx</FONT></A> <BR><BR><B>1. 从奴隶社会到封建后期</B><BR><BR>工作流(WorkFlow)的概念是在现代信息系统的建设中逐步形成的，它有一个从局部到整体、从初级到高级、从简单到复杂、从奴隶社会到封建盛世的发展过程，按其发展历程，我们一般把它分为三个阶段:<BR><BR><B>﹡ EDF(电子数据流)阶段</B><BR><BR>EDF(电子数据流)阶段是工作流的奴隶社会阶段。此时的工作流在信息技术中的应用,仅着眼于利用信息技术减轻人们在流程中的计算强度,如设计一个流程用来协调多个会计统计帐目。所以,EDF最主要的特点是仅对企业单项业务进行处理,基本不涉及管理的内容。<BR><BR><B>﹡ TPF(事务处理流)阶段</B><BR><BR>TPF(事务处理流)阶段是工作流的封建初期。TPF并没有形成对企业的全局业务的管理,而着眼于对企业局部业务的管理,比如,设计一套工作流程,来管理物资的采购和供应。<BR><BR><B>﹡ IMF(信息管理流)阶段</B><BR><BR>当今的工作流已经发展到封建后期-------IMF(信息管理流)阶段, IMF强调对企业业务的全局的整体性的管理。在这个阶段,工作流就是为了完成同一目标而相互衔接、自动进行的一系列业务活动或任务。目前,工作流技术与信息技术以及企业管理紧密结合,已经悄悄渗入MIS系统、ERP系统和CRM系统等企业级关键系统中,并迅速成为这些系统的核心。在这个阶段,保皇派工作流经历了大发展,革新派工作流也风涌而现。<BR><BR><B>2. 保皇派与革新派</B><BR><BR>与其它信息技术相比,工作流技术属于较新的一个, 它现在仍处于标准的制定阶段,目前已有的标准按采用的技术分为两大派别,第一派是保皇派,基于纯XML技术;第二派是革新派,基于Web服务技术。保皇派与革新派打得难分难解,所以,现在仍有一些工作流引擎没有采用任何标准而独立实现,也就是说,它们不依靠保皇派,也不依靠革新派。<BR><BR><B>2.1 保皇派分支</B><BR><BR><B>﹡ XPDL（Xml Process Definition Language）</B><BR><BR>XPDL是保皇派最得人心的一派,因为它是太子。在工作流领域第一个致力于标准化工作的是Workflow Management Coalition (WfMC)，它成立于1993年。1994年11月，wfmc发布了工作流管理系统的参考模型。参考模型提出了五类接口，有关过程模型的定义则构成了接口一的核心内容。接口一早期的标准为WPDL（Workflow Process Definition Language），后来,这一接口的规范变更为XPDL。XPDL是至今工作流领域最为重要的一个标准,目前大多数工作流引擎是依据该标准设计开发的。<BR><BR><B>﹡ BPML(Business Process Model Language)</B><BR><BR>因为对太子派的工作方式不满意，BPMI发布BPML规范,成立新的八爷党。由于八爷党发展的非常之快，WfMC和BPMI在2002年6月26日宣布将合作制定业务流程和工作流标准，即采用BPML来描述工作流过程，同时采用XPDL所定义的工作流模型。<BR><BR><B>﹡ OMG的Workflow Management Facility</B><BR><BR>四爷OMG是支持太子的,不过四爷这个人很有报负,在其他领域也做的有声有色。四爷OMG的Workflow Management Facility联合太子的WfMC规范，定义如何将工作流向CORBA转换---要知道, CORBA可是四爷的强项。现在很多老百姓支持四爷OMG的Workflow Management Facility。四爷这招,发展了自己的势力,又不惹太子生气,真是妙啊!<BR><BR>保皇派其它分支势力很小,这里就不多说了。<BR><BR><B>2.2 革新派分支</B><BR><BR><B>﹡ WSCI</B><BR><BR>2002年6月26日，BEA,Intalio,SAP,Sun四家公司提出了基于xml的WSCI规范，推动Web服务进入了一个全新的阶段。这个规范主要描述了一个参与和其它服务进行协作交互的Web服务所交换的消息流。WSCI是第一个革新派,后来又发展了几个新的革新派,<BR><BR>如WSFL(属IBM),Xlang(属MS),因有天生缺陷,均没有很大起色。<BR><BR><B>﹡ ebXML</B><BR><BR>ebXML是一组支持模块化电子商务框架的规范。ebXML支持一个全球化的电子市场，它使得任意规模的企业通过交换基于XML的信息，不受地域限制地接洽和处理生意。ebXML是联合国（UN/CEFACT，贸易促进和电子商务中心）和OASIS（结构化信息标准发展组织）共同倡导、全球参与开发和使用的规范。由于现在老百姓都不喜欢抬着羊去换米,而喜欢在网上来个B2C,所以革新派ebXML最近发展很快。<BR><BR><B>﹡ BPEL</B><BR><BR>2002年8月9日，Microsoft, BEA, IBM, SAP &amp; Siebel联合提交发布了BPEL规范。 BPEL联合了一系列革新派/保皇派力量（ XLANG, WSFL, BPML）。此规范描述如何处理输入的消息，它不是一个关于业务流程规格化定义的规范。简单的说，可以将它看作XML形式的编程语言，提供将WSDL-Services组合成控制流的能力。顾名思义，此规范重点在（也不只限于）Web Service。<BR><BR>还有其它的革新派如RosettaNet等，因为势力很小,这里也不多说了。<BR><BR><B>3. 大户人家</B><BR><BR>这里所谈的大户人家指工作流领域的商业软件供应商，他们都背靠靠山,或穷或富。我们这里按地区来划分他们。<BR><BR><B>3.1中国之外的大户</B><BR><BR>﹡ BEA 的WLI</B><BR><BR>﹡ Fujitsu的 i-Flow<BR><BR>﹡ IBM的 Holosofx<BR><BR>﹡ SAP 的NetWeaver<BR><BR>﹡ Sonic 的Orchestration Server<BR><BR>﹡ Ultimus<BR><BR>﹡ Versata<BR><BR>这些人家大都非常富有;如果需要,请自己搜索他们的信息。<BR><BR><B>3.2国内的大户人家</B><BR><BR>﹡ 信雅达的SunFlow 这个公司留给我的印象很好,包括他们的总经理石总。<BR><BR>﹡ 西安协同的协同工作流<BR><BR>﹡ 上海东兰的DLFlo<BR><BR>这里对公司就不多介绍了,否则有做广告的嫌疑J。本人有国内工作流产品的比较报告,大家需要可以给我发邮件索取。<BR><BR><B>4. 寒门傲骨</B><BR><BR>这里的寒门傲骨指的是开源工作流引擎的实现，寒门子弟也是有政治取向的,我们还是按保皇派和革新派来区分他们，而自由派指没有按固定的标准来实现的工作流门派。<BR><BR><B>4.1保皇派寒门</B><BR><BR>﹡ OFBiz<BR><BR>OFBiz最主要的特点是OFBiz提供了一整套的开发基于Java的web应用程序的组件和工具。其中包括实体引擎, 服务引擎, 消息引擎, 工作流引擎, 规则引擎等。OFBiz先前的工作流引擎基于WfMC和OMG的规范，使用XPDL作为流程定义语言,也就是说,它是支持太子XPDL的,而且和十三爷OMG的关系非常之好。OFBiz新版的工作流引擎采用Shark工作流引擎,我们不建议再去学习OFBiz自身的工作流引擎。<BR><BR>﹡ OBE<BR><BR>OBE 是由Adrian Price主持开发的一个开放源码的Java工作流引擎，支持WfMC规范，包括接口1（XPDL）、接口2/3（WAPI）和接口5。OBE主要基于J2EE实现。OBE的接口1实现得非常好,可惜,OBE的载体公司Zaplet已经于前不久被合并，合并后的公司没有继续发展OBE的打算。Adrian Price离开了原来的公司,投奔我们前面说过的大户Versata。Versata也不打算继续OBE。OBE至今没有release版，很是可惜。<BR><BR>﹡ Shark<BR><BR>Shark是完全根据WFMC规范实施的，可扩展功能的工作流引擎，它利用xpdl来定义流程，同时还包括服务器端的用于活动节点执行的WFMC工具代理API。Shark中的每个组件例如持久层，事物管理器，脚本引擎，流程库，都是可以按照标准实施运用的，而且还可以被具体项目的模块扩展和替换。Shark和XPDL定义工具的事实标准JAWE同出名门,市场前景被很多人看好。OFBiz新版的工作流引擎采用Shark工作流引擎，OBE的载体公司Zaplet被合并，对Shark的发展将很有利。2004年9月9日，shark发布1.0版本,对它的发展无疑是一剂强心针。笔者从Shark发展的早期就在国内力推它,有幸成为Shark工作流引擎在国内的主要推广者之一(http://blog.csdn.net/hongbo781202/),感到十分荣幸。Shark的讨论请看http://211.95.124.238:22/cgi-bin/forums.cgi?forum=24。<BR><BR><B>4.2 革新派寒门</B><BR><BR>﹡ OpenebXML<BR><BR>OpenebXML项目致力于提供一个ebXML框架，主要支持 UN/CEFACT和OASIS发布的ebXML规范2.0版。<BR><BR>﹡ Bonita<BR><BR>Bonita是一个符合WfMC规范、灵活的协同工作流系统。Bonita基于浏览器、使用SOAP和XML数据绑定技术的Web Services封装了已有的工作流业务方法并将它们以基于J2EE的Web Service形式发布。<BR><BR>﹡ Twister<BR><BR>Twister的目标是提供新一代、易集成、应用Java领域中最新成果、面向B2B的工作流解决方案。流程引擎基于BPEL业务流程规范和Web Service标准。<BR><BR>﹡ ActiveBpel<BR><BR>ActiveBPEL引擎是一个于今年7月发布的健壮的运行时环境,它能执行用户按BPWL4WS规范编写的业务流程。ActiveBPEL引擎由Active Endpoints公司开发和维护,该公司同时在它的多个商业产品中使用了该技术。本人将密切观注ActiveBPEL引擎的技术发展和产品状态。<BR><BR><B>4.3 自由派寒门</B><BR><BR>﹡ OSWorkflow<BR><BR>OSWorkflow的最大特点是灵活<BR><BR>﹡ OpenWFE<BR><BR>OpenWFE是一个开放源码的Java工作流引擎。 它的思想来源于 Scheme，包括可升级的三个组件：引擎、工作列表和Web界面。<BR><BR>﹡jBpm<BR><BR>jBpm是tom baeyens编写的一个灵活可扩展的工作流管理系统。jBmp将工作流应用开发的便利性和杰出的企业应用集成（EAI）能力结合了起来。jBmp包括一个Web应用程序和一个日程安排程序。jBmp是一组J2SE组件，可以作为J2EE应用集群部署。国内目前有部分人研究jBpm。<BR><BR><B>5 大局势</B><BR><BR>目前是封建社会后期，以太子党XPDL为首的保皇派还将辉煌一段时间。我个人认为，在Ofbiz投靠Shark，强势派OBE倒台，自由派不得人心的情况下，Shark工作流引擎依靠与XPDL定义工具JAWE的兄弟关系，将坐上保皇派头把交椅。<BR><BR>目前，革新派和保皇派的争夺并不激烈。因为在现在的情况下, 革新派的根基Web服务并不劳靠，在老百姓中的影响不太大，所以革新派只求从保皇派嘴边分口食就行了。但随着社会的发展, Web服务将越来越流行，现在，MS/IBM/BEA等跨国巨头越来越主推BPEL4WS标准，并且已经发布基于BPEL4WS标准的系列产品，而且，他们还主推Integration/Portal的概念，这些概念将把工作流带入资本主义阶段。 <img src ="http://www.blogjava.net/jinfeng_wang/aggbug/5655.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2005-06-07 12:51 <a href="http://www.blogjava.net/jinfeng_wang/archive/2005/06/07/5655.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>driving develop from agile use cases</title><link>http://www.blogjava.net/jinfeng_wang/archive/2005/04/14/3274.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Thu, 14 Apr 2005 04:36:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2005/04/14/3274.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/3274.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2005/04/14/3274.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/3274.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/3274.html</trackback:ping><description><![CDATA[<A href="http://www.netobjectives.com/streamzines/CurrentStreamzine/player.html">http://www.netobjectives.com/streamzines/CurrentStreamzine/player.html</A><BR><BR><BR>swf download url:&nbsp; <A href="http://www.netobjectives.com/streamzines/CurrentStreamzine/data/swf/slide1.swf">http://www.netobjectives.com/streamzines/CurrentStreamzine/data/swf/slide1.swf</A><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ......<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<A href="http://www.netobjectives.com/streamzines/CurrentStreamzine/data/swf/slide36.swf">http://www.netobjectives.com/streamzines/CurrentStreamzine/data/swf/slide36.swf</A><img src ="http://www.blogjava.net/jinfeng_wang/aggbug/3274.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2005-04-14 12:36 <a href="http://www.blogjava.net/jinfeng_wang/archive/2005/04/14/3274.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Dynamic Delegation and Its Applicationsby（zz）</title><link>http://www.blogjava.net/jinfeng_wang/archive/2005/03/20/2264.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Sun, 20 Mar 2005 10:23:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2005/03/20/2264.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/2264.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2005/03/20/2264.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/2264.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/2264.html</trackback:ping><description><![CDATA[Dynamic Delegation and Its Applicationsby <A href="http://www.onjava.com/pub/au/2000" lid="Lu Jian">Lu Jian</A><BR>11/17/2004<BR clear=all><!--  sidebar begins  --><!--  don't move sidebars  --><!--  sidebar ends  --><!--  co: jamie - the "so" is gratuitous, but the previous sentence ended with
    a <code>...</code> term, and two of them together look like a java
    object reference: Something.somethingElse.  ca  -->
<P>The Proxy pattern is an important and widely used design pattern in object-oriented programming. Do you ever use <CODE><FONT color=#003366>Proxy</FONT></CODE> in Java since its introduction in JDK 1.3? A dynamic proxy class is a class that implements a list of interfaces specified at runtime. An implementation for the proxy's behavior can be provided at runtime through an <CODE><FONT color=#003366>InvocationHandler</FONT></CODE>. So <CODE><FONT color=#003366>Proxy</FONT></CODE> is an important class in Java's reflection package, and is widely used in many Java applications.</P>
<P>One limitation of <CODE><FONT color=#003366>Proxy</FONT></CODE> is that it can only accept interfaces. In some circumstances, you need to apply the Proxy pattern not only to interfaces, but also to abstract classes, and even concrete classes.</P>
<P>This article introduces <I>Dynamic Delegation</I>, which can create delegation for both interfaces and classes at runtime.</P>
<H3>Proxy Overview</H3>
<P>In JDK 1.3, the <CODE><FONT color=#003366>Proxy</FONT></CODE> class was added to <CODE><FONT color=#003366>java.lang.reflect</FONT></CODE>. It can create a concrete class that implements all of the specified interfaces at runtime. The dynamically generated class redirects all of the method calls defined in the interfaces to an <CODE><FONT color=#003366>InvocationHandler</FONT></CODE>.</P>
<P>Given two interfaces, <CODE><FONT color=#003366>Idel1</FONT></CODE> and <CODE><FONT color=#003366>Idel2</FONT></CODE>, <CODE><FONT color=#003366>Proxy</FONT></CODE> will create a <CODE><FONT color=#003366>IdelProxy</FONT></CODE> class as the proxy of these two interfaces (I use <CODE><FONT color=#003366>IdelProxy</FONT></CODE> as the generated proxy class name for convenience). Figure 1 shows this arrangement.</P>
<P><IMG height=259 alt="Class Diagram of IdelProxy" src="http://www.onjava.com/onjava/2004/11/17/graphics/proxy.gif" width=500><BR><I>Figure 1. Class diagram of <CODE><FONT color=#003366>IdelProxy</FONT></CODE></I></P>
<P>Below is the related code snippet.</P><PRE><CODE>
<FONT color=#003366>    Class clazz = Proxy.getProxyClass(
         Idel1.class.getClassLoader(), 
         new Class[] { Idel1.class, Idel2.class });
</FONT></CODE></PRE>
<H3>Delegation Versus Proxy</H3>
<P><CODE><FONT color=#003366>Proxy</FONT></CODE> only works for interfaces. What if we need it to work for both classes and interfaces? The <A href="http://dunamis.dev.java.net/" el="http://dunamis.dev.java.net" lid="Dunamis project">Dunamis project</A> on <A href="http://www.java.net/" lid="java.net">java.net</A> introduces <CODE><FONT color=#003366>Delegation</FONT></CODE> as an alternative to <CODE><FONT color=#003366>Proxy</FONT></CODE>. <CODE><FONT color=#003366>Delegation</FONT></CODE> uses a different approach than <CODE><FONT color=#003366>Proxy</FONT></CODE>.</P>
<P>Given a class named <CODE><FONT color=#003366>TestBean</FONT></CODE>, the delegation class <CODE><FONT color=#003366>TestBeanDelegation</FONT></CODE>'s class diagram is shown in Figure 2.</P>
<P><A href="http://www.onjava.com/onjava/2004/11/17/graphics/delegation.gif" lid="/onjava/2004/11/17/graphics/delegation_t.gif" fn="delegation.gif"><IMG height=197 alt="Class Diagram of TestBeanDelegation" src="http://www.onjava.com/onjava/2004/11/17/graphics/delegation_t.gif" width=400 border=0></A><BR><I>Figure 2. Class diagram of <CODE><FONT color=#003366>TestBeanDelegation</FONT></CODE> (click for full-size image)</I></P>
<P><CODE><FONT color=#003366>TestBeanDelegation</FONT></CODE> implements the <CODE><FONT color=#003366>Delegation</FONT></CODE> interface and extends the <CODE><FONT color=#003366>TestBean</FONT></CODE> class. It also contains references to <CODE><FONT color=#003366>TestBean</FONT></CODE> and <CODE><FONT color=#003366>DelegationInvocationHandler</FONT></CODE>. All of the method calls on <CODE><FONT color=#003366>TestBeanDelegation</FONT></CODE> will be delegated to them.</P>
<P>Take <CODE><FONT color=#003366>getName()</FONT></CODE> as an example. The chart in Figure 3 illustrates the sequence of the method call.</P>
<P><A href="http://www.onjava.com/onjava/2004/11/17/graphics/sequence.gif" lid="/onjava/2004/11/17/graphics/sequence_t.gif" fn="sequence.gif"><IMG height=332 alt="Sequence Chart of TestBeanDelegation.getName()" src="http://www.onjava.com/onjava/2004/11/17/graphics/sequence_t.gif" width=350 border=0></A><BR><I>Figure 3. Sequence chart of <CODE><FONT color=#003366>TestBeanDelegation.getName()</FONT></CODE> (click for full-size image)</I></P>
<P>The related pseudocode is: </P><PRE><CODE>
<FONT color=#003366>//The delegation class is a sub-class of the class to be delegated
public class TestBeanDelegation extends TestBean
        implements Delegation {
    //The object to be delegated
    TestBean bean;
    //The invocation handler
    DelegationInvocationHandler handler;
    ...
    static Method m0 = null;
    ...

    static {
        ...
        try {
            m0 = TestBean.class.getMethod("getName",
                                 new Class[] {});
        } catch (Exception exception) {
        }
        ...
    }

    public TestBeanDelegation(Object bean) {
        this.bean = (TestBean)bean;
    }

    public String getName() {
        boolean goon = true;
        String ret = null;
        Throwable t = null;
        try {
            goon = handler.invokeBefore(bean,
                        m0, new Object[] {});
            if (goon)
                try {
                    ret = bean.getName();
                } catch (Throwable throwable) {
                    t = throwable;
                }
            if (t != null)
                ret = handler.invokeAfterException(bean,
                            m0, new Object[] {}, t);
            else
                ret = handler.invokeAfter(bean,
                            m0, new Object[] { name }, null);
            return ret;
        } catch (RuntimeException e) {
            throw e;
        } catch (Error e) {
            throw e;
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }
}
</FONT></CODE></PRE>
<H3>An Introduction to Dynamic Delegation</H3>
<P>Dynamic Delegation is based on the Jakarta <A href="http://jakarta.apache.org/bcel/index.html" el="http://jakarta.apache.org/bcel/index.html" lid="Byte-Code Engineering Library (BCEL)">Byte-Code Engineering Library (BCEL)</A>. It can analyze the existing class and generate a delegation class in byte code for an interface, abstract class, or even a concrete class at runtime.</P><!--  sidebar begins  --><!--  sidebar ends  -->
<P>The interface/class to be delegated should meet the following conditions:</P>
<UL>
<LI>Dynamic Delegation can accept one class at most, but can accept multiple interfaces. 
<P>This limitation is based on Java's single inheritance model. One Java class can have at most one superclass. Since the generated delegation class takes the given class as its superclass, it is illegal to specify more than one class. If no class specified, the default superclass is <CODE><FONT color=#003366>Object</FONT></CODE>.</P>
<LI>The input class should have a default constructor with a public or protected modifier. 
<P>The delegation class will call the superclass' default constructor in its own constructor.</P>
<LI>The input class cannot be final, and should be visible to the caller. 
<P>The proxy class generated by <CODE><FONT color=#003366>Proxy</FONT></CODE> is final. It will not be accepted by Dynamic Delegation.</P>
<LI>Dynamic Delegation cannot accept any class that implements the <CODE><FONT color=#003366>Delegation</FONT></CODE> interface. 
<P>Since it is already a delegation class, why would you need to delegate it again?</P></LI></UL>
<P>The generated delegation class has the following characteristics:</P>
<UL>
<LI>It is generated on the fly and has no class file. 
<LI>It implements all of the given interfaces and extends the given class. 
<LI>It also implements the <CODE><FONT color=#003366>Delegation</FONT></CODE> interface. 
<LI>It has a constructor that accepts an <CODE><FONT color=#003366>Object</FONT></CODE> instance as a parameter. </LI></UL>
<P><CODE><FONT color=#003366>DelegationGenerator</FONT></CODE> is the main class of Dynamic Delegation. A client can use it to generate a delegation class/object for a specific class/interface/object. <CODE><FONT color=#003366>DelegationInvocationHandler</FONT></CODE> is an interface defining all of the delegation behaviors and is expected to be implemented by the client's developer. The delegation object can use the <CODE><FONT color=#003366>_getInvocationHandler()</FONT></CODE> and <CODE><FONT color=#003366>_setInvocationHandler()</FONT></CODE> methods defined in <CODE><FONT color=#003366>Delegation</FONT></CODE> to access the <CODE><FONT color=#003366>DelegationInvocationHandler</FONT></CODE> instance in the delegation object.<BR><BR></P>
<H4>Exercise 1. Create a Delegation Class for a Concrete Class</H4>
<P>Suppose there is a concrete class named <CODE><FONT color=#003366>ConcreteClass</FONT></CODE>:</P><PRE><CODE>
<FONT color=#003366>//ConcreteClass.java
package org.jingle.util.dydelegation.sample;

public class ConcreteClass {
    public void hello() {
        System.out.println("Hello from ConcreteClass");
    }
    
    protected void hello2() {
        System.out.println("Hello again from ConcreteClass");
    }
}
</FONT></CODE></PRE>
<P>The following code generates a delegation class for <CODE><FONT color=#003366>ConcreteClass</FONT></CODE>.</P><PRE><CODE>
<FONT color=#003366>//ConcreteClassTest.java
package org.jingle.util.dydelegation.sample;

import org.jingle.util.dydelegation.DelegationGenerator;

public class ConcreteClassTest {
    public static void main(String[] args) {
        Class clazz = DelegationGenerator
                .getDelegationClass(new Class[] { ConcreteClass.class });
        System.out.println("Delegation class name = " +
                            clazz.getName());
        System.out.println(
            ConcreteClass.class.isAssignableFrom(clazz));
    }
}
</FONT></CODE></PRE>
<P>The output shows:</P><PRE><CODE>
<FONT color=#003366>Delegation class name =
org.jingle.util.dydelegation.sample.ConcreteClass_Delegation_0
true
</FONT></CODE></PRE>
<P><CODE><FONT color=#003366>DelegationGenerator.getDelegationClass()</FONT></CODE> accepts a class array as parameter and return a Java <CODE><FONT color=#003366>Class</FONT></CODE> that extends/implements the given class/interfaces. By default, the generated delegation class is in the same package as the class to be delegated.</P>
<P>The delegation class can be instantiated as below:</P><PRE><CODE>
<FONT color=#003366>//object to be delegated
Object obj = ...; 
//some concrete invocation handler instance
DelegationInvocationHandler h = ...; 

Constructor c = clazz.getConstructor(new Class[] { Object.class });
Object inst = c.newInstance(new Object[] {obj});
((Delegation) inst)._setInvocationHandler(h);
</FONT></CODE></PRE>
<H4>Exercise 2. Create a Delegation Class for an Abstract Class</H4>
<P><CODE><FONT color=#003366>DelegationGenerator</FONT></CODE> can also generate a concrete delegation class for an abstract class.</P><PRE><CODE>
<FONT color=#003366>//AbstractClass.java
package org.jingle.util.dydelegation.sample;

public abstract class AbstractClass {
    public abstract void wave();
}


//AbstractClassTest.java
package org.jingle.util.dydelegation.sample;

import java.lang.reflect.Modifier;

import org.jingle.util.dydelegation.DelegationGenerator;

public class AbstractClassTest {
    public static void main(String[] args) {
        Class clazz = DelegationGenerator
                .getDelegationClass(new Class[] { AbstractClass.class });
        System.out.println("Delegation class name = " +
            clazz.getName());
        System.out.println(
            Modifier.isAbstract(clazz.getModifiers()));
    }
}
</FONT></CODE></PRE>
<P>Output:</P><PRE><CODE>
<FONT color=#003366>Delegation class name = 
org.jingle.util.dydelegation.sample.AbstractClass_Delegation_0
false
</FONT></CODE></PRE>
<P>The generated delegation class is a concrete class instead of an abstract class.</P>
<H4>Exercise 3. Create a Delegation Class for Both a Class and Multiple Interfaces</H4>
<P><CODE><FONT color=#003366>DelegationGenerator.getDelegationClass()</FONT></CODE> can accept a class and multiple interfaces simultaneously to generate a delegation class to delegate the given class and interfaces. Duplicate interfaces will be eliminated.</P><PRE><CODE>
<FONT color=#003366>//Idel1.java
package org.jingle.util.dydelegation.sample.bean;

public interface Idel1 {
    public void idel1();
}


//Idel2.java
package org.jingle.util.dydelegation.sample.bean;

public interface Idel2 {
    public void idel2();
}


//ComplexClassTest.java
package org.jingle.util.dydelegation.sample;

import org.jingle.util.dydelegation.DelegationGenerator;
import org.jingle.util.dydelegation.sample.bean.Idel1;
import org.jingle.util.dydelegation.sample.bean.Idel2;

public class ComplexClassTest {
    public static void main(String[] args) {
        Class clazz = DelegationGenerator.getDelegationClass(new Class[] {
                ConcreteClass.class, Idel1.class, Idel2.class });
        System.out.println(
            Idel1.class.isAssignableFrom(clazz));
        System.out.println(
            Idel2.class.isAssignableFrom(clazz));
        System.out.println(
            ConcreteClass.class.isAssignableFrom(clazz));
    }
}
</FONT></CODE></PRE>
<P>Output:</P><PRE><CODE>
<FONT color=#003366>true
true
true
</FONT></CODE></PRE>
<P>The generated delegation class extends the given class <CODE><FONT color=#003366>ConcreteClass</FONT></CODE> and implements all of the given interfaces: <CODE><FONT color=#003366>Idel1</FONT></CODE> and <CODE><FONT color=#003366>Idel2</FONT></CODE>.</P>
<H4>Exercise 4. Create a Delegation Object for a Specific Object</H4>
<P><CODE><FONT color=#003366>DelegationGenerator</FONT></CODE> can generate a delegation object directly, according to a specific object to be delegated.</P><PRE><CODE>
<FONT color=#003366>// ConcreteClassTest2.java
package org.jingle.util.dydelegation.sample;

import java.lang.reflect.Method;

import org.jingle.util.dydelegation.DelegationGenerator;
import org.jingle.util.dydelegation.DelegationInvocationHandler;
import org.jingle.util.dydelegation.DummyInvocationHandler;

public class ConcreteClassTest2 {
    public static void main(String[] args) {
        ConcreteClass inst = new ConcreteClass();
        DelegationInvocationHandler handler =
            new SimpleHandler();
        ConcreteClass delegation = (ConcreteClass)
            DelegationGenerator.newDelegationInstance(inst, handler);
        delegation.hello();
        delegation.hello2();
        System.out.println(delegation.toString());
    }
}

class SimpleHandler extends DummyInvocationHandler {
    public boolean invokeBefore(Object bean,
                                Method method, Object[] args)
            throws Throwable {
        System.out.println("Interrupted by SimpleHandler");
        return super.invokeBefore(bean, method, args);
    }
}
</FONT></CODE></PRE>
<P>Output:</P><PRE><CODE>
<FONT color=#003366>Interrupted by SimpleHandler
Hello from ConcreteClass
Hello again from ConcreteClass
Interrupted by SimpleHandler
org.jingle.util.dydelegation.sample.ConcreteClass@ef5502
</FONT></CODE></PRE>
<P><CODE><FONT color=#003366>DummyInvocationHandler</FONT></CODE> is a dummy implementation of <CODE><FONT color=#003366>DelegationInvocationHandler</FONT></CODE>. It always returns <CODE><FONT color=#003366>true</FONT></CODE> in <CODE><FONT color=#003366>invokeBefore()</FONT></CODE>, returns the input result directly in <CODE><FONT color=#003366>invokeAfter()</FONT></CODE>, and throws the input throwable directly in <CODE><FONT color=#003366>invokeAfterException()</FONT></CODE>. The delegation object with <CODE><FONT color=#003366>DummyInvocationHandler</FONT></CODE> has same behavior as the object to be delegated.</P>
<P><CODE><FONT color=#003366>DelegationGenerator.newDelegationInstance()</FONT></CODE> accepts an object and an <CODE><FONT color=#003366>DelegationInvocationHandler</FONT></CODE> instance as parameters. It returns a delegation object to delegate the given object.</P>
<P>All of the methods called on the delegation object will be delegated to the <CODE><FONT color=#003366>DelegationInvocationHandler</FONT></CODE> instance, except:</P>
<UL>
<LI>Methods without a public modifier. 
<LI>Methods with a final modifier. 
<LI>Methods with a static modifier. 
<LI>Methods declared in the <CODE><FONT color=#003366>Object</FONT></CODE> class, other than <CODE><FONT color=#003366>hashCode()</FONT></CODE>, <CODE><FONT color=#003366>equals()</FONT></CODE>, and <CODE><FONT color=#003366>toString()</FONT></CODE>. </LI></UL>
<P><BR></P>
<H4>Exercise 5. Create Delegation Object for the Object of a Java Core Class</H4>
<P>Did you ever want to delegate an object of an existing Java core class? Delegate it as usual.</P><PRE><CODE>
<FONT color=#003366>//DateTest.java
package org.jingle.util.dydelegation.sample;

import java.lang.reflect.Method;
import java.util.Date;

import org.jingle.util.dydelegation.DelegationGenerator;
import org.jingle.util.dydelegation.DelegationInvocationHandler;
import org.jingle.util.dydelegation.DummyInvocationHandler;

public class DateTest {
    public static void main(String[] args) {
        Date date = new Date();
        DelegationInvocationHandler handler = 
            new DateClassHandler();
        Date delegation = (Date) DelegationGenerator
                .newDelegationInstance(date, handler);
        System.out.println("Delegation class = " +
            delegation.getClass().getName());
        System.out.println("True date = " +
            date.getTime());
        System.out.println("Delegation date = " +
            delegation.getTime());
    }
}

class DateClassHandler extends DummyInvocationHandler {
    public Object invokeAfter(Object bean,
                    Method method, Object[] args,
                    Object result) throws Throwable {
        if (method.getName().equals("getTime")) {
            return new Long(((Long)result).longValue() - 1000);
        }
        return super.invokeAfter(bean, method, args, result);
    }
}
</FONT></CODE></PRE>
<P>Output:</P><PRE><CODE>
<FONT color=#003366>Delegation class = org.jingle.util.dydelegation.Date_Delegation_0
True date = 1099380377665
Delegation date = 1099380376665

</FONT></CODE></PRE>
<P>When creating a delegation class for a Java core class, the delegation class will not be in the same package as the Java core class, because the Java security model does not allow a user-defined <CODE><FONT color=#003366>ClassLoader</FONT></CODE> to define a class in a package starting with <CODE><FONT color=#003366>java</FONT></CODE>.</P>
<P><CODE><FONT color=#003366>DateClassHandler</FONT></CODE> catches the <CODE><FONT color=#003366>getTime()</FONT></CODE> method call in <CODE><FONT color=#003366>invokeAfter()</FONT></CODE>, and makes the return value 1000 less than the normal return value.</P>
<H3>Advanced Usage</H3>
<H4>Exercise 6. Simulate Proxy Behavior</H4>
<P>Can Dynamic Delegation do what <CODE><FONT color=#003366>Proxy</FONT></CODE> does? Absolutely! Dynamic Delegation covers the functions of <CODE><FONT color=#003366>Proxy</FONT></CODE>. Given a proper delegation handler, it can simulate the behavior of a Java <CODE><FONT color=#003366>Proxy</FONT></CODE>.</P><PRE><CODE>
<FONT color=#003366>// ProxyTest.java
package org.jingle.util.dydelegation.sample;

import java.lang.reflect.Method;

import org.jingle.util.dydelegation.DelegationGenerator;
import org.jingle.util.dydelegation.DelegationInvocationHandler;
import org.jingle.util.dydelegation.DummyInvocationHandler;
import org.jingle.util.dydelegation.sample.bean.Idel1;
import org.jingle.util.dydelegation.sample.bean.Idel2;

public class ProxyTest {
    public static void main(String[] args) {
        DelegationInvocationHandler handler = new ProxyHandler();
        Object delegation =
            DelegationGenerator.newDelegationInstance(null,
                new Class[] { Idel1.class, Idel2.class },
                null, handler);
        ((Idel1) delegation).idel1();
        ((Idel2) delegation).idel2();
    }
}

class ProxyHandler extends DummyInvocationHandler {
    public boolean invokeBefore(Object bean,
            Method method, Object[] args)
            throws Throwable {
        return false;
    }

    public Object invokeAfter(Object bean, 
            Method method, Object[] args,
            Object result) throws Throwable {
        String name = method.getName();
        if (name.equals("idel1"))
            System.out.println("Hello from idel1");
        else if (name.equals("idel2"))
            System.out.println("Hello from idel2");
        return super.invokeAfter(bean, method, args, result);
    }
}
</FONT></CODE></PRE>
<P>Output:</P><PRE><CODE>
<FONT color=#003366>Hello from idel1
Hello from idel2
</FONT></CODE></PRE>
<P><CODE><FONT color=#003366>ProxyHandler</FONT></CODE> returns <CODE><FONT color=#003366>false</FONT></CODE> in <CODE><FONT color=#003366>invokeBefore()</FONT></CODE>, which means all of the method calls on the delegation object will not be delegated to the original object. It uses <CODE><FONT color=#003366>invokeAfter()</FONT></CODE> to define the delegation behavior as being what <CODE><FONT color=#003366>Proxy</FONT></CODE> does.</P>
<P><CODE><FONT color=#003366>DelegationGenerator.newDelegationInstance()</FONT></CODE> has another version. It contains four arguments: </P>
<UL>
<LI><B>The <CODE><FONT color=#003366>Object</FONT></CODE> to be delegated</B>. 
<P>This can be <CODE><FONT color=#003366>null</FONT></CODE>. If it is not <CODE><FONT color=#003366>null</FONT></CODE>, it must be an instance of all of the given classes and interfaces.</P>
<LI><B>An array of <CODE><FONT color=#003366>Class</FONT></CODE> to be delegated</B>. 
<P>This can contain multiple interfaces and, at most, one class.</P>
<LI><B>Delegation class name</B>. 
<P>If <CODE><FONT color=#003366>null</FONT></CODE>, a system-generated name will be provided.</P>
<LI><B>A <CODE><FONT color=#003366>DelegationInvocationHandler</FONT></CODE> instance, which is used to define the delegation's behavior</B>. </LI></UL>
<P>From the output, we can see that the delegation object is an instance of both <CODE><FONT color=#003366>Idel1</FONT></CODE> and <CODE><FONT color=#003366>Idel2</FONT></CODE>. Its behavior is just what is defined in the handler.</P>
<H4>Exercise 7. Partial Delegation</H4>
<P>Until now, we've delegated all of the functions of the specific object. How about just delegating part of the object's functions?</P><PRE><CODE>
<FONT color=#003366>//MyDate.java
package org.jingle.util.dydelegation.sample.bean;

import java.util.Date;

public class MyDate extends Date implements Idel1, Idel2 {
    public void idel1() {
    }

    public void idel2() {
    }
}


// MyDateTest.java
package org.jingle.util.dydelegation.sample;

import java.util.Date;

import org.jingle.util.dydelegation.DelegationGenerator;
import org.jingle.util.dydelegation.DelegationInvocationHandler;
import org.jingle.util.dydelegation.DummyInvocationHandler;
import org.jingle.util.dydelegation.sample.bean.Idel1;
import org.jingle.util.dydelegation.sample.bean.Idel2;
import org.jingle.util.dydelegation.sample.bean.MyDate;

public class MyDateTest {
    public static void main(String[] args) {
        MyDate inst = new MyDate();
        DelegationInvocationHandler handler =
            new DummyInvocationHandler();
        Object delegation = 
            DelegationGenerator.newDelegationInstance(inst,
                new Class[] { Idel1.class, Idel2.class },
                null, handler);
        System.out.println(delegation instanceof Idel1);
        System.out.println(delegation instanceof Idel2);
        System.out.println(delegation instanceof Date);
    }
}
</FONT></CODE></PRE>
<P>Output:</P><PRE><CODE>
<FONT color=#003366>true
true
false
</FONT></CODE></PRE>
<P><CODE><FONT color=#003366>MyDate</FONT></CODE> extends <CODE><FONT color=#003366>Date</FONT></CODE> and implements the <CODE><FONT color=#003366>Idel1</FONT></CODE> and <CODE><FONT color=#003366>Idel2</FONT></CODE> interfaces. <CODE><FONT color=#003366>DelegationGenerator.newDelegationInstance()</FONT></CODE> uses a <CODE><FONT color=#003366>MyDate</FONT></CODE> instance as the object instance to be delegated, and limits the delegation scope in <CODE><FONT color=#003366>Idel1</FONT></CODE> and <CODE><FONT color=#003366>Idel2</FONT></CODE>. In other words, the generated delegation object is an instance of <CODE><FONT color=#003366>Idel1</FONT></CODE> and <CODE><FONT color=#003366>Idel2</FONT></CODE>, but not an instance of <CODE><FONT color=#003366>Date</FONT></CODE>.</P>
<H3>Conclusion</H3>
<P>The Dunamis project introduces Dynamic Delegation to extend the function of the Java <CODE><FONT color=#003366>Proxy</FONT></CODE> reflection utility. It can generate delegation for both classes and interfaces at runtime. This article introduces Dynamic Delegation in brief with simple examples. In the real world, Dynamic Delegation can be used in many areas, such as mock objects in unit testing, Java GUI MVC framework, and more.</P>
<H3>Reference</H3>
<UL>
<LI>Dunamis project: <A href="http://dunamis.dev.java.net/" el="http://dunamis.dev.java.net" lid="dunamis.dev.java.net">dunamis.dev.java.net</A> 
<LI>Download sample code for this article: <A href="http://dunamis.dev.java.net/servlets/ProjectDocumentList" el="http://dunamis.dev.java.net/servlets/ProjectDocumentList" lid="sample code">sample code</A> 
<LI>BCEL: <A href="http://jakarta.apache.org/bcel/index.html" el="http://jakarta.apache.org/bcel/index.html" lid="jakarta.apache.org/bcel/index.html">jakarta.apache.org/bcel/index.html</A> </LI></UL>
<P><I><A href="http://www.onjava.com/pub/au/2000" lid="Lu Jian">Lu Jian</A> is a senior Java architect/developer with four years of Java development experience. </I><BR><BR></P>
<H4>Exercise 1. Create a Delegation Class for a Concrete Class</H4>
<P>Suppose there is a concrete class named <CODE><FONT color=#003366>ConcreteClass</FONT></CODE>:</P><PRE><CODE>
<FONT color=#003366>//ConcreteClass.java
package org.jingle.util.dydelegation.sample;

public class ConcreteClass {
    public void hello() {
        System.out.println("Hello from ConcreteClass");
    }
    
    protected void hello2() {
        System.out.println("Hello again from ConcreteClass");
    }
}
</FONT></CODE></PRE>
<P>The following code generates a delegation class for <CODE><FONT color=#003366>ConcreteClass</FONT></CODE>.</P><PRE><CODE>
<FONT color=#003366>//ConcreteClassTest.java
package org.jingle.util.dydelegation.sample;

import org.jingle.util.dydelegation.DelegationGenerator;

public class ConcreteClassTest {
    public static void main(String[] args) {
        Class clazz = DelegationGenerator
                .getDelegationClass(new Class[] { ConcreteClass.class });
        System.out.println("Delegation class name = " +
                            clazz.getName());
        System.out.println(
            ConcreteClass.class.isAssignableFrom(clazz));
    }
}
</FONT></CODE></PRE>
<P>The output shows:</P><PRE><CODE>
<FONT color=#003366>Delegation class name =
org.jingle.util.dydelegation.sample.ConcreteClass_Delegation_0
true
</FONT></CODE></PRE>
<P><CODE><FONT color=#003366>DelegationGenerator.getDelegationClass()</FONT></CODE> accepts a class array as parameter and return a Java <CODE><FONT color=#003366>Class</FONT></CODE> that extends/implements the given class/interfaces. By default, the generated delegation class is in the same package as the class to be delegated.</P>
<P>The delegation class can be instantiated as below:</P><PRE><CODE>
<FONT color=#003366>//object to be delegated
Object obj = ...; 
//some concrete invocation handler instance
DelegationInvocationHandler h = ...; 

Constructor c = clazz.getConstructor(new Class[] { Object.class });
Object inst = c.newInstance(new Object[] {obj});
((Delegation) inst)._setInvocationHandler(h);
</FONT></CODE></PRE>
<H4>Exercise 2. Create a Delegation Class for an Abstract Class</H4>
<P><CODE><FONT color=#003366>DelegationGenerator</FONT></CODE> can also generate a concrete delegation class for an abstract class.</P><PRE><CODE>
<FONT color=#003366>//AbstractClass.java
package org.jingle.util.dydelegation.sample;

public abstract class AbstractClass {
    public abstract void wave();
}


//AbstractClassTest.java
package org.jingle.util.dydelegation.sample;

import java.lang.reflect.Modifier;

import org.jingle.util.dydelegation.DelegationGenerator;

public class AbstractClassTest {
    public static void main(String[] args) {
        Class clazz = DelegationGenerator
                .getDelegationClass(new Class[] { AbstractClass.class });
        System.out.println("Delegation class name = " +
            clazz.getName());
        System.out.println(
            Modifier.isAbstract(clazz.getModifiers()));
    }
}
</FONT></CODE></PRE>
<P>Output:</P><PRE><CODE>
<FONT color=#003366>Delegation class name = 
org.jingle.util.dydelegation.sample.AbstractClass_Delegation_0
false
</FONT></CODE></PRE>
<P>The generated delegation class is a concrete class instead of an abstract class.</P>
<H4>Exercise 3. Create a Delegation Class for Both a Class and Multiple Interfaces</H4>
<P><CODE><FONT color=#003366>DelegationGenerator.getDelegationClass()</FONT></CODE> can accept a class and multiple interfaces simultaneously to generate a delegation class to delegate the given class and interfaces. Duplicate interfaces will be eliminated.</P><PRE><CODE>
<FONT color=#003366>//Idel1.java
package org.jingle.util.dydelegation.sample.bean;

public interface Idel1 {
    public void idel1();
}


//Idel2.java
package org.jingle.util.dydelegation.sample.bean;

public interface Idel2 {
    public void idel2();
}


//ComplexClassTest.java
package org.jingle.util.dydelegation.sample;

import org.jingle.util.dydelegation.DelegationGenerator;
import org.jingle.util.dydelegation.sample.bean.Idel1;
import org.jingle.util.dydelegation.sample.bean.Idel2;

public class ComplexClassTest {
    public static void main(String[] args) {
        Class clazz = DelegationGenerator.getDelegationClass(new Class[] {
                ConcreteClass.class, Idel1.class, Idel2.class });
        System.out.println(
            Idel1.class.isAssignableFrom(clazz));
        System.out.println(
            Idel2.class.isAssignableFrom(clazz));
        System.out.println(
            ConcreteClass.class.isAssignableFrom(clazz));
    }
}
</FONT></CODE></PRE>
<P>Output:</P><PRE><CODE>
<FONT color=#003366>true
true
true
</FONT></CODE></PRE>
<P>The generated delegation class extends the given class <CODE><FONT color=#003366>ConcreteClass</FONT></CODE> and implements all of the given interfaces: <CODE><FONT color=#003366>Idel1</FONT></CODE> and <CODE><FONT color=#003366>Idel2</FONT></CODE>.</P>
<H4>Exercise 4. Create a Delegation Object for a Specific Object</H4>
<P><CODE><FONT color=#003366>DelegationGenerator</FONT></CODE> can generate a delegation object directly, according to a specific object to be delegated.</P><PRE><CODE>
<FONT color=#003366>// ConcreteClassTest2.java
package org.jingle.util.dydelegation.sample;

import java.lang.reflect.Method;

import org.jingle.util.dydelegation.DelegationGenerator;
import org.jingle.util.dydelegation.DelegationInvocationHandler;
import org.jingle.util.dydelegation.DummyInvocationHandler;

public class ConcreteClassTest2 {
    public static void main(String[] args) {
        ConcreteClass inst = new ConcreteClass();
        DelegationInvocationHandler handler =
            new SimpleHandler();
        ConcreteClass delegation = (ConcreteClass)
            DelegationGenerator.newDelegationInstance(inst, handler);
        delegation.hello();
        delegation.hello2();
        System.out.println(delegation.toString());
    }
}

class SimpleHandler extends DummyInvocationHandler {
    public boolean invokeBefore(Object bean,
                                Method method, Object[] args)
            throws Throwable {
        System.out.println("Interrupted by SimpleHandler");
        return super.invokeBefore(bean, method, args);
    }
}
</FONT></CODE></PRE>
<P>Output:</P><PRE><CODE>
<FONT color=#003366>Interrupted by SimpleHandler
Hello from ConcreteClass
Hello again from ConcreteClass
Interrupted by SimpleHandler
org.jingle.util.dydelegation.sample.ConcreteClass@ef5502
</FONT></CODE></PRE>
<P><CODE><FONT color=#003366>DummyInvocationHandler</FONT></CODE> is a dummy implementation of <CODE><FONT color=#003366>DelegationInvocationHandler</FONT></CODE>. It always returns <CODE><FONT color=#003366>true</FONT></CODE> in <CODE><FONT color=#003366>invokeBefore()</FONT></CODE>, returns the input result directly in <CODE><FONT color=#003366>invokeAfter()</FONT></CODE>, and throws the input throwable directly in <CODE><FONT color=#003366>invokeAfterException()</FONT></CODE>. The delegation object with <CODE><FONT color=#003366>DummyInvocationHandler</FONT></CODE> has same behavior as the object to be delegated.</P>
<P><CODE><FONT color=#003366>DelegationGenerator.newDelegationInstance()</FONT></CODE> accepts an object and an <CODE><FONT color=#003366>DelegationInvocationHandler</FONT></CODE> instance as parameters. It returns a delegation object to delegate the given object.</P>
<P>All of the methods called on the delegation object will be delegated to the <CODE><FONT color=#003366>DelegationInvocationHandler</FONT></CODE> instance, except:</P>
<UL>
<LI>Methods without a public modifier. 
<LI>Methods with a final modifier. 
<LI>Methods with a static modifier. 
<LI>Methods declared in the <CODE><FONT color=#003366>Object</FONT></CODE> class, other than <CODE><FONT color=#003366>hashCode()</FONT></CODE>, <CODE><FONT color=#003366>equals()</FONT></CODE>, and <CODE><FONT color=#003366>toString()</FONT></CODE>. </LI></UL><img src ="http://www.blogjava.net/jinfeng_wang/aggbug/2264.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2005-03-20 18:23 <a href="http://www.blogjava.net/jinfeng_wang/archive/2005/03/20/2264.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>推荐一篇文章：架构更新</title><link>http://www.blogjava.net/jinfeng_wang/archive/2005/03/18/2191.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Fri, 18 Mar 2005 05:58:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2005/03/18/2191.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/2191.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2005/03/18/2191.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/2191.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/2191.html</trackback:ping><description><![CDATA[<A href="http://forum.javaeye.com/viewtopic.php?t=11474&amp;highlight">http://forum.javaeye.com/viewtopic.php?t=11474&amp;highlight</A>=<BR><BR>《企业架构模式》中，对其中各局部的具体选择，有了非常棒的讨论。<BR><BR><img src ="http://www.blogjava.net/jinfeng_wang/aggbug/2191.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2005-03-18 13:58 <a href="http://www.blogjava.net/jinfeng_wang/archive/2005/03/18/2191.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Maven存在的问题/疑惑？</title><link>http://www.blogjava.net/jinfeng_wang/archive/2005/03/10/1898.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Thu, 10 Mar 2005 04:52:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2005/03/10/1898.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/1898.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2005/03/10/1898.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/1898.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/1898.html</trackback:ping><description><![CDATA[1、如果整个项目使用maven管理，那么每个开发客户端都需要配置maven才行。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果要在Eclipse里面集成maven，例如使用maven ide，那么还要对maven ide进行配置。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这里提醒一下哦，Eclipse里面使用maven ide的时候会下载maven，在eclipse\plugins\org.apache.maven_1.0.0\lib目录中，如果你想，还需要象maven那样自己配置。<BR><BR>2、如果你想在客户端debug怎么办？那还是需要将lib库拷贝到本地。现在只能统一映射网络硬盘。那就是在开发的时候是一种方式，在发布的时候又是一种模式。maven对开发的帮助并不是很大，有意义的内容在于maven会“强迫”要求你尽量分开projcet之间的各层。<BR><BR>3、maven的各artifact 之间的依赖问题。maven artifact 的version决定与POM中的currentversion，而没用能够和CVS的version连接起来。如果在开发过程中，会生成A、B两个artifact，A依赖于B，但是B经过改动后，编译A、B，此时Maven并不能自动发觉B已经改动过。只要maven在repository发现了B.currentversion.jar，那么它就不会将B重新打包，maven还是必须通过种种人工手段才能够完成先编译B再编译A。在测试的时候也是如此。总之，必须还是需要人为的参与才能保证顺序的正确，才能保证你所使用的库，是最新的库。<BR><BR>4、如果maven只能提供一个repository的功能和利用POM减少script的功能，那用maven干吗呢？何况每个developer还需要自己机器上拥有repository。如果说maven提供了许多的plugin，那么现在的ant也可以支持，只是未能正式成形。<BR><BR>我的意思是说：maven带来的内容并不是ant的完全替代品，有时候甚至需要人工参与才能让maven完成任务。当然，maven提供jelly，自己写script，但那不是又麻烦了么？<BR><BR><BR><FONT color=#008000>//maven 可以先排队哦，问题3解决了</FONT><img src ="http://www.blogjava.net/jinfeng_wang/aggbug/1898.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2005-03-10 12:52 <a href="http://www.blogjava.net/jinfeng_wang/archive/2005/03/10/1898.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Why do I like TDD?(zz)</title><link>http://www.blogjava.net/jinfeng_wang/archive/2005/03/09/1873.html</link><dc:creator>jinfeng_wang</dc:creator><author>jinfeng_wang</author><pubDate>Wed, 09 Mar 2005 06:11:00 GMT</pubDate><guid>http://www.blogjava.net/jinfeng_wang/archive/2005/03/09/1873.html</guid><wfw:comment>http://www.blogjava.net/jinfeng_wang/comments/1873.html</wfw:comment><comments>http://www.blogjava.net/jinfeng_wang/archive/2005/03/09/1873.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jinfeng_wang/comments/commentRss/1873.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jinfeng_wang/services/trackbacks/1873.html</trackback:ping><description><![CDATA[<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><A href="http://www.theserverside.com/news/thread.tss?thread_id=32394#160253">http://www.theserverside.com/news/thread.tss?thread_id=32394#160253</A><BR><BR>Why do I like TDD?<BR><BR>1) by the nature of software engineering any code needs refactoring. Having code covered with unit-tests, gives me confidence during the refactoring. I do not know any other reliable way of having the same kind of confidence. Without the confidence, I would be afraid to do refactorings often, which would make the software product of lesser quality.</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US>1)</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">本质上，软件开发中一切代码都需要重构。经过单元测试覆盖的代码可以让我拥有信心去重构。我也不知道还有什么其他办法能够让我获得如此的信心。如果没有信心，那么我就不太敢经常的重构，这也必然影响代码的品质。</SPAN><SPAN lang=EN-US><BR><BR>2) Due to the nature of unit-tests (emphasize: unit), it is impossible to test a "badly-smelling" code. In order to be able to unit-test your code, it has to be cleaner, and better designed: short, focused methods, writing to Interfaces, lously coupled etc.<BR>2</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）由于单元测试的自然特性（注意是单元测试），无法对具有“坏味道”的代码进行单元测试。而为了能够顺利的对你的代码进行单元测试，那么你的代码就会逐渐的变得更加清晰、设计更加完善：代码短小、专注方法、针对接口编程、降低耦合等。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US>&nbsp;<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US>I think, this might not have been something that was foreseen initially but discovered later. My guess is, initially, people just wanted to make computer do what it is best for - repetitive work (in this case - testing) and have code test the application, not humans. But as a "byproduct" they noticed that testing requires design improvement, too. When they discovered it, somebody smart-enough had an idea - if it is so, why not write tests first? Design is supposed to come before the implementation and if tests affect design, it makes sense to write them before the implementation, too.</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">我想，也许单元测试的提倡者事前也未曾会预料到它能够带来这已经证实了的益处。我想，刚开始人们也就只是希望发挥计算机的特点，让它完成重复性的工作（这里是指测试），而不再需要人去进行测试。但是他们发现了“副产品”―测试需要更好的设计。接着，他们中的杰出者提出了一个全新的想法－既然如此，那何不事先写好测试呢？设计是应该在代码实现之前的，而如果测试可以影响设计，那么何不也将测试在代码实现之前进行编写呢？</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US>&nbsp;<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US>And the TDD started...</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">于是</SPAN><SPAN lang=EN-US>TDD</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">开始了</SPAN><SPAN lang=EN-US>…….</SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。<BR><BR><BR>====================================<BR><BR>http://www.theserverside.com/news/thread.tss?thread_id=32394#160294 <BR><BR>I think I agree with some of the objections raised with TDD, but the problem seems more with how people use it than a basic flaw in the concept. The 2 primary objections raised are: <BR>1. There is a lot of test-centric coding with less focus on ensuring overall business requirement is fulfilled. <BR>2. Developers seem to think that having run the product through the Unit tests ensures that the product is well-tested and production ready. <BR><BR>我对TDD所引起的问题非常的同意，但是问题更在于人们如何解决它，而不是仅停留在基本的观念上。TDD主要引起的问题是： <BR>1、 存在着太多的“以测试为中心”的代码，而更少的关注于整体的业务需求。 <BR>2、开发者好像开始认为跑遍单元测试就可以保证产品的可测试和产品的质量。 <BR><BR><BR><BR>All that TDD should be expected to do is run a sanity check at the end of a new build to ensure that the contracts that each unit of code is supposed to fulfill have not been broken. You still need to go through your entire QA cycle to ensure you have a functional product. So, the automated unit tests are just additional checks and do not replace QA. But, unfortunately I have seen situations where people believe that once they have a proper build and unit tested they can reduce the time they spend in QA. Not really true!!! It just ensures that if the unit tests were written properly, the quality of the code reaching QA will be a little better. <BR><BR>所有的TDD能做的是在整个项目构建结束之后完成一个检查工作，保证原有的单元之间的契约没用被打破。在项目构建完成后，还需要一个质量保证(quality assurance)的过程，以保证整个项目的功能。也就是说自动化测试只是一个附加的检查，而不是对质量保证的全盘替代。但不幸的是，我看到的人们却非如此。他们认为一旦单元测试成功，那么就可以减少QA上面的时间。但事实真的不是这样的。单元测试所能做倒的也仅在于单元测试已经很好的编写完成，代码的质量更容易达到QA的标准。 </SPAN></P><img src ="http://www.blogjava.net/jinfeng_wang/aggbug/1873.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jinfeng_wang/" target="_blank">jinfeng_wang</a> 2005-03-09 14:11 <a href="http://www.blogjava.net/jinfeng_wang/archive/2005/03/09/1873.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>