《软件测试自动化之道》读书笔记 之 底层的Web UI 测试

2014-09-28

测试自动化程序的任务
待测程序
测试程序
  启动IE并连接到这个实例
  如何判断待测web程序完全加载到浏览器
  操纵并检查IE Shell
  操作待测Web页面上的HTML元素的值
  验证Web页面上HTML元素
  示例代码

测试自动化程序的任务

底层技术的核心是,通过直接调用mshtml.dll和shdocvw.dll库来访问并且操纵IE客户区域的HTML对象。

待测程序

新建一个网站“WebAUT”,删除原来的Default.aspx,创建一个新的Default.aspx。在其中添加3个Label控件、2个RadioButton控件、1个TextBox控件、1个Button控件和1个ListBox控件。

图1 Web UAT

待测程序代码:

 using System;
using System.Collections.Generic; using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls; public partial class _Default : System.Web.UI.Page
{
private System.Collections.ArrayList al = new System.Collections.ArrayList();
protected void Page_Load(object sender, EventArgs e)
{
Product p1 = new Product("widgets", "1A11A", 11.11);
Product p2 = new Product("gadgets", "2B22B", 22.22);
Product p3 = new Product("foozles", "3C33C", 33.33); al.Add(p1);
al.Add(p2);
al.Add(p3);
Label3.Text = "Search Complete";
Label3.Visible = false;
}
protected void Button1_Click(object sender, EventArgs e)
{
ListBox1.Items.Clear();
string filter = TextBox1.Text;
ListBox1.Items.Add("ProdName ProdID Price");
ListBox1.Items.Add("====================="); if (RadioButtonList1_1.Checked)
{
foreach (Product p in al)
{
if (p.name.IndexOf(filter) >= )
ListBox1.Items.Add(p.name + ", " + p.id + ", " + p.price);
}
}
else if (RadioButtonList1_2.Checked)
{
foreach (Product p in al)
{
if (p.id.IndexOf(filter) >= )
ListBox1.Items.Add(p.name + ", " + p.id + ", " + p.price);
}
}
Label3.Visible = true;
} public class Product
{
public string name;
public string id;
public double price;
public Product(string name, string id, double price)
{
this.name = name;
this.id = id;
this.price = price;
}
}
}

测试程序

启动IE并连接到这个实例

         static void Main(string[] args)
{
//... SHDocVw.InternetExplorer ie = null;
Console.WriteLine("\nLaunching an instance of IE");
Process p = Process.Start("iexplore.exe", "about:blank");
System.Threading.Thread.Sleep();
if (p == null)
throw new Exception("Could not launch IE");
Console.WriteLine("Process handle = " + p.MainWindowHandle.ToString()); SHDocVw.ShellWindows allBrowsers = new SHDocVw.ShellWindows();
Console.WriteLine("Number active browsers = " + allBrowsers.Count); if (allBrowsers.Count == )
throw new Exception("Cannot find IE"); Console.WriteLine("Attaching to IE");
int i = ; while (i < allBrowsers.Count && ie == null)
{
InternetExplorer e = (InternetExplorer)allBrowsers.Item(i);
if (e != null)
{
if (e.HWND == (int)p.MainWindowHandle)
ie = e;
}
++i;
} if (ie == null)
throw new Exception("Failed to attach to IE"); //...
}

如何判断待测web程序完全加载到浏览器

         static void Main(string[] args)
{
SHDocVw.InternetExplorer ie = null;
//把ie对象连接到IE程序所在的进行 ie.DocumentComplete += new DWebBrowserEvents2_DocumentCompleteEventHandler(ie_DocumentComplete); Console.WriteLine("\nNavigating to the Web app");
object nil = new object();
ie.Navigate("http://localhost:30614/WebAUT/Default.aspx", ref nil, ref nil, ref nil, ref nil); documentComplete.WaitOne(); //...
}
private static void ie_DocumentComplete(object pDisp, ref object URL)
{
documentComplete.Set();
}

