2017-06-29 83 views
1

背景黄瓜红宝石 - 在一个模块内的台阶

我用各种不同的步骤,在多个项目中使用两种写黄瓜库,并试图通过他们的分裂成3,以减少步骤定义复杂不同的模块,适用于iOS,Android和网络 - 特别是包括所有3.

一个步骤库将包括基于安全的步骤负荷的项目,我想明确地包含进使用的步骤之前的项目。

if $profile[:app_type] == 'android' 
    World(ProjectSteps::Android) 
else 
    if $profile[:app_type] == 'ios' 
     World(ProjectSteps::IOS) 
    else 
     World(ProjectSteps::Web) 
    end 
end 

这些不更换辅助方法,但给我们节省时间,新项目启动时:

该项目分库将根据什么在配置中规定被明确列入也将让我们有写在这取决于我们是否正在测试的网络,本地iOS应用或内置有完全相同的功能原生Android应用程序不同的方式项目的具体步骤的定义,但有足够的不同需要不同的步骤定义

的问题

定义模块中的步骤后,该功能的文件仍然可以执行这个令人高兴的是,即使模块没有被列入“世界”是这样的:World(CommonSteps::Security),这是你平时会用于让黄瓜知道隐藏在模块内部的辅助方法。

When 'I provide my personal details' do 
    select :title, 'Mr' 
    fill :first_name, 'John' 
    fill :last_name, 'Doe' 

    unless $profile[:app_type] == 'web' 
     click :progress 
    end 

    if $profile[:app_type] == 'android' 
     fill :postcode, 'TE37ER' 
     select :address, '1 Test Street' 
     click :progress 
     fill :occupation, 'Tester' 
     fill :company, 'Test Company' 
     click :progress 
    else 
     fill :occupation, 'Tester' 
     fill :company, 'Test Company' 
     unless $profile[:app_type] == 'web' 
      click :progress 
     end 
     fill :postcode, 'TE37ER' 
     select :address, '1 Test Street' 
     click :progress 
    end 
end 

这一步定义一次尝试测试3个应用程序,但它正在测试完全相同的功能,完全一样的场景和完全相同的功能。如果这被分成3个步骤定义,那么将来调试会更简单,但同一个功能文件可以用于每个定义(这不是没有问题的,因为有很多应用程序它们在网络和原生移动版本中共享完全相同的功能)。在我看来,这种类型的步骤定义试图实现太多。

尽管是更多这将是更容易维护,因为它是简单的:

module ProjectSteps::IOS 
    When 'I provide my personal details' do 
     select :title, $user[:title] 
     fill :first_name, $user[:first_name] 
     fill :last_name, $user[:last_name] 
     click :progress 
     fill :occupation, $user[:occupation] 
     fill :company, $user[:company] 
     click :progress 
     fill :postcode, $user[:postcode] 
     select :address, $user[:line1] 
     click :progress 
    end 
end 
module ProjectSteps::Android 
    When 'I provide my personal details' do 
     select :title, $user[:title] 
     fill :first_name, $user[:first_name] 
     fill :last_name, $user[:last_name] 
     click :progress 
     fill :postcode, $user[:postcode] 
     select :address, $user[:line1] 
     click :progress 
     fill :occupation, $user[:occupation] 
     fill :company, $user[:company] 
     click :progress 
    end 
end 
module ProjectSteps::Web 
    When 'I provide my personal details' do 
     select :title, $user[:title] 
     fill :first_name, $user[:first_name] 
     fill :last_name, $user[:last_name] 
     fill :occupation, $user[:occupation] 
     fill :company, $user[:company] 
     fill :postcode, $user[:postcode] 
     select :address, $user[:line1] 
     click :progress 
    end 
end 
When 'some thing that is the same across platforms' do 
    # Some stuff 
end 

请记住,这是我想要实现一个简单的版本,并没有显示我试图解决的一些问题的完全复杂性。在这种情况下,我很可能会使用if/unless版本而不是拆分版本,但是有几种情况极其复杂,并且可以从拆分为3个部分中受益。

我们还可以为我们在开发过程中发现的错误添加静默检查,以确保这些不会退步,并且随着web,android和ios应用程序具有不同的错误,我们最终会得到大量if/unless声明。

我试过了什么?- 我听到你问

嗯,我要么真的关闭或真的为期不远。

GivenWhenThen不同的模块,这就是为什么我不得不寻找,我相信他们是一个别名的方法中时不能按预期工作。

下面是结果代码:

require_relative 'xss.rb' 
require 'cucumber' 

module CommonSteps 
    module Security 
    Cucumber::RbSupport::RbDsl.register_rb_step_definition(
     'I attempt to write a step definition that has to be included to work', 
     Proc.new { 
      # Some stuff here 
     }) 
    end 
