Rails 关于代码量和测试覆盖率的问题

jarorwar · 2013年10月30日 · 最后由 huacnlee 回复于 2013年11月01日 · 6 次阅读

是否还记得今年rubyconfchina,陈金洲同学的演讲,总体来说非常精彩,只不过这哥们说话太快太快了~!呵呵。这是前提,其实我要说的是代码量和测试覆盖率。关于陈老大的3000行理论和104%?140%的测试覆盖率问题,一直心存疑惑,后来rake stats一下自己的工程,代码量2280+行,覆盖率1:0.3==30%(其实没怎么写)。于是乎很感兴趣的把rubychina的代码clone下来,跑了一下。结果如下:

@huacnlee @Rei @all ??

求解释啊~!

共收到 33 条回复

这就像是天气预报和pm2.5的关系。

#1楼 @liwei78 这是什么关系?呵呵

其实我后面写了一堆话,删掉了。。。感觉也没什么意思。 我的意思是,测试覆盖率跟测试成效,不相关。它仅仅是一个指标而已,你都可以翻翻它统计的代码,绝对看不出它能反映出来什么。

覆盖率_百度百科 http://baike.baidu.com/view/249951.htm

#3楼 @liwei78 覆盖率,只需覆盖关键逻辑即可~!我是这么认为的~!,呵呵

我最近的 writings.io 是 0.4

#4楼 @jarorwar 比如view,真的是闲的蛋疼的话可以写写,肉测也是测view。真正的逻辑必须覆盖到一定程度。。话说大家用什么工具来管理测试用例呢??比如杨濯宇讲的那个话题,其实重构之后,还会会有10倍以上的测试用例增长,那时候还是很难维护的,即便怎么重构都不会减少用例。 何况停止一个用例也是要承担风险的。 这种工具,求一个。。。。最近在看书,貌似还没看到适合rails测试用例管理的,真正给Rails的DSL用例管理工具。

#6楼 @liwei78 好的,懂了~! 举个例子,例如我有这么一个use case :一个图片管理系统,用户可以上传图片,并且对图片进行大小裁剪,压缩,打水印。同步图片到cdn,那么其实真正核心的功能就是:上传/大小裁剪,压缩,打水印/同步cdn 这几个的相应逻辑操作,而不是view层,对吗?

#6楼 @liwei78 我们在试用 禅道 。各论坛的伙伴和同事们都说好。但是那界面我想吐。忍着吐用一用就习惯了。

#7楼 @jarorwar 是的。如果你觉得不好找到测试的对象,就重新整理一下它,将功能最小化后,就找到合适测试的目标了。这其实应该叫单元测试,Text::Unit可以做的很好。 对于if...else 这种逻辑测试,可以再用rspec来处理,就当练习吧。

#8楼 @Victor 别提了,当时看到禅道 就直接关了。可能我偏激,但是我受不了这个。。。

最重要的是如何写有效的测试,去年我的 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

#11楼 @fredwu ‘Technical Debit’这个词会被重视的。。。如何写有效的测试,以及应对需求变更对测试的影响,或许交给一个工具来管理,更加的便捷。 另外:用测试用例为项目签收,大家有涉及么??

根据项目, 小站,小测。(给客户做个企业形象站,没测试代码。) 重要项目,事关重大,多测。(曾经50号<都是专业无新手>人专职测试半年,就发现了几个bug<5个) 要命的核心项目的核心模块,测试远大于开发。

#12楼 @liwei78 项目如果质量要求高,可以要求测试用例也作为签收/交付条件,当然不仅仅是用例。

#11楼 @fredwu 下面那个绿色的数字和红色的数字是怎么得出的?比较关心哦。我一直以为是Code to Test Ratio: 1:0.4这货,好像陈金洲那天说的也是这货哦

#9楼 @liwei78 谢谢。。我现在纯粹是为了写测试。因为之前有个项目就没有测试。

#15楼 @jarorwar SimpleCov

观察测试覆盖率的意义不是太大,仅仅只能找出哪里忘了测试而已……

#17楼 @fredwu 同意

#16楼 @jarorwar 两点建议:1、估计你要重构一些代码,那么就先写测试和确认流程,再重构。2、测试逻辑根据流程来,比如条件覆盖,这个常见。测试用例多了会比较麻烦,但是一套逻辑走下来,几百个用例是正常的,别嫌多。。。。

测试要有耐心,加油。

#18楼 @liwei78 嗯,谢谢。这个rubyconfchina的最大收获就是让我有信心开始写测试~!感谢~!

#17楼 @fredwu 1929 / 2045 LOC (94.33%) covered

我第一次测覆盖度,原来0.4已经覆盖这么广,我满足了……

SimpleCov 的覆盖是 statement coverage。说的是,每个语句是否有执行而已,比较容易。还有branch coverage,path coverage 之类的。

#21楼 @yfractal 留给用户测~

@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:'demo@test.com')
    assert user.valid?,'user email is  valid '
end

在上面我验证了用户的email。下面我要验证用户的手机号。 我不得不修改上面的代码,加上手机号,这样保证上面的代码是正常的,然后才可以继续验证手机号~!,这样是不是写的太多了。或者说,我可以把验证用户的信息放在同一个测试用力里面完成,例如

test 'user attribute is valid ' do 
    user = User.new(email:'demo@test.com',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个人都同时写一个测试。

#24楼 @liwei78 感谢这么用心的回答~!回答的非常明了了~!其实。我在上面那个测试用力中遇到的问题就是我没有规划好~你这句 所以测试用例规划是要很科学的进行 点出了万我问题的根本。现在是联系阶段,所以。我就希望能扎扎实实的写下来,从单元测试到功能测试,到集成测试,甚至于压力测试等等~!

#26楼 @jarorwar 恩恩,我也不敢说教,这些是最近看书整理出来的,借这个机会分享下。

#23楼 @jarorwar

# valid user attributes
def user_attributes
  { :email => 'demo@test.com', :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

近来感觉,测试写的真的很爽。。。 4500行代码包括了1200+单元测试

$ 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

有个新项目的,我绝对覆盖到不到,你看你对代码的把握度,不能单纯从行数来看

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册