Кто-нибудь понял, как запустить один и тот же сценарий огурца на нескольких браузерах/веб-драйверах?

Я использую огурец + capybara для тестирования веб-автоматизации. Мне бы хотелось, чтобы у меня был собственный тег (что-то вроде @all_browsers до сценария), и он запускается против списка установленных мной веб-драйверов (celerity, selenium on firefox, ie и chrome). Я не хочу писать сценарий 4 раза с 4 разными тегами спереди. Я искал попытку сделать это с помощью нового драйвера, через который я зарегистрировался через:

Capybara.register_driver :all_browsers do |app|
 # What would even work in here? I don't think anything will.
end  

И затем следуйте за ним:

Before('@all_browsers') do
 # Same problem here.
end

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

Я пробовал использовать крючки огурца, в частности:

Around('@all_browsers') do |scenario, block|
  Capybara.current_driver = :selenium_firefox
  block.call

  Capybara.current_driver = :selenium_chrome
  block.call
  # etc
end

Но это не ведет себя так, как я надеялся. Он использует один и тот же драйвер и дважды запускает сценарий с ним.

Следуя вдоль линий крюка, это из документации огурца:
You may also provide an AfterConfiguration hook that will be run after Cucumber has been configured. This hook will run only once; after support has been loaded but before features are loaded. You can use this hook to extend Cucumber, for example you could affect how features are loaded...
Это может быть потенциальным препятствием для этого, но мне не удалось придумать что-нибудь, что здесь работает.

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

Я посмотрел на переориентирующую функцию огурца, но это не выглядит просто или дружелюбно. Помоги пожалуйста? Кто-нибудь?

Ответ 1

Итак, я запустил свое собственное решение. Не уверен, был ли это лучший или самый изящный подход, но я на самом деле просто закончил:

  • Абстрагирование всего содержимого среды в env.rb
  • Использование профилей огурца, для которых потребуется определенный файл среды (например, firefox.rb), который потребовал env.rb, а затем установить драйвер по умолчанию для Capybara соответствующему драйверу.
  • Написал большой класс ol < thor с задачами, которые собирают кучу команд огурца и вызывают для запуска плохого мальчика с правильный профиль.
  • Написал задачу "all_browsers", которая связывает команды, затем вызывает каждую конкретную задачу драйвера, поэтому теперь у меня есть одна задача, которая запускает любой набор сценариев, которые я поставляю на всех поддерживаемых драйверах.

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

cucumber.yaml:
Здесь файл all_features просто делает глобус всего, что заканчивается на .feature, потому что если я потянул во весь каталог функций, он потянул бы все под ним, включая все файлы профиля и т.д., Чего я не хотел, так как каждый файл профиля задает драйвер capybara по умолчанию для другого значения. Как только вы укажете -r как опцию огурца, вся автозагрузка любого файла будет остановлена.

default: --format pretty

chrome: --format pretty -r features/support/profiles/chrome.rb -r features/all_features -r features/step_definitions

firefox: --format pretty -r features/support/profiles/firefox.rb -r features/all_features -r features/step_definitions

celerity: --format pretty -r features/support/profiles/celerity.rb -r features/all_features -r features/step_definitions

firefox.rb(файл 'profile'):

require File.dirname(__FILE__) + "/../env.rb"

Capybara.configure do |config|
  config.default_driver = :selenium_firefox
end

selenium_firefox.rb(где я регистрирую драйвер и устанавливаю некоторые возможности тегов, которые мне не нужны сейчас, поскольку тег @selenium_firefox был частью моей первоначальной попытки опубликовать это в вопросе):

# Register a specific selenium driver for firefox
Capybara.register_driver :selenium_firefox do |app|
  Capybara::Driver::Selenium.new(app, :browser => :firefox)
end

# Allows the use of a tag @selenium_firefox before a scenario to run it in selenium with firefox
Before('@selenium_firefox') do
  Capybara.current_driver = :selenium_firefox
end

feature_runner.thor:

require 'benchmark'

class FeatureRunner < Thor
  APP_ROOT = File.expand_path(File.dirname(__FILE__) + "/../")

  # One place to keep all the common feature runner options, since every runner in here uses them.
  # Modify here, and all runners below will reflect the changes, as they all call this proc.
  feature_runner_options = lambda { 
    method_option :verbose, :type => :boolean, :default => true, :aliases => "-v"
    method_option :tags, :type => :string
    method_option :formatter, :type => :string
    method_option :other_cucumber_args, :type => :string
  }


  desc "all_drivers_runner", "Run features in all available browsers"
  method_option :benchmark, :type => :boolean, :default => false
  method_option :threaded, :type => :boolean, :default => true
  feature_runner_options.call # Set up common feature runner options defined above
  def all_drivers_runner
    if options[:threaded]
      feature_run = lambda { 
        thread_pool = []

        t = Thread.new do |n|
          invoke :firefox_runner
        end
        thread_pool << t

        t = Thread.new do |n|
          invoke :chrome_runner
        end
        thread_pool << t

        t = Thread.new do |n|
          invoke :celerity_runner
        end
        thread_pool << t

        thread_pool.each {|th| th.join}
      }
    else
      feature_run = lambda { 
        invoke "feature_runner:firefox_runner", options
        invoke "feature_runner:chrome_runner", options
        invoke "feature_runner:celerity_runner", options
      }
    end

    if options[:benchmark]
      puts "Benchmarking feature run"
      measure = Benchmark.measure { feature_run.call }
      puts "Benchmark Results (in seconds):"
      puts "CPU Time: #{measure.utime}"
      puts "System CPU TIME: #{measure.stime}"
      puts "Elasped Real Time: #{measure.real}"
    else
      feature_run.call
    end
  end

  desc "firefox_runner", "Run features on firefox"
  feature_runner_options.call # Set up common feature runner options defined above
  def firefox_runner
    command = build_cucumber_command("firefox", options)
    run_command(command, options[:verbose])
  end

  desc "chrome_runner", "Run features on chrome"
  feature_runner_options.call # Set up common feature runner options defined above
  def chrome_runner
    command = build_cucumber_command("chrome", options)
    run_command(command, options[:verbose])
  end

  desc "celerity_runner", "Run features on celerity"
  feature_runner_options.call # Set up common feature runner options defined above
  def celerity_runner
    command = build_cucumber_command("celerity", options)
    run_command(command, options[:verbose])
  end

  private
  def build_cucumber_command(profile, options)
    command = "cd #{APP_ROOT} && ./bin/cucumber -p #{profile}"
    command += " --tags=#{options[:tags]}" if options[:tags]
    command += " --formatter=#{options[:formatter]}" if options[:formatter]
    command += " #{options[:other_cucumber_args]}" if options[:other_cucumber_args]
    command
  end

  def run_command(command, verbose)
    puts "Running: #{command}" if verbose
    output = `#{command}`
    puts output if verbose
  end

