Of course! This is a very common and powerful combination for automated mobile testing. Let's break down how to use Python, Appium, and TestNG together.

First, a crucial clarification: TestNG is a Java framework. You cannot directly use the @Test, @BeforeMethod, etc., annotations in Python.
However, the spirit and structure of TestNG are so popular that the Python community has adopted them. The primary way to achieve a TestNG-like experience in Python is by using the pytest framework with specific plugins.
So, the modern, recommended stack is: Python + Appium + Pytest (with plugins for TestNG-like features)
I will guide you through this setup, which is the industry standard. I'll also briefly touch on the older, less common way of using a Python-to-Java bridge for TestNG.

The Recommended Approach: Python + Appium + Pytest
This combination gives you the best of all worlds: Python's readability, Appium's cross-platform power, and Pytest's flexibility and rich plugin ecosystem.
Key Pytest Plugins for TestNG-like Features:
pytest-testng: This plugin allows you to use TestNG-style XML files to define your test suites, test methods, and parameters. This is the closest you can get to the native TestNG XML configuration.pytest-metadata: Useful for adding metadata to your test reports, similar to TestNG's built-in reporting.pytest-html: Generates a beautiful, standalone HTML report, which is the Python equivalent of TestNG's HTML reports.pytest-xdist: For parallel test execution, a key feature for speeding up test suites.
Step-by-Step Guide
Step 1: Project Setup
Let's create a structured project directory.
appium-python-testng/
├── tests/ # Your test files will go here
│ └── test_calculator.py
├── pages/ # Page Object Model (POM) classes
│ └── calculator_page.py
├── config/
│ └── capabilities.py # Appium capabilities
│ └── testng.xml # Our TestNG-style configuration file
├── requirements.txt # Python dependencies
└── README.md
Step 2: Install Dependencies
Create a requirements.txt file with the following content:
# For Appium and mobile automation Appium-Python-Client pytest pytest-testng pytest-html pytest-metadata
Now, install them:
pip install -r requirements.txt
Step 3: Configure Appium Capabilities (config/capabilities.py)
This file defines how Appium should connect to your device or emulator.
# config/capabilities.py
# For Android
desired_caps = {
'platformName': 'Android',
'deviceName': 'Pixel_4_API_30', # Change this to your device/emulator name
'app': '/path/to/your/app.apk', # Absolute path to your APK
'automationName': 'UiAutomator2',
'appPackage': 'com.google.android.calculator', # Example: Calculator app
'appActivity': 'com.android.calculator2.Calculator' # Example: Calculator activity
}
# For iOS (just for reference)
# desired_caps = {
# 'platformName': 'iOS',
# 'deviceName': 'iPhone 14',
# 'app': '/path/to/your.app',
# 'automationName': 'XCUITest',
# 'wdaStartupRetries': 4,
# 'wdaStartupTimeout': 120
# }
Step 4: Create a TestNG-style XML Configuration (config/testng.xml)
This is the core of the TestNG-like setup. You define your test suites and the test classes/methods to run.
<!-- config/testng.xml -->
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Calculator Test Suite" verbose="1">
<test name="Basic Arithmetic Tests">
<classes>
<class name="tests.test_calculator.CalculatorTests"/>
</classes>
</test>
</suite>
Note: The name attribute for the <class> should be the full path to your test class (module path.ClassName).
Step 5: Implement the Page Object Model (POM)
POM is a design pattern that makes your tests more readable and maintainable.
# pages/calculator_page.py
from appium.webdriver.common.appiumby import AppiumBy
class CalculatorPage:
def __init__(self, driver):
self.driver = driver
# Locators
_field_result = (AppiumBy.ID, 'com.google.android.calculator:id/result_final')
_btn_5 = (AppiumBy.ID, 'com.google.android.calculator:id/digit_5')
_btn_plus = (AppiumBy.ACCESSIBILITY_ID, "plus")
_btn_equals = (AppiumBy.ID, 'com.google.android.calculator:id/eq')
_btn_6 = (AppiumBy.ID, 'com.google.android.calculator:id/digit_6')
def get_result_text(self):
return self.driver.find_element(*self._field_result).text
def calculate(self, num1, operator, num2):
# Click first number
if num1 == 5:
self.driver.find_element(*self._btn_5).click()
elif num1 == 6:
self.driver.find_element(*self._btn_6).click()
# Click operator
if operator == '+':
self.driver.find_element(*self._btn_plus).click()
elif operator == '-':
self.driver.find_element(*self._btn_plus).click() # Assuming minus is 'plus' for this example
# Click second number
if num2 == 5:
self.driver.find_element(*self._btn_5).click()
elif num2 == 6:
self.driver.find_element(*self._btn_6).click()
# Click equals
self.driver.find_element(*self._btn_equals).click()
return self.get_result_text()
Step 6: Write the Test (tests/test_calculator.py)
Here we write the actual test logic. The pytest-testng plugin will automatically pick up the testng_suite fixture and use the testng.xml file.
# tests/test_calculator.py
import pytest
from config.capabilities import desired_caps
from appium import webdriver
from pages.calculator_page import CalculatorPage
@pytest.fixture(scope='class')
def testng_suite(request):
# This fixture is provided by the pytest-testng plugin.
# It reads the testng.xml file and sets up the test class.
pass
@pytest.fixture(scope='class')
def driver(request):
# Setup: Start the Appium driver
driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
yield driver
# Teardown: Quit the driver
driver.quit()
@pytest.fixture(scope='class')
def calculator_page(driver):
return CalculatorPage(driver)
class CalculatorTests:
# This test will be discovered by pytest-testng because it's in a class
# defined in testng.xml
def test_addition(self, calculator_page):
result = calculator_page.calculate(5, '+', 6)
assert result == "11"
def test_subtraction(self, calculator_page):
# Assuming subtraction works with the same button for simplicity
result = calculator_page.calculate(6, '-', 5)
assert result == "1"
Step 7: Run Your Tests
You can now run your test suite using pytest, and it will automatically use the testng.xml file.
# Run tests specified in testng.xml pytest # Run tests and generate an HTML report pytest --html=reports/report.html # Run tests in parallel (if you have multiple devices/instances) # First, install pytest-xdist: pip install pytest-xdist pytest -n 2 # Run tests on 2 workers
When you run pytest, the pytest-testng plugin will find your config/testng.xml file, identify the CalculatorTests class, and execute the test methods within it.
The Old (Not Recommended) Way: Python-Java Bridge
There was a time when people used a bridge like JPype or PyJNIus to call a Java TestNG runner from Python. This is highly discouraged today because:
- Complexity: It adds a heavy dependency on the Java Virtual Machine (JVM) in your Python environment.
- Maintenance: You have to manage two language ecosystems (Python and Java).
- Performance: The bridge adds overhead.
- Modern Alternatives: Pytest with plugins is now mature, powerful, and the de-facto standard.
Summary: Python + Appium + Pytest vs. TestNG
| Feature | Python + Appium + Pytest | Java + Appium + TestNG |
|---|---|---|
| Language |
