Calabash:如何设置测试数据

时间:2014-07-23 16:06:12

标签: android ios cucumber factory-bot calabash

我正在使用Calabash实现GUI测试。在The Cucumber Book中,强调场景应在本地设置测试数据,最好使用factory_girl等库。这个问题是关于使用Calabash测试Android和iOS应用程序的性能,清洁度和可管理性。

factory_girl等工具的好处是,测试应该不那么脆弱,并且可以在不使用GUI的情况下创建/插入测试数据,这大大加快了测试速度(这使得它们更有价值)给开发者)。此外,每个scenario应该独立于所有其他方案,因此如果A正常工作,则不需要在B之前运行方案B。这允许开发人员只运行一个场景。

这对于本地运行的程序来说似乎是合理的,例如可以直接访问Web服务数据库,以便可以插入测试数据。但是,测试人员如何在另一台设备(仿真器,模拟器,真实电话)上运行的程序中插入数据。

具体来说,在针对iOS和Android目标运行时,如何管理测试数据?我很想使用Set of Fixture Data中描述的The Cucumber Book,但是,他们明确表示要避免这种情况。

我问,因为我创建的应用程序在用户可以进入主应用程序视图之前有很多设置。用户需要:

  1. 注册,其中包含多个步骤:

    一个。按"注册"

    B中。接受条款

    ℃。链接到第三方服务(多个步骤)

    d。输入用户详细信息(名称,...)

    电子。按"注册"按钮

    F。按已发送电子邮件中的链接确认电子邮件

  2. 使用新创建的用户登录

  3. 与服务器同步数据
  4. 正如您所看到的,如果每个场景都必须在干净的状态下工作,那么只需在应用程序中找到正确的视图就可以成为实时消费者。几乎所有场景都必须执行这些步骤。我希望能够从所需的状态开始,并从正确的视图开始。如何使用Calabash实现iOS和Android?

3 个答案:

答案 0 :(得分:1)

我们能够使用' Rest-Client'gem(调用端点)和Cucumber钩子(用于确定何时生成测试数据)来创建我们自己的测试数据。

请参阅下面的示例,了解我们如何使用Rest-Client gem,黄瓜钩子,数据管理器类和工厂模块创建新帐户/客户。这是一个link,其中包含更多有关其工作原理的信息。

<强> AccountDataManager.rb

require 'rest-client'

require_relative '../factory/account'

class AccountDataManager

  include Account

  def create
    current_time = Time.now.to_i
    username = 'test_acc_' + current_time.to_s
    password = 'password1'
    url = 'http://yourURLhere.com/account/new'

    request_body = manufacture_account(username, password)

    response = RestClient.post url, request_body.to_json, {:content_type => 'application/json', :accept => 'application/json'}

    if response.code != 200
      fail(msg ="POST failed. Response status code was: '#{response.code}'")
    end

    response_body = JSON.parse(response

    clientId = response_body['Account']['ClientId']

    # return a hash of account details
    account_details = {
        username: username
        password: password,
        clientId: clientId
    }
  end    
end

<强> Account.rb

以下工厂制造请求的主体。

module Account

  def manufacture_account(username, password)
    payload = {
        address:{
            :Address1 => '2 Main St',
            :Address2 => '',
            :Suburb => 'Sydney',
            :CountryCode => 8
        },
        personal:{
            :Title => 'Mr',
            :Firstname => 'John',
            :Surname => 'Doe',
            :UserName => "#{username}",
            :Password => "#{password}",
            :Mobile => '0123456789',
            :Email => "#{username}@yopmail.com",
            :DOB => '1990-12-31 00:00:00'
        }
    }
  end
end

<强> Hook.rb

您应该将hook.rb文件添加到共享目录,然后将其引用添加到您的env.rb文件中(我们将钩子文件添加到&#34; / features / support&#34;目录中)。

require_relative '../data_manager/data_manager_account'

Before() do
  $first_time_setup ||= false

  unless $first_time_setup
    $first_time_setup = true

    # call the data managers needed to create test data before
    # any of your calabash scenarios start
  end
end

Before('@login') do
  # declare global variable that can be accessed by step_definition files
  $account_details = AccountDataManager.new.create
end

at_exit do
  # call the data managers to clean up test data
end

<强> Login_steps.rb

拼图的最后一部分是让您的葫芦场景消耗您刚刚生成的测试数据。为了解决这个问题,我们在hook.rb文件中声明了一个全局变量($ account_details),并在我们的step_definition文件中引用它。

Given(/^I log in with newly created customer$/) do
  @current_page = @current_page.touch_login_button

  unless @current_page.is_a?(LoginPage)
    raise "Expected Login page, but found #{@current_page}"
  end

  # use global variable declared in hook.rb
  @current_page = @current_page.login($account_details)

 unless @current_page.is_a?(HomePage)
    raise "Expected Home page, but found #{@current_page}"
  end
end

答案 1 :(得分:0)

我自己还没有使用过任何夹具数据库,但是我只是运用简单的模型,比如下面的用户。

class User

  @validUser = "valid@mydomain.com"
  @validPass = "123"

  @invalidUser = "invalid@healthwyse.com"     
  @invalidPass = "foobar"

  def initialize(username, password)
    @username = username
    @password = password
  end

  def username
    @username
  end

  def password
    @password
  end

  def self.getValidUser
    return new(@validUser, @validPass)
  end

  def self.getInvalidUser
    return new(@invalidUser, @invalidPass)
  end

end 

我们说我有以下功能:

Scenario: Successful login
  When I enter valid credentials into the login form
  Then I should see a logout button

然后,当我需要有效用户时,它就像:

一样简单
When(/^I enter valid credentials into the login form$/) do
  user = User.getValidUser
  enterCredentials(user)
end

显然,您可以复制此模型结构,而不是需要保存简单的信息量。再说一次,我不能说任何装置库,因为我还没有使用它们。

但是,关于场景A对场景B不依赖的另一个问题 - 这是事实,但这并不意味着您不能将步骤定义串在一起以实现您的目标。让我们说上面的测试只是用来验证我是否可以使用有效用户成功登录到应用程序 - 一切都很好,用户已登录,并且每个人都很高兴。但是当我需要测试用户的个人资料页面时会发生什么?好吧,我显然需要登录,但我不需要在我的功能文件中明确说明,我可以创建一个将其他步骤定义链接在一起的步骤定义:

Scenario: Validate behavior of user profile page
  Given I'm on my profile page
  Then I should see a selfie


Given(/^I'm on my profile page$/) do
  step "I enter valid credentials into the login form"
  navigateToProfilePage()
end

这是一个简单的例子,但希望您能够确实将步骤定义链接在一起,而不会让方案本身彼此依赖。这种糟糕的黄瓜风格会让您使用Scenario&#34; Login Successful&#34;登录到应用程序。但是然后永远不要将用户注销,只需继续使用Scenario&#34;验证配置文件的行为&#34;只需导航到个人资料页面而无需先重新登录。我希望我与原始请求相距太远!

答案 2 :(得分:0)

在运行测试之前,您可以编写Backdoor来清理数据:

public class MainActivity extends Activity {

    public void setUp() {
        // Here you can clean and setup the data needed by your tests
   }

}