Parallel Execution

Before anything, spring up two different servers running on different ports.

appium --port 4723

and

appium --port 4724

Now we have two servers running on different terminal windows.

conftest.py

import pytest
import logging
import time
import random

from appium import webdriver
from typing import Any, Dict
from appium.options.common.base import AppiumOptions
from appium.webdriver.common.appiumby import AppiumBy
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import ElementNotVisibleException, NoSuchElementException

@pytest.fixture(scope="function")
def driver1():
    
    # Set desired capabilities for the Android emulator
    cap: Dict[str, Any] = {
        "platformName": "Android",
        "appium:automationName": "uiautomator2",
        "appium:platformVersion": "12",
        "udid": "---",
        "port": 4723,
        "appium:appPackage": "---",
        "appium:appActivity": "---"
    }


    url = "http://localhost:4723"


    driver = webdriver.Remote(url, options=AppiumOptions().load_capabilities(cap))
    return driver


@pytest.fixture(scope="function")
def driver2():
    
    # Set desired capabilities for the Android emulator
    cap: Dict[str, Any] = {
        "platformName": "Android",
        "appium:automationName": "uiautomator2",
        "appium:platformVersion": "12",
        "appium:udid": "---",
        "appium:appPackage": "---",
        "port": 4724,
        "appium:appActivity": "---"
    }


    url = "http://localhost:4724"


    driver = webdriver.Remote(url, options=AppiumOptions().load_capabilities(cap))
    return driver

the fixtures are going to return a different driver that is going to interact with their respective ports.

test_script1.py

our example test script 1.

import time

def test_script2(driver2):
    driver2.tap([(534,721)])
    time.sleep(2)
    driver2.quit()

test_script2.py

our example test script 2.

import time

def test_script1(driver1):
    driver1.tap([(534,721)])
    time.sleep(2)
    driver1.quit()

As you can see, these example scripts don’t do much, but the possibilities are endless.

Running Sequentially

Since we’re using pytest, let’s just run pytest from the project directory.

pytest -v

-v is for verbose.
You should see that the scripts are running one device after the other.

Running Parallelly

Let’s use pytest-xdist which schedules tests via LoadScheduling.

Now if we run the below command to trigger the pytest framework, we should be able to run both the test scripts parallelly.

pytest -v -n 2

-n is for the number of workers. since we are using only two devices for this example, let’s just use 2 runners

VOILA!

the output would look something like this

PS C:> pytest -v -n 2
================================================================================================== test session starts ==================================================================================================
platform win32 -- Python 3.12.1, pytest-8.3.5, pluggy-1.5.0 -- C:\Users\r.charan\Documents\appium_parallel\venv\Scripts\python.exe
cachedir: .pytest_cache
rootdir: C:
plugins: xdist-3.7.0
2 workers [2 items]     
scheduling tests via LoadScheduling

test_script2.py::test_script2
test_script1.py::test_script1
[gw0] [ 50%] PASSED test_script1.py::test_script1 
[gw1] [100%] PASSED test_script2.py::test_script2 

and the test scripts should be running parallelly on both the devices.

Updated on