编写传递额外信息的黄瓜测试

时间:2018-07-09 14:54:25

标签: ruby-on-rails devise cucumber capybara

我有一个Ruby on Rails程序,在Cucumber中进行了功能测试。

我刚刚实现了一项功能,管理员可以为客户端用户创建新密码。现在,在“编辑客户端”页面上,还有一个附加按钮,允许管理员设置密码。现在,我只需要进行一次黄瓜测试。

我试图以此为基础来进行客户端更改密码的正常测试,以及管理员更改用户信息的测试的正常测试。我有这个:

Feature: Analyst changes client's password
  As an Analyst
  I want to change client's password
  So that I can reset the client's account

  Background:
    Given the following client accounts
      | email             | password |
      | user1@someorg.com | password |
    And I am logged in as an admin

  @javascript
  Scenario: Update a Client user
    Given I navigate to the Clients Management Page
    When I edit the Client User "user1@someorg.com"
    And I click on "button"
    Then I should be on the Clients Password Page

  @javascript
  Scenario: Can change password if confirmation matches
    Given I navigate to the Clients Password Page
    And I enter "Password1" as the password
    And I enter "Password1" as the password confirmation
    And I submit the form
    Then I should be taken to the Client Landing Page
    And The client's password should be "Password1"

在步骤中,我有:

Given /^I navigate to the Clients Password Page$/ do
  client_management_index_page = ClientsPasswordPage.new Capybara.current_session
  client_management_index_page.visit
end

Then /^I should be on the Clients Password Page$/ do
  client_password_page = ClientsPasswordPage.new Capybara.current_session
  expect(client_password_page).to be_current_page
end

和ClientsPaswordPage:

class ClientsPasswordPage
  include PageMixin
  include Rails.application.routes.url_helpers

  def initialize session
    initialize_page session, edit_admin_client_password_path
  end
end

,对于正在编辑的用户,edit_admin_client_password_path带有:id。我不知道该如何获取这些信息。

如果有问题,我正在使用Devise作为安全材料...

2 个答案:

答案 0 :(得分:1)

有几种方法可以做到这一点。最简单的是要意识到您在测试期间仅创建一个客户端,所以

Client.first # whatever class represents clients

将始终是该客户端。显然,如果您进行的测试要比客户端创建多,那么这是行不通的,因此您可以在黄瓜步骤中创建实例变量,该变量在World上设置,然后可以从其他步骤访问并传递给页面对象< / p>

When I edit the Client User "user1@someorg.com"
  @current_client = Client.find_by(email: "user1@someorg.com") # obviously would actually be a parameter to the step
  ...
end

Then /^I should be on the Clients Password Page$/ do
  client_password_page = ClientsPasswordPage.new Capybara.current_session, @current_client
  expect(client_password_page).to be_current_page
end

当然,如果没有页面对象的开销,它将变成

Then /^I should be on the Clients Password Page$/ do
  expect(page).to have_current_path(edit_admin_client_password_path(@current_client))
end

答案 1 :(得分:0)

您可以做很多事情来简化这种情况。如果您的场景更简单,步骤定义也更简单,那么解决实现问题将变得更加容易,例如您如何在第一步中获得客户才能在第二步中使用。

简化方案的主要方法是在方案中根本没有任何内容来说明您如何实现此功能。如果您不使用所有单击按钮,填写字段和访问页面,就可以专注于业务问题。

Background
  Given there is a client
  And I am logged in as an admin

Scenario: Change clients password
  When I change the clients password
  Then the client should have a new password

注意:这立即引发一个问题:“客户如何找到新密码?”,这是简单的好方案,它们使您提出有价值的问题。在这里回答这个问题可能超出范围。

现在让我们看一下实现。

Given 'there is a client' do
  @client = create_new_client
end

When 'I change the clients password' do
  visit admin_change_password_path(@client)
  change_client_password(client: @client)
end

这足以使您走上正确的道路。另外类似

Given 'I am logged in as an admin' do
  @i = create_admin_user
  login_as(user: @i)
end

会有所帮助。

我们在这里所做的是

  1. 将操作方法​​向下推入堆栈,以使现在执行此工作的正确代码不在您的方案和步骤定义之内
  2. 使用变量在步骤之间进行通信,行@client = create_new_client创建一个全局变量(对于Cucumber :: World而言实际上是全局变量),该变量在所有步骤定义中均可用

您可以通过将模块添加到Cucumber world并在其中定义方法来创建帮助方法。请注意,这些方法是全局的,因此您必须仔细考虑名称(这些方法具有全局性的理由非常充分)。所以

module UserStepHelper
  def create_new_client
    ...
  end

  def create_admin_user
    ...
  end

  def change_client_password(client: )
    ...
  end
end
World UserStepHelper

将创建可在任何步骤定义中使用的辅助方法。

您可以看到此方法here的示例。我在CukeUp 2013演讲中使用的一个项目。也许您可以将其用作您的教程示例。