自己动手写Web自动化测试框架

记得几年前一本《自己动手写操作系统》在全国的技术范围内引起了学习操作系统的热潮。我不才在这里使用这本书的大名,来分享一下我在写Web自动化测试框架上面的一些经验。 首先定义一下Web自动化测试框架:Web自动化测试框架是一个类库,他可以帮助测试人员快速写出Web自动化测试代码,并帮助测试人员在自动化报错的时候快速找到Bug。

目前市场上成熟的Web自动化测试框架有不少,很出名的是Watir,是用现在大名鼎鼎的Ruby写成的,相对于Watir,有一个也很不错的.net版本,就是WatiN,WatiN可以说是市面上可以找到的最好的C# Web自动化测试框架。微软和其他的大公司也有自己的一些Web自动化测试框架,但是公布的并不多。

我这里将会使用C#,一步一步的写出一个最简单不过的自动化测试框架。这个框架的功能是基本可以测试简单的没有Ajax,没有框架,没有Windows对话框的一些网页。而如何测试Ajax之类的网页,我将会在其他的专题中写出。

首先我们看使用的非托管的类库。我们在这里将会使用两个非托管类库:mshtml.dll和Interop.SHDocVw.dll。 mshtml是微软IE的核心类库,下面是Wiki百科的解释

Trident (also known as MSHTML) is the name of the layout engine for the Microsoft Windows version of Internet Explorer. It was first introduced with the release of Internet Explorer version 4 in October 1997, has been steadily upgraded and remains in use today. For version 7 of Internet Explorer, Microsoft made significant changes to the Trident layout engine to improve compliance with web standards and add support for new technologies.

开发人员可以通过mshtml提供的接口,访问到IE布局对象,从而达到对Web的控制和检查。

另一个类库Interop.SHDocVw.dll则提供了一个InternetExploer的接口,可以帮助我们操纵IE进程,并且进行一些简单的如前进,后退等操作。

这两个类库如果装了VS2005都可以找到。mshtml是IE自带的,在项目中选择添加引用,然后在.net标签下面找到Microsoft.mshtml就可以找到了。而Interop.SHDocVw要复杂一点,添加引用中,选择浏览标签,然后在下面的路径就可以找到:C:\Program Files\Microsoft Visual Studio 8\Application\PreEmptive Solutions\Dotfuscator Community Edition

这一个部分我们来讲用SHDocVw对IE进行操作。

接下来的几篇文章我们都会以Console Application来向大家介绍Web自动化的一些基础。

以下的代码在VS2005上通过测试,相信在VS2005 express已经VS2008上也可以通过,不过在VS2003上可能要稍微修改。使用vs2003的朋友,建议大家使用VS2005 express。

浏览器使用了IE7。 IE6以及更低版本并没有做过试验。

首先我们打开VS2005,建立一个Console Application项目:

自己动手写Web自动化测试框架_第1张图片

新建一个命令行工程

接下来我们需要包含两个引用了,就是mshtml和SHDocVw。

自己动手写Web自动化测试框架_第2张图片

包含mshtml引用

第二个SHDocVw一定要在下面这个路径找:(C:\Program Files\Microsoft Visual Studio 8\Application\PreEmptive Solutions\Dotfuscator Community Edition)

自己动手写Web自动化测试框架_第3张图片

包含SHDocVw

包含两个类库之后,我们就可以使用C#来对IE进行一些基本的操作了。

我们要添加几个命名空间,来简化我们下面的代码:

using System.Diagnostics; //要用到进程来启动IE窗口

using System.Threading; //使用Thread.Sleep来等待

using SHDocVw;

using mshtml;

除了mshtml和SHDocVw之外,我们还使用了其他的两个命名空间,因为我们要使用System.Diagnostics.Process类启动IE进程,并且获取IE的进程信息,使用System.Threading.Thread的sleep()方法等待

接下来,我们就可以写入代码了:

Console.WriteLine("Launching IE ...");

Process p = Process.Start("iexplore.exe","about:blank");

Thread.Sleep(3000);

第一步,我们要打开IE进程,这里使用了Process的Start静态方法生成一个进程。很好理解,传入了两个参数,一个是IE的exe文件名,也可以写入完整地址;第二个参数是IE自己的参数,表示要打开的链接地址,我们在这里使用一个空白页面。

接下来的事情就是等待,等待IE进程启动,这里为了让大家更快的抓到本质,没有使用很复杂的等待代码,只是很机械的等待了3秒钟,大家可以根据自己机器的状况进行修改。

这里为了让大家可以更好的理解,我插一点Process的讲解,如果大家对上面的Process打开没有任何问题的话,直接跳过往下就好了。这里Process.Start()方法其实有4个重载,我们使用了第三个重载函数,也就是第一个输入文件名,第二个输入参数,我们可以在运行命令行中打"iexplore about:blank"直接打开一个空的IE窗口,也可以打"iexplorehttp://www.colblog.net/"直接打开一个浏览到目标网站的IE窗口

IE启动了,我们接下来的事情就是把IE附加给SHDocVw.InternetExlporer以便我们可以进行接下来的操作。

上面的两次课程我们介绍了mshtml和SHDocVw的一些用途,以及如何打开并且附加到IE上,实现IE的宏观上的控制。

这次我们将会用代码找到我们想要的控件,然后对控件进行一些操作。

首先我们引入一个很好的IE控件:Internet Explorer Developer Toolbar,这个控件可以帮助我们方便的找到我们想要的控件的属性。

安装好这个控件之后,我们就可以方便的找到每一个控件的ID,或者其他属性了,如下图

自己动手写Web自动化测试框架_第4张图片

IE Developer

注意,打开IE Developer Toolbar之后,要点选下面的鼠标按钮,才可以用鼠标来选择我们想要的控件。有了这个控件,我们就不用去查看源文件来找到我们想要的信息了。其他的功能这里不多说了。

接下来我们以百度的三个控件为例,分别告诉大家如何使用ID得到TextBox,如何点击使用ID得到的Button,如何使用子控件缩小范围的方法得到一个HyperLink。

首先我们修改上次的代码,把IE指到百度去:

Console.WriteLine("Navigating ...");

object o = null;

ie.Navigate("baidu.com", ref o, ref o, ref o, ref o);

Thread.Sleep(2000)

打开和操纵IE都讲解过了。只有一点,我们在完成IE的跳转之后,等待了2秒钟的时间,原因是IE的工作是需要时间的,我们在后面的测试框架部分会讲解如何判断IE已经完成了页面的跳转,在这里为了让大家更好的了解我们本节的主题,只是用了简单的等待。

然后我们用IE Developer Tools得到了关键字文本框的ID是kw,所以我们用下面的代码在关键字文本框里面输入了我们想要的关键字:

//得到一个Text Box

Console.WriteLine("Inputing Keyword ...");

HTMLDocument doc = (HTMLDocument)ie.Document;

HTMLInputElement keyword = (HTMLInputElement)doc.getElementById("kw");

keyword.value = "colblog.net";

Thread.Sleep(1000);

首先我们用ie.Document对象得到了HTMLDocument。目的没什么可说的,因为我们需要HTMLDocument得到下面的控件。而这里之所以使用强制类型转换,是因为Document对象在这里返回一个object的引用,但其实是一个HTMLDocument的实例。所以转换一下就好了,在mshtml里面,这种情况还不少,在msdn上有详细的讲解,使用的时候查一下就好了。

然后使用HTMLDocument.getElementById方法,直接从Document里面按照ID取出想要的控件,返回一个 IHTMLElement,IHTMLElement是HTMLElement的抽象,所有的HTML的tag都可以是一个IHTMLElement,返回这样的一个引用,我们在知道将会返回什么类型的情况下,可以使用强制类型转换来把对象转成我们想要的引用。就像上面我们所做的,返回的其实是一个 Input tag,所以我们要把他转换成HTMLInputElement就好了。

