0

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

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

我试图将此基于客户端更改密码的正常测试,以及管理员更改用户信息的测试。我所拥有的是:

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

和客户密码页:

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,用于正在编辑的用户。我不知道如何将这些信息输入其中。

万一这很重要,我正在使用设计来解决安全问题......

4

2 回答 2

1

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

Client.first # whatever class represents clients

永远是那个客户。显然,如果您在测试中创建了比客户端多一个的测试,那么这将不起作用,因此您可以在黄瓜步骤中创建实例变量,这些步骤设置在 World 上,然后可以从其他步骤访问并传递给您的页面对象

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
于 2018-07-09T16:19:09.200 回答
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. 将 HOW 下推到您的堆栈中,以便现在您正确执行此工作的代码不在您的场景和步骤定义中
  2. 使用变量在步骤之间进行通信,该行@client = create_new_client创建了一个全局(实际上是 Cucumber::World 的全局)变量,该变量在所有步骤定义中都可用

您可以通过将模块添加到 Cucumber 世界并在其中定义方法来创建辅助方法。请注意,这些方法是全局的,因此您必须仔细考虑名称(这些方法是全局的有很好的理由)。所以

module UserStepHelper
  def create_new_client
    ...
  end

  def create_admin_user
    ...
  end

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

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

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

于 2018-07-10T18:19:45.573 回答