如何将测试参数中的设备UDID传入独立类的DesiredCapabilities
问题描述
我有一个独立的CommonAndroidDriver类,用来封装Capabilities和Driver实例。现在需要为每个测试用例单独传入设备UDID参数。我尝试通过ITestContext.getCurrentXmlTest().getParameter()来获取参数,但没能找到把UDID传入DesiredCapabilities的可行方式。
现有代码
CommonAndroidDriver类
public class CommonAndroidDriver { public static AndroidDriver driver; private URL serverUrl; private DesiredCapabilities capabilities = new DesiredCapabilities(); public CommonAndroidDriver(ITestContext context) throws MalformedURLException { this.serverUrl = new URL("https:"); capabilities.setCapability("appium:platformName", MobilePlatform.ANDROID); capabilities.setCapability("appium:automationName", "UiAutomator2"); capabilities.setCapability("appium:appPackage", "blabla"); capabilities.setCapability("appium:appActivity", "blabla"); capabilities.setCapability("uftm:oauthClientId", "blabla"); capabilities.setCapability("uftm:oauthClientSecret", "blabla"); capabilities.setCapability("uftm:tenantId", "blabla"); capabilities.setCapability("appium:udid", context.getCurrentXmlTest().getParameter("udid")); capabilities.setCapability("appium:noReset", true); capabilities.setCapability("appium:autoGrantPermissions", true); this.driver = new AndroidDriver(serverUrl, capabilities); } public AndroidDriver getDriver() { return this.driver; } }
测试类LoginTest
public class LoginTest extends BaseAppium { public LoginTest() throws IOException { } @Test @Parameters({"login", "password", "udid"}) public void Login(String login, String password, String udid) throws Exception { //some test steps } }
TestNG配置文件
<suite name="AndroidAppiumTest"> <test name="LoginTests"> <parameter name="loginmp" value="test@test.com"/> <parameter name="passwordtest" value="Test1234"/> <parameter name="udid" value="DeviceId"/> <classes> <class name="tests.LoginTest"/> <methods> <include name="Login"/> </methods> </classes> </test> </suite>
BaseAppium基类
public class BaseAppium { public AndroidDriver driver; public BaseAppium() throws IOException { } @BeforeClass public void setUp(ITestContext context) throws IOException { this.driver = new CommonAndroidDriver(context).getDriver(); } @BeforeTest public void setTest() { } @AfterClass public void tearDown() throws IOException, InterruptedException { this.driver.terminateApp("app.name"); this.driver.quit(); } }
解决方案
核心问题是当前@BeforeClass在测试方法之前执行,此时测试方法上的udid参数还未传递,且测试方法拿到udid后未传给Driver初始化逻辑。按以下步骤调整即可:
1. 修改CommonAndroidDriver构造方法,直接接收UDID参数
去掉对ITestContext的依赖,改为直接传入udid,避免上下文参数获取的问题:
public class CommonAndroidDriver { // 禁止用static修饰driver,否则多测试用例会共享实例,导致设备冲突 private AndroidDriver driver; private URL serverUrl; private DesiredCapabilities capabilities = new DesiredCapabilities(); public CommonAndroidDriver(String udid) throws MalformedURLException { this.serverUrl = new URL("https:"); capabilities.setCapability("appium:platformName", MobilePlatform.ANDROID); capabilities.setCapability("appium:automationName", "UiAutomator2"); capabilities.setCapability("appium:appPackage", "blabla"); capabilities.setCapability("appium:appActivity", "blabla"); capabilities.setCapability("uftm:oauthClientId", "blabla"); capabilities.setCapability("uftm:oauthClientSecret", "blabla"); capabilities.setCapability("uftm:tenantId", "blabla"); // 直接使用传入的udid capabilities.setCapability("appium:udid", udid); capabilities.setCapability("appium:noReset", true); capabilities.setCapability("appium:autoGrantPermissions", true); this.driver = new AndroidDriver(serverUrl, capabilities); } public AndroidDriver getDriver() { return this.driver; } }
2. 调整Driver初始化时机到@BeforeMethod
因为要为每个测试方法单独传UDID,需要把初始化逻辑从@BeforeClass移到@BeforeMethod,并传递参数:
修改BaseAppium类
public class BaseAppium { public AndroidDriver driver; public BaseAppium() throws IOException { } // 替换@BeforeClass为@BeforeMethod,接收udid参数 @BeforeMethod public void setUp(String udid) throws IOException { this.driver = new CommonAndroidDriver(udid).getDriver(); } // 对应改成@AfterMethod,确保每个测试方法执行后销毁Driver @AfterMethod public void tearDown() throws IOException, InterruptedException { if (driver != null) { this.driver.terminateApp("app.name"); this.driver.quit(); } } }
修改LoginTest测试类
通过@Parameters把UDID传递给@BeforeMethod的初始化方法,确保每个测试用例用对应UDID启动Driver:
public class LoginTest extends BaseAppium { public LoginTest() throws IOException { } // 先把udid参数传给父类的setUp方法 @BeforeMethod @Parameters({"udid"}) public void setUp(String udid) throws IOException { super.setUp(udid); } @Test @Parameters({"login", "password", "udid"}) public void Login(String login, String password, String udid) throws Exception { // 此处driver已用当前udid初始化完成,可直接编写测试步骤 //some test steps } }
3. 修正TestNG配置文件的参数名
测试方法的login、password参数名要和配置文件一致,否则会出现参数找不到的错误:
<suite name="AndroidAppiumTest"> <test name="LoginTests"> <!-- 参数名与测试方法中的参数对应 --> <parameter name="login" value="test@test.com"/> <parameter name="password" value="Test1234"/> <parameter name="udid" value="DeviceId"/> <classes> <class name="tests.LoginTest"/> <methods> <include name="Login"/> </methods> </classes> </test> </suite>
关键注意事项
- 禁止给
AndroidDriver加static修饰符,否则多个测试用例会共享同一个Driver实例,导致设备冲突或测试污染。 - 若需要多设备并行测试,可在TestNG配置文件中添加多个
<test>节点,每个节点设置不同的udid参数,TestNG会自动并行执行。
内容的提问来源于stack exchange,提问作者Bart Soha
相关产品推荐
相关产品推荐

