[Update]
Refer [Appium]Run tests in parallel with parallel_tests gem if you’re finding a way to run tests in parallel with existing gem.
When we run Appium in parallel on one Machine and one Appium server with Ruby, we have two ways to implement it. (For Android, we don’t need to configure this kind of environment. We must cover this for iOS because of the platform’s limitations.)
One is thread programming and another is process-fork programming. I’ll put examples to run tests with each method in the below.
rake run_parallel_t- Run tests with thread programming. In this case, each thread shares their data on the memory, classes. It means once our scenario depends on class method, we can’t keep clean test environment.
rake run_parallel_p- Run tests with process-fork programming. In this case, each process is isolated each other. So, we can keep the hermetic environment in each process.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # test file | |
| require_relative '../../lib/appium_lib' | |
| def des_server_caps | |
| { | |
| debug: true, | |
| server_url: "#{ENV['appium_server'] ||= 'http://127.0.0.1:4723'}/wd/hub", | |
| wait: 25, | |
| wait_timeout: 20, | |
| wait_interval: 0.3 | |
| } | |
| end | |
| class TestParallelRunThread | |
| def initialize(capability) | |
| @capability = capability | |
| end | |
| def setup | |
| @appium = Appium::Driver.new({ caps: @capability, appium_lib: des_server_caps }, false) | |
| @appium.start_driver | |
| end | |
| def teardown | |
| @appium.quit_driver | |
| puts "finish: #{@capability}" | |
| end | |
| def test_run | |
| setup | |
| # tap alert | |
| @appium.find_element(:name, 'Alerts').click | |
| @appium.wait_true do | |
| @appium.find_element(:name, 'Show OK-Cancel').click | |
| @appium.find_element(:name, 'UIActionSheet <title>').displayed? | |
| end | |
| @appium.alert action: 'accept' | |
| @appium.back | |
| sleep 5 | |
| # TouchAction | |
| text_elem = @appium.text(@appium.app_strings['ButtonsExplain']) | |
| @appium.tap x: 0, y: 0, element: text_elem | |
| @appium.back | |
| teardown | |
| end | |
| end | |
| class TestParallelRunProcess | |
| def initialize(capability) | |
| @capability = capability | |
| end | |
| def setup | |
| @appium = Appium::Driver.new({ caps: @capability, appium_lib: des_server_caps }, false) | |
| Appium.promote_appium_methods TestParallelRunProcess, @appium | |
| start_driver | |
| end | |
| def teardown | |
| quit_driver | |
| puts "finish: #{@capability}" | |
| end | |
| def test_run | |
| setup | |
| # tap alert | |
| find_element(:name, 'Alerts').click | |
| wait_true do | |
| find_element(:name, 'Show OK-Cancel').click | |
| find_element(:name, 'UIActionSheet <title>').displayed? | |
| end | |
| alert action: 'accept' | |
| back | |
| sleep 5 | |
| # TouchAction | |
| text_elem = text(app_strings['ButtonsExplain']) | |
| tap x: 0, y: 0, element: text_elem | |
| back | |
| teardown | |
| end | |
| end | |
| # Rakefile | |
| class Device | |
| def self.one | |
| { | |
| automationName: 'xcuitest', | |
| platformName: 'ios', | |
| platformVersion: '11.0', | |
| deviceName: 'iPhone 6', | |
| app: "#{Dir.pwd}/../test_apps/UICatalog.app", | |
| wdaLocalPort: 8100, | |
| isCommandsQueueEnabled: false | |
| } | |
| end | |
| def self.two | |
| { | |
| automationName: 'xcuitest', | |
| platformName: 'ios', | |
| platformVersion: '11.0', | |
| deviceName: 'iPhone 6s', | |
| app: "#{Dir.pwd}/../test_apps/UICatalog.app", | |
| wdaLocalPort: 8200, | |
| isCommandsQueueEnabled: false | |
| } | |
| end | |
| end | |
| desc 'Run tests with parallel thread' | |
| task :run_parallel_t do | |
| require 'thread' | |
| require_relative 'parallel/test' | |
| threads = [] | |
| [Device.one, Device.two].each do |capability| | |
| threads << Thread.new do | |
| TestParallelRunThread.new(capability).test_run | |
| end | |
| end | |
| threads.each(&:join) | |
| end | |
| desc 'Run tests with parallel processes' | |
| task :run_parallel_p do | |
| require_relative 'parallel/test' | |
| [Device.one, Device.two].each do |capability| | |
| fork do | |
| TestParallelRunProcess.new(capability).test_run | |
| end | |
| end | |
| Process.waitall | |
| end |
I think process fork model is good for this time since we don’t need to depend on thread programming when we’d like to run tests in parallel.
How do you execute parallel tests with Android?
As addressed in https://kazucocoa.wordpress.com/2018/08/10/appiumrun-tests-in-parallel-with-parallel_tests-gem/, you can run tests in parallel handling
systemPortinstead ofwdaLocalPortin iOS case.