测试 Cucumber 经验总结

mafai · 2012年11月27日 · 最后由 JohnLu 回复于 2013年01月23日 · 26816 次阅读

原文放在我的博客中 http://scriptogr.am/mafai/post/cucumber-best-practices Title: Cucumber 经验总结 Tag: cucumber,auto test,selenium slug: cucumber-best-practices

背景

使用一段时间 cucumber 了,也看过一些书 The cucumber book, rspec book, 翻过一些 github 上开源项目的 cucumber,再结合自己项目和团队项目的经验做个总结

Process 流程

是否采用

不是必须,看实际情况。我个人是非常推荐使用。总要考虑几个问题

  • 投入成本,包括编写,和维护(保持更新),运行时间
  • 效果,是否需要持续集成

好处

  • 当要 deploy 前,绿色一大片的感觉让你觉得更有安全感。
  • 自动化测试,减少大量的从复劳动
  • 代码变更时,自动化测试可追踪代码变更是否对现有功能有所影响

谁来编写

是否由测试人员撰写,我个人是推荐由开发人员编写,但每个 feature 的定义和 Scenario 由产品经理/测试人员是定义。

Case 1 测试人员编写

  • 没再为功能性测试编写 Test case
  • 不能快速完成,因为 steps 需要了解背后实现(理论上不需要,但很多 exceptional case)
  • 需要开发人员支持,讲述给测试人员,一些 steps 的 trick way

Case 2 开发人员编写

  • 估算时带来好处,不需要为测试人员等待开发人员完成代码的时间作估算
  • 开发人员一般都不喜欢写测试用例,强制要求,也只能写出基本流程的测试(总比没有强)

结论

  • 开发人员写 cucumber,代码重用性和质量会高很多,效率也高
  • 测试人员定制 scenario,和定义测试用例 test case 的道理一样,会全面很多

其它可能性

可以采取由开发人员轮流坐庄写 cucumber,不过这个我没机会实践,所以不知道效果会如何。

采用 BDD?

写 rspec 时,好流行安装 guard,然后代码改变时,同时运行相应的 rspec,理论上 cucumber 也可以这样做,我反对这样做。

主要是 cucumber 运行的实在太慢,会严重打击你的积极性。另外,spork 和 guard spork 也是默认不对代码修改,运行 cucumber,这也是有道理的。

代码

Naming convention 文件命名规范

一般采用,对像加行为的描述,也用附加特定条件或范围的。也可以将行为放在前面。

[module][action][prep]_[condition].feature

Example:

user_signin_through_oauth_sina.feature

post_add.feature

post_delete_when_no_permission.feature

Steps 不要 overload web_steps

不要直接添加在 web_steps.rbsupport/env.rb了,非常快就 overload 失控 实际上 web_steps 已经不再默认生成。

可按功能拆分 steps:

user_steps post_steps blog_steps

是否使用 Background

分两种观点,一种利用 background,可以抽取公用到 background 一种是不写 background,每个 scenario 独立

这里没有定论,我编向是写 background,简单来讲,就是可重复使用前提条件,不好的地方就是降低可阅读性。但维护时会减轻工作量。如果不是为了生成的 cucumber 文档给产品经理看,我觉得还是使用 background 比较好。

DRY 原则 (imperative or declarative)

将相同步骤 cucumber 变成一个 step,即复用你的 cucumber steps 网上有大量的讨论,关于使用哪个好,我个人偏好是 imperative,原因是,大量的 declarative steps 会造成维护困难,改起来非常累

可以看看这两篇

cucumber-imperative-or-declarative-that-is-the-question/

Imperative vs declarative scenarios in user story

Cucumber steps 基本规范

Cucumber 的 steps 尽量用人类看得懂的语言,所有 正则表达式,css, xpath,等各种代码不应该在 cucumber steps 中出现。需要时,就另外写一个 steps 封装一下就好。

文件目录结构,附开源项目的做法

可以将按模块划分,将相应的 features 放入子目录,如果 features 少,也可以省略。但不要用 sprint11, 或 milestone11 这种目录,一定要的话,可以写在 tag 上,如 s@sprint11,否则维护起来就杯具了。

是否按标准的 User story 写背景和 description

