目前团队使用的自动化测试框架是robotframework+webdriver(IE)+python,据说是从趋势那边搬过来的。webdriver里面,IEdriver是运行最慢的,因此每次跑一遍用例都要花上4个小时,这个如果在工作日跑的话,半天工作时间就没了,如果在下班后跑,发现问题又不能及时调试,很烦……
Java里的webdriver有个好东西是htmlunit,这个在python版的webdriver里却没有,应该跟htmlunit纯用java写的有关。htmlunit跑用例可以不打开浏览器在后台跑,因此在webdriver里面是最快的。python里面虽然没有htmlnuit,但是有个第三方库是Jpype,可以通过模拟java虚拟机直接调用jar包!因此我的想法是用java写个接口把htmlunit常用方法再封装下,然后用python通过jpype来调用接口。
package htunit; import java.util.concurrent.TimeUnit; import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.Keys; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.htmlunit.HtmlUnitDriver; import org.openqa.selenium.ie.InternetExplorerDriver; import org.openqa.selenium.remote.DesiredCapabilities; import com.thoughtworks.selenium.DefaultSelenium; public class htunit { WebDriver driver; public htunit(){ DesiredCapabilities htmlunitcapabilities=DesiredCapabilities.htmlUnit(); htmlunitcapabilities.setJavascriptEnabled(true); htmlunitcapabilities.setCapability(HtmlUnitDriver.INVALIDSELECTIONERROR, false); htmlunitcapabilities.setCapability(HtmlUnitDriver.INVALIDXPATHERROR, false); //driver=new InternetExplorerDriver(); driver=new HtmlUnitDriver(htmlunitcapabilities); driver.manage().timeouts().pageLoadTimeout(10, TimeUnit.SECONDS); driver.manage().timeouts().setScriptTimeout(5, TimeUnit.SECONDS); driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); //driver.setJavascriptEnabled(true); } public void deletecookie() throws Exception{ driver.manage().deleteAllCookies(); } public String getpage(){ return driver.getPageSource(); } public String gettitle(){ return driver.getTitle(); } public void get(String url){ driver.get(url); } public void SetInputTextById(String Id,String value) throws Exception{ driver.findElement(By.id(Id)).clear(); driver.findElement(By.id(Id)).sendKeys(value); } public void SetInputTextByName(String name,String value) throws Exception{ driver.findElement(By.name(name)).clear(); driver.findElement(By.name(name)).sendKeys(value); } public void SetInputTextByXpathWithoutClear(String xpath,String value) throws Exception{ driver.findElement(By.xpath(xpath)).sendKeys(value); } public void SetInputTextByXpath(String xpath,String value) throws Exception{ driver.findElement(By.xpath(xpath)).clear(); driver.findElement(By.xpath(xpath)).sendKeys(value); } public void ClickButtonByXpath(String CSS) throws Exception{ driver.findElement(By.xpath(CSS)).click(); //sleep short time in python } public void ClickById(String Id) throws Exception{ driver.findElement(By.id(Id)).click(); } public void ClickByName(String name) throws Exception{ driver.findElement(By.name(name)).click(); } public void ClickByXpath(String xpath) throws Exception{ driver.findElement(By.xpath(xpath)).click(); } public void DoubleClickByXpath(String xpath) throws Exception{ driver.findElement(By.xpath(xpath)).click(); } public void SelectFrame(String frame) throws Exception{ driver.switchTo().frame(frame); //driver.switchTo().window(frame); //return frame; } public void ClickMsgBox() throws Exception{ driver.switchTo().activeElement().sendKeys(Keys.RETURN); } //problem public void SelectComboxById(String Id,int dts) throws Exception{ ClickById(Id); WebElement a=driver.switchTo().activeElement(); while (dts!=0){ a.sendKeys(Keys.DOWN); dts--; } a.sendKeys(Keys.RETURN); } public void SwitchToActiveFrame() throws Exception{ driver.switchTo().defaultContent(); } public void SelectComboxByXpath(String xpath,int dts) throws Exception{ ClickByXpath(xpath); WebElement a=driver.switchTo().activeElement(); while (dts!=0){ a.sendKeys(Keys.DOWN); dts--; } a.sendKeys(Keys.RETURN); } public void UIIsElementPresent(String locator) throws Exception{ int a=103; } public void UIVerifyTextByXpath(String xpath,String val) throws Exception{ } public String UIGetTextByXpath(String xpath) throws Exception{ return driver.findElement(By.xpath(xpath)).getText(); } public boolean UIVerifyTextByJsId(String Id,String val) throws Exception{ JavascriptExecutor js=(JavascriptExecutor)driver; String tx=js.executeScript("return document.getElementById('"+ Id+ "').value").toString(); //question boolean re=tx.contains(val); return re; } public boolean UIVerifyValueByJsIdIsPositive(String Id) throws Exception{ JavascriptExecutor js=(JavascriptExecutor)driver; String tx=js.executeScript("return document.getElementById('"+ Id+ "').value").toString(); if (Integer.parseInt(tx)>0) return true; else return false; } public void SelectDateByName(String name, String sdate) throws Exception{ } public void SelectDateById(String Id, String sdate) throws Exception{ } public void SelectDate(String element,String sdate) throws Exception{ } public void AddContactInfo(String Id,String phone,String address) throws Exception{ ClickById(Id); driver.switchTo().activeElement(); ClickById("btnAdd.ContactInfoWin"); SetInputTextById("phoneNo.ContactInfoModifyWin", phone); SetInputTextById("custAddr.ContactInfoModifyWin", address); ClickById("btnSave.ContactInfoModifyWin"); ClickById("btnSave.ContactInfoWin"); ClickMsgBox(); } public void AddEventInfo(String Xpath,String btnId, String Id1,int Id2,int Id3,String name1,String name2) throws Exception{ ClickByXpath(Xpath); ClickById(btnId); SetInputTextById("eventTitle.EventDetail", Id1); SelectComboxById("alertType.EventDetail", Id2); SelectDateByName("alertStrDate", name1); SetInputTextByName("alertStrTime", name2); driver.switchTo().activeElement().sendKeys(Keys.RETURN); SelectComboxById("fowardTime.EventDetail", Id3); ClickById("save.EventDetail"); ClickMsgBox(); } public int switch_to_active_element(int cmd) throws Exception{ if(cmd==1){ driver.switchTo().activeElement().sendKeys(Keys.DOWN); return 1;} else if(cmd==2){ driver.switchTo().activeElement().sendKeys(Keys.RIGHT); //driver.switchTo().activeElement().sendKeys(Keys.RETURN); return 2;} else if(cmd==3){ driver.switchTo().activeElement().sendKeys(Keys.RETURN); return 3;} return 4; } public void switch_to_default_content() throws Exception{ driver.switchTo().defaultContent(); //driver.switchTo(). } public void waitfor(String xpath) throws Exception{ } public String getsource() throws Exception{ return driver.getPageSource(); } }
由于后来其他原因失败了,导致这边只封装了最基本的接口。这里拿网易邮箱来做测试,python代码:
#coding=utf8 import jpype import time import os.path start=time.time() jarpath=os.path.join(os.path.abspath('.'),'E:/lib') print jarpath jvmPath=jpype.getDefaultJVMPath() jpype.startJVM(jvmPath,"-Djava.ext.dirs=%s"%jarpath) jpype.java.lang.System.out.println("hello world!") javaclass=jpype.JClass("htunit.htunit") temp=javaclass() temp.deletecookie() url='http://mail.163.com' username='****' pwd='****' id='loginBtn' temp.get(url) temp.SetInputTextById("idInput", username) temp.SetInputTextById("pwdInput", pwd) temp.ClickById(id) print time.time()-start
上面java代码中如果24行不注释,注释25行则会调用IE接口。下面是在我机器上跑的时间对比:
结果是htmlunit壮烈牺牲了,java报了一个跟证书有关的错,这个应该跟网易邮箱有安全认证有关……因此只能在按提交前把时间打印出来了下,大概是IEdriver的三分之一,如果有应用的地方,确实很快啊!
我是把java所有htmlunit的jar包都拖到E:\lib下面,并且把导出的jar包也放到E:\lib下面,要不然jpype会找不到的。另外这种情况下使用htmlunit的时候浏览器不要设代理,否则也会报错,当然htmlunit本身是可以设代理的,我没研究。
最后之所以不在项目中应用主要是因为团队项目对js依赖很大,而这个是htmlunit最大的软肋………