是否还记得今年 rubyconfchina,陈金洲同学的演讲,总体来说非常精彩,只不过这哥们说话太快太快了~!呵呵。这是前提,其实我要说的是代码量和测试覆盖率。关于陈老大的 3000 行理论和 104%?140% 的测试覆盖率问题,一直心存疑惑,后来 rake stats 一下自己的工程,代码量 2280+ 行,覆盖率 1:0.3==30%(其实没怎么写)。于是乎很感兴趣的把 rubychina 的代码 clone 下来,跑了一下。结果如下:
求解释啊~!
其实我后面写了一堆话,删掉了。。。感觉也没什么意思。 我的意思是,测试覆盖率跟测试成效,不相关。它仅仅是一个指标而已,你都可以翻翻它统计的代码,绝对看不出它能反映出来什么。
最重要的是如何写有效的测试,去年我的 RubyConf China 演讲里有稍微提到一点点。
我们团队的项目——
$ rake stats
+----------------------+-------+-------+---------+---------+-----+-------+
| Name | Lines | LOC | Classes | Methods | M/C | LOC/M |
+----------------------+-------+-------+---------+---------+-----+-------+
| Decorators | 71 | 60 | 3 | 10 | 3 | 4 |
| Entities | 1181 | 984 | 31 | 44 | 1 | 20 |
| Inputs | 14 | 10 | 1 | 1 | 1 | 8 |
| Presenters | 467 | 420 | 21 | 30 | 1 | 12 |
| Repositories | 352 | 301 | 24 | 1 | 0 | 299 |
| Services | 738 | 589 | 38 | 59 | 1 | 7 |
| Uploaders | 55 | 13 | 1 | 3 | 3 | 2 |
| Validators | 149 | 128 | 7 | 16 | 2 | 6 |
| Controllers | 937 | 766 | 28 | 121 | 4 | 4 |
| Helpers | 85 | 68 | 0 | 18 | 0 | 1 |
| Models | 531 | 420 | 35 | 35 | 1 | 10 |
| Mailers | 0 | 0 | 0 | 0 | 0 | 0 |
| Javascripts | 351 | 258 | 0 | 73 | 0 | 1 |
| Libraries | 1042 | 860 | 31 | 110 | 3 | 5 |
| Controller specs | 559 | 460 | 0 | 0 | 0 | 0 |
| Decorator specs | 14 | 10 | 0 | 0 | 0 | 0 |
| Entity specs | 539 | 430 | 0 | 5 | 0 | 84 |
| Helper specs | 36 | 29 | 0 | 0 | 0 | 0 |
| Lib specs | 85 | 69 | 0 | 0 | 0 | 0 |
| Model specs | 124 | 95 | 3 | 0 | 0 | 0 |
| Presenter specs | 248 | 190 | 0 | 0 | 0 | 0 |
| Routing specs | 8 | 7 | 0 | 0 | 0 | 0 |
| Service specs | 599 | 487 | 3 | 2 | 0 | 241 |
| Validator specs | 269 | 210 | 1 | 3 | 3 | 68 |
| Javascript specs | 148 | 102 | 0 | 34 | 0 | 1 |
+----------------------+-------+-------+---------+---------+-----+-------+
| Total | 8602 | 6966 | 227 | 565 | 2 | 10 |
+----------------------+-------+-------+---------+---------+-----+-------+
Code LOC: 4979 Test LOC: 1987 Code to Test Ratio: 1:0.4
根据项目, 小站,小测。(给客户做个企业形象站,没测试代码。) 重要项目,事关重大,多测。(曾经 50 号<都是专业无新手>人专职测试半年,就发现了几个 bug<5 个) 要命的核心项目的核心模块,测试远大于开发。
SimpleCov 的覆盖是 statement coverage。说的是,每个语句是否有执行而已,比较容易。还有 branch coverage,path coverage 之类的。
@liwei78 @fredwu @Rei 现在遇到 一个问题。求教: 例如。我要写一个单元测试去验证用户的 email 是否合法,tdd 应该怎么做啊?先写测试?写一个不能通过的测试,然后让这个测试通过?例如
test 'user email not valid' do
user = User.new(email:'abce')
assert user.invalid?,'user email is not valid '
end
这样可以吗? 我是不是还需要一下测试
test 'user email is valid' do
user = User.new(email:'[email protected]')
assert user.valid?,'user email is valid '
end
在上面我验证了用户的 email。下面我要验证用户的手机号。 我不得不修改上面的代码,加上手机号,这样保证上面的代码是正常的,然后才可以继续验证手机号~!,这样是不是写的太多了。或者说,我可以把验证用户的信息放在同一个测试用力里面完成,例如
test 'user attribute is valid ' do
user = User.new(email:'[email protected]',telphone:'18900000001')
assert user.valid?,'user attribute is valid '
end
太菜太菜。虚心听取建议~!
#23 楼 @jarorwar 不用这么折腾,测试可以这么来考虑。
1、测试不求全,求准。那么,email 有 2 个测试,手机有 2 个测试,你就可以写 4 个测试放在那里。其实没必要说先什么后什么,但是,你要先知道,“我有 4 个测试放在那了,我要让他们完成”。
2、测试最小化。email 测试,假设有 N 种情形,那么你就需要 N 种情形的测试放在那(这个例子让人乏味,何况,你 user 一定用了很好的 gem,它里面已经把 email 测试的很准确了,你不用重复劳动。)这个最小,就是测试目标最小。一个 email,一个手机号,一个商品的编号,一个用户的交易状态,等等,这些最小的测试目标(最好是从最重要的开始),一定要测试用例丰富一些,包含的范围广一些。 一句话:先测试最重要的。
3、写完的测试就不要追加了。因为(1)测试不是业务逻辑,你针对新出现的变动单独的做测试即可,不用去改之前的测试用例,除非有绝对的必要。(2)测试用例变动是很危险的。因为,签收后的测试用例不能再变动了,我的观点是,测试变动以为流程变动,所以测试用例规划是要很科学的进行,不能想加就加的。
做个别的练习,别用这个例子纠结。比如图书购买,vip 和普通用户的区别,购买优惠,运费优惠,你可以自己制定一个流程,然后写测试用例的条目,我们一起探讨。。
测试的“准”是说验证情形准,丰富,一个订单逻辑走下来,1 个 C,2 个 M,估计就能上百个测试用例了。书上讲有的项目上万的测试用例,维护起来都要专门的人员。测试用例编写和代码一样,所以结对编程可以一个开发一个测试,当然也可以 2 个人都同时写一个测试。
# valid user attributes
def user_attributes
{ :email => '[email protected]', :telphone => '18900000001' }
end
test 'user attributes is valid' do
user = User.new user_attributes
assert user.valid?
end
test 'user email not valid' do
user = User.new( user_attributes.merge( :email => 'abce' ) )
assert user.invalid?
end
这是不借助其他 gems 做的,实际上还会遇到 email 是否唯一的问题,更方便的是借助 FactoryGirl 来定义 valid 的测试对象。
#28 楼 @Rei 不错。看啦。谢谢啦~,现在学习阶段暂时先从 test-unit 然后到 rspec 然后在考虑 factorygirl 和别的东西吧~!
另外。我这样写
def setup
@paper = Paper.new
@paper.title = "测试调查问卷"
@paper.start_time = DateTime.now - 2.days
@paper.end_time = DateTime.now + 2.days
end
test "没有标题不能保存調查问卷" do
@paper.title = nil
assert !@paper.save ,'保存了没有标题的调查问卷!'
end
test "保存有标题的调查问卷" do
assert @paper.save ,'未能成功保存有标题的调查问卷'
end
test '标题应该大于3个字符' do
assert @paper.valid? ,'标题应该大于3个字符'
end
test '开始时间为空' do
@paper.start_time = nil
assert @paper.invalid?,'开始时间为空'
end
test '开始时间不为空' do
assert @paper.valid? , '开始时间不能为空'
end
test '结束时间不能为空' do
@paper.end_time = nil
assert @paper.invalid?, '结束时间不能为空'
end
test '结束时间大于开始时间' do
@paper.end_time = @paper.start_time + 5.days
assert @paper.valid? ,'结束时间大于开始时间'
end
这样是否 ok,或者有什么地方有问题呢?
好吧,我项目 2100 行,测试是代码的两倍。。
+----------------------+-------+-------+---------+---------+-----+-------+ | Name | Lines | LOC | Classes | Methods | M/C | LOC/M | +----------------------+-------+-------+---------+---------+-----+-------+ | Controllers | 1889 | 776 | 12 | 70 | 5 | 9 | | Helpers | 2 | 2 | 0 | 0 | 0 | 0 | | Models | 1272 | 798 | 7 | 82 | 11 | 7 | | Libraries | 931 | 563 | 19 | 64 | 3 | 6 | | Controller specs | 5395 | 4259 | 0 | 8 | 0 | 530 | | Lib specs | 286 | 233 | 0 | 1 | 0 | 231 | | Model specs | 118 | 92 | 0 | 0 | 0 | 0 | +----------------------+-------+-------+---------+---------+-----+-------+ | Total | 9893 | 6723 | 38 | 225 | 5 | 27 | +----------------------+-------+-------+---------+---------+-----+-------+ Code LOC: 2139 Test LOC: 4584 Code to Test Ratio: 1:2.1
$ rake stats
+----------------------+-------+-------+---------+---------+-----+-------+
| Name | Lines | LOC | Classes | Methods | M/C | LOC/M |
+----------------------+-------+-------+---------+---------+-----+-------+
| Controllers | 129 | 85 | 4 | 19 | 4 | 2 |
| Helpers | 12 | 8 | 0 | 0 | 0 | 0 |
| Models | 224 | 176 | 10 | 13 | 1 | 11 |
| Mailers | 0 | 0 | 0 | 0 | 0 | 0 |
| Javascripts | 24 | 0 | 0 | 0 | 0 | 0 |
| Libraries | 0 | 0 | 0 | 0 | 0 | 0 |
| Api specs | 139 | 113 | 0 | 1 | 0 | 111 |
| Controller specs | 19 | 12 | 0 | 0 | 0 | 0 |
| Helper specs | 14 | 9 | 0 | 0 | 0 | 0 |
| Model specs | 344 | 278 | 2 | 0 | 0 | 0 |
| Request specs | 13 | 9 | 0 | 0 | 0 | 0 |
+----------------------+-------+-------+---------+---------+-----+-------+
| Total | 918 | 690 | 16 | 33 | 2 | 18 |
+----------------------+-------+-------+---------+---------+-----+-------+
Code LOC: 269 Test LOC: 421 Code to Test Ratio: 1:1.6
有个新项目的,我绝对覆盖到不到,你看你对代码的把握度,不能单纯从行数来看