一种写法是 As xxx Role, I would do yyy so that zzz 这种写法会对项目新成员会有一定的帮助,不好的地方就是维护成本了,所以那几个开源项目都没有严格按照 User story 的写法,只是简单完成即可。我偏向是简单写,直观明了。

diaspora

命名规范 [action]_[item].feature 没有子目录

accepts_invitation.feature edits_profile.feature oembed.feature activity_stream.feature follows_tags.feature photo_lightbox.feature aspect_navigation.feature invitations.feature posts_from_main_page.feature blocks_user.feature logged_out_browsing.feature reshare.feature change_email.feature logs_in_and_out.feature show_more.feature change_password.feature manages_aspects.feature signs_up.feature closes_account.feature mentions.feature step_definitions comments.feature mentions_from_profile_page.feature stops_following_users.feature connects_users.feature mobile.feature support conversations.feature not_safe_for_work.feature tags.feature download_photos.feature notifications.feature tags_and_comments.feature

Step

大体都差不多和 teambox 一样, [module]_sptes.rb

aspects_steps.rb factory_steps.rb oembed.rb stream_steps.rb comment_steps.rb lightbox_steps.rb posts_steps.rb template_steps.rb conversations_steps.rb mention_steps.rb profile_steps.rb uri-step.rb custom_web_steps.rb message_steps.rb scope_steps.rb user_steps.rb debug_steps.rb mobile_steps.rb session_steps.rb web_steps.rb

teambox

[item]_[action].feature 我偏向这种,因为分类清楚点

project_archive.feature upload_rename.feature project_create.feature user_change_password.feature project_delete.feature user_edit_profile.feature project_invitations.feature user_edit_settings.feature project_join.feature user_first_steps.feature project_leave.feature user_login.feature project_public.feature user_logout.feature public_downloads.feature user_profile.feature search_projects.feature user_reset_password.feature sidebar.feature user_signup.feature

Step

action_steps.rb organization_steps.rb task_list_steps.rb activity_steps.rb page_steps.rb task_list_template_steps.rb authentication_steps.rb pickle_steps.rb task_reminders_steps.rb comment_steps.rb project_steps.rb task_steps.rb conversation_steps.rb public_downloads_steps.rb teamboxdata_steps.rb db_steps.rb relative_time_steps.rb time_steps.rb email_steps.rb reset_password_steps.rb upload_steps.rb folder_steps.rb search_steps.rb user_steps.rb invitation_steps.rb see_within_steps.rb watchers_steps.rb oauth_steps.rb sidebar_steps.rb web_steps.rb

Cucumber 样例

diaspora

  1. features/activity_stream.feature

    Feature: The activity stream Scenario: Sorting Given a user with username "bob" #没有使用 pickle When I try to sign in manually" #一起来看看 sign in 吧

  2. features/step_definitions/session_steps.rb

    When /^I try to sign in manually$/ do manual_login end

  3. features/support/user_cuke_helpers.rb

    # use the @me user to perform a manual login via the sign_in page def manual_login visit login_page login_as @me.username, @me.password #login_as 其实就是 wrap 了 fill_in 方法 end

  4. features/support/paths.rb

    def login_page path_to "the new user session page" end

    def path_to(page_name) when /^the ([\w ]+) page$/ send("#{$1.gsub(/\W+/, '_')}_path")

Cucumber 的测试附件存放位置

不要再使用 app/assets 下的东西了。

➜ sample_files git:(dev) ls /Users/mafai/Projects/teambox/features/support/sample_files dragon.jpg tiger.jpg

其它工具,cucumber 好帮手

Capybara

这个应该是默认的了,The cucumber book 中,提及到为什么不用 webrat 和 selenium,在这里就不废话了。

Pickle

这个 gem 帮你省确了大量的 module 创建的 steps,用上好,你的 steps 会减少好多,但同时,你的 cucumber 描述就变得不是那么容易阅读。 !注意,开源项目引入了这个 gem,但并不使用它,如果你想你的 cucumber steps 变得更简洁和易于阅读,pickle 不是你工具。

Factory girl

用上 factory girl 建立对像时,可以设定默认值或指定规则的 value,也可以省下不少代码

Pickle.configure do |config| #config.adapters = [:machinist] config.adapters = [:factory_girl] #以后通过 factory girl 来创建对像 #config.map 'I', 'myself', 'me', 'my', :to => 'user: "me"' end