测试程序有可能在待测程序尚未完全加载的情况下试图对其进行操作,这么做,很可能引发异常。测试程序可通过事件DocumentComplete和AutoResetEvent类,对自动化程序进行同步。

AutoResetEvent类还有带参数的WaitOne()方法,用于指定最大等待时间,超过就不再等待:

//9000毫秒,true标识可以再等待结束之前推出同步域
documentComplete.WaitOne(,true)

操纵并检查IE Shell

         static void Main(string[] args)
{
SHDocVw.InternetExplorer ie = null;
//把ie对象连接到IE程序所在的进行 Console.WriteLine("Setting IE to size 450x360");
ie.Width = ;
ie.Height = ;
Thread.Sleep(); if (ie.StatusText.IndexOf("Done") == -)
Console.WriteLine("could not find 'Done' in status bar");
else
Console.WriteLine("Find 'Done' in status bar");
//...
}

当编写针对Web UI的自动化测试程序师,需要把IE的3个区域考虑在内:

  • 客户区域,即待测页面所在区域;
  • Shell区域,即诸如地址栏和回退按钮等IE控件所在的区域;
  • 以及其他窗口,比如alert对话框等,这些窗口与IE是分开的。

SHDocVw.InternetExplorer对象提供了一些属性和方法用于操纵(可用来模拟用户操作)和检查Shell(可用来判断某个测试场景通过与否)。下面是几种属性和方法:

  • GoBack(), GoForward(), GoHome(), Refresh(), Quit();
  • Height, Width: 设置IE外壳的高度和宽度(以像素为单位)。
  • Top, Left: 设置IE外壳左上角的位置(以像素为单位)。
  • FullScreen:如果IE在全屏模式下运行,则返回true。
  • MenuBar:如果IE菜单栏可见,则返回true。
  • Resizable:如果可以调整IE的大小,则返回true。
  • LocationURL:返回IE当前显示页面的URL。
  • StatusText:返回IE状态栏的文本。

操作待测Web页面上的HTML元素的值

示例代码:

using mshtml;  // .NET component = Microsoft.mshtml. HTML interfaces
static void Main(string[] args)
{
//...
HTMLDocument theDoc = (HTMLDocument)ie.Document; Console.WriteLine("\nSelecting 'ID' radio button");
HTMLInputElement radioButton = (HTMLInputElement)theDoc.getElementById("RadioButtonList1_2");
radioButton.@checked = true; Console.WriteLine("Setting text box to '2B'");
HTMLInputElement textBox = (HTMLInputElement)theDoc.getElementById("TextBox1");
textBox.value = "2B"; Console.WriteLine("Clicking search button");
HTMLInputElement butt = (HTMLInputElement)theDoc.getElementById("Button1");
butt.click(); documentComplete.WaitOne(); //...
}

在上述代码中,要模拟用户选中radio button控件,必须使用@checked,因为checked是C#语言的一个关键字。

在上述代码中,按钮控件和文本控件的类型都是HTMLInputElement,而下拉空间的类型则是HTMLSelectElement。可通过下面代码知道到底该用哪个类:

HTMLInputElement textBox = (HTMLInputElement)theDoc.getElementById("TextBox1");
Console.WriteLine("The textbox has type" + textBox.GetType().ToString());

注意:因为我们是通过getElementById()方法获得HTML元素/控件的引用的,所以这个控件必须要有ID attribute,从而可以唯一的表示这个控件。若Web页面是由Visual Studio .NET UI设计器创建的,那么所有控件都有一个ID attribute。但是如果Web程序是手工创建(比如通过Notepad),那么最好修改这个程序,给他们加上一个ID attribute。

验证Web页面上HTML元素

通过mshtml.dll库里的getElementByTagName()方法和item()方法得到你想要的特定的元素。然后可以通过InnerText属性取回HTML元素的实际值。

