转载:https://blog.youkuaiyun.com/baidu_37711332/article/details/82584928
时下H5应用很火,微信公众号,微信小程序,支付宝服务窗等,其应用跟PC端的Web应用有共同也有区别之处,但其实H5应用跟pc端的web应用是差不多的,其本质都是web应用,都是要通过浏览器或者Webview浏览器进行操作,只不过H5应用更多的是运行在手机端而不是PC端。由于设备端不一样,H5应用是在手机端,没法像PC端的WEB应用那么简单,所以很多时候,可能是把H5划归到APP自动化进行管理的。既然有这么多共同之处,那么有没有办法把它封装成一种浏览器,归类到Web自动化测试中呢,达到跟WEB UI统一的操作入口?看了思寒的微信Webview自动化测试方法的帖子,给了我灵感,特分享出来
网上流传的H5自动化测试有两种方案,一种是利用PC端谷歌浏览器的设备UA模式,模拟手机浏览器,一种是利用Appium连接手机,进入应用切换到Webview;一种方案是比较简单的,但是没有办法完全模拟手机浏览器的环境,所以采用第二种方法。下面说下具体的过程
一、将apium注册到selenium gird
采用Appium 的方式,Appium Driver启动方式与Webdriver的启动方式略有不同,那么如何达到统一的入口呢?Selenium有一种分布式解决方案Selenium Grid,如果把Appium Server 注册到Selenium Grid hub上就实现了统一的入口了。appium 注册到selenium grid的方法,网上有很多例子,但经过实验发现,有几个地方需要特别注意:
1、注册node节点的时候需指定udid, 2、启动的时候要顺带启动appium 内置的chromedriver,3、appium 地址,grid hub地址不能指定为127.0.0.1,不然其他机器就没办法通过ip进行访问了。下面是我的appium 注册代码:
nodeconfig如下:
-
{
-
"capabilities": [
-
{
-
"browserName":
"chrome",
-
"version":
"5.0.1",
-
"maxInstances":
1,
-
"platform":
"ANDROID",
-
"udid":
"127.0.0.1:62001",
-
"deviceName":
"127.0.0.1:62001"
-
}
-
],
-
"configuration": {
-
"cleanUpCycle":
2000,
-
"timeout":
30000,
-
"proxy":
"org.openqa.grid.selenium.proxy.DefaultRemoteProxy",
-
"hub":
"192.168.1.103:4455/grid/register",
-
"url":
"http://192.168.1.103:4723/wd/hub",
-
"host":
"192.168.1.103",
-
"port":
4723,
-
"maxSession":
1,
-
"register":
true,
-
"registerCycle":
5000,
-
"hubPort":
4455,
-
"hubHost":
"192.168.1.103"
-
}
-
}
appium 启动脚本:
appium --address 192.168.1.103 --port 4723 --bootstrap-port 4724 --chromedriver-port 8000 --session-override --nodeconfig D:\auto\appium-node\appium-node.json
二、设计testbase(浏览器启动和关闭)类
原理:由于微信浏览器没有像PC浏览器一样有网址输入口,所以需要通过文件传输助手输入自己设计的网址入口地址(类似hao123入口)
-
public
class TestBaseCase {
-
public
static WebDriver driver;
-
public
static String description;
-
public Log
log=
new Log(
this.getClass().getSuperclass());
-
public void setup( String driver,String nodeURL) throws MalformedURLException {
-
log.info(
"------------------开始执行测试---------------");
-
log.info(
"读取xml配置:浏览器:"+driver+
";gridNodeURL:"+nodeURL);
-
try {
-
this.driver=setRemoteDriver(driver,nodeURL);
-
}
catch (Exception e) {
-
log.error(
"没有成功浏览器环境配置错误");
-
}
-
-
this.driver.manage().window().maximize();
-
-
}
-
-
@
AfterTest
-
public
void
tearDown
() {
-
try {
-
this.driver.close();
-
this.driver.quit();
-
}
catch (Exception e) {
-
log.info(
"android driver 退出需切换会NATIVE_APP");
-
AndroidDriver androidDriver=(AndroidDriver) driver;
-
androidDriver.quit();
-
}
-
}
-
private WebDriver setRemoteDriver(String browsername,String nodeURL) throws MalformedURLException
-
{
-
switch (browsername)
-
{
-
-
case
"FirefoxDriver" :
-
DesiredCapabilities capabilities=DesiredCapabilities.firefox();
-
capabilities.setBrowserName(
"firefox");
-
capabilities.setPlatform(Platform.WINDOWS);
-
driver=
new RemoteWebDriver(
new URL(nodeURL), capabilities);
-
break;
-
case
"ChormeDriver":
-
DesiredCapabilities dcchorme=DesiredCapabilities.chrome();
-
dcchorme.setBrowserName(
"chrome");
-
dcchorme.setVersion(
"46.0.2490.86 m");
-
dcchorme.setPlatform(Platform.WINDOWS);
-
driver=
new RemoteWebDriver(
new URL(nodeURL), dcchorme);
-
break;
-
case
"WeiXIN":
-
DesiredCapabilities capability =
new DesiredCapabilities();
-
capability.setCapability(
"app",
"");
-
capability.setCapability(
"appPackage",
"com.tencent.mm");
-
capability.setCapability(
"appActivity",
".ui.LauncherUI");
-
capability.setCapability(
"deviceName",
"127.0.0.1:62001");
-
capability.setCapability(
"fastReset",
"false");
-
capability.setCapability(
"fullReset",
"false");
-
capability.setCapability(
"noReset",
"true");
-
capability.setCapability(
"unicodeKeyboard",
"True");
-
capability.setCapability(
"resetKeyboard",
"True");
-
//关键是加上这段
-
ChromeOptions options2 =
new ChromeOptions();
-
options2.setExperimentalOption(
"androidProcess",
"com.tencent.mm:tools");
-
capability.setCapability(ChromeOptions.CAPABILITY, options2);
-
//启动微信浏览器
-
log.info(
"启动微信浏览器");
-
driver=
new AndroidDriver(
new URL(nodeURL), capability);
-
driver.manage().timeouts().implicitlyWait(
500, TimeUnit.MILLISECONDS);
-
sleep(
5);
-
log.info(
"点击微信搜索菜单");
-
WebElement webElement=driver.findElement(By.xpath(
"//*[@content-desc='搜索']"));
-
webElement.click();
-
log.info(
"输入文件字符串");
-
webElement=driver.findElement(By.xpath(
"//*[@text='搜索']"));
-
webElement.click();
-
webElement.clear();
-
webElement.sendKeys(
"文件");
-
sleep(
4);
-
log.info(
"点击文件传输助手");
-
webElement=driver.findElement(By.xpath(
"//*[@text='文件传输助手']"));
-
webElement.click();
-
sleep(
8);
-
log.info(
"发送跳转网站的网页URL");
-
webElement= driver.findElement(By.xpath(
"//*[@resource-id='com.tencent.mm:id/z4']"));
//不同微信版本,定位不一样
-
webElement.sendKeys(
"http://192.168.1.103:8080/openurl/open.html");
-
log.info(
"点击发送按钮");
-
webElement=driver.findElement(By.xpath(
"//*[@text='发送']"));
-
webElement.click();
-
sleep(
3);
-
log.info(
"点击网址");
-
webElement=driver.findElement(By.xpath(
"//*[@text='"+
"http://192.168.1.103:8080/openurl/open.html"+
"']"));
-
webElement.click();
-
sleep(
3);
-
log.info(
"切换到微信webView");
-
//Webdriver转AndroidDriver
-
AndroidDriver androidDriver=(AndroidDriver) driver;
-
androidDriver.context(
"WEBVIEW_com.tencent.mm:tools");
-
driver=androidDriver;
-
-
case
"HtmlUnitDriver":
-
this.driver=
new HtmlUnitDriver();
-
break;
-
default:
-
this.driver=
new FirefoxDriver();
-
break;
-
}
-
return driver;
-
}
-
}
-
三、设计网址入口网页
-
<html>
-
<head>
-
<meta charset="GBK"/>
-
<script src="http://cdn.static.runoob.com/libs/jquery/1.10.2/jquery.min.js">
-
</script>
-
</head>
-
<body style="text-align:center">
-
<div>
-
<input id="url" type="text"/>
-
<input id="openurl" type="button" value="打开网页"/>
-
</div>
-
<script>
-
$(
"#openurl").click(
function(){
-
var url=$(
"#url").val();
-
location.href=url;
-
}
-
)
-
</script>
-
</body>
-
</html>
四、设计open方法
-
//微信浏览器操作
-
public void openWeiXinBrowser(String url) {
-
WebElement webElement=driver.findElement(By.id(
"url"));
-
log.info(
"输入网址:"+url);
-
webElement.sendKeys(url);
-
try {
-
Thread.sleep(
1000);
-
}
catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
webElement=driver.findElement(By.id(
"openurl"));
-
log.info(
"点击打开网页");
-
webElement.click();
-
}
五、设计截图方法
-
public
class ScreenShot {
-
public WebDriver driver;
-
private String screenName;
-
Log
log =
new Log(
this.getClass());
-
public void setscreenName(String screenName)
-
{
-
this.screenName=screenName;
-
}
-
public ScreenShot(WebDriver driver)
-
{
-
this.driver=driver;
-
}
-
private void takeScreenshot(String screenPath) {
-
try{
-
scrFile=((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
-
}
catch (Exception e)
//关键就在于此
-
{
-
//appium 内chrome没法截图,需用原生app下进行截图
-
System.out.println(
"进入到了webview 截图需切换回 NATIVE_APP content");
-
AndroidDriver driver2=((AndroidDriver) driver);
//关键就在于此
-
log.info(
"contextName:"+driver2.getContext());
-
System.out.println(driver2.getContextHandles());
-
// log.info(driver2.getContextHandles().toString());
-
log.info(
"切换到NATIVE_APP进行app截图");
-
driver2.context(
"NATIVE_APP");
-
scrFile=((TakesScreenshot) driver2).getScreenshotAs(OutputType.FILE);
-
log.info(
"切换回微信webviw");
-
driver2.context(
"WEBVIEW_com.tencent.mm:tools");
-
}
-
try {
-
Files.copy(scrFile,
new File(screenPath));
-
log.error(
"错误截图:"+screenPath);
-
}
catch (Exception e) {
-
e.printStackTrace();
-
}
-
}
-
-
public void takeScreenshot() {
-
String screenName =
this.screenName+
".jpg";
-
File dir =
new File(
"test-output\\snapshot");
-
if (!dir.exists())
-
{dir.mkdirs();}
-
String screenPath = dir.getAbsolutePath() +
"\\" + screenName;
-
this.takeScreenshot(screenPath);
-
}
-
-
}
-
到此就完成了微信浏览器入口统一,这里面的坑是AndroidDriver的Contentext方法并没有在Webdriver里定义,而微信截图等很多地方需要切换Contentext才能操作,而要达到入口统一肯定需要通过Webdriver接口作为浏览器的管理;这个坑在网上也没有答案,冥思苦想后终于想出了类型转换的方法,我也是佩服自己能想出接口与实现类之间类型转换的方法。