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

В процес съм на прилагане на GUI тестове с помощта на Calabash. В The Cucumber Book се подчертава, че сценариите трябва да настройват самите тестови данни, локално, за предпочитане използване на библиотеки като factory_girl. Този въпрос е относно производителността, чистотата и управляемостта на тестването на приложения за Android и iOS с помощта на Calabash.

Ползата от инструменти като factory_girl е, че тестовете трябва да са по-малко крехки и че тестовите данни могат да бъдат създадени/вмъкнати без използване на GUI, което ускорява значително тестовете (което ги прави по-ценни за разработчиците). Освен това всеки scenario трябва да бъде независим от всички други сценарии, така че да не изисква сценарий A да се изпълнява преди B, ако B трябва да работи правилно. Това позволява на разработчиците да изпълняват само един сценарий.

Това изглежда разумно за програми, които се изпълняват локално, където например базата данни на уеб услугата може да бъде достъпна директно, така че да могат да се вмъкнат тестови данни. Как обаче тестерът вмъква данни в програми, които работят на друго устройство (емулатор, симулатор, реален телефон).

По-конкретно, как може да се управляват тестови данни, вероятно когато се изпълнява срещу цел за iOS и Android? Изкушавам се да използвам Set of Fixture Data, както е описано в The Cucumber Book, но те изрично казват да избягвам това.

Питам, защото приложението, което създавам, има много настройки, преди потребителят да може да влезе в основния изглед на приложението. Потребителят трябва:

  1. Регистрирайте се, което се състои от няколко стъпки:

    A. Натиснете „Регистрация“

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

    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 hooks (използвани за определяне кога да се генерират тестови данни).

Вижте по-долу пример за това как създадохме нови акаунти/клиенти с помощта на скъпоценния камък 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

Последната част от мозайката е да накарате вашите calabash сценарии да консумират тестовите данни, които току-що сте генерирали. За да разрешим този проблем, декларирахме глобална променлива ($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

И вие очевидно можете да възпроизведете тази моделна структура за всичко, освен необходимо да съдържа просто количество информация. Отново, не мога да говоря за библиотеки с приспособления, тъй като не съм ги използвал.

Но на другия ви въпрос относно независимостта на Сценарий А от Сценарий Б - това е вярно, но това не означава, че не можете да нанижете дефиниции на стъпки, за да постигнете целите си. Да кажем, че тестът по-горе беше просто използван за проверка, че мога успешно да вляза в приложението с валиден потребител - всичко е наред, потребителят е влязъл и всички са доволни. Но какво се случва, когато трябва да тествам страницата на потребителския профил? Е, очевидно трябва да вляза, но не е необходимо това да бъде изрично посочено в моя файл с функции, мога да създам дефиниция на стъпка, която свързва други дефиниции на стъпка:

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
Здравей lux и благодаря за отговора. Трябва да имате някакъв вид Fixture Data, т.е. данни, които се настройват за целите на тестването. Имате валиден потребител, но къде е създаден този валиден потребител? Друга забележка е, че с вашето решение ще завършите в бавни тестове, защото тествате страницата за вход отново и отново. Това прави тестовете, които изискват влизане, бавни и следователно по-малко използваеми за програмист. Конкретно това исках да избегна. - person foens; 03.08.2014
comment
Потребителският клас по-горе е просто клас мъниче, реалният потребител трябва да съществува в системата, която тествате, в противен случай влизането няма да бъде успешно. И ако това е коренът на вашия въпрос, тогава просто трябва да се уверите, че използвате едни и същи данни от бекенда (т.е. едно и също копие на база данни) за всеки от вашите тестове. Просто вземете копие от продукцията и я използвайте повторно, за да можете да осигурите последователност и също така ще тествате спрямо това, което е на полето, вместо това, което мислите че е на място. Отново, 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