设想某个待测页面含有几个<P>元素,和一个ID为“div2”的<div>元素。下面的代码在<p>元素中查找“aloha”,在<div>元素中查找"adios":

                 Console.WriteLine("Seek 'aloha' in <p>[2]");
Console.WriteLine("<p> type is:" + theDoc.getElementsByTagName("p").GetType().ToString());
HTMLParaElement paraElement = (HTMLParaElement)theDoc.getElementsByTagName("p").item(, null);
if (paraElement.innerText.ToString().IndexOf("aloha") >= )
Console.WriteLine("Found target 'aloha'");
else
Console.WriteLine("Target string not found"); Console.WriteLine("Seek 'adios' in <div id='div2'>");
HTMLDivElement divElement = (HTMLDivElement)theDoc.getElementsByTagName("div").item("div2", null);
if (divElement.innerText.ToString().IndexOf("adios") >= )
Console.WriteLine("Found target 'adios'");
else
Console.WriteLine("Target string not found");

上述代码中,item()方法:

  • 第一个参数可以为整数(整数时为从0开始的索引值)或字符串(字符串时为tag名字);
  • 第二个参数是个索引值,但只有当item()返回得是一个集合时才用得到。

有时候这些元素的值并不属于任何子的HTML元素,可用以下代码解决:

                 // non-HTML element
Console.WriteLine("Seeking 'Search Complete' in body");
HTMLBody body = (HTMLBody)theDoc.getElementsByTagName("body").item(, null);
if (body.createTextRange().findText("Search Complete", , ) == true)
{
Console.WriteLine("Found target string");
}
else
{
Console.WriteLine("*Target string not found*");
pass = false;
}

上述代码中,findText()方法:

  • 第一个参数是必添的目标字符串
  • 第二个参数用于制定查找起始位置
  • 第二个参数用于指定查找类型

示例代码

 // Chapter 7 - Low-Level Web UI Testing
