اگر Appium فقط «روی لپتاپ من» یک بار تست را سبز کند، هنوز اتوماسیون موبایل ندارید. یک مجموعه تست قابل اعتماد باید نسخه سرور و درایور، هویت Build، دستگاه و سیستمعامل، داده شروع، Locator، انتظارها و شواهد شکست را قابل بازتولید کند. در این آموزش Appium ۳، از نصب تا اجرای اولین تست Android با Python پیش میرویم و بعد همان نمونه را به معماری مناسب iOS، دستگاه واقعی و CI تبدیل میکنیم.
هدف، تولید انبوه اسکریپت UI نیست. ابتدا باید بدانیم کدام ریسکها به تست سطح UI نیاز دارند و کدامها با Unit، API، Contract یا تست دستی ارزانتر و دقیقتر پوشش داده میشوند. اگر هنوز ماتریس Device/OS/Network را ندارید، راهنمای تست اپلیکیشن موبایل را پیش از انتخاب سناریوها مرور کنید.
پاسخ کوتاه: Appium یک سرور و اکوسیستم متنباز برای خودکارسازی UI است. کلاینت Python/Java/JavaScript فرمانهای WebDriver را به سرور میفرستد؛ سرور آنها را به درایور پلتفرم میسپارد؛ UiAutomator2 در Android و XCUITest در iOS با فناوری بومی دستگاه کار میکنند. Appium «یک تست کاملاً مشترک برای هر دو سیستمعامل» یا «کیفیت تضمینشده» نمیدهد؛ این نتیجه به Testability اپ، انتخاب لایه، داده، محیط و طراحی تست وابسته است.
Appium چیست و در Appium ۳ چه چیزی نصب میشود؟
Appium رابطی مبتنی بر WebDriver برای پلتفرمهای مختلف فراهم میکند. خود Appium Server فرمانهایی مانند ساخت Session، یافتن Element، Click و Screenshot را دریافت میکند؛ اما اجرای واقعی فرمان بر عهده Driver نصبشده است. به همین دلیل نصب سرور بهتنهایی برای خودکارسازی Android یا iOS کافی نیست.
معماری Client، Server، Driver و ابزار بومی
- Test Runner: برای نمونه pytest، JUnit یا runner جاوااسکریپت، چرخه Setup/Test/Teardown و Assertion را مدیریت میکند.
- Appium Client: API زبان انتخابی را به درخواست WebDriver تبدیل میکند.
- Appium Server: Session را میسازد، فرمان را اعتبارسنجی و به Driver هدایت میکند.
- Driver: UiAutomator2 یا XCUITest فرمان عمومی را به رفتار پلتفرمی نگاشت میکند.
- Backend بومی: ADB/Android SDK در Android و XCTest/WebDriverAgent/Xcode در iOS با دستگاه و اپ تعامل میکنند.
- AUT: همان Application Under Test با Build، امضا، Package/Bundle و داده مشخص است.
مستندات رسمی نصب Appium ۳ نیز تأکید میکند که Driver همراه سرور نصب نمیشود. این جداسازی مزیت مهمی دارد: میتوان نسخه هر Driver را مستقل مدیریت کرد؛ در عوض تیم باید سازگاری Server/Driver/Client/SDK/OS را در Manifest اجرای تست ثبت کند.
Native، Hybrid و Mobile Web یک چیز نیستند
- Native: Elementها از درخت Accessibility/UI پلتفرم دیده میشوند و فرمانها در Context بومی اجرا میشوند.
- Hybrid: بخشی از اپ Native و بخشی WebView است. تست باید Context موجود را کشف و آگاهانه بین
NATIVE_APPو WebView جابهجا شود. - Mobile Web: مرورگر موبایل هدف است؛ Driver معمولاً از Safari/Chromedriver و نسخه سازگار مرورگر استفاده میکند.
شباهت API به معنی یکسانبودن semantics نیست. Permission dialog، Back navigation، Keyboard، Deep Link، WebView debugging و lifecycle در Android و iOS تفاوت دارند. «هسته سناریو» میتواند مشترک باشد، اما Adapter و Oracle پلتفرمی باید این تفاوت را صریح نگه دارد.
تفاوت Appium ۳ با راهنماهای قدیمی اینترنت
- فرمت قدیمی JSON Wire Protocol مبنای Appium ۳ نیست؛ Capabilityها باید مطابق W3C و با پیشوند Vendor مانند
appium:ارسال شوند. Client رسمی Python این پیشوندها را از طریق Options مدیریت میکند. - Driverها و Pluginها Extension مستقلاند و با CLI خود Appium مدیریت میشوند.
- برای بررسی پیشنیازها، دستور فعلی
appium driver doctor <driver>است؛ نصب سراسری بسته قدیمیappium-doctorنقطه شروع این آموزش نیست. - Appium Inspector سرور Appium نیست. Desktop App یا Plugin مستقل آن به یک Server در حال اجرا متصل میشود.
- قابلیتهای ناامن در Appium ۳ scope میخواهند؛ بازکردن عمومی
--relaxed-securityراهحل عیبیابی امنی نیست.
آیا Appium انتخاب مناسبی برای تیم شماست؟
Appium ابزار عمومی و قدرتمندی است، اما هر سناریوی موبایل را نباید با آن حل کرد. تصمیم را با اقتصاد بازخورد و ریسک محصول بگیرید، نه با محبوبیت ابزار. برای ساخت معیار انتخاب، راهنمای اتوماسیون تست نرمافزار مرز ارزش و هزینه را توضیح میدهد.
کاندیداهای مناسب
- Journeyهای حیاتی و تکرارشونده مانند ورود، افزودن به سبد، پرداخت آزمایشی و مشاهده نتیجه سفارش؛
- رفتارهایی که به تعامل واقعی چند Screen، Permission، Deep Link یا lifecycle دستگاه وابستهاند؛
- Regression باریک و باارزش روی چند ترکیب Device/OS که اجرای دستی آن مستعد تفاوت است؛
- Smoke تست Build نصبشونده پیش از توزیع داخلی؛
- بررسی محدود Native/WebView با قرارداد فنی مشخص.
مواردی که Appium معمولاً اولین انتخاب نیست
- قواعد محاسباتی، Validationهای دامنه و state machine که در Unit یا Component سریعتر تست میشوند؛
- قرارداد API، authorization ماتریسی و خطاهای سرویس که در لایه API/Contract دقیقترند؛
- Load و Performance بکاند؛ Appium میتواند تجربه یک Client را مشاهده کند، اما Load Generator مناسبی برای هزاران کاربر نیست؛
- ارزیابی کامل Accessibility، Usability یا ظاهر که همچنان به ابزار تخصصی و قضاوت انسانی نیاز دارد؛
- سناریویی که Testability ID، داده کنترلشده یا Oracle معتبر ندارد.
یک Gate ساده پیش از توسعه Framework
یک Journey حیاتی را انتخاب و روی دو ترکیب نماینده اجرا کنید. اگر تیم نمیتواند در دو هفته Setup تکرارپذیر، سه اجرای مستقل، Artifact شکست و زمان نگهداری را اندازه بگیرد، افزودن دهها Case بدهی را بزرگتر میکند. معیارهای Pilot را از ابتدا در استراتژی اتوماسیون تست ثبت کنید.
قرارداد Testability پیش از نوشتن تست
Locator باید بخشی از API رابط کاربری باشد
تیم اپ برای کنترلهای تعاملی شناسه پایدار و معنادار تعریف کند؛ مانند checkout.pay یا refund.amount. Accessibility ID معمولاً انتخاب خوب مشترک است، به شرط آنکه معنی دسترسپذیری را خراب نکند. Resource ID در Android و Predicate/Class Chain در iOS میتوانند Adapterهای پلتفرمی باشند. XPath سراسری و مبتنی بر index را آخرین گزینه بدانید، نه پیشفرض.
قرارداد Locator سه ویژگی دارد: در یک Screen یکتا است، به متن ترجمهشده یا مکان بصری وابسته نیست و تغییر آن مانند breaking change به تیم تست اعلام میشود. Inspector برای مشاهده و آزمودن Locator مفید است، اما پیشنهاد خودکار آن الزاماً پایدارترین Selector نیست.
حالت شروع و پایان باید معلوم باشد
هر تست باید بداند کاربر، سفارش، Session و Permission در چه وضعیتی شروع میشوند و پس از شکست چگونه پاکسازی میشوند. noReset=true درمان کندی نیست؛ ممکن است state قبلی را پنهان کند و Caseها را به ترتیب اجرا وابسته سازد. Factory API، namespace یکتا، seed نسخهدار و cleanup idempotent معمولاً از Tapهای طولانی برای ساخت داده بهترند. برای جزئیات، مدیریت داده تست را ببینید.
Oracle را از حرکت انگشت جدا کنید
«دکمه کلیک شد» نتیجه کسبوکار نیست. برای پرداخت آزمایشی، Oracle میتواند ترکیبی از نمایش وضعیت موفق، شناسه سفارش، وضعیت API و نبود درخواست تکراری باشد. هر Assertion باید بگوید کدام ادعا را اثبات میکند؛ Screenshot صرفاً شاهد بصری است و بهتنهایی اثبات درستی state سرور نیست.
پیشنیازهای نصب Appium ۳
پیشنیاز مشترک Server
در زمان آخرین بازبینی این مقاله، System Requirements رسمی Appium ۳ بازه Node.js را ^20.19.0 || ^22.12.0 || >=24.0.0 و npm را >=10 اعلام میکند و LTS را پیشنهاد میدهد. نسخهها را با مستندات فعلی دوباره کنترل کنید؛ Driver انتخابی ممکن است پیشنیاز سختگیرانهتری داشته باشد.
node --version
npm --version
برای CI و کار تیمی، نسخه Node و packageها را pin کنید. ارتقای Server و Driver را در Pull Request جدا با Smoke تست انجام دهید؛ اجرای شناور «latest» میتواند بدون تغییر کد تست، محیط را عوض کند.
پیشنیاز Android
- Android Studio یا Android Command-line Tools، یک SDK Platform و Platform-Tools؛
- JDK سازگار با Android toolchain و Driver؛
- تنظیم
ANDROID_HOMEوJAVA_HOME؛ - AVD روشن یا دستگاه واقعی با USB debugging؛
- خروجی سالم
adb devicesبا وضعیتdevice، نهunauthorizedیاoffline؛ - APK یا Package/Activity نصبشده و قابل راهاندازی.
راهنمای رسمی UiAutomator2 مراحل SDK، JDK، دستگاه، نصب Driver و Doctor را یکجا نگه میدارد. برای پروژه واقعی، API/OS و معماری CPU تصویر Emulator را با Build هماهنگ کنید.
پیشنیاز iOS
- Host مبتنی بر macOS برای مسیر رایج XCUITest؛
- Xcode و Command Line Tools سازگار با نسخه iOS هدف؛
- Simulator runtime یا دستگاه واقعی؛
- برای دستگاه واقعی: Developer Mode، signing/provisioning معتبر، UDID و پیکربندی WebDriverAgent؛
- فایل
.appساختهشده برای Simulator یا Build امضاشده مناسب دستگاه واقعی.
جدول سازگاری Driver/Xcode/iOS در مستندات نصب XCUITest Driver تغییر میکند. بهجای کپیکردن دستورهای قدیمی Carthage یا حدس نسخه، نسخه OS هدف را در همان جدول بررسی و سپس Doctor را اجرا کنید.
نصب Appium ۳ برای Android، قدمبهقدم
۱. نصب Server و کنترل نسخه
npm install -g appium
appium --version
نصب global برای شروع ساده است. در تیم Node.js میتوان Server و Driverها را به dependency پروژه و lockfile سپرد؛ مهم این است که روش نصب در Local و CI یکسان و نسخه واقعی در Artifact ثبت شود.
۲. نصب UiAutomator2
appium driver install uiautomator2
appium driver list --installed
appium driver doctor uiautomator2
عبارت 0 required fixes needed نشانه عبور از پیشنیازهای الزامی Driver است؛ Warning اختیاری را کورکورانه نادیده نگیرید، بلکه ببینید به قابلیت مورد استفاده شما مربوط است یا نه. برای مشاهده ارتقاهای موجود میتوانید از appium driver list --updates استفاده کنید، اما Update را مستقیم روی مسیر انتشار اجرا نکنید.
۳. آمادهکردن Emulator یا دستگاه واقعی
adb devices
adb shell getprop ro.build.version.release
adb shell wm size
یک شناسه دستگاه را انتخاب کنید و آن را در Manifest Run ثبت کنید. اگر چند دستگاه متصلاند، Capability udid را صریح بدهید. نام عمومی deviceName=Android برای انتخاب دقیق دستگاه کافی نیست.
۴. اجرای Server
appium
Server پیشفرض روی 127.0.0.1:4723 در دسترس کلاینت محلی است. Log آغازین باید UiAutomator2 را در فهرست Driverهای موجود نشان دهد. این Terminal را باز نگه دارید و تست را از Terminal دوم اجرا کنید.
۵. نصب Appium Inspector
مخزن رسمی Appium Inspector نسخه Desktop برای macOS/Windows/Linux و نسخه Plugin را معرفی میکند. فایل را از Release رسمی دریافت و checksum/امضای سازمانی را طبق سیاست تیم بررسی کنید. Inspector را با همان Capabilityهای تست به Server متصل کنید؛ اگر Inspector Session میسازد اما کد نه، تفاوت Client، Capability و URL را مقایسه کنید.
اولین تست Appium با Python و pytest
نمونه زیر عمداً اپ Settings خود Android را باز میکند تا برای شروع به APK خارجی نیاز نباشد. زبان Session روی English قرار گرفته و Element «Apps» با UiSelector پیدا میشود. این تست برای تأیید زنجیره نصب است، نه الگوی نهایی محصول؛ در اپ خودتان Accessibility ID پایدار درخواست کنید.
۱. ساخت محیط Python
python -m venv .venv
# macOS / Linux
source .venv/bin/activate
# Windows PowerShell
# .venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install Appium-Python-Client pytest
Client رسمی Appium Python، Selenium binding لازم را نیز میآورد. نمونه رسمی Python نقطه مرجع خوبی برای تغییرات API Client است.
۲. ساخت فایل test_settings.py
from appium import webdriver
from appium.options.android import UiAutomator2Options
from appium.webdriver.common.appiumby import AppiumBy
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
SERVER_URL = "http://127.0.0.1:4723"
def test_open_apps_screen():
capabilities = {
"platformName": "Android",
"automationName": "UiAutomator2",
"deviceName": "Android",
"appPackage": "com.android.settings",
"appActivity": ".Settings",
"language": "en",
"locale": "US",
"noReset": False,
}
options = UiAutomator2Options().load_capabilities(capabilities)
driver = webdriver.Remote(SERVER_URL, options=options)
try:
wait = WebDriverWait(driver, 15)
apps_item = wait.until(
EC.element_to_be_clickable(
(
AppiumBy.ANDROID_UIAUTOMATOR,
'new UiSelector().text("Apps")',
)
)
)
apps_item.click()
apps_heading = wait.until(
EC.visibility_of_element_located(
(
AppiumBy.ANDROID_UIAUTOMATOR,
'new UiSelector().text("Apps")',
)
)
)
assert apps_heading.is_displayed()
finally:
driver.quit()
۳. اجرای تست
python -m pytest -v test_settings.py
ترتیب درست عیبیابی چنین است: Server روشن، Driver بارگذاریشده، دستگاه در ADB، Package/Activity معتبر، Session ساختهشده، Element پیدا شده، Assertion و در پایان quit. اگر تست Fail شد، نخستین خطای معنادار Appium Server را همراه Capability و هویت دستگاه بخوانید؛ آخرین Exception کلاینت معمولاً فقط پیام خلاصه است.
۴. این تست دقیقاً چه چیزی را اثبات میکند؟
- کلاینت Python به URL درست Server وصل میشود؛
- Appium میتواند UiAutomator2 Session بسازد؛
- Android SDK/ADB/Driver برای دستگاه انتخابی کار میکنند؛
- Settings راهاندازی و یک Element پیدا و کلیک میشود؛
- Screen بعدی یک Element قابل مشاهده با متن مورد انتظار دارد؛
- Session حتی در صورت Failure بسته میشود.
این تست صحت اپ شما، پرداخت، همه نسخههای Android یا نبود Flake را ثابت نمیکند. Evidence باید با Claim هماندازه باشد.
Capability در Appium؛ حداقل لازم و خطاهای رایج
Capability قرارداد ساخت Session است. در JSON خام، قابلیتهای اختصاصی باید پیشوند appium: داشته باشند؛ برای نمونه appium:automationName. Options در Client Python این تبدیل را انجام میدهد. مرجع فعلی Session Capabilities و مرجع Driver را همزمان بخوانید، زیرا بیشتر گزینههای Android/iOS در Driver تعریف میشوند.
Capabilityهای هویتی
platformName: خانواده پلتفرم، مانند Android یا iOS؛automationName: Driver/Backend مورد نظر، مانند UiAutomator2 یا XCUITest؛udid: شناسه دقیق دستگاه، بهویژه برای Real Device و Parallel؛appیاappPackage/appActivityیاbundleId: هویت Build/اپ هدف؛platformVersion: برای انتخاب یا ثبت OS، نه جایگزین UDID در مزرعه شلوغ؛language/locale: فقط اگر Driver/سیستم هدف آن را پشتیبانی کند و تست واقعاً به آن نیاز داشته باشد.
چرا Desired Capabilities قدیمی دردسر میسازد؟
مقالهها و ویدئوهای Appium ۱ ممکن است endpoint دارای /wd/hub، JSONWP، Driverهای bundled یا Capability بدون پیشوند را نشان دهند. URL پایه Appium جدید معمولاً http://127.0.0.1:4723 است، مگر Server را با base path دیگری اجرا کرده باشید. Client و Server را حدس نزنید؛ Log startup URLهای معتبر را چاپ میکند.
Reset را به تصمیم داده تبدیل کنید
noReset=falseبه معنی پاکشدن قطعی همه stateهای بیرونی مانند Backend، Keychain یا سرویس پیامک نیست.noReset=trueمیتواند Login را نگه دارد، اما Test isolation را کاهش میدهد.fullReset=trueهزینه زمانی و side effect دارد و باید برای سناریوی نصب/ارتقا یا پاکسازی مشخص استفاده شود.
بهترین پاسخ یک Boolean جهانی نیست؛ قرارداد state برای هر Suite است.
Locator و Wait پایدار در اتوماسیون موبایل
ترتیب پیشنهادی انتخاب Locator
- Accessibility ID پایدار و معنادار که تیم محصول مالک آن است؛
- Resource ID یکتا در Android یا Locator بومی پایدار در iOS؛
- Predicate/Class Chain یا Android UiSelector برای نیاز پلتفرمی مشخص؛
- متن فقط وقتی همان متن موضوع Assertion یا قرارداد locale است؛
- XPath کوتاه و محدود، تنها وقتی hook بهتری در دسترس نیست.
نام Class، index، مختصات و XPath طولانی به ساختار داخلی یا اندازه Screen متصلاند. Recorder/Inspector میتواند نقطه شروع بسازد، ولی خروجی آن باید review و ساده شود.
Explicit Wait بهجای sleep
sleep(5) پنج ثانیه صبر میکند، نه تا زمانی که شرط کسبوکار برقرار شود. Explicit Wait باید برای state قابل مشاهده نوشته شود: Element قابل کلیک، Screen marker قابل مشاهده، Progress ناپدید یا متن نتیجه تغییر کرده است. Timeout بخشی از Oracle است؛ مقدار بسیار بزرگ Failure واقعی را پنهان میکند و مقدار بسیار کوچک تغییرات سالم دستگاه را Flaky میسازد.
سه زمان متفاوت را قاطی نکنید
- App readiness: اپ آماده تعامل است؛
- Element readiness: Element وجود دارد، visible و enabled است؛
- Business completion: عملیات backend واقعاً به state مورد انتظار رسیده است.
ممکن است دکمه فوراً کلیک شود ولی پرداخت آزمایشی چند ثانیه بعد نهایی شود. Wait روی Toast موقت اگر ادعای شما ثبت سفارش است Oracle ضعیفی است؛ یک Screen marker پایدار یا Query کنترلشده API اضافه کنید.
تبدیل نمونه به تست واقعی یک اپ ایرانی
فرض کنید اپ فروشگاهی باید Journey «ورود کاربر آزمایشی → انتخاب کالا → پرداخت Sandbox → مشاهده سفارش» را پوشش دهد. سناریو را به یک Tap Script طولانی تبدیل نکنید.
Setup خارج از UI
- کاربر با API داخلی امن و namespace همان Run ساخته شود؛
- موجودی و کد تخفیف deterministic باشند؛
- درگاه پرداخت روی Sandbox/Fake کنترلشده قرار گیرد؛
- OTP واقعی مشتری ارسال نشود؛ Stub یا حساب تست مجاز استفاده شود؛
- Build با SHA و endpoint محیط شناخته شود.
Journey باریک UI
- ورود با credential موقت؛
- بازکردن محصول از Deep Link یا مسیر کوتاه؛
- افزودن به سبد و بررسی مبلغ با واحد ریال/تومان صریح؛
- شروع پرداخت Sandbox و بازگشت به اپ؛
- بررسی شناسه و state سفارش؛
- Query backend برای اثبات تنها یک سفارش/پرداخت.
ماتریس فارسی و ایران
حداقل سناریوهای ریسکمحور برای fa-IR شامل RTL، ترکیب رقم فارسی/عربی/لاتین، نیمفاصله، نام و آدرس بلند، تومان/ریال، منطقه زمانی Asia/Tehran، تاریخ جلالی/میلادی، Keyboard فارسی، Deep Link، قطع و بازگشت شبکه و callback درگاه است. همه را در یک E2E نریزید؛ هر ریسک را در ارزانترین لایه معتبر پوشش دهید.
راهاندازی Appium برای iOS با XCUITest
نصب و Doctor
appium driver install xcuitest
appium driver list --installed
appium driver doctor xcuitest
این مسیر به Host macOS و Xcode سازگار نیاز دارد. برای Simulator فایل .app باید برای Simulator ساخته شده باشد؛ IPA دستگاه واقعی را نمیتوان مانند Build Simulator فرض کرد.
Capability پایه iOS
{
"platformName": "iOS",
"appium:automationName": "XCUITest",
"appium:deviceName": "iPhone Simulator",
"appium:platformVersion": "<target-os>",
"appium:app": "/absolute/path/MyApp.app"
}
برای اجرای موازی یا دستگاه واقعی، appium:udid را صریح تعیین کنید. Signing شناسه تیم، provisioning و WebDriverAgent باید توسط مالک حساب Apple تنظیم شود و Secretها در repository یا Log عمومی نوشته نشوند.
Simulator و Real Device چه تفاوتی دارند؟
- Simulator برای Fast feedback، state قابل reset و پوشش گستردهتر OS مفید است؛
- Real Device برای عملکرد سختافزار، notification، camera، biometrics، network radio، signing و رفتارهای دستگاه واقعی لازم میشود؛
- هیچکدام جای دیگری را کامل نمیگیرد. ترکیب را از ریسک محصول انتخاب کنید.
تست Hybrid App و WebView
Context را کشف کنید، حدس نزنید
Session معمولاً در NATIVE_APP شروع میشود. بعد از بازشدن WebView، فهرست Contextها را بگیرید، WebView درست را با هویت صفحه انتخاب کنید و پس از کار به Context بومی برگردید. index یک Context در فهرست میتواند با startup و تبلیغ/صفحه اضافی تغییر کند.
پیششرط WebView
- WebView باید برای debugging در Build تست قابل دسترس باشد؛
- Chromedriver و Chrome/WebView در Android باید سازگار باشند؛
- در iOS، WebView و signing/debug configuration باید امکان inspection بدهند؛
- Locatorهای Native در Web Context و CSS/XPath وب در Native Context یکسان عمل نمیکنند.
اگر Context دیده نمیشود، مشکل را با sleep بیشتر پنهان نکنید. Build configuration، Driver log، نسخه مرورگر، debuggability و زمان ایجاد WebView را بررسی کنید.
معماری Framework؛ اشتراک رفتار، نه پنهانکردن تفاوتها
لایهبندی پیشنهادی
- Tests: Claim کسبوکار، داده ورودی و Assertion؛
- Flows: Login، Checkout و Refund با زبان دامنه؛
- Screens/Components: Locator و تعامل هر Screen/Component؛
- Platform Adapters: تفاوت Android/iOS، Permission و navigation؛
- Fixtures: ساخت/پاکسازی داده، Driver lifecycle و محیط؛
- Evidence: Log، Screenshot، page source محدود، video/trace در صورت نیاز و Manifest.
Page Object Model یک گزینه معماری است، نه قانون اجباری. Screenهای بزرگ، inheritance عمیق و Assertionهای پراکنده میتوانند نگهداری را سختتر کنند. Composition و Component Object برای کنترلهای تکراری اغلب روشنتر است.
Cross-platform reuse واقعبینانه
Flow کسبوکار مثل checkout.pay() میتواند مشترک باشد؛ Locator، permission و navigation در Adapter پلتفرم میماند. اگر UI دو پلتفرم واقعاً متفاوت است، شرطهای متعدد داخل یک Page Object «reuse» نیست؛ coupling پنهان است. میزان اشتراک کد را Metric موفقیت نکنید؛ پایداری رفتار و هزینه تغییر مهمتر است.
هر Test باید مستقل باشد
تست دوم نباید به سفارشی که تست اول ساخته وابسته باشد. ترتیب اجرا، retry یا اجرای موازی نباید نتیجه را عوض کند. شناسه داده شامل Run ID/Worker ID باشد و cleanup چندبار قابل اجرا بماند. اگر Failure پیش از cleanup رخ داد، TTL یا job جمعآوری نهایی از آلودگی محیط جلوگیری کند.
اجرای موازی و CI/CD
هویت Resourceها را یکتا کنید
Parallel فقط افزودن Worker نیست. هر Worker به Device/Simulator، Appium port یا Node، Driver portهای اختصاصی، data namespace، account و Artifact path یکتا نیاز دارد. در Android معمولاً systemPort و در iOS wdaLocalPort باید برای Workerها برخورد نداشته باشند؛ گزینه دقیق را در مرجع همان Driver بررسی کنید.
سه Lane بازخورد
- Pull Request: چند Smoke پرارزش روی Emulator/Simulator ثابت؛
- Post-merge: Regression ریسکمحور روی ماتریس متوسط؛
- Scheduled/Release: Real Device، locale/network گستردهتر و Journeyهای پرهزینه.
قرار دادن همه E2Eها روی هر Commit، feedback را کند و Quarantine را زیاد میکند. معماری Lane و Quality Gate را با تست مداوم در CI/CD هماهنگ کنید.
Manifest اجرای قابل بازتولید
run_id: mobile-20260806-1842
commit_sha: a1b2c3d
app_artifact_sha256: "<sha256>"
appium_server: "3.x.y"
driver:
name: uiautomator2
version: "x.y.z"
client:
name: Appium-Python-Client
version: "x.y.z"
device_alias: android-api-target-worker-1
os_build: "<exact-build>"
locale: fa-IR
timezone: Asia/Tehran
data_seed: checkout-v4
environment: mobile-test
در Manifest واقعی نسخهها را از runtime استخراج کنید، نه با placeholder دستی. Binary و Secret داخل Manifest قرار نمیگیرند؛ فقط hash یا reference امن ثبت میشود. برای قرارداد محیط، مدیریت محیط تست را اعمال کنید.
Artifactهای Failure
- نام Case، attempt، زمان UTC و Run ID؛
- Screenshot در لحظه Failure؛
- Page source فقط در صورت نیاز و پس از حذف داده حساس؛
- Client log و بخش مرتبط Server/Driver log؛
- Device log محدود و همبسته با Session؛
- Video فقط برای Suiteهای لازم با retention کوتاه؛
- Capability نهایی با redaction Secretها.
امنیت Appium Server، داده و حریم خصوصی
Server را روی اینترنت باز نکنید
مستندات امنیت Appium Server اجرای محلی یا داخل شبکه محافظتشده و دور از کاربران غیرقابل اعتماد را شرط ایمن میداند. Server میتواند کنترل گسترده روی دستگاه داشته باشد. پورت ۴۷۲۳ را عمومی نکنید، Runner را isolate کنید و feature ناامن را فقط با scope و نیاز مستند فعال سازید.
Secret و PII را از Evidence حذف کنید
- Token، OTP، password، session cookie و signing credential در کد یا Capability ثابت نباشد؛
- Log و page source ممکن است شماره موبایل، نام، آدرس و پیام را در خود داشته باشند؛
- حساب و شماره واقعی مشتری برای E2E استفاده نشود؛
- Screenshot/Video با دسترسی محدود، retention و حذف خودکار نگهداری شود؛
- دستگاه واقعی پیش و پس از Run با سیاست سازمان پاکسازی شود.
محدودیت دسترسی تیمهای ایرانی
دسترسی ناپایدار به npm/GitHub، Device Cloud یا سرویسهای Apple/Google را به Failure محصول تبدیل نکنید. registry/cache سازمانی مجاز، lockfile، hash بستهها و mirror داخلی تأییدشده داشته باشید؛ Artifact لازم را پیش از Release آماده کنید. مسیر fallback باید قانونی، امنیتی و ثبتشده باشد. درگاه پرداخت، SMS و Push را با Sandbox/Fake کنترلشده تست کنید و یک Lane محدود برای سرویس واقعی مجاز نگه دارید.
عیبیابی خطاهای رایج Appium
| نشانه | علتهای محتمل | بررسی بعدی |
|---|---|---|
| Could not connect | Server خاموش، host/port/base path اشتباه | URL چاپشده در startup log و دسترسی همان Runner را بررسی کنید. |
| Could not find a driver | Driver نصب یا با Server فعلی load نشده | appium driver list --installed و log آغاز Server. |
| Session not created | Capability نامعتبر، Device/Build/SDK ناسازگار | اولین خطای Driver، Capability نهایی و ماتریس نسخهها. |
| adb unauthorized/offline | مجوز USB، کابل/ADB یا Device state | adb devices و تأیید dialog دستگاه؛ سپس اتصال را پایدار کنید. |
| Element not found | Context غلط، Locator شکننده، Screen آماده نیست | Context، Screen marker، source و Locator contract؛ نه sleep تصادفی. |
| Element دیده میشود ولی Click نمیشود | Overlay، animation، disabled state یا مختصات stale | شرط clickable، hierarchy، screenshot و state بیزینسی. |
| WebView نمایش داده نمیشود | Debug غیرفعال یا Browser/Driver ناسازگار | Build config، Context list، نسخه WebView/Chromedriver و Driver log. |
| WDA در iOS بالا نمیآید | Xcode/signing/provisioning/Developer Mode/port | Doctor، Xcode log، UDID، Team/Bundle config و جدول سازگاری Driver. |
| فقط در Parallel Fail میشود | Device/port/data/account/artifact مشترک | Manifest Workerها و یکتایی همه Resourceها. |
| فقط در CI Fail میشود | تفاوت SDK، permission، locale، path یا resource | Manifest Local و CI را diff و Build یکسان را دوباره اجرا کنید. |
Failure taxonomy پیش از Retry
- Product: رفتار اپ/Backend برخلاف Oracle؛
- Test: Locator، assertion، teardown یا race داخل کد تست؛
- Data: fixture ناقص، state آلوده یا collision؛
- Environment: Device، SDK، Appium node، شبکه داخلی؛
- Dependency: درگاه/SMS/API بیرونی؛
- Unknown: Evidence برای طبقهبندی کافی نیست.
Retry خودکار نباید Failure اول را پاک کند. attempt نخست و همه Artifactها حفظ شوند؛ Passed-on-retry بهعنوان Flaky candidate بررسی شود، نه Pass عادی.
Anti-patternهای اتوماسیون Appium
- همهچیز E2E: Suite کند، تشخیص دیر و مالکیت مبهم میشود.
- XPath everywhere: کوچکترین تغییر hierarchy تعداد زیادی تست را میشکند.
- Sleep everywhere: هم اجرای سالم را کند و هم رفتار کندتر را Flaky میکند.
- یک Test بسیار بلند: مکان Failure و recovery را مبهم میکند.
- اشتراک یک حساب: اجرای موازی و state را به هم آلوده میکند.
- تغییر latest در روز Release: علت Failure بین App، Server و Driver گم میشود.
- Quarantine بدون owner/expiry: پوشش ادعایی میماند ولی سیگنال از بین میرود.
- Screenshot بهعنوان تنها Oracle: state backend و side effect تکراری را نشان نمیدهد.
- relaxed-security عمومی: سطح حمله Runner و Device را بیدلیل گسترش میدهد.
- یک Page مشترک پر از if: تفاوت واقعی Android/iOS را پنهان میکند.
متریکهایی که به تصمیم کمک میکنند
سلامت Test System
- نرخ ساخت موفق Session به تفکیک Device/OS/Driver؛
- مدت p50/p95 Session startup و Case duration؛
- Flaky rate بر اساس Passed-on-retry با حفظ Failure اول؛
- Failure سهم Product/Test/Data/Environment/Dependency/Unknown؛
- زمان میانه تشخیص و رفع Broken Test؛
- Quarantine age و owner/expiry؛
- درصد Runهایی که Manifest و Artifact حداقلی کامل دارند.
اعتماد محصول
- پوشش Journeyهای پرریسک، نه تعداد خام Test Case؛
- پوشش ترکیبهای Device/OS/locale براساس ماتریس ریسک؛
- Defectهای مهمی که اتوماسیون پیش از Release پیدا کرده؛
- Escaped defect مرتبط با Journey و شکاف لایه/Oracle؛
- زمان Feedback از Commit تا Evidence قابل اقدام.
Pass rate بدون تفکیک Blocked/Skipped/Quarantined و بدون denominator ثابت میتواند گمراهکننده باشد. افزایش تعداد تست یا درصد کد مشترک را هدف مستقل نکنید.
برنامه ۱۴روزه شروع Appium
روز ۱ تا ۳: Contract و Baseline
- یک Journey با Impact بالا و داده کنترلشده انتخاب کنید؛
- Build، Device/OS و expected result را ثبت کنید؛
- Testability IDهای لازم را با تیم اپ توافق کنید؛
- زمان دستی، خطاهای فعلی و هزینه Setup را baseline بگیرید.
روز ۴ تا ۷: اجرای محلی قابل بازتولید
- Server/Driver/Client را pin و Doctor را سبز کنید؛
- Fixture API، teardown و Artifact شکست را بسازید؛
- سه اجرای مستقل از state تمیز روی Emulator/Simulator انجام دهید؛
- Failureها را با taxonomy طبقهبندی و علت را رفع کنید.
روز ۸ تا ۱۰: ماتریس کوچک
- یک ترکیب دوم Device/OS یا Platform اضافه کنید؛
- Adapter پلتفرمی را فقط جایی بسازید که تفاوت واقعی وجود دارد؛
- fa-IR، RTL و یک حالت شبکه پرریسک را جدا ارزیابی کنید؛
- duration و Flaky candidate را اندازه بگیرید.
روز ۱۱ تا ۱۴: CI و تصمیم
- یک Lane Smoke با Manifest و Artifact وارد CI کنید؛
- Retry محدود را با ثبت attempt نخست پیاده کنید؛
- هزینه Runner/Device و زمان نگهداری واقعی را ثبت کنید؛
- تصمیم Adopt/Revise/Stop را با شواهد Pilot بگیرید.
Scale فقط وقتی منطقی است که سناریوی Pilot سیگنال قابل اعتماد، owner مشخص، زمان بازخورد قابل قبول و هزینه نگهداری شناختهشده داشته باشد.
چکلیست نهایی آموزش Appium
- نقش Appium Server، Client، Driver و backend بومی را جدا میدانیم.
- نسخه Node/npm مطابق Appium فعلی است و نسخهها pin شدهاند.
- UiAutomator2 یا XCUITest جدا نصب و Doctor اجرا شده است.
- Build، Device/OS، locale، Driver و داده در Manifest ثبت میشوند.
- Locator contract داریم و XPath سراسری پیشفرض نیست.
- Explicit Wait روی state معنادار داریم، نه sleep ثابت.
- Setup/cleanup تست مستقل، idempotent و مناسب Parallel است.
- Oracle UI را در صورت نیاز با state API/Backend کامل میکنیم.
- Failure taxonomy و Artifact قابل اقدام پیش از Retry داریم.
- Appium Server در شبکه محافظتشده است و Secret/PII از Evidence حذف میشود.
- Matrix از ریسک و کاربران واقعی میآید، نه از تعداد Deviceهای در دسترس.
- CI به Laneهای سریع، میانی و Release تقسیم شده است.
- Quarantine دارای owner، دلیل و تاریخ انقضا است.
- قبل از Scale، Pilot و هزینه نگهداری را اندازه گرفتهایم.
سوالات متداول درباره Appium
آیا Appium ۳ برای Android و iOS یک کد کاملاً مشترک میدهد؟
خیر. WebDriver API و بخشی از Flow کسبوکار میتواند مشترک باشد، اما Driver، Locator، Permission، navigation، Build و برخی Oracleها پلتفرمیاند. اشتراک اجباری معمولاً شرطهای زیاد و تست شکننده میسازد.
برای شروع Appium از Java بهتر است یا Python؟
زبان تیم، Client نگهداریشده، runner، مهارت عیبیابی و هماهنگی با repository مهمتر از یک برنده عمومی است. Python برای آموزش کوتاه و خوانا است؛ Java یا JavaScript ممکن است با stack تیم شما سازگارتر باشند. با یک Spike یکسان، قابلیت، کیفیت IDE، parallel و CI را مقایسه کنید.
آیا برای Appium باید کد اپلیکیشن را تغییر دهیم؟
معمولاً لازم نیست SDK اختصاصی Appium داخل اپ Embed شود؛ اما یک اپ قابل تست به Accessibility ID، Build configuration، Deep Link، Sandbox و hookهای امن داده نیاز دارد. این تغییرها Testability مهندسیشدهاند، نه وابستگی به ابزار.
Emulator/Simulator کافی است یا دستگاه واقعی لازم داریم؟
برای Feedback سریع و پوشش OS، محیط مجازی ارزشمند است؛ اما رفتار سختافزار، notification، signing، شبکه واقعی و برخی lifecycleها به Real Device نیاز دارند. نسبت این دو را از ریسک و داده کاربران تعیین کنید و در ماتریس تست سازگاری ثبت کنید.
چگونه Flaky Testهای Appium را کم کنیم؟
ابتدا علت را میان Product/Test/Data/Environment/Dependency تفکیک کنید. Locator پایدار، Explicit Wait، state مستقل، Device/port یکتا، Build و نسخه pinشده، Artifact کافی و Quarantine زماندار بیشترین اثر را دارند. Retry بدون حفظ Failure اول فقط سیگنال را پنهان میکند.
جمعبندی: نقطه شروع حرفهای Appium، نصب یک ابزار نیست؛ ساخت یک زنجیره قابل بازتولید از Build و Device تا Driver، داده، Oracle و Evidence است. با یک Journey باریک شروع کنید، Appium ۳ و Driver را نسخهدار نگه دارید، نمونه Python را ابتدا محلی و بعد در CI ثابت کنید و تنها پس از اندازهگیری پایداری و هزینه، Suite را گسترش دهید.