下面一句我们直接对这个对象的value进行设置,就可以完成在关键词文本框里面输入我们想要的关键词的动作。

接下来我们要点击搜索按钮:

有了上面文本框的解释,这一段代码就容易多了吧。这里不在赘述。

聪明的读者一定会问:我们现在使用ID查询控件,如果我们的控件没有ID怎么办?如果ID是重复的怎么办?

上面的两种情况都是完全可能的,而且在实际中几乎占据了大部分的情况。(不过ASP.NET里面的控件倒是都有ID,使用这种方法比较方便。)我们下面的例子就是去点击百度首页右上角的登录超级链接。

首先我们分析一下,登录超级链接是放在一个id为u的div里面,而登录超级链接是没有ID的。我们的思路就是先找到这个id为u的div,然后找他的chidren找到我们想要的这个超级链接,下面是源代码:

//得到一个链接

Console.WriteLine("Clicking Login Button ...");

IHTMLElement userPanel = doc.getElementById("u");

IHTMLElementCollection HyperLinks = ((IHTMLElement2)userPanel).getElementsByTagName("a");

IHTMLElement login = (IHTMLElement)HyperLinks.item(null, 0);

login.click();

首先我们得到了那个id为u的div,命名为userPanel。这一步和上面没啥区别。

下面一个语句我们得到了userPanel的控件的所有tag为a的控件,也就是所有的超级链接。这里有一个小小的需要注意的地方,我们看到这个语句吧IHTMLElement对象强制类型转换成了IHTMLElement2,很有意思,为啥会这样呢?其实IHTMLElement有4个这样的兄弟,他们之间的方法不同,可以互相转换,我们想要的getElementsByTagName在IHTMLElement2下面,所以我们就强制类型转换到IHTMLElement2。这个方法返回一个IHTMLCollection。我们用HyperLinks来储存这个引用。

因为userPanel的子控件只有登录超级链接这一个,所以我们直接使用index为0来取道这个对象就好了。IHTMLElementCollection里面的item方法详见msdn,我们只需要把第二个index设置为0,就可以取到第一个子对象。

上次我们讲到了如何控制Web控件,有了上次的基础,我们这一次的东西就会比较简单:如何验证Web控。

我们知道我们测试的目的就是判断被测产品是不是符合要求,如果是手动的测试,就是点到我们要判断的地方,然后用眼睛去判断出现的东西是不是我们想要的。

而自动化就稍微复杂一点。我们需要解决两大问题:一个是操纵电脑去点击,另一个就是去检查是不是我们想要的结果。我们前面的文章可以解决操纵浏览器进行浏览,而接下来我们讲的就是如何判断是否正确了。

不考虑性能测试的话,检查点无非有这么几个:

* 内容是否正确

* 样式是否正确

下面我们以实际代码来讲解如何判断。

首先判断一下样式,我们接着上次的代码,判断一下百度首页的文本框的大小是不是我们想要的(这个代码接着上次的得到keyword控件之后,Submit之前):

//验证

if (keyword.getAttribute("size", 0).ToString().Equals("36"))

Console.WriteLine("Validation Passed! Size is Correct");

else

Console.WriteLine("Validation Failed! Size is wrong");

我们可以看到IHTMLElement有getAttribute方法,这个方法可以得到一个Element里面的Attribute,比如value,type,以及css样式之类的,都可以用这个方法得到,见msdn对这个方法的更详细的讲解。

我们用下面的代码对百度的搜索结果的内容和标题进行判断:

//验证

if(string.Equals(doc.title.Trim(),"百度搜索_colblog.net"))

Console.WriteLine("Validation Passed! Title is Corrected");

else

Console.WriteLine("Validation Failed! Title is wrong");

if (doc.body.innerText.Contains("生生不息"))

