Calabash: Как настроить тестовые данные

Я занимаюсь внедрением тестов графического интерфейса с использованием Calabash. В The Cucumber Book подчеркивается, что сценарии должны сами настраивать тестовые данные, локально, предпочтительно использовать библиотеки, такие как factory_girl. Этот вопрос касается производительности, чистоты и управляемости тестирования приложений Android и iOS с помощью Calabash.

Преимущество таких инструментов, как factory_girl, заключается в том, что тесты должны быть менее хрупкими и что тестовые данные могут быть созданы / вставлены без использования графического интерфейса, что значительно ускоряет тесты (что делает их более ценными для разработчиков). Кроме того, каждый scenario должен быть независимым от всех других сценариев, чтобы не требовалось, чтобы сценарий A запускался до B, если B должен работать правильно. Это позволяет разработчикам запускать только один сценарий.

Это кажется разумным для программ, которые выполняются локально, где, например, можно получить прямой доступ к базе данных веб-службы, так что можно вставить тестовые данные. Однако как тестировщик вставляет данные в программы, которые работают на другом устройстве (эмулятор, симулятор, настоящий телефон).

В частности, как можно управлять тестовыми данными, вероятно, при работе с целевым устройством iOS и Android? Я испытываю искушение использовать Set of Fixture Data, как описано в The Cucumber Book, однако они явно говорят, что этого следует избегать.

Я спрашиваю, потому что приложение, которое я создаю, имеет много настроек, прежде чем пользователь сможет войти в главное представление приложения. Пользователю необходимо:

  1. Регистрация, которая состоит из нескольких этапов:

    A. Нажмите "Зарегистрироваться"

    Б. Примите условия

    C. Ссылка на сторонний сервис (несколько шагов)

    D. Введите данные пользователя (имя, ...)

    E. Нажмите кнопку «Зарегистрироваться».

    F. Подтверждение адреса электронной почты путем нажатия ссылки в отправленном электронном письме.

  2. Войдите в систему, используя только что созданного пользователя

  3. Синхронизировать данные с сервером

Как видите, если каждый сценарий должен работать из чистого состояния, то просто переход к правильному представлению в приложении может быть потребителем в реальном времени. Эти шаги необходимо выполнить почти для всех сценариев. Я хотел бы иметь возможность начать с требуемого состояния и начать с правильного представления. Как это достигается для iOS и Android с помощью Calabash?


person foens    schedule 23.07.2014    source источник
comment
Интересно, какую стратегию вы в конечном итоге использовали, поскольку я столкнулся с той же проблемой / на iOS /?   -  person Petar    schedule 07.12.2016


Ответы (3)


Мы смогли создать наши собственные тестовые данные с помощью гема Rest-Client (для вызова конечных точек) и хуков Cucumber (используемых для определения того, когда генерировать тестовые данные).

См. Ниже пример того, как мы создавали новые учетные записи / клиентов с помощью драгоценного камня Rest-Client, огурцов, класса диспетчера данных и фабричного модуля. Вот ссылка с дополнительной информацией о как это работает.

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 (мы добавили наш файл hook в каталог «/ 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

Последняя часть головоломки - заставить ваши сценарии калебаша использовать только что сгенерированные вами тестовые данные. Чтобы решить эту проблему, мы объявили глобальную переменную ($ account_details) в нашем файле hook.rb и сослались на нее в нашем файле 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
person Austin    schedule 11.02.2017

Я сам не использовал какие-либо библиотеки данных фикстур, однако мне повезло, что я использовал простые модели, такие как следующие для пользователя.

class User

  @validUser = "[email protected]"
  @validPass = "123"

  @invalidUser = "[email protected]"     
  @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

Это краткий пример, но, надеюсь, вы видите, что действительно можете связать определения шагов, не имея сценариев, зависящих друг от друга. Такой плохой стиль огурца будет таким, что вы входите в приложение со сценарием «Успешный вход», но затем НИКОГДА не выходите из системы, а просто переходите к сценарию «Проверить поведение профиля», который просто переходит на страницу профиля без предварительного повторный вход в систему. Надеюсь, я был не так уж далек от вашего первоначального запроса!

person lux    schedule 01.08.2014
comment
Привет, люкс, спасибо за ответ. У вас должны быть какие-то данные прибора, т.е. данные, которые настроены для целей тестирования. У вас есть действующий пользователь, но где он создан? Еще одно замечание: с вашим решением вы столкнетесь с медленными тестами, потому что вы снова и снова проверяете страницу входа. Это делает тесты, требующие входа в систему, медленными и, следовательно, менее удобными для разработчика. Именно этого я хотел избежать. - person foens; 03.08.2014
comment
Вышеупомянутый класс User - это просто класс-заглушка, реальный пользователь должен существовать в системе, которую вы тестируете, очевидно, иначе вход в систему не будет успешным. И если это корень вашего вопроса, вам просто нужно убедиться, что вы используете одни и те же данные серверной части (то есть одну и ту же копию базы данных) для каждого из ваших тестов. Просто возьмите копию продукции и повторно используйте ее, чтобы обеспечить согласованность, и вы также будете тестировать на предмет того, что находится в поле, а не того, что, как вы думаете, находится в поле. Опять же, Calabash - это приемочный тест пользовательского интерфейса, поэтому, если вам не нужны нестабильные / зависимые сценарии, вы должны разделить все действия - person lux; 03.08.2014
comment
Но именно против этого в «Книге огурцов» выступают явные аргументы. Данные просто имеют тенденцию к росту, никто не знает, где они используются, и если данные будут изменены, все виды сценариев могут взорваться, что сделает систему хрупкой. - person foens; 04.08.2014
comment
Не уверен, почему вы думаете, что данные просто имеют тенденцию к росту, когда вы используете СТАТИЧЕСКУЮ копию серверной базы данных. У меня никогда не было проблем с этим, и мои данные остаются идентичными во всех тестах. Но удачи! - person lux; 04.08.2014
comment
Кроме того, перечитайте раздел «Данные фикстур», и вы заметите, что авторы сочли это антипаттерном: соответствующие данные должны создаваться внутри самого теста, а не закрываться в данных фикстур. - person lux; 04.08.2014
comment
Но со статическими бэкэнд-данными данные НЕ создаются в самом тесте, а закапываются. Данные имеют тенденцию расти, потому что вы внедряете новые функции. Для новых функций обычно необходимо создавать новые наборы данных. Таким образом, данные просто имеют тенденцию к росту. - person foens; 06.08.2014

Вы можете написать Backdoor для очистки данных перед запуском тесты:

public class MainActivity extends Activity {

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

}
person bfarache    schedule 30.11.2015