end

Где все закончилось по отношению к корневому каталогу:

.
|____cucumber.yml
|____features
| |____all_features.rb
| |____google_search.feature
| |____step_definitions
| | |____google_steps.rb
| | |____web_steps.rb
| |____support
| | |____custom_formatters
| | | |____blah.rb
| | |____env.rb
| | |____paths.rb
| | |____profiles
| | | |____celerity.rb
| | | |____chrome.rb
| | | |____firefox.rb
| | |____selenium_drivers
| | | |____selenium_chrome.rb
| | | |____selenium_firefox.rb
| | | |____selenium_ie.rb
| | | |____selenium_remote.rb
| | |____selenium_drivers.rb
|____tasks
| |____feature_runner.thor
| |____server_task.rb  

Вывод thor -T

feature_runner
--------------
thor feature_runner:all_drivers_runner  # Run features in all available browsers
thor feature_runner:celerity_runner     # Run features on celerity
thor feature_runner:chrome_runner       # Run features on chrome
thor feature_runner:firefox_runner      # Run features on firefox  

Теперь я могу запустить что-то вроде:
thor feature_runner:all_drivers_runner --benchmark
Это позволит запускать все функции на всех драйверах capybara в потоке для каждого драйвера, сравнивая результаты.

Или
thor feature_runner:celerity_runner
Это приведет к тому, что все функции будут выполняться только с неограниченностью.

Но теперь я могу также предоставить некоторые другие варианты команды thor, которые передаются на огурец, например:
[email protected]_browsers
--formatter=hotpants
--other_cucumber_args="--dry-run --guess --etc"

Теперь может выглядеть файл функций:

Feature: Start up browser
  @all_browsers
  Scenario: Search Google
   Given I am on the home page
   When I fill in the search bar with "Capybara"
   And I press "Search"
   Then I should see "Capybara"

Кажется, что много настроек, но теперь, если я помечаю функцию с помощью @all_browsers, я могу построить набор для тестирования всех драйверов capybara в многопоточной среде с помощью одной команды thor:
thor feature_runner:all_drivers_runner --threaded [email protected]_browsers

Или создайте пакет smoke test, который работает в неограниченном режиме:
thor feature_runner:celerity_runner [email protected]_test

Ответ 2

Это возможно благодаря размещенной службе SauceLabs. Огуречный соус" дает вам параллельные тесты с несколькими браузерами.

В качестве альтернативы вы можете заимствовать у источника этого драгоценного камня, если хотите реализовать его самостоятельно.

Ответ 3

Вот мой хак: (моя ситуация доказывает, что функция работает с отключением javascript и javascript)

  • Поместите каждый сценарий в свой собственный файл свойств.
  • Переместите каждую строку, кроме последней, в раздел "Фон:".
  • Поместите последнюю строку в сценарий для браузера
  • Пометьте каждый сценарий соответствующим образом

    Feature: a feature
    
    Background:
    Given a user "Jim" exists
    Given a user "Mike" exists
    
    When I login as "mike"
    And I follow "Lesson 1"
    
    And I follow "Upload a video"
    Then "#upload_a_video" should be active
    
    And I fill in "video_title" with "my film"
    And I attach the file "video.mov" to "video_upload"
    And I press "Post"
    
    Scenario: normal
    And I should see "my film"
    
    @javascript
    
    Scenario: javascript
    And I should see "my film"
    

Ответ 4

Я делаю это так, как рекомендует проект "watir". Я использую require parallel_cucumber в своем Rakefile, и каждый сценарий Cucumber получает свой собственный параллельный поток (до 20 в этом случае):

task :run_cucumber do
  FileUtils.mkpath(ENV['OUT_DIR'])
  begin
    # cannot format report as HTML because of parallel forking
    threads = 20
    @result = system "parallel_cucumber features -o \"--format junit --out #{ENV['OUT_DIR']} --format pretty --tag @sauce\" -n #{threads}"
  ensure
    @success &= @result
  end
end

Затем оставшуюся часть вашего проекта Cucumber можно записать как обычно! Так просто! Мой полный пример здесь: https://github.com/djangofan/cuke-parallel-starter