【问题标题】:Calabash: How to set up test dataCalabash:如何设置测试数据
【发布时间】:2014-07-23 16:06:12
【问题描述】:

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

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

这对于在本地运行的程序来说似乎是合理的,例如可以直接访问 Web 服务数据库,从而可以插入测试数据。但是,测试人员如何在其他设备(模拟器、模拟器、真手机)上运行的程序中插入数据。

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

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

  1. 注册,包括多个步骤:

    A.按“注册”

    B.接受条款

    C.链接到第 3 方服务(多个步骤)

    D.输入用户详细信息(姓名,...)

    E.按“注册”按钮

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

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

  3. 与服务器同步数据

如您所见,如果每个场景都必须从干净的状态开始工作,那么只需在应用程序中获取正确的视图即可成为实时消费者。几乎所有场景都必须执行这些步骤。我希望能够从所需的状态开始并从正确的视图开始。这是如何使用 Calabash 为 iOS 和 Android 实现的?

【问题讨论】:

  • 我想知道你最终使用了什么策略,因为我在 iOS/ 上面临同样的问题?

标签: android ios cucumber factory-bot calabash


【解决方案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 文件中(我们将我们的挂钩文件添加到“/features/support”目录)。

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

【讨论】:

    【解决方案2】:

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

    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
    

    这是一个简单的示例,但希望您看到确实可以将步骤定义链接在一起,而无需让场景本身相互依赖。如此糟糕的黄瓜风格会导致您使用场景“登录成功”登录到应用程序,但然后永远不要将用户注销,而只需继续使用场景“验证配置文件的行为”,它只会导航到配置文件页面而无需先重新登录。我希望我与您最初的要求相差不远!

    【讨论】:

    • 嗨,勒克斯,感谢您的回答。你必须有某种“夹具数据”,即。为测试目的而设置的数据。您有一个有效用户,但这个有效用户是在哪里创建的?另一句话是,使用您的解决方案,您最终会遇到“缓慢”的测试,因为您一遍又一遍地测试登录页面。这使得需要登录的测试变慢,因此对开发人员来说不太有用。我特别想避免这种情况。
    • 上面的User类只是一个stub类,真实用户显然必须存在于你正在测试的系统中,否则登录不会成功。如果这是您问题的根源,那么您只需要确保您对每个测试都使用相同的后端数据(即相同的数据库副本)。只需获取一份生产副本并重复使用它,这样您就可以确保一致性,并且您还将针对该领域中的内容而不是您认为在该领域中的内容进行测试。同样,Calabash 是 UI 验收测试,因此除非您想要脆弱/依赖的场景,否则您必须拆分所有活动
    • 但这正是《黄瓜书》中明确反对的内容。数据只是趋于增长,没有人知道它在哪里使用,如果数据被更改,各种场景都会爆炸,使系统变得脆弱。
    • 当您使用后端数据库的静态副本时,不知道为什么您认为“数据只是趋于增长”。我从来没有遇到过任何问题,而且我的数据在测试中保持不变。祝你好运!
    • 另外,重新阅读“夹具数据”部分,您会注意到作者认为它是一种反模式:“相关数据应该在测试本身中创建,而不是隐藏在夹具数据中”
    【解决方案3】:

    你可以写一个Backdoor在运行测试之前清理你的数据:

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

    【讨论】:

      猜你喜欢
      • 2016-08-02
      • 2014-03-30
      • 1970-01-01
      • 1970-01-01
      • 2012-07-10
      • 1970-01-01
      • 2011-01-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多