#所有的 module 都须要在 FactoryGirl 登记一下,否则在运行时,pickle 会有问题,undefined steps FactoryGirl.define do factory :post do title { "Dummy title" } body { "#{title}!" } end end

Spork

spork cucumber Spork 可以先 preload 整个测试环境

cucumber -r features features/posts.feature --drb 然后就享受一下速度吧,但注意这样做好,如果你将代码修改后,其实 spork 不会懂得 reload 的。

Guard spork

guard init spork

生成

/Users/mafai/Projects/compass/Guardfile

你会发觉,即使代码出错,也不会影响 cucumber 的测试,主要是默认缓存了 class 的原因

config.cache_classes = false #改成 false 就好了

你也可以选择 watch 所有的*.rb 文件,restart spork server,不过这实践不是这些工具所提倡的。

http://stackoverflow.com/questions/5855587/spork-is-really-great-but-how-can-i-get-it-to-refresh-validations-and-other-cod

使用 webkit 代替 selenium

使用 webkit 做前端测试,速度会提升,因为不需要打开 browser,只要在env.rb用上Capybara.javascript_driver = :webkit

Trick

默认路径 path

如果是一些标准命名的 page,再不须添加 path 了,否则真的很烦

else begin page_name =~ /the (.*) page/ path_components = $1.split(/\s+/) self.send(path_components.push('path').join('').to_sym) #这个 send 方法我不清楚是调用哪一个,其实就是将 user profile page,转换成 user_profile_path,这将其转成 symbol 字符串 rescue Object => e raise "Can't find mapping from \"#{page_name}\" to a path.\n" + "Now, go and add a mapping in #{FILE_}" end

运行单个 cucumber

cucumber features/billing/credit_card.feature:104 -f progress -r features

Cucumber rerun 重复运行出错的 scenario

$ cucumber -f rerun --out rerun.txt

#结果 features/one.feature:367 features/another.feature:91:117

启动时清数据

改一下 hook.rb就好

Before do
  $redis.flushall
end

After do
  $redis.flushall
  # clean out the Solr index after each scenario
  Sunspot.remove_all!
end

Devise 登录

见到一种较特别的写法,就是在测试环境时,动态添加一个 route 和 action,具体看 diaspora 项目的代码。其它都是模似用户的 steps 做的。

其它 Topic,但不在此讨论

多台机器分布式运行 cucumber,提速

分别打开 IE, FireFox, Opera, Chrome 等浏览器跑界面,进行对 layout 的快速 review

结合 bamboo server 做持续集成测试

Reference

好贴,收鸟

难得有些长篇的

我很不好意思地说,多数我都没看懂。

经验好文。 不过 cucumber 实在太慢,打击写的积极性。 Cucumber 对比 RSpec request,lz,你怎么看

#4 楼 @camel Rspec 非常适合 unit test,即代码级别的测试,cucumber 主要是 user acceptance test,从业务角度考虑,特别是当你写 scenario 时,和产品经理和测试人员一起讨论,你会对产品有一个非常全面的了解和定义。另外就是,你用 rspec 很难测试前端的东西,例如各种 ajax 请求,popup 页面。我认为两者都需要,不冲突,从开源项目来看,也是这样。但如果财力有限,2 选 1 的话,我会选 rspec。

好文,pickle 的确是好东西,对简单的 model 数据准备的确可以省很多 step,容易上瘾,复杂的数据准备还是需要用 factory girl 来提高重用

好文章,受教了。

太好了!最近正在折腾这个,帮助很大~~

楼主,我最近也在学 Cucumber,请教个问题: 如何使用 Global hooks 进行登录?我用 Capybara 做驱动 我的目的是只登录一次,其余的 Scenario 不用每次都要登录了。

#9 楼 @JohnLu

不知道我没有理解正确,你的意思是有一些用例需要先登录吗?我的做法是用 background 运行。hooks 设计的目的不是用来登录。

#10 楼 @MaFai 我接触过的项目都需要登录,才能进行其它操作;很明显其它测试用例就必须要登录了。background 中运行登录,但其后的所有 Scenario 在执行前都要进行 Background 的用例,也就相当于每个 Scenario 都要执行 1 次登录。 我希望的是,所有的用例都只用一个登录 Session,就只登录一次。

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