Java控制Appium server start/stop
相信很多人都會遇到這種場景,在進行appium自動化的時候用Windows OS,不好實現后臺運行,每次啟動Appium server:
- 使用Appium GUI版手動點擊
- 就是在cmd line 啟動Appium
如果要實現CI,使用Appium GUI是不可行的,因為如果在跑case的過程中Appium session無法創建必須重啟Appium server,也無法自動獲取相應的參數直接啟動Appium
那么這個時候只能使用command line
PS:使用command line需要把Appium相關加入到環境變量
在path 添加
;C:\Program Files (x86)\Appium\node_modules\.bin;
然后在command line驗證一下
如果出現這個,說明Appium使用默認參數啟動成功
其實這個默認啟動的是:C:\Program Files (x86)\Appium\node_modules\.bin\appium.bat
使用默認的參數,如果想使用指定的ip和port log等內容需要加參數
比如使用:
C:\Users\Test>appium -a 127.0.0.1 -p 1235
info: Welcome to Appium v1.4.16 (REV ae6877eff263066b26328d457bd285c0cc62430d)
info: Appium REST http interface listener started on 127.0.0.1:1235
info: [debug] Non-default server args: {"address":"127.0.0.1","port":1235}
info: Console LogLevel: debug 具體參數這里不再詳解,可以使用appium --help
那么好了,直接使用Java調用這個command的就好了
于是寫了就這樣:
public void excuteCMD(String comand)
{
Runtime rt = Runtime.getRuntime();
RuntimeExec rte = new RuntimeExec();
StreamWrapper error, output;
try
{
Process proc = rt.exec(comand);
error = rte.getStreamWrapper(proc.getErrorStream(), "ERROR");
output = rte.getStreamWrapper(proc.getInputStream(), "OUTPUT");
BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String s;
while ((s = stdInput.readLine()) != null)
{
System.out.println(s);
if (s.contains("Appium REST http"))
{
System.out.println("STARTED!");
}
}
error.start();
output.start();
error.join(3000);
output.join(3000);
System.out.println("Output: " + output.message + "\nError: " + error.message);
} catch (IOException e)
{
e.printStackTrace();
} catch (InterruptedException e)
{
e.printStackTrace();
}
} 使用Java runtime class
傳入相應的command, 然后執行并把輸入顯示出來
然后發現這樣做行不通, 因為沒法執行下面的code
查了相關資料才知道這個叫線程阻塞
于是乎只能找到一種非線程阻塞的方法
這個時候找到一個commons-exec的project能給解決問題
根據官方文檔,如果使用非阻塞執行,可以這樣做:
- 首先創建一個非阻塞的handler DefaultExecuteResultHandler,這個是專門用來處理非阻塞
- 在創建一個watchdog用來監控輸出,設置timeout時間60s
- 創建一個執行器設置退出代碼為1,代表執行成功
注意,這里必須設置一個waitfor time,如果沒有設置會報錯
resultHandler.waitFor(5000);
public static String APPIUMSERVERSTART = "C:\\Program Files (x86)\\Appium\\node_modules\\.bin\\appium.cmd";
public static void startServer() throws IOException, InterruptedException
{
startServer("4723");
// RuntimeExec appiumObj = new RuntimeExec();
// appiumObj.excuteCMD(APPIUMSERVERSTART);
DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler();
CommandLine commandLine = CommandLine.parse(APPIUMSERVERSTART);
ExecuteWatchdog dog = new ExecuteWatchdog(60 * 1000);
Executor executor = new DefaultExecutor();
executor.setExitValue(1);
executor.setWatchdog(dog);
executor.execute(commandLine, resultHandler);
resultHandler.waitFor(5000);
System.out.println("Appium server start");
} 以上code實現的是使用默認的port啟動Appium server ,如果遇到Appium端口被占用,啟動失敗怎么辦?
我的策略是先殺掉所以占用這個端口的進程:
可以嘗試使用command line
cmd /c echo off & FOR /F "usebackq tokens=5" %a in (`netstat -nao ^| findstr /R /C:"4723"`) do (FOR /F "usebackq" %b in (`TASKLIST /FI "PID eq %a" ^| findstr /I node.exe`) do taskkill /F /PID %a)
/**
* @author Young
* @param appiumServicePort
* @throws ExecuteException
* @throws IOException
*/
public static void stopAppiumServer(String appiumServicePort) throws ExecuteException, IOException
{
ExectorUtils.runWithWatchDog("cmd /c echo off & FOR /F \"usebackq tokens=5\" %a in"
+ " (`netstat -nao ^| findstr /R /C:\"" + appiumServicePort + "\"`) do (FOR /F \"usebackq\" %b in"
+ " (`TASKLIST /FI \"PID eq %a\" ^| findstr /I node.exe`) do taskkill /F /PID %a)");
} 這樣就可以在每個test case啟動相應的Appium server并且給出指定的參數。
相關資料: http://commons.apache.org/proper/commons-exec/tutorial.html