end 

寄存器的步骤定义精绝。但这是问题的一部分。我只想注册该步骤定义,如果该模块已包含在我正在开发的项目的世界中。

这也意味着如果我们需要,我们可以切换iOS和Android步骤的Web步骤,同时保持功能文件完全相同。 (是的,我知道if陈述的事情,但也嫌多,一步DEFS得到真快复杂。)

编辑

我想要实现的是不喜欢“网站的步骤”是我们已经看到过去。没有通用步骤显示代码,只有我们与开发团队一起同意与我们合作的业务的语言。由于我们工作的很多项目都是跨平台的,我本质上试图实现将切换使用哪种类型的步骤定义的方法。 - 如果您使用的是Chrome,请使用此步骤定义的Web版本,如果您使用的是iOS,请使用此步骤定义的iOS版本,但也可以包含各种通用步骤,它可以链接回我们的页面对象模型 - 保持场景完全基于业务。

Given I am on the "Personal Details" page # (generic) 
When I provide my personal details # (non-generic, but Web, iOS and Android versions exist) 
But leave the "First Name" field blank # (generic) 
And I attempt to continue to the next page # (generic) 
Then I should see a validation error for the "First Name" text box stating: "Please provide your first name" # (generic) 

例如,如果确认是什么,企业想知道是否正常工作,并已同意企业的要求it'a部分,是有交流的更多的业务理解的方式那些信息? - 为什么我们要确保用户填写信息以便验证不显示,但是如果他们没有提供这些信息,我们也应该测试出现的验证需要的场景。

我们使用页面对象模型时,“个人详细信息”将在urls地图中找到:personal_details键。密钥可以传递到下一步,链接到包含:first_name密钥的Pages.personal_details方法。我们所有的项目都使用这种设置,它是我们的核心帮助程序库的文档的一部分。

我想要达到的效果并不一定是不好的做法,如果以我建议的方式使用,但如果使用不正确,则可能会这样使用。

回答

-1

在黄瓜历史上已经有很多次,当这样的事情已经完成时,黄瓜本身曾经有过网络步骤,前一段时间被删除。这些现在在Gem https://github.com/cucumber/cucumber-rails-training-wheels。你可能会从你的库中得到一些提示。

这就是说,我强烈建议不要编写一个步骤定义库。相反,我会写一个可以被步骤定义使用的方法库。粗略的例子可能有助于说明这一点。

可以说你有一个非常复杂的方法登录到应用程序。你可以写一个真正commplicated步骤定义,随着各种东西记录,如

When I login (hugely complex regex to deal with things like ... # loads of code to deal with you params and regex's and make things work with lots of different scenarios

或交易,你可以写一个方法,像

def login(as:, args={})

,让人们用这个方法当他们写东西,例如

When 'I login' do 
    login as: @i 
end 

When 'I login as Fred' do 
    login as: create_or_find_user(firstname: 'Fred') 
end 

When 'I login as Fred with Jill's password' do 
    login as: @fred, password: @jill.password 
end 

辅助方法提供了实用程序来帮助你编写简单的步骤定义是切合阁下个别情况下。共享步骤定义限制您使用高度复杂且不能具有任何特定上下文的内容。

场景应该是上下文特定的,并且允许灵活简单的语言,它是特定于他们所属的单个世界的上下文的。他们应该是所有关于为什么正在完成的事情,那是什么,并没有关于如何做的事情。根据定义,它们不共享,因此从定义上讲也不是分步定义。

一旦你通过调用你进入的代码领域留下了步骤定义和代码是真正有效的共享

黄瓜了解到,共享的步骤定义是一个非常糟糕的主意的教训(见http://aslakhellesoy.com/post/11055981222/the-training-wheels-came-off)。谨防重复过去的错误。

+1

这些步骤库适用于导航到网址,安全测试和API测试等内容,这些内容可能非常通用,适用于内部目的。但是,它们只是可以通用而不显示任何代码的功能文件。我明白写出的步骤更像是:当我用“Bar”填充“#foo”时,这是非常糟糕的做法,这就是为什么我已经不再使用它了。 –

+0

阅读链接的文章,并考虑重新阅读我的答案。一个场景中永远不应该有一个URL,那就是你在做什么,而不是为什么。 API的应用场景不应该关于你如何调用API,他们应该是关于你为什么要调用API。真的没有通用的场景!整个场景的目的是写出一些特定于世界的事物,这就是为什么Cucumber:World被称为世界,为什么事物是全球性的。场景中的每件事情都应该针对世界,世界上不应该有任何歧义。 – diabolist

+0

也许考虑给出具体的例子,您可以在单独的问题中看到一些通用的步骤,我们可以更详细地看一看 – diabolist