本文是本人正在准备的《Selenium Webdriver 从零开始到放弃》一文中的一个章节,主要用于收集在测试过程中遇到的各种比较奇葩的问题,分享给大家。一方面自己做个总结,另一方面如果有人遇到同样的问题可以做个参考。本章节的内容会持续更新,其他章节的内容在写完后也会陆续发布在这里,让大家先睹为快,共同学习和提高。
话说最近在做自动化测试项目的时候,遇到一个比较奇葩的问题,比较棘手,刚开始拿到几乎毫无头绪。最后终于在不断的尝试过程中将其解决。而且该类问题在网上几乎找不到可供参考的完整文章,有人曾经问过类似的问题(http://bbs.csdn.net/topics/390528583),但看答案基本没有靠谱的。所以特总结于此,与各位进行分享。
那么这究竟是个什么样的问题呢?其实是这样,在登录我司内部web测试网站时,输入网址之后,由于是测试服务器,运维人员在服务器上做了权限验证,所以每次打开新的浏览器实例,系统都会首先要求你输入有效的用户名和密码进行验证。如果验证不通过,则根本无法进入系统。这个机制非常像我们平时在登陆自家路由器控制台时的验证机制,必须先输入正确的用户名和密码,否则不让登陆,界面根本就无法显示。如下图所示:
点击“取消”之后,页面是这样的:
有些朋友看到这个界面,可能会觉得很简单,平时见过太多用户名密码验证框了,这个不是很easy吗?呵呵,最开始我见到它的时候也这样想,但随后的操作立马就让我感觉“一脸懵逼”啊。
这里有什么坑呢?首先第一个坑就是,你会发现这个框、包括这个页面完全没有办法使用“右键”来“查看”对象属性!也就意味着你根本没有办法知道它内部的任何对象属性,也就没有办法用webdriver来对它进行任何操作了。所以,首先可以放弃直接使用webdriver来输入用户名和密码,并点击“确定”按钮的想法。
此路不通,还有别路可走么?由于此界面确实非常简单,webdriver操作不了,那用其他辅助工具能操作吗?我首先想到的是sikuli。sikuli作为一个以图像对比作为基础的测试工具,可以直接解决对象属性拿不到的问题,而且该页面是静态页面,元素并不复杂,所以图片对比也没有什么问题,貌似该办法可行。
基本想好思路后,立马就开始到官网下载sikuli的IDE和webdriver调用时sikuli会用到的相关jar包,配好环境后,就可以开始动手试验了。说到配置sikuli环境,我不得不吐槽两句,太麻烦了,官网自带bug不说,而且目前的版本做得非常烂(根本不像麻省的水准 啊)。都什么年代了还只支持jdk1.6 32位版本(1.7及以上的版本或64位jdk版本均不支持,一个大写的“雷”啊!)待会最后再总结一下sikuli在windows 7 环境中的配置过程。
环境配置好后,在IDE中把selenium工程建好,加入sikuli相关的jar包,就可以开始写脚本了。最开始我写的脚本如下:
package selenium.sikuli.demo
import ...
public class LoginPage {
public static void main(String[] args) throws InterruptedException, FindFailed{
System.setProperty("webdriver.firefox.bin", "C:\\Program Files\\Mozilla Firefox\\firefox.exe");
WebDriver driver = new FirefoxDriver();
//打开路由器管理控制台地址
driver.get("http://192.168.1.1");
//sikuli对比时用的图片路径,我是放工程目录下的pic文件夹的
String imgPath = "pic/";
Screen screen = new Screen();
//依次输入用户名、密码,再点击确定按钮,进行登录
screen.type(imgpath + "username.png", "admin");
screen.type(imgpath + "password.png", "admin");
screen.click(imgpath + "login.png");
System.out.println("操作结束");
//driver.quit();
}
}
好了,吭哧吭哧敲完,点击运行。结果firefox启动后,路由器控制台界面顺利打开,弹出用户名和密码输入框。。。。纳尼????我足足等待了五分钟,用户名和密码一个字母都没有输入进去,准确的说是“毫无动静”,关键还不报错!!!!控制台console中也没有任何信息输出。只有当我手动点击弹出框的取消按钮后,才开始在控制台输出sikuli的运行日志,说明此时sikuli在正常运行。但由于提示框已经被我点击取消按钮并消失了,所以自然就会抛出findfailed这个异常了。这TM简直是哔了dog了!!一股沮丧的心情油然而生,忙活了半天居然不起作用??kao,我不服!再继续想办法。
接下来,仔细分析原因。在确保环境方面没有任何问题之后,开始分析代码。这里有个现象非常奇怪,为什么每次都是一弹出输入框脚本就没有反应了,并且每次都要我手动点击取消按钮后,sikuli运行日志才输出出来表明它在运行呢?在左思右想之后,我终于想到了问题所在。原来这个页面除了根本无法识别对象这个坑之外,还有一个“巨坑”是,这个弹出的输入框是个系统级的标准模态输入框,在你没有输入正确的值的时候,它会完全block住后面的所有操作,也就意味着,在执行完driver.get(“http://192.168.1.1”)之后,webdriver脚本就完全停止下来了,后面的语句根本就没法执行,除非这个模态输入框消失。这也就解释了刚刚说的那个非常奇怪的现象。
原因找到了,接下来就是想解决办法了。要解决这个问题,必须做到两点:
问题和解决办法都想到了,其实脚本就相对比较好写了。毫无疑问,这里必须用到多线程了,而且运行sikuli这个线程必须先于driver.get()方法启动。但由于这样sikuli和webdriver就运行在不同的线程中,所以其实sikuli并不知道driver什么时候开了页面,所以这里只能先做一下线程等待,具体的等待时间大家可以根据待测页面的实际情况来决定。核心代码如下:
public class LoginPage {
public static void main(String[] args) throws InterruptedException, FindFailed{
System.setProperty("webdriver.firefox.bin", "C:\\Program Files\\Mozilla Firefox\\firefox.exe");
WebDriver driver = new FirefoxDriver();
//启动sikuli线程
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
Screen screen = new Screen();
String imgpath = "pic/";
try {
screen.type(imgpath + "username.png", "admin" );
screen.type(imgpath + "password.png", "admin");
screen.click(imgpath + "login.png");
} catch (FindFailed e) {
e.printStackTrace();
}
}
});
t.start();
//主线程中继续跑webdriver的业务
driver.get("http://192.168.1.1");
}
}
写完之后,点击运行,这个时候再来观察。哈哈,我们想要的值终于被输入到对应的文本框中,并顺利用脚本完成了登录过程,问题终于解决了。
最后再总结一下,本文中所涉及这个问题,主要有两个“坑”点:
好了,这个问题也算是一个疑难杂症了,好歹化了几个小时时间最终还是顺利解决,希望能对大家有所帮助和启发。
文章最后,再简单记录下sikuli的环境配置过程:(详细过程如果有朋友不太清楚的话,请参考网上其他专门讲述该配置的文章)