• 00
  • 00小时
  • 00
  • 00
2023敏捷武林大会-上海站,正火热免费报名中...
Search
Close this search box.

矛盾:全部测试,除了Accessor类?

在Raikes学院的敏捷开发者技能课程上,我说我们通常不测试Accessor。但是我们不是可以测试所有的吗,这是不是很矛盾啊?
上周,我和切特, Cheezy参加内布拉斯加大学(林肯)Raikes学院的CSM 课程和一节敏捷开发者技能课。真是很有意思。在快结束的时候,大家提到一件关心的事,我决定提笔写写这个。
课程中间有一个环节,我们将参与者的代码显示在屏幕上。很自然地,我们让他们试着做TDD。
许多团队已经在课堂上写过一堆关于Accessor的文章,并且每写一篇都尽职尽责。我的意见是我不会专门来为Accessor写测试。我试着这样解释Accessor的测试可以包含在其他测试之中,但显然这样讲也不奏效,因为最后他们会说这很矛盾。所以,我决定在这儿做更进一步的全面解释。
为了让课程参与者更加了解熟悉,我就来讲讲工资表的例子,这个我之前在课堂上也用过。同时为增加趣味,我就在Scala里做。我相信读者们都能读明白。
来看我是怎么做的吧。我的计划是这样的:我接下去补充讲一些工资表的例子,一气讲下去,设计中需要许多Accessor。我不写Accessor测试,在最后,所有的Accessor都会被测试!没有Accessor测试,但是Accessor却被检测了?这怎么可能?继续读吧……
我提议的设计是设个“时间表”项和“职员”项,然后将二者运用到付款人一项中。
在最终的系统中,我想工资项在职员项循环结束,将职员和时间表导向付款人,但是现在,这一操作将在测试的控制之下完成。
这三个主要项应该能充足说明我为什么不直接测试Accessor。
恐怕我的这个例子对于TDD 初学者来说有点难度 ……甚至对我自己来说。作为一个辅助项目,大家来看看我是否会遇到问题。
我假设凯特 奥尼尔每小时挣150美金,她常规工作40个小时,10个小时的百分之一百五十加班,以及5个小时的双倍工资加班。 (但凯特那么聪明,她才不会那么干) 不管怎样,以下是我们的测试:
import org.scalatest.Spec

class PayrollTests extends Spec {
describe ( “Payroll Testing” ) {

it ( “should calculate Kate base pay” ) {
val employee = new Employee(“Kate”, 150)
val timesheet = new Timesheet(40,10,5)
val payer = new Payer(employee , timesheet )
expect(9750)(payer.grossPay)
}
}
}
这里也没有什么可看的,真的。我们假设一位职员,凯特,她的工资率是150。我们来给她的工作时间做个表单。在这两项的基础上,我们这边做付款人,然后看看凯特的总工资(希望我计算是正确的。你们知道Windows 7 计算器允许括号吗?它允许的。
当然,这个编码不能汇编。所有,我来设立分项。这样很快,在测试规则运行的十分钟之内……   我希望!
class Employee(private val _name: String, private val _payrate:Int) {

}

class Timesheet(
private val _regularHours:Int,
private val _ot1Hours:Int,
private val _ot2Hours:Int) {

}

class Payer(private val _employeee:Employee, private val _timesheet:Timesheet) {

}
这三项几乎足够让程序进行汇编。最后一件点:我们需要总工资方法:
class Payer(private val employeee:Employee, private val timesheet:Timesheet) {
def grossPay = 666
}
这就足够汇编,并且能运行测试。我们得到的答案是“期望得到9750,而不是666”。我们可以继续补充。当然,我们知道,总工资应该这么计算:工资率*常规工作时间 + 工资率* 1.5 * 加班1小时+工资率 * 2 * 加班2小时。我们把这些敲进去:
def grossPay = _timesheet.regularHours*_employee.payrate +
_timesheet.ot1Hours*_employee.payrate*1.5 +
_timesheet.ot2Hours*_employee.payrate*2
这个没法汇编(一点也不意外)因为 我们不能从职员和时间表这两项中得出值。那么就一个一个来吧,我们补充进Accessor,直到编译器乖乖听话。
class Employee(private val _name: String, private val _payrate:Int) {
def payrate = _payrate
}

class Timesheet(
private val _regularHours:Int,
private val _ot1Hours:Int,
private val _ot2Hours:Int) {

def regularHours = _regularHours
def ot1Hours = _ot1Hours
def ot2Hours = _ot2Hours
}
现在我们再来运行一下测试……颜色变成绿色了!
真是个大难题……
三个分类项, 一堆Accessor,一种方法,来自同一个测试。这可比我通常所做的要多点,比我建议 TDD初学者的也多点。运行良好,可也有出错的可能,调试的话也许要话费不少时间。 在这种情况下,我心里很清楚自己要做什么…… 我很幸运。你弱势喜欢在家里也可以试试……记得保持清醒,一旦它出错,小的步骤兴许更好。无论如何,我们达到了期望的效果了:
所有的都能测试……但就是不能测试Accessor!
标示下结果:所有的Accessor都被检测了……但我们可从没有给Accessor写过什么测试。 相反,我们有操作性能测试,但这是要求我们写某些Accessor的:只有在Accessor存在且正确的情形下才能正常运行。为了让测试运行,所有功能性测试需要我们补充Accessor(但是有更多的操作代码)
当你发现自己需要Accessor测试驱动,你没有其他的失败测试,如果你有那个Accessor写个只能运作的测试。测试实际上是推进应用的,而不仅仅是一种价值的检测。
这可不是玩文字游戏。任何时候只要我们认为自己需要Accessor,我们会一直等,知道编码告诉我们确实需要,通过一个错误的测试。然后,使得,只是在这之后,我们来写Accessor……我们现存的错误测试来对Accessor进行跟踪测试。这样的工作方式让我们将注意力放在推进提高应用上,而不是协和简单的代码测试,也不是到哪天需要的测试。

 

作者:Ron Jeffries

原文地址:http://xprogramming.com/articles/contradiction-test-everything-but-not-accessors/

Search
最新敏捷认证课 ~ 火热报名中
4月26-27日
Scrum Master (CSM) 认证课
王军 Jim Wang授课
5月18-19日
Leading SAFe领导大规模敏捷认证课
Eric & Scott 授课
5月18-19日
专业Scrum Master (PSM I) 认证公开课
丁志润 Derek Ding 授课
5月25-26日
Scrum Master (CSM) 认证课
Lance Zhang 授课
6月22-23日
Scrum Master (CSM) 认证课
Scott Dunn & Eric Liao授课
6月22-23日
专业Scrum产品负责人(PSPO)认证公开课
丁志润 Derek Ding 授课
分类文章
9月15-17日
SAFe ScrumMaster & Leading SAFe官方认证双证班
Eric Liao & Scott Wang 授课
9月18-22日
SAFe认证-SPC SAFe认证培训师导师班
Kurt Jäger & Eric Liao 授课

预约回电

课程顾问将尽快给您回电
电话咨询 400 696 6280