// Example Program: LowLevelUITest using System;
using SHDocVw; // COM component = Microsoft Internet Controls. IE object
using mshtml; // .NET component = Microsoft.mshtml. HTML interfaces
using System.Diagnostics; // Process
using System.Threading; // Sleep() namespace RunTest
{
class Class1
{
static AutoResetEvent documentComplete = new AutoResetEvent(false); [STAThread]
static void Main(string[] args)
{
try
{
Console.WriteLine("\nStarting test run"); bool pass = true; // assume test run will pass SHDocVw.InternetExplorer ie = null;
Console.WriteLine("\nLaunching an instance of IE");
Process p = Process.Start("iexplore.exe", "about:blank");
System.Threading.Thread.Sleep();
if (p == null)
throw new Exception("Could not launch IE");
Console.WriteLine("Process handle = " + p.MainWindowHandle.ToString()); SHDocVw.ShellWindows allBrowsers = new SHDocVw.ShellWindows();
Console.WriteLine("Number active browsers = " + allBrowsers.Count); if (allBrowsers.Count == )
throw new Exception("Cannot find IE"); Console.WriteLine("Attaching to IE");
int i = ; while (i < allBrowsers.Count && ie == null)
{
InternetExplorer e = (InternetExplorer)allBrowsers.Item(i);
if (e != null)
{
if (e.HWND == (int)p.MainWindowHandle)
ie = e;
}
++i;
} if (ie == null)
throw new Exception("Failed to attach to IE"); ie.DocumentComplete += new DWebBrowserEvents2_DocumentCompleteEventHandler(ie_DocumentComplete); Console.WriteLine("\nNavigating to the Web app");
object nil = new object();
ie.Navigate("http://localhost:30614/WebAUT/Default.aspx", ref nil, ref nil, ref nil, ref nil); documentComplete.WaitOne(); Console.WriteLine("Setting IE to size 450x360");
ie.Width = ;
ie.Height = ;
Thread.Sleep(); //if (ie.StatusText.IndexOf("Done") == -1)
// Console.WriteLine("could not find 'Done' in status bar");
//else
// Console.WriteLine("Find 'Done' in status bar"); HTMLDocument theDoc = (HTMLDocument)ie.Document; Console.WriteLine("\nSelecting 'ID' radio button");
HTMLInputElement radioButton = (HTMLInputElement)theDoc.getElementById("RadioButtonList1_2");
radioButton.@checked = true; Console.WriteLine("Setting text box to '2B'");
HTMLInputElement textBox = (HTMLInputElement)theDoc.getElementById("TextBox1");
Console.WriteLine("The textbox has type" + textBox.GetType().ToString());
textBox.value = "2B"; Console.WriteLine("Clicking search button");
HTMLInputElement butt = (HTMLInputElement)theDoc.getElementById("Button1");
butt.click(); documentComplete.WaitOne(); Console.WriteLine("Seek 'aloha' in <p>[2]");
Console.WriteLine("<p> type is:" + theDoc.getElementsByTagName("p").GetType().ToString());
HTMLParaElement paraElement = (HTMLParaElement)theDoc.getElementsByTagName("p").item(, null);
if (paraElement.innerText.ToString().IndexOf("aloha") >= )
Console.WriteLine("Found target 'aloha'");
else
Console.WriteLine("Target string not found"); Console.WriteLine("Seek 'adios' in <div id='div2'>");
HTMLDivElement divElement = (HTMLDivElement)theDoc.getElementsByTagName("div").item("div2", null);
if (divElement.innerText.ToString().IndexOf("adios") >= )
Console.WriteLine("Found target 'adios'");
else
Console.WriteLine("Target string not found"); // non-HTML element
Console.WriteLine("Seeking 'Search Complete' in body");
HTMLBody body = (HTMLBody)theDoc.getElementsByTagName("body").item(, null);
if (body.createTextRange().findText("Search Complete", , ) == true)
{
Console.WriteLine("Found target string");
}
else
{
Console.WriteLine("*Target string not found*");
pass = false;
} if (pass)
Console.WriteLine("\nTest result = Pass\n");
else
Console.WriteLine("\nTest result = *FAIL*\n"); Console.WriteLine("Closing IE in 4 seconds . . . ");
Thread.Sleep();
ie.Quit(); }
catch (Exception ex)
{
Console.WriteLine("Fatal error: " + ex.Message);
Console.ReadLine();
} } // Main() private static void ie_DocumentComplete(object pDisp, ref object URL)
{
documentComplete.Set();
} } // class Class1
} // ns RunTest