Console.WriteLine("Validation Passed! Body contains your string");

else

Console.WriteLine("Validation Failed! Body do not contain");

IE的标题就直接用HtmlDocument的title属性就好,而判断字符就是用到了IHTMLElement的innerText属性,这个属性是我们很常用的属性之一,他会将该Element中显示在IE的字符串返回给我们,另一个相对应的属性就是InnerHtml属性,这个属性会把这个 Element里的所有html代码返回。

比如说一个简单的Dropdownlist,用InnerText就会返回这个List里面每一项的text,而使用InnerHtml就会返回这个list里面的html代码

在这里我们使用innerText来判断是否有我们想要的文字在里面。

NoticeNotice

注意:innerText和innerHtml属性,是IHTMLELement的属性,所以我们得到的每一个IHTMLElement都可以拿到这样的属性,并不是只有body才可以。这样我们以后就可以用前面的知识得到想要的IHTMLElement元素,然后再使用InnerHtml和 InnerText来判断内容。

除了这两个,还有outerHtml和outerText可以使用。

这次的内容比较简单。下一篇将会提到如何判断IE是否完成了页面读取的问题。

上面的几次课程中,我们介绍了如何打开浏览器,如何获取每个web控件的信息,并且控制并验证他们。

从上面的文章中,我相信大家已经可以写出简单的测试程序了。但是还有一个很重要的问题没有解决:如何判断浏览器是否加载完成?

前面的文章我们没有对浏览器的加载进行判断,而只是简简单单的等一段时间,这不是一个很好的解决方法,一方面浪费了时间,另一方面,我们也无法知道应该等多久,导致我们的测试程序不够稳定。

接下来我们假设被测网页没有Ajax和框架,以这种情况来分析如何判断网页加载完毕。

现在比较常用判断是否加载的方法有三种:

1. 不停判断IE的状态,如果没有准备好就等待。

2. 实现IE的DocumentComplete事件,标志完成。

3. 不停去查找页面有没有我们想要控件,没有就等待。

第一种方法:不停判断IE的状态,我们要判断IE的哪些状态呢?

一方面,我们需要判断IE的Busy状态,看IE是不是在忙着解析东西,另一方面判断IE的ReadyState状态,看html文档是不是被完全加载进来

while (ie.Busy || ie.ReadyState != tagREADYSTATE.READYSTATE_COMPLETE)

{

Thread.Sleep(100);

}

用如上的代码就可以等待IE到完成。

这里只是简简单单的Demo,所以用了很简单的预计进行判断,我们假设我们的网页没有Ajax,也不会出现Load的死锁,真正的实际工作要比这个复杂一些,比如要定一个Time out,如果除了Timeout的范围,就强行终止,以防止测试过程中的死锁。

而如何判断Ajax是否被加载完,不是我们这个系列的讨论范围,请关注以后的其他系列文章。

这种方法是我比较推荐的一种方法,虽然《.net软件测试自动化之道》推荐的是第二种方法,不过我经过实际的测试,推荐第一种方法。这个方法可以比较好的处理Navigate、Submit等情况,也是WatiN使用的方法(WatiN的用法要复杂很多,考虑到了Frame等其他情况)第二种方法:通过绑定DocumentComplete,用AutoResetEvent来等待。

InternetExplorer给我们提供了DocumentComplete事件,会在IE被Load之后被调用,我们可以使用这个来等待。等待方法就是使用System.Threading.AutoResetEvent对象来。

所以我们需要做的是:

1. 声明一个AutoResetEvent对象的实例,因为要在两个方法直接调用,所以需要放到类的成员变量。

2. 在InternatExplorer被获取之后,绑定DocumentComplete事件。

3. 在DocumentComplete事件中,调用AutoResetEvent.set()方法。

4. 在等待页面加载的时候调用AutoResetEvent.WaitOne()方法

你可能感兴趣的:(软件测试技术)