??xml version="1.0" encoding="utf-8" standalone="yes"?>
http://www.molss.gov.cn/gb/news/2007-06/30/content_184630.htm
B)?/span>?/span>人民共和?/span>力_合同?/span>?/span>施条?/span>(解释力_法实?/span>)
http://www.gov.cn/flfg/2008-09/19/content_1099500.htm
C)关于立力_关系有关事项的通知
http://www.law-lib.com/law/law_view.asp?id=92395
D)上v市女职工力_保护办法
http://www.shanghai.gov.cn/shanghai/node2314/node3124/node3125/node3133/userobject6ai655.html
· C)的相兛_容:(x)
用h单位未与力_者签订劳动合同,认定双方存在力_关系时可参照下列凭证Q?/span>
(一)工资支付凭证或记?/span>(职工工资发放花名?/span>)、缴U_社?x)保险费的记录?/span>
(?/span>)用h单位向劳动者发攄“工作?#8221;?#8220;服务?#8221;{能够证明n份的证gQ?/span>
· B) 的相兛_容:(x)
W六?span style="font: 7pt 'Times New Roman'"> 用h单位自用工之日v过一个月不满一q?/span>未与力_者订立书面劳动合同的Q应当依?span style="color: blue">力_合同法第八十二条的规定向力_者每月支付两倍的工资Qƈ与劳动者补订书面劳动合?/span>Q劳动者不与用人单位订立书面劳动合同的Q用人单位应当书面通知力_者终止劳动关p,q依照劳动合同法W四十七条的规定支付l济补偿?/span>(1Q相当于l?/strong>2倍工资,2Q补合同Q?/strong>3Q如果辞退Q再按照有合同补偿)
W二十七条 力_合同法第四十七条规定?strong>l济补偿的月工资按照力_者应得工资计,包括计时工资或者计件工资以?qing)奖?/strong>?/span>
· A)的相兛_容:(x)
W四十二条 力_者有下列情Ş之一的,用h单位不得依照本法W四十条、第四十一条的规定解除力_合同Q?/span>
Q四Q女职工在孕期、期、哺x?/strong>
W四十七条 l济补偿按劳动者在本单位工作的q限Q?strong>每满一q支付一个月工资的标准向力_者支付。六个月以上不满一q的Q按一q计;不满六个月的Q向力_者支付半个月工资的经补ѝ?/span>
W八十二条 用h单位自用工之日v过一个月不满一q未与劳动者订立书面劳动合同的Q应当向力_者每月支付二倍的工资?/strong>
用h单位q反本法规定不与力_者订?strong>无固定期限劳动合?/strong>的,自应当订立无固定期限力_合同之日起向力_者每?strong>支付二倍的工资?/span>
W八十七条 用h单位q反本法规定解除或者终止劳动合同的Q应?strong>依照本法W四十七?/span>规定的经补?strong>标准的二?/span>向劳动者支付赔偉K?/span>
W十四条 无固定期限劳动合同,是指用h单位与劳动者约定无定l止旉的劳动合同?/span>
用h单位与劳动者协商一_(d)可以订立无固定期限劳动合同。有下列情Ş之一Q劳动者提出或者同意箋订、订立劳动合同的Q除力_者提立固定期限劳动合同外Q应?strong>订立无固定期限劳动合?/strong>Q?/span>
Q一Q劳动者在该用人单?span style="color: red">q箋工作满十q?/strong>的;
Q二Q用人单位初ơ实行劳动合同制度或者国有企业改刉新订立劳动合同时Q劳动者在该用人单位连l工作满十年且距法定退休年龄不_q的Q?/span>
Q三Q?strong>q箋订立二次固定期限力_合同Q且力_者没有本法第三十?ji)条和第四十条第一V第二项规定的情形,l订力_合同的?/span>
用h单位自用工之日v满一q不与劳动者订立书面劳动合同的Q视为用人单位与力_者已订立无固定期限劳动合?/strong>?/span>
· D) 的相兛_容:(x)
W十一?/span>对妊娠期的女职工Q?strong>不应廉其劳动时?/strong>Q?/span>
W十四条奌工假分别按下列情况执行Q?/span>
Q一Q单胎顺产者,l予产假?ji)十天,其中产前休息十五天,产后休息七十五天?/span>
W十五条奌工生育后Q在其婴儿一周岁内应照顾其在每班力_旉?span style="color: red">授^两次Q包括h工喂养)?span style="color: red">每次单胎U授x间ؓ(f)三十分钟Q亦可将两次授^旉合ƈ使用。多?yu)胎生育者,每多生一胎,每次Z^旉增加三十分钟?/span>
W十八条奌工在产假期间的工资照发。按本规定n受的产前假和Z^假的工资按本人原工资?span style="color: red">癑ֈ之八十发l?/span>。单位增加工资时Q女职工按规定n受的产前假、假、哺乛_Q应作出勤对待?/span>
· l论Q?/span>
1Q?span style="font: 7pt 'Times New Roman'"> 认定力_关系Q工作证
2Q?span style="font: 7pt 'Times New Roman'"> 是否{?/span>
3Q?span style="font: 7pt 'Times New Roman'"> 如果没签合同Q怎么补偿Q?/span>1Q?strong>相当于给2倍工资,2Q补合同Q?/strong>3Q如果辞退Q再按照有合同补偿)
4Q?span style="font: 7pt 'Times New Roman'"> 如果是固定合同,怎么补偿Q?/span>N+1Q?/strong>
5Q?span style="font: 7pt 'Times New Roman'"> 如果是无期合同,2?/strong>
6Q?span style="font: 7pt 'Times New Roman'"> 孕妇怎么处理Q?/span>
1、公司辞退孕妇的补偿情冉|准是怎样Q?/span>
{:(x)发放工资到哺x满;按工作年限计经补偉K?/span>
2、公司是否可以以我的考核和我是孕产妇不能胜Q工作为由Ҏ(gu)q行降职降降薪处理Q?/span>
{:(x)不可以?/span>
我们的工资分为基本工资(U占1/4)+岗位工资+l效工资{。是否可能出现只要不降低我的基本工资是合法的行为?
{:(x)不合理。工资是包括了岗位工资和l效工资?/span>
3、如果公怾法破产,我是否有向集团主张赔偿的权利Q?/span>
{:(x)破也可以主张权利,在破产胦产中优先演戏ѝ?/span>
4、如果可能需要诉诸法律,我应该准备哪些方面的举证Q?/span>
{:(x)存在力_关系的证据最重要Q此外,工资条、怀孕的证据、结婚证、准生证
也比较重要?/span>Q?/span>按照力_?/span>42条,不得解除三期【孕期、期、哺x】妇奟뀂那么如果一定要q反力_法解除劳动关p,只能按照q反力_法,按照W八十七条进行二倍赔偿,也就?/span>3倍)
案例:
http://www.tianya.cn/publicforum/content/law/1/119373.shtml
案情Q?/span>A公司辞退B?/span>?/span>Q不?/span>?/span>B可能存在?/span>q错Q假?/span>A毫无道理毫无依据的辞退B?/span>?/span>Q?/span>
一审结果:(x)?/span>?/span>?/span>?/span>孕期?/span>?/span>、全额期(?/span>?/span>q?/span>加了15天)?/span>?/span>?/span>75%的哺x?/span>?/span>Qƈ以入职时?/span>至三期届满ؓ(f)力_合同?/span>pdl?/span>?/span>间计在职时?/span>Q然后以?/span>?/span>职时?/span>按照?/span>力_合同法》第八十七条?/span>?/span>?/span>赔偿金(卛_法解除的补偿金的双倍)。一?/span>不是我代理的?/span>
?/span>?/span>A公司扑ֈ我,我想当然的以?/span>Q按照?/span>力_合同法》第八十七条?/span>?/span>定,力_者可?/span>选择要求l箋履行Q不要求l箋履行的,?/span>?/span>?/span>支付双?/span>补偿卛_Q一?/span>判决属适用法律错误?/span>
地址D范? | 220.181.0.0 - 220.181.255.255 |
|络? | CHINANET-IDC-BJ |
国家: | CN |
单位描述: | CHINANET Beijing province network |
单位描述: | China Telecom |
单位描述: | No.31,jingrong street |
单位描述: | Beijing 100032 |
理联系? | CH93-AP |
技术联pMh: | HC55-AP |
附注: | hostmaster is not for spam complaint, |
附注: | please send spam complaint to anti-spam@ns.chinanet.cn.net |
l护方帐? | MAINT-CHINANET |
ơl护? | MAINT-CHINATELECOM-BJ |
地址D늊? | ALLOCATED NON-PORTABLE |
更改记录: | hostmaster@ns.chinanet.cn.net 20030620 |
更改记录: | hm-changed@apnic.net 20050715 |
数据来源: | APNIC |
联系? | Chinanet Hostmaster |
联系人帐? | CH93-AP |
?sh)子邮g: | anti-spam@ns.chinanet.cn.net |
通信地址: | No.31 ,jingrong street,beijing |
通信地址: | 100032 |
?sh)? | +86-10-58501724 |
传真: | +86-10-58501724 |
国家: | CN |
更改记录: | lqing@chinatelecom.com.cn 20051212 |
l护方帐? | MAINT-CHINANET |
数据来源: | APNIC |
联系? | Hostmaster of Beijing Telecom corporation CHINA TELECOM |
联系人帐? | HC55-AP |
?sh)子邮g: | bjnic@bjtelecom.net |
通信地址: | Beijing Telecom |
通信地址: | No. 107 XiDan Beidajie, Xicheng District Beijing |
?sh)? | +86-010-58503461 |
传真: | +86-010-58503054 |
国家: | cn |
更改记录: | bjnic@bjtelecom.net 20040115 |
l护方帐? | MAINT-CHINATELECOM-BJ |
数据来源: | APNIC |
你可以想象的出,一个库函数的异怿息不完整Q对于他的用h_(d)是多么不友好的事情。假?/span>
MSDN
?/span>
File.Open()
?x)抛?/span>
IOException
Q你的程序就很难惛_很规矩的?/span>
IOException
做了
catch
Q然后提C用h查相应位|的文g是否存在
/
被打开{。别指望
MSDN
的那些信息能够对l端用户有多大的帮助Q太多不懂计机的h在傻呆呆的握着鼠标了。再加上
MicroSoft
的提CZ息本w就存在着“答非所问”,“莫名其妙”的事情Q用L(fng)到这些情况就更不知道怎么解决问题了。再加上自己的应用程序中?x)弹Z个个“蹩脚”的q行旉误的错误框,真的不是一个很如意的创作?/span>
但是Q如果用的?/span>
Checked Exception
Q这时候编译器?x)强q你的外部接口的异常相当的完_(d)最L(fng)可以做到?/span>
MSDN
的异常类型齐整?/span>
(zhn)还记得以前大多数开发h员是如何q求代码质量的吗。在那时Q有技巧地攄 main()
Ҏ(gu)被视为灵zM适当的测试方法。经历了漫长的道路以后,现在自动试已经成ؓ(f)高质量代码开发的基本保证Q对此我很感谢。但是这q不是我所要感谢的全部。Java?开发h员现在拥有很多通过代码度量、静态分析等Ҏ(gu)来度量代码质量的工具。我们甚臛_l设法将重构分类成一pd便利的模式!
![]() |
|
所有的q些新的工具使得保代码质量比以前简单得多,不过(zhn)还需要知道如何用它们。在q个pd中,我将重点阐述有关保证代码质量的一些有时看上去有点秘的东ѝ除了带(zhn)一L(fng)(zhn)有关代码质量保证的众多工具和技术之外,我还ؓ(f)(zhn)说明:(x)
在这个月Q我首先看?Java 开发h员中最行也是最Ҏ(gu)的质量保证工具包Q测试覆盖度量?/p>
q是一个晚上鏖战后的早晨,大家都站在饮水机边上。开发h员和理人员们了解到一些经q良好测试的cd以达到超q?90% 的覆盖率Q正在高兴地互换着 NFL 风格的点心。团队的集体信心I前高涨。从q处可以听到 “放d重构吧?的声韻Ig~陷已成为遥q的记忆Q响应性也已微不道。但是一个很的反对声在_(d)(x)
奛_们,先生们,不要被覆盖报告所愚弄?/p>
现在Q不要误解我的意思:(x)q不是说使用试覆盖工具是愚蠢的。对单元试范例Q它是很重要的。不q更重要的是(zhn)如何理解所得到的信息。许多开发团队会(x)在这儿犯W一个错?/p>
高覆盖率只是表示执行了很多的代码Qƈ不意味着q些代码?i>很好?/i> 执行。如果?zhn)x的是代码的质量,必ȝ地理解试覆盖工具能做什么,不能做什么。然后?zhn)才能知道如何使用q些工具去获取有用的信息。而不是像许多开发h员那P只是满于高覆盖率?/p>
![]() ![]() |
![]()
|
试覆盖工具通常可以很容易地d到确定的单元试q程中,而且l果可靠。下载一个可用的工具Q对(zhn)的 Ant ?Maven 构徏脚本作一些小的改动,(zhn)和(zhn)的同事有了在饮水上谈论的一U新报告Q?i>试覆盖报告。当 foo
?bar
q样的程序包令h惊奇地显C?i>?/i> 覆盖率时Q?zhn)可以得到不小的安慰。如果?zhn)怿臛_(zhn)的部分代码可以保证?“没?BUG?的,(zhn)会(x)觉得很安心。但是这样做是一个错误?/p>
存在不同cd的覆盖度量,但是l大多数的工具会(x)x行覆?/i>Q也叫做语句覆盖。此外,有些工具?x)报?i>分支覆盖。通过用一个测试工h行代码库q捕h个测试过E中与被 “触?qing)?的代码对应的数据Q就可以获得试覆盖度量。然后这些数据被合成盖报告。在 Java 世界中,q个试工具通常?JUnit 以及(qing)名ؓ(f) Cobertura、Emma ?Clover {的覆盖工具?/p>
行覆?/i>只是指出代码的哪些行被执行。如果一个方法有 10 行代码,其中?8 行在试中被执行Q那么这个方法的行覆盖率?80%。这个过E在M层次上也工作得很好:(x)如果一个类?100 行代码,其中?45 行被触及(qing)Q那么这个类的行覆盖率就?45%。同P如果一个代码库包含 10000 个非注释性的代码行,在特定的试q行中有 3500 行被执行Q那么这D代码的行覆盖率是 35%?/p>
报告分支覆盖 的工兯囑ֺ量决{点Q比如包含逻辑 AND
?OR
的条件块Q的覆盖率。与行覆盖一P如果在特定方法中有两个分支,q且两个分支在测试中都被覆盖Q那么?zhn)可以说这个方法?100% 的分支覆盖率?/p>
问题是,q些度量有什么用Q很明显Q很Ҏ(gu)获得所有这些信息,不过(zhn)需要知道如何用它们。一些例子可以阐明我的观炏V?/p>
![]() ![]() |
![]()
|
我在清单 1 中创Z一个简单的cM具体表述cdơ的概念。一个给定的cd以有一q串的父c,例如 Vector
Q它的父cL AbstractList
Q?code>AbstractList 的父cd?AbstractCollection
Q?code>AbstractCollection 的父cd?Object
Q?/p>
清单 1. 表现cdơ的c?/b>
|
正如(zhn)看到的Q清?1 中的 Hierarchy
cd有一?baseClass
实例以及(qing)它的父类的集合。清?2 中的 HierarchyBuilder
通过两个复制 buildHierarchy
的重载的 static
Ҏ(gu)创徏?Hierarchy
cR?/p>
清单 2. cdơ生成器
|
![]() ![]() |
![]()
|
有关试覆盖的文章怎么能缺测试案例呢Q在清单 3 中,我定义了一个简单的有三个测试案例的 JUnit 试c,它将试图执行 Hierarchy
cd HierarchyBuilder
c:(x)
|
因ؓ(f)我是一个狂热的试人员Q我自然希望q行一些覆盖测试。对?Java 开发h员可用的代码覆盖工具中,我比较喜Ƣ用 CoberturaQ因为它的报告很友好。而且QCorbertura 是开放源码项目,它派生出?JCoverage 目的前w?/p>
![]() ![]() |
![]()
|
q行 Cobertura q样的工具和q行(zhn)的 JUnit 试一L(fng)单,只是有一个用专门逻辑在测试时查代码以报告覆盖率的中间步骤Q这都是通过工具?Ant d?Maven 的目标完成的Q?/p>
正如(zhn)在?1 中看到的Q?code>HierarchyBuilder 的覆盖报告说明部分代?i>没有 被执行。事实上QCobertura 认ؓ(f) HierarchyBuilder
的行覆盖率ؓ(f) 59%Q分支覆盖率?75%?/p>
?1. Cobertura 的报?/b>
q样看来Q我的第一ơ覆盖测试是p|的。首先,带有 String
参数?buildHierarchy()
Ҏ(gu)Ҏ(gu)没有被测试。其ơ,另一?buildHierarchy()
Ҏ(gu)中的两个条g都没有被执行。有的是,所要关注的正是W二个没有被执行?if
块?/p>
因ؓ(f)我所需要做的只是增加一些测试案例,所以我q不担心q一炏V一旦我到达了所x的区域,我就可以很好地完成工作。注意我q儿的逻辑Q我使用试报告来了解什?i>没有 被测试。现在我已经可以选择使用q些数据来增强测试或者l工作。在本例中,我准备增强我的测试,因ؓ(f)我还有一些重要的区域未覆盖?/p>
清单 4 是一个更新过?JUnit 试案例Q增加了一些附加测试案例,以试囑֮全执?HierarchyBuilder
Q?
|
当我使用新的试案例再次执行试覆盖q程Ӟ我得C如图 2 所C的更加完整的报告。现在,我覆盖了未测试的 buildHierarchy()
Ҏ(gu)Q也处理了另一?buildHierarchy()
Ҏ(gu)中的两个 if
块。然而,因ؓ(f) HierarchyBuilder
的构造器?private
cd的,所以我不能通过我的试cL试它Q我也不兛_Q。因此,我的行覆盖率仍然只有 88%?/p>
?2. 谁说没有W二ơ机?/b>
正如(zhn)看到的Q用一个代码覆盖工?i>可以 揭露重要的没有相应测试案例的代码。重要的事情是,在阅L告(特别 是覆盖率高的Q时需要小心,它们也许隐含危险的信息。让我们看看两个例子Q看看在高覆盖率后面隐藏着什么?/p>
![]() ![]() |
![]()
|
正如(zhn)已l知道的Q代码中的许多变量可能有多种状态;此外Q条件的存在使得执行有多条\径。在留意q些问题之后Q我在清单 5 中定义一个极其简单只有一个方法的c:(x)
|
(zhn)是否发C清单 5 中有一个隐藏的~陷呢?如果没有Q不要担心,我会(x)在清?6 中写一个测试案例来执行 pathExample()
Ҏ(gu)q确保它正确地工作:(x)
|
我的试案例正确q行Q我的神奇的代码覆盖报告Q如下面?3 所C)使我看上d个超U明星,试覆盖率达C 100%Q?/p>
?3. 覆盖率明?
我想现在应该到饮水机边上去说了,但是{等Q我不是怀疑代码中有什么缺陷呢Q认真检查清?5 ?x)发玎ͼ如?condition
?false
Q那么第 13 行确实会(x)抛出 NullPointerException
?i>YeeshQ这儿发生了什么?
q表明行覆盖的确不能很好地指C测试的有效性?/p>
![]() ![]() |
![]()
|
在清?7 中,我定义了另一个包?indirect 的简单例子,它仍然有不能容忍的缺陗请注意 branchIt()
Ҏ(gu)?if
条g的后半部分。(HiddenObject
cd在清?8 中定义。)
|
呀Q清?8 中的 HiddenObject
?i>有害?/i>。与清单 7 中一P调用 doWork()
Ҏ(gu)?x)导?RuntimeException
Q?/p>
清单 8. 上半部分Q?
|
但是我的可以通过一个良好的试捕获q个异常Q在清单 9 中,我编写了另一个好的测试,以图挽回我的明星光环Q?/p>
清单 9. 使用 JUnit 规避风险
|
(zhn)对q个试案例有什么想法?(zhn)也怼(x)写出更多的测试案例,但是误想一下清?7 中不定的条件有不止一个的~短操作?x)如何。设惛_果前半部分中的逻辑比简单的 int
比较更复杂,那么(zhn)?/i> 需要写多少试案例才能满意Q?/p>
现在Q对清单 7?? 的测试覆盖率的分析结果不再会(x)使?zhn)感到惊讶。在?4 的报告中昄我达C 75% 的行覆盖率和 100% 的分支覆盖率。最重要的是Q我执行了第 10 行!
从第一印象看,q让我骄傌Ӏ但是这个报告有什么误导吗Q只是粗略地看一看报告中的数字,?x)导致(zhn)怿代码是经q?i>良好试?/i>。基于这一点,(zhn)也怼(x)认ؓ(f)出现~陷的风险很低。这个报告ƈ不能帮助(zhn)确?or
~短操作的后半部分是一个定时炸弹!
![]() ![]() |
![]()
|
我不止一ơ地_(d)(x)(zhn)可以(而且应该Q用测试覆盖工具作为?zhn)的测试过E的一部分。但?i>不要被覆盖报告所愚弄。关于覆盖报告?zhn)需要了解的主要事情是,覆盖报告最好用来检查哪些代?i>没有l过 充分的测试。当(zhn)检查覆盖报告时Q找低的|q了解ؓ(f)什么特定的代码没有l过充分的测试。知道这些以后,开发h员、管理h员以?QA 专业人员可以在真正需要的地方使用试覆盖工具。通常有下列三U情况:(x)
现在我可以断定对试覆盖报告的一些用方法会(x)?zhn)引入歧途,下面q些最?jng)_践可以得测试覆盖报告可以真正ؓ(f)(zhn)所用?/p>
对一个开发团队而言Q针对代码编写测试案例自然可以增加集体的信心。与没有相应试案例的代码相比,l过试的代码更Ҏ(gu)重构、维护和增强。测试案例因为暗CZ代码在测试工作中?i>如何 工作的,所以还可以充当内行的文。此外,如果被测试的代码发生改变Q测试案例通常也会(x)作相应的改变Q这与诸如注释和 Javadoc q样的静态代码文档不同?/p>
在另一斚wQ没有经q相应测试的代码更难于理解和安全?/i> 修改。因此,知道代码有没有被试Qƈ看看实际的测试覆盖数|可以让开发h员和理人员更准地预知修改已有代码所需的时间?/p>
再次回到饮水上,可以更好地阐明我的观炏V?/p>
市场部的 LindaQ“我们想让系l在用户完成一W交易时?x 工作。这需要多长时间。我们的用户需要尽快实现这一功能。?
理人员 JeffQ“让我看看,q个代码?Joe 在几个月前编写的Q需要对业务层和 UI 做一些变动。Mary 也许可以在两天内完成q项工作。?
LindaQ“JoeQ他是谁Q?
JeffQ“哦QJoeQ因Z不知道自己在q什么,所以被我解雇了。?
情况g有点不妙Q不是吗Q尽如此,Jeff q是Q务分配给?MaryQMary 也认够在两天内完成工?—?切地说Q在看到代码之前Ҏ(gu)q么认ؓ(f)的?/p>
MaryQ“Joe 写这些代码时是不?i>睡着?/i>Q这是我所见过的最差的代码。我甚至不能认q是 Java 代码。除非推倒重来,要不我根本没法修攏V?
情况?“饮水机?团队不妙Q不是吗Q但是我们假设,如果在这个不q的事g的当初,Jeff ?Mary 拥有一份测试报告,那么情况?x)如何呢Q当 Linda 要求实现新功能时QJeff 做的W一件事是查以前生成的覆盖报告。注意到需要改动的软g包几乎没有被覆盖Q然后他׃(x)?Mary 商量?/p>
JeffQ“Joe ~写的这个代码很差,l大多数没经q测试。?zhn)认?f)要支?Linda 所说的功能需要多长时_(d)?
MaryQ“这个代码很混ؕ。我甚至都不想看到它。ؓ(f)什么不?Mark 来做呢??
JeffQ“因?Mark 不编写测试,刚被我解雇了。我需要?zhn)试q个代码q作一些改动。告诉我(zhn)需要多长时间。?
MaryQ“我臛_需要两天编写测试,然后我会(x)重构q个代码Q增加新的功能。我xd需要四天吧。?
正如他们所说的Q知识的力量是强大的。开发h员可以在试图修改代码之前 使用覆盖报告来检查代码质量。同P理人员可以使用覆盖数据更好C计开发h员实际所需的时间?/p>
开发h员的试可以降低代码中存在缺L(fng)风险Q因此现在很多开发团队在新开发和更改代码的同旉要编写单元测试。然而正如前面所提到?Mark 一Pq不L在编码的同时q行单元试Q因而会(x)D低质量代码的出现?/p>
监控覆盖报告可以帮助开发团队迅速找Z断增长的没有 相应试的代码。例如,在一周开始时q行覆盖报告Q显C项目中一个关键的软g包的覆盖率是 70%。如果几天后Q覆盖率下降C 60%Q那么?zhn)可以推断Q?/p>
能够监控事情的发展,无疑是g好事。定期地查阅报告使得讑֮目标Q例如获得覆盖率、维护代码行的测试案例的比例{)q监控事情的发展变得更ؓ(f)Ҏ(gu)。如果?zhn)发现试没有如期~写Q?zhn)可以提前采取一些行动,例如对开发h员进行培训、指导或帮助。与其让用户 “在使用中?发现E序~陷Q这些缺h应该在几个月前通过单的试暴露出来Q,或者等到管理h员发现没有编写单元测试时再感到惊Ӟ和愤怒)Q还不如采取一些预防性的措施?/p>
使用覆盖报告来确保正的试是一伟大的实践。关键是要训l有素地完成q项工作。例如,使每晚生成ƈ查阅覆盖报告成ؓ(f)q箋累计 q程的一部分?/p>
假设覆盖报告在指?i>没有l过 _试的代码部分方面非常有效,那么质量保证人员可以使用q些数据来评定与功能试有关的关注区域。让我们回到 “饮水机?团队来看?QA 的负责h Drew 是如何评?Joe 的代码的Q?/p>
Drew ?Jeff _(d)(x)“我们ؓ(f)下一个版本编写了试案例Q我们注意到很多代码没有被覆盖。那好像是与股票交易有关的代码。?
JeffQ“哦Q我们在q个领域有好些问题。如果我是一个赌徒的话,我会(x)对这个功能区域给予特别的x。Mary 正在对这个应用程序做一些其他的修改 —?她在~写单元试斚w做得很好Q但是这个代码也太差了点。?
DrewQ“是的,我正在确定工作的资源和别,看上L没必要那么担心了Q我估计我们的团队会(x)对股交易模块引赯够的x。?
知识再次昄了其强大的力量。与其他软g生命周期中的风险承担者(例如 QAQ配合,(zhn)可以利用覆盖报告所提供的信息来降低风险。在上面的场景中Q也?Jeff 可以?Drew 的团队提供一个早期的不包?Mary 的所有修改的版本。不q无论如何,Drew 的团队都应该x应用E序的股交易方面,与其他具有相应单元测试的代码相比Q这个地方似乎存在更大的~陷风险?/p>
![]() ![]() |
![]()
|
对单元测试范例而言Q测试覆盖度量工h一个有点奇怪的l成部分。对于一个已存在的有益的q程Q覆盖度量可以增加其深度和精度。然而,(zhn)应该仔l地阅读代码覆盖报告。单独的高覆盖率q不能确保代码的质量。对于减缺P代码的高覆盖q不是必要条Ӟ管高覆盖的代码的确更少 有缺陗?/p>
试覆盖度量的窍门是使用覆盖报告扑և未经 试的代码,分别在微观和宏观两个U别。通过从顶层开始分析?zhn)的代码库Q以?qing)分析单个类的覆盖,可以促进深入的覆盖测试。一旦?zhn)能够l合q些原则Q?zhn)和(zhn)的组l就可以在真正需要的地方使用覆盖度量工具Q例如估计一个项目所需的时_(d)持箋监控代码质量以及(qing)促进?QA 的协作?/p>
The Proxy pattern is an important and widely used design pattern in object-oriented programming. Do you ever use Proxy
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 InvocationHandler
. So Proxy
is an important class in Java's reflection package, and is widely used in many Java applications.
One limitation of Proxy
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.
This article introduces Dynamic Delegation, which can create delegation for both interfaces and classes at runtime.
In JDK 1.3, the Proxy
class was added to java.lang.reflect
. 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 InvocationHandler
.
Given two interfaces, Idel1
and Idel2
, Proxy
will create a IdelProxy
class as the proxy of these two interfaces (I use IdelProxy
as the generated proxy class name for convenience). Figure 1 shows this arrangement.
Figure 1. Class diagram of IdelProxy
Below is the related code snippet.
Class clazz = Proxy.getProxyClass(
Idel1.class.getClassLoader(),
new Class[] { Idel1.class, Idel2.class });
Proxy
only works for interfaces. What if we need it to work for both classes and interfaces? The Dunamis project on java.net introduces Delegation
as an alternative to Proxy
. Delegation
uses a different approach than Proxy
.
Given a class named TestBean
, the delegation class TestBeanDelegation
's class diagram is shown in Figure 2.
Figure 2. Class diagram of TestBeanDelegation
(click for full-size image)
TestBeanDelegation
implements the Delegation
interface and extends the TestBean
class. It also contains references to TestBean
and DelegationInvocationHandler
. All of the method calls on TestBeanDelegation
will be delegated to them.
Take getName()
as an example. The chart in Figure 3 illustrates the sequence of the method call.
Figure 3. Sequence chart of TestBeanDelegation.getName()
(click for full-size image)
The related pseudocode is:
//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);
}
}
}
Dynamic Delegation is based on the Jakarta Byte-Code Engineering Library (BCEL). 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.
The interface/class to be delegated should meet the following conditions:
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 Object
.
The delegation class will call the superclass' default constructor in its own constructor.
The proxy class generated by Proxy
is final. It will not be accepted by Dynamic Delegation.
Delegation
interface.
Since it is already a delegation class, why would you need to delegate it again?
The generated delegation class has the following characteristics:
Delegation
interface.
Object
instance as a parameter. DelegationGenerator
is the main class of Dynamic Delegation. A client can use it to generate a delegation class/object for a specific class/interface/object. DelegationInvocationHandler
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 _getInvocationHandler()
and _setInvocationHandler()
methods defined in Delegation
to access the DelegationInvocationHandler
instance in the delegation object.
Suppose there is a concrete class named ConcreteClass
:
//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");
}
}
The following code generates a delegation class for ConcreteClass
.
//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));
}
}
The output shows:
Delegation class name =
org.jingle.util.dydelegation.sample.ConcreteClass_Delegation_0
true
DelegationGenerator.getDelegationClass()
accepts a class array as parameter and return a Java Class
that extends/implements the given class/interfaces. By default, the generated delegation class is in the same package as the class to be delegated.
The delegation class can be instantiated as below:
//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);
DelegationGenerator
can also generate a concrete delegation class for an abstract class.
//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()));
}
}
Output:
Delegation class name =
org.jingle.util.dydelegation.sample.AbstractClass_Delegation_0
false
The generated delegation class is a concrete class instead of an abstract class.
DelegationGenerator.getDelegationClass()
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.
//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));
}
}
Output:
true
true
true
The generated delegation class extends the given class ConcreteClass
and implements all of the given interfaces: Idel1
and Idel2
.
DelegationGenerator
can generate a delegation object directly, according to a specific object to be delegated.
// 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);
}
}
Output:
Interrupted by SimpleHandler
Hello from ConcreteClass
Hello again from ConcreteClass
Interrupted by SimpleHandler
org.jingle.util.dydelegation.sample.ConcreteClass@ef5502
DummyInvocationHandler
is a dummy implementation of DelegationInvocationHandler
. It always returns true
in invokeBefore()
, returns the input result directly in invokeAfter()
, and throws the input throwable directly in invokeAfterException()
. The delegation object with DummyInvocationHandler
has same behavior as the object to be delegated.
DelegationGenerator.newDelegationInstance()
accepts an object and an DelegationInvocationHandler
instance as parameters. It returns a delegation object to delegate the given object.
All of the methods called on the delegation object will be delegated to the DelegationInvocationHandler
instance, except:
Object
class, other than hashCode()
, equals()
, and toString()
. Did you ever want to delegate an object of an existing Java core class? Delegate it as usual.
//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);
}
}
Output:
Delegation class = org.jingle.util.dydelegation.Date_Delegation_0
True date = 1099380377665
Delegation date = 1099380376665
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 ClassLoader
to define a class in a package starting with java
.
DateClassHandler
catches the getTime()
method call in invokeAfter()
, and makes the return value 1000 less than the normal return value.
Can Dynamic Delegation do what Proxy
does? Absolutely! Dynamic Delegation covers the functions of Proxy
. Given a proper delegation handler, it can simulate the behavior of a Java Proxy
.
// 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);
}
}
Output:
Hello from idel1
Hello from idel2
ProxyHandler
returns false
in invokeBefore()
, which means all of the method calls on the delegation object will not be delegated to the original object. It uses invokeAfter()
to define the delegation behavior as being what Proxy
does.
DelegationGenerator.newDelegationInstance()
has another version. It contains four arguments:
Object
to be delegated.
This can be null
. If it is not null
, it must be an instance of all of the given classes and interfaces.
Class
to be delegated.
This can contain multiple interfaces and, at most, one class.
If null
, a system-generated name will be provided.
DelegationInvocationHandler
instance, which is used to define the delegation's behavior. From the output, we can see that the delegation object is an instance of both Idel1
and Idel2
. Its behavior is just what is defined in the handler.
Until now, we've delegated all of the functions of the specific object. How about just delegating part of the object's functions?
//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);
}
}
Output:
true
true
false
MyDate
extends Date
and implements the Idel1
and Idel2
interfaces. DelegationGenerator.newDelegationInstance()
uses a MyDate
instance as the object instance to be delegated, and limits the delegation scope in Idel1
and Idel2
. In other words, the generated delegation object is an instance of Idel1
and Idel2
, but not an instance of Date
.
The Dunamis project introduces Dynamic Delegation to extend the function of the Java Proxy
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.
Lu Jian is a senior Java architect/developer with four years of Java development experience.
Suppose there is a concrete class named ConcreteClass
:
//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");
}
}
The following code generates a delegation class for ConcreteClass
.
//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));
}
}
The output shows:
Delegation class name =
org.jingle.util.dydelegation.sample.ConcreteClass_Delegation_0
true
DelegationGenerator.getDelegationClass()
accepts a class array as parameter and return a Java Class
that extends/implements the given class/interfaces. By default, the generated delegation class is in the same package as the class to be delegated.
The delegation class can be instantiated as below:
//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);
DelegationGenerator
can also generate a concrete delegation class for an abstract class.
//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()));
}
}
Output:
Delegation class name =
org.jingle.util.dydelegation.sample.AbstractClass_Delegation_0
false
The generated delegation class is a concrete class instead of an abstract class.
DelegationGenerator.getDelegationClass()
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.
//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));
}
}
Output:
true
true
true
The generated delegation class extends the given class ConcreteClass
and implements all of the given interfaces: Idel1
and Idel2
.
DelegationGenerator
can generate a delegation object directly, according to a specific object to be delegated.
// 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);
}
}
Output:
Interrupted by SimpleHandler
Hello from ConcreteClass
Hello again from ConcreteClass
Interrupted by SimpleHandler
org.jingle.util.dydelegation.sample.ConcreteClass@ef5502
DummyInvocationHandler
is a dummy implementation of DelegationInvocationHandler
. It always returns true
in invokeBefore()
, returns the input result directly in invokeAfter()
, and throws the input throwable directly in invokeAfterException()
. The delegation object with DummyInvocationHandler
has same behavior as the object to be delegated.
DelegationGenerator.newDelegationInstance()
accepts an object and an DelegationInvocationHandler
instance as parameters. It returns a delegation object to delegate the given object.
All of the methods called on the delegation object will be delegated to the DelegationInvocationHandler
instance, except:
Object
class, other than hashCode()
, equals()
, and toString()
. 1)本质上,软g开发中一切代码都需要重构。经q单元测试覆盖的代码可以让我拥有信心去重构。我也不知道q有什么其他办法能够让我获得如此的信心。如果没有信心,那么我就不太敢经常的重构Q这也必然媄响代码的品质?/SPAN>
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.
2Q由于单元测试的自然Ҏ(gu)(注意是单元测试)Q无法对h“坏味道”的代码q行单元试。而ؓ(f)了能够顺利的对你的代码进行单元测试,那么你的代码׃(x)逐渐的变得更加清晰、设计更加完善:(x)代码短小、专注方法、针Ҏ(gu)口编E、降低耦合{?/SPAN>
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.
我想Q也许单元测试的提倡者事前也未曾?x)预料到它能够带来这已经证实了的益处。我惻I刚开始h们也只是希望发挥计机的特点,让它完成重复性的工作Q这里是指测试)Q而不再需要h去进行测试。但是他们发C“副产品”―测试需要更好的设计。接着Q他们中的杰提Z一个全新的xQ既然如此,那何不事先写好测试呢Q设计是应该在代码实C前的Q而如果测试可以媄响设计,那么何不也将试在代码实C前进行编写呢Q?/SPAN>
And the TDD started...
于是TDD开始了…??BR>
====================================
http://www.theserverside.com/news/thread.tss?thread_id=32394#160294
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:
1. There is a lot of test-centric coding with less focus on ensuring overall business requirement is fulfilled.
2. Developers seem to think that having run the product through the Unit tests ensures that the product is well-tested and production ready.
我对TDD所引v的问题非常的同意Q但是问题更在于Z如何解决它,而不是仅停留在基本的观念上。TDD主要引v的问题是Q?
1?存在着太多的“以试Z心”的代码Q而更的x于整体的业务需求?
2、开发者好像开始认遍单元测试就可以保证产品的可试和品的质量?
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.
所有的TDD能做的是在整个项目构建结束之后完成一个检查工作,保证原有的单元之间的契约没用被打破。在目构徏完成后,q需要一个质量保?quality assurance)的过E,以保证整个项目的功能。也是说自动化试只是一个附加的查,而不是对质量保证的全盘替代。但不幸的是Q我看到的h们却非如此。他们认Z旦单元测试成功,那么可以减QA上面的时间。但事实真的不是q样的。单元测试所能做倒的也仅在于单元试已经很好的编写完成,代码的质量更Ҏ(gu)辑ֈQA的标准?