《软件测试自动化之道》读书笔记 之 底层的Web UI 测试的更多相关文章

  1. 《软件测试自动化之道》读书笔记 之 基于Windows的UI测试

    <软件测试自动化之道>读书笔记 之 基于Windows的UI测试 2014-09-25 测试自动化程序的任务待测程序测试程序  启动待测程序  获得待测程序主窗体的句柄  获得有名字控件的 ...

  2. 《软件测试自动化之道》读书笔记 之 基于反射的UI测试

    <软件测试自动化之道>读书笔记 之 基于反射的UI测试 2014-09-24 测试自动化程序的任务待测程序测试程序  启动待测程序  设置窗体的属性  获取窗体的属性  设置控件的属性  ...

  3. 《软件测试自动化之道》读书笔记 之 XML测试

    <软件测试自动化之道>读书笔记 之 XML测试 2014-10-07 待测程序测试程序  通过XmlTextReader解析XML  通过XmlDocument解析XML  通过XmlPa ...

  4. 《软件测试自动化之道》读书笔记 之 SQL 存储过程测试

    <软件测试自动化之道>读书笔记 之 SQL 存储过程测试 2014-09-28 待测程序测试程序   创建测试用例以及测试结果存储  执行T-SQL脚本  使用BCP工具导入测试用例数据  ...

  5. 《黑客攻防技术宝典Web实战篇@第2版》读书笔记1:了解Web应用程序

    读书笔记第一部分对应原书的第一章,主要介绍了Web应用程序的发展,功能,安全状况. Web应用程序的发展历程 早期的万维网仅由Web站点构成,只是包含静态文档的信息库,随后人们发明了Web浏览器用来检 ...

  6. 【哲学角度看软件测试】要想软件“一想之美”,UI 测试少不了

    摘要:软件测试的最高层次需求是:UI测试,也就是这个软件"长得好不好看". 为了让读者更好地理解测试,我们从最基础的概念开始介绍.以一个软件的"轮回"为例,下图 ...

  7. <<google软件测试之道>>读书笔记

    以前一直从开发的角度来看待测试,看完这本书以后感觉错了,难怪之前公司的测试一直搭建不起来 1.开发人员,开发测试人员,测试人员 * 开发人员负责开发 * 开发测试人员近距离接触代码,负责编写测试用例, ...

  8. <微软的软件测试之道>读书笔记3

    一.自动化的标准步骤: 1.环境初始化,并检查环境是否处于正确的状态,能否开始测试 2.执行步骤 3.判断结果,并将结果保存到其它地方以供检查分析 4.环境清理,清理本用例产生的垃圾(临时文件.环境变 ...

  9. VC++编程之道读书笔记(2)

    第三篇 技术细节 第七章:细说开发人员必知必会的39个开发细节 细节36:单例模式的应用 在开发程序时,往往需要在整个工程中只需要一个类的实例.而这个实例一旦被创建就不能被其他的实例再创建了,通常我们 ...

随机推荐

  1. python3之Django表单(一)

    1.HTML中的表单 在HTML种,表单是在<form>...</form>种的元素,它允许用户输入文本,选择选项,操作对象等,然后发送这些数据到服务器 表单元素允许用户在表单 ...

  2. JAVA编程:字符串转为数字求和

    程序从命令行接入数字,求和,如果接入的是字符串的解决办法 设计思想: 首先定义一个double类型的一维数组,然后在定义一个double型的变量sum,并赋值为0,用if循环判断从命令行是否有参数输入 ...

  3. Linux运维笔记(一)网络基础知识

    网络基础知识 一.基本概念 1.ARPANET & TCP/IP:以“软件”技术将网络硬件整合,使得不同的计算机或者数据可以通过这个软件达成数据沟通(TCP/IP技术也被称为Internet) ...

  4. 早期(编译器)优化--Java语法糖的味道

    1.泛型与类型擦除 泛型的本质是参数化类型的应用,也就是说所操作的数据类型被指定为一个参数.这种参数类型可以用在类.接口和方法的创建中,分别称为泛型类.泛型接口和泛型方法.在泛型没有出现之前,只能通过 ...

  5. input输入框只能输入数字而且开头不能为零

    <div class="input-choseNum"> <input type="number" id="inp-chooseNu ...

  6. socket的相关知识理解

    http://blog.csdn.net/feiniu55662/article/details/16948639 https://www.baidu.com/baidu?tn=monline_3_d ...

  7. Oracle 11g透明网关连接Sqlserver 2000(转)

    Oracle 11g透明网关连接Sqlserver 2000: http://www.cnblogs.com/lightnear/archive/2013/02/03/2890858.html 透明网 ...

  8. java引用类型简述

    主要内容: 1.引用类型简述 2.对象的可达性 3.软引用的垃圾回收分析 4.WeakHashMap分析 5.ThreadLocal内存泄漏分析 1.引用类型简述 在Java语言中除了基本数据类型外, ...

  9. AngularJS中转换响应内容

    从远程API获取到的响应内容,通常是json格式的,有时候需要对获取到的内容进行转换,比如去除某些不需要的字段,给字段取别名,等等. 本篇就来体验在AngualrJS中如何实现. 在主页面,还是从co ...

  10. 解决Cordova开发的iOS的app界面被状态栏覆盖

    解决方法如下: 一:在MainViewController.m中添加如下代码: -(void)viewWillDisappear:(BOOL)animated { if([[[UIDevice cur ...