WinRunner

更新时间:2023-03-08 18:16:31 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

用WinRunner实现软件的全球化测试

作者:月白(笔名)

甲骨文软件研究开发中心(北京)有限公司

北京市海淀区中关村软件园孵化器2号楼A座一层 邮编:100094 移动电话:13651010781,邮件:tina.wang@oracle.com

摘要

本文采用循序渐进的方法详细的介绍了如何用WinRunner实现软件的全球化测试。当然,单靠WinRunner本身是无法完全实现的,我们开发了一个小程序COFAL来帮助WinRunner实现全球化测试。通过学习这篇文章,您可以掌握: ● WinRunner的在全球化测试中的缺陷 ● WinRunner本身可用于全球化测试的地方 ● COFAL如何帮助WinRunner实现全球化测试 ● COFAL的实现细节

关键字

Globalization(g11n),Internationalization(i18n),localization(l10n),Code Once Fit All Language(COFAL)

1. 背景

全球化已经成为当今软件发展的趋势,许多大型跨国软件公司都在亚洲设立了自己的专门从事全球化测试的部门。2004年的8月,我加入Oracle甲骨文北京研发中心,正式成为这其中的一员,我测试的软件是Oracle Application Server 10g,以下简称Oracle AS。Oracle AS是一个基于J2EE架构的应用系统,详细的介绍您可以参考OTN上的相关文档。

1.1 全球化中的概念

全球化的英文是Globalization,由于单词较长,所以为了书写方便,通常缩写为G11N,

中间的11代表首字母”G”和尾字母”N”之间省略的11个字母。

引用”中国本地化”网站上对全球化的定义:Globalization是使产品或软件进入全球市场而进行的有关的商务活动。包括正确的国际化设计,本地化集成,以及在全球市场进行的市场推广、销售和支持的全部过程。

全球化中与我们测试直接相关的有国际化设计和本地化集成。

国际化的英文是internationlization,由于单词较长,通常缩写为I18N,中间的

18代表首字母”I”和尾字母”N”之间省略的18个字母。引用”中国本地化”网站上的定义:国际化设计是指设计一个适用于多种语言和地区的应用程序的过程。适用于多种语言和地区

1

的含义是当使用不同语言及处于不同的地区的用户在使用这个应用程序时,应用程序必须使用他们能看懂的语言和符合他们文化习惯来显示信息。

本地化的英文是localization,由于单词较长,通常缩写为L10N,中间的10代表首字

母”L”和尾字母”N”之间生罗的10个字母。引用”中国本地化”网站上的定义:本地化是指将产品或软件针对特定国际语言和文化进行加工,使之符合特定区域市场的过程。真正的本地化要考虑目标区域市场的语言、文化、习俗和特性。通常包括改变软件的书写系统(输入法)、键盘使用、字体、日期、时间和货币格式等。

Locale表示表示一个特定的地理、政治或文化的区域,在java中有Locale类,我们会在1.3小节中给出详细的描述

1.2 全球化测试的内容

简单的说,全球化测试主要是测试软件的处理数据和显示数据的功能。以Oracle AS为例: ● 处理不同的字符集(encoding)数据

Oracle Internet Directory(简称OID)是一个LDAP服务器,数据保存在Oracle数据库中,现在想测试它创建用户的功能,要求用户的DN可以为不同国家的字符集,通俗的说,可以创建英文的DN,简体中文的DN和日文的DN等。当然具体可以创建哪些字符集的DN也要看当前Oracle数据库的字符集,只是那些在可以和当前字符集正确转换的字符集中的DN才可以正确的创建,否则很有可能无法创建或者创建的结果错误,如我们经常会看到的一些数据变成了问号(?)。 ● 动态显示与Locale有关的数据

Oracle Delegated Administration Services(简称DAS)是一个通过web页面访问的组件,页面的编码方式为UTF8,要求当选择不同的浏览器语言时,以下各项都可以显示为与当前Locale相符的形式:

☆ 页上元素的文本类型的属性

如某个页的标题,在英文下为“Home”,在中文下为“主页”;某个按钮上的标签,在英文下为“OK”,在中文下为“确定”。 ☆ 表示日期、时间、时区和货币等的文字

如某个页上的一段表示出生日期的文字,在英文下显示为“January 1, 1976”,在中文下显示为“1976年1月1日”。

1.3 Java程序的国际化设计

Java语言是平台无关的,它采用双字节字符编码(UTF16),在解决国际化问题上有天生的优势。下面我要介绍的是Java中“动态显示与Locale有关的数据”的原理。

这里要用到的几个主要类都在java.util包(package)中,包括有Locale、ResourceBundle、ListResourceBundle、PropertyResourceBundle等,其继承关系如下图所示:

2

● Locale

该类包含对主要地理区域的地域化特征的封装。通过设定Locale,我们可以为特定的国家或地区提供符合当地文化习惯的字体、符号、图标和表达格式。例如,我们可以通过获得特定Locale下的Calendar类的实例,显示符合特定表达格式的日期。Locale有以下三个构造函数:

☆ Locale(String language)

☆ Locale(String language,String country)

☆ Locale(String language,String country,String variant)

language参数:代表两个小写英文字符的ISO语言编码,如zh表示Chinese,可用的语言编码可以参考:

http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt

country参数:代表两个大写英文字符的ISO国家或地区编码,如,CN表示China,TW表示TAIWAN,国家代码对照表如下:

http://userpage.chemie.fu-berlin.de/diverse/doc/ISO_3166.html variant参数:代表与供应商或浏览器相关的代码。如,WIN表示windows,MAC表示Macintosh,POSIX表示POSIX。当有两个variant存在的话,用下划线(uderscore)连接,并把最重要的variant放在前面。

下面是几个典型的Locale的例子 Locale(\

Locale(\

Locale(\

Locale(\

Locale.getDefault(),得到当前Java虚拟机的宿主系统上默认的Locale

● ResourceBundle

该类是一个抽象类,它定义了三个静态方法来获得具体的实现类(ListResourceBundle的子类或PropertyResourceBundle类)的实例:

☆ static final ResourceBundle getBundle(String baseName) 等同于调用:

getBundle(baseName,Locale.getDefault(),this.getClass.getClassLoader())

使用的是系统缺省的Locale。

☆ static final ResourceBundle getBundle(String baseName,Locale

3

locale) 等同于调用:

getBundle(baseName,locale,this.getClass.getClassLoader()) 使用的是参数locale指定的Locale。

☆ static final ResourceBundle getBundle(String baseName,Locale

locale,ClassLoader loader)

下面我们来说说baseName参数和locale参数。

BaseName参数指定的是一组ReourceBundle的公共的基础名称,例如,设baseName等于“TestBundle”。如果用ListResourceBundle子类来实现,则要有如下这样的类:TestBundle.class、 TestBundle_zh_CN.class和 TestBundle_fr.class等;如果用PropertyResourceBundle来实现,则要有如下这样的属性文件:TestBundle.properties、 TestBundle_zh_CN.properties和 TestBundle_fr.properties等。

locale参数和选择策略一起决定运行时具体选择这组ResourceBundle中的哪一个。 假设locale参数指定的Locale为(language1,country1,variant1),系统默认的Locale为(language2,country2,variant2),则按照以下优先级的顺序查找最满足条件的ResourceBundle:

? baseName + \+ language1 + \+ country1 + \+ variant1 ? baseName + \? baseName + \

? baseName + \+ language2 + \+ country2 + \+ variant2 ? baseName + \? baseName + \? baseName

在每一种情况下,会先尝试按ListResourceBundle类的方式加载,失败后会再尝试按照访问属性文件的方式加载PropertyResourceBundle类。如果所有这些情况都没有找到的话最后会抛出一个MissingResourceException的异常。

注意,在第一个getBundle静态函数中locale参数指定的Locale就是系统默认的Locale。

● ListResourceBundle

该类继承ResourceBundle类,也是一个抽象类。它实现了ResourceBundle类中的抽象函数getKeys()和handleGetObject(String key),并提供了一个抽象函数getContents()。在应用中,通过创建继承ListResourceBundle的子类来实现ResourceBundle。要求子类必须实现getContents函数并提供一个包含有一组属性对的数组,如:

package oracle.cdc.sgt.unicode;

import java.util.ListResourceBundle;

public class MResources extends ListResourceBundle {

4

public Object[][] getContents() { return contents; }

static final Object[][] contents = { {\ }; }

package oracle.cdc.sgt.unicode;

import java.util.ListResourceBundle;

public class MResources_zh_CN extends ListResourceBundle { public Object[][] getContents() { return contents; }

static final Object[][] contents = { {\主页\ }; }

下面是一个java类根据不同的Locale从相应的ListResourceBundle子类中取数据来显示:

package oracle.cdc.sgt.unicode; import java.util.ResourceBundle; import java.util.Locale;

public class TestListResourceBundle {

public static void main(String[] args) { ResourceBundle messages; Locale curloc; try {

if (args.length != 2) {

curloc = Locale.getDefault(); } else {

curloc = new Locale(args[0], args[1]); }

messages = ResourceBundle.getBundle(

\ System.out.println(messages.getString(\ } catch (Exception e) { System.out.println(e); } } }

把这三个类加入到classpath中,运行“java TestListResourceBundle zh CN”或在简体中文操作系统上运行“java TestListResourceBundle”,打印出“主页”;运行“java TestListResourceBundle en”或在英文操作系统上运行“java

5

TestListResourceBundle”,打印出“Home”。

● PropertyResourceBundle

继承ResourceBundle类,它不是抽象类,也不需要创建它的子类。与ListResourceBundle相同的是它也实现了ResourceBundle类的抽象函数getKeys()和handleGetObject(String key);不同的是,它是从属性文件(.properties)中读入属性对的。例如,

定义如下一组properties文件,并加入到classpath中: MResources.properties: s1=Home

MResources_zh_CN.properties s1=主页

下面是一个java类根据不同的locale从相应的Properties文件中取数据来显示: package oracle.cdc.sgt.unicode; import java.util.Locale;

import java.util.ResourceBundle;

public class TestPropertyResourceBundle { public static void main(String[] args) { ResourceBundle messages; Locale curloc;

if (args.length != 2) {

curloc=Locale.getDefault(); } else {

curloc = new Locale(args[0],args[1]); }

messages = ResourceBundle.getBundle(

\ curloc);

System.out.println(messages.getString(\ } }

运行的方式和结果同TestListResourceBundle一样。

留意一下TestListResourceBunlde和TestPropertyResourceBundle唯一不同的地方就是在调用getBundle函数的那个语句,按照我们上面所说的,完全可以统一写成:“oracle.cdc.sgt.unicode.MResources”,因为getBundle会缺省先找基础名称为MRseources的类,失败后再找基础名称为MResources的属性文件,在查找属性文件前它会自动把“.”转换为“/”。当然,如果通过存在基础名称为MResources的类和属性文件时,也可以通过直接使用“oracle/cdc.sgt/unicode/MResources”来略过查找基础名称为MResources的类。

当然,java程序的国际化设计并不只是这么简单,当涉及日期和时间显示等问题时,还可以利用java.text包以及java.util包中的TimeZone、SimpleTimeZone和Calendar等类进行辅助处理。我们就不在这里详细叙述了,您只需要记住一个

6

ResourceBundle的概念就可以了,本文的后续部分都是围绕着这个概念展开的。

2. WinRunner调研

WinRunner适合于测试那些有图形操作界面的组件。目前,我们手头可用的版本WinRunner7.5,启用Web和Java插件(plugin)。 让我们先从WinRunner的技术特点说起吧。

2.1 WinRunner的技术特征

由于本文不是专门介绍WinRunner的,所以只列举一些WinRunner的重要特征。注意:这里定义了一些非官方的术语,为的是便于您的理解。

● WinRunner将对象(object)分为两种:窗口(window)和子对象,任一个子对象

都隶属于一个窗口。

注意:窗口也是对象,如一个页面就是一个窗口。

● WinRunner通过一组属性来唯一的识别窗口,也就是说不能有所有属性值都相同的多

个窗口;同样的,WinRunner通过一组属性来唯一的识别同一个窗口下的子对象,也就是说,在同一个窗口下,不能有所有属性值都相同的多个子对象。

● 如果把对象的所有属性的集合称为对象的定义,WinRunner可以把对象的定义保存在

以下两个地方:

☆ 独立script的单独的扩展名为GUI的文件

简称为GUI文件,同时为每个object定义了一个绝对逻辑名,有了绝对逻辑名就一定有相对逻辑名。对于窗口来说,它的绝对逻辑名等于它的相对逻辑名;对于子对象,它的绝对逻辑名等于它隶属的窗口的绝对逻辑名后面加一个”.”再加上它的相对逻辑名。在script开始部分导入GUI文件,在后面部分中只需要写出对象的绝对逻辑名,就可以从GUI文件中获得这个对象的定义了。如:

\{

class: window,

MSW_class: html_frame,

html_name: \} {

ltree_state: open, list_open_data: close }

\Certificate Authority-Certificate Management\Search\{

class: object,

MSW_class: html_text_link,

7

html_name: \}

\Certificate Authority-Edit Policy Result: UniqueCertificateCo\{

class: window,

MSW_class: html_frame,

html_name: \} {

rtree_state: open, ltree_state: open, list_open_data: close }

☆ script本身

把object定义写在script是可以的。一种方法是象GUI文件那样在script的开始部分为对象定义一个绝对逻辑名,这样在script的后续部分就可以通过这个绝对逻辑名来访问对象的;另一种方法是不为对象定义绝对逻辑名,而是在每个要访问对象的地方,直接写该对象的定义。这两种在script中定义对象的方法我们都不推荐,第一种完全就是GUI文件在script中的实现,那么为什么不它放在GUI文件中统一管理呢,第二种虽然省略了导入GUI文件的一步,但是维护起来更麻烦了,如果对象的属性发生变化,那就要修改所有脚本中所有这样定义了该对象的地方。

也许我们还没有意识到在script中定义对象的好处,但是存在就是道理。如: #Gui Objects initialization

set_window(\\\\}\

list_select_item(\class: list, MSW_class: html_combobox, html_name: matchType}\\);

rc=global_web_obj_text_exists(access_info,\Settings\);

if(text!=\)

set_window(\ \\\ \¬ification&\

rc=global_web_obj_text_exists(text_object,\\Information\,\

set_window(\

8

\\\}\

2.2 WinRunner在全球化测试中的局限性

在1.1“全球化测试的内容”一节中我们知道,要在不同的Locale下测试软件的处理数据和显示数据的能力。在不同Locale下,WinRunner赖以识别对象的属性列中有的属性也可能不同,因此在不同的Locale下,同一个对象的定义也可能不同。如同一个窗口,在英文下的html_name属性值为 “OracleAS Certificate Authority-Certificate Management”,在简体中文下的html_name属性值为 “OracleAS Certificate Authority-证书管理”。也就是如果用该窗口在英文下的定义是无法在简体中文或其他Locale下识别该窗口的。

换句话说,在一种Locale下录制的脚本,不论对象定义是保存在GUI文件中还是保存在script中,都无法直接拿到另一种Locale下直接运行。注意:所谓直接拿到,也包括进行少量的修改。

虽然可以在不同的Locale下用WinRunner录制各自的脚本,但是这并不是我们所希望的,那样做的成本是非常高的。

我们的目标是只在一种Locale下录制脚本,经过一定处理后,就可以在其他Locale下使用,即Code Once Fit All Language(简称COFAL)。

2.3 WinRunner满足COFAL的技术可行性

既然WinRunner是通过对象的定义(一组属性)来标识对象的,那么我们就要研究对象的属性在不同的Locale下有什么不同:

● 有的对象在不同的Locale下所有属性值都不变 ● 有的对象在不同的Locale下部分属性发生变化 只要找到变化的属性的规律和属性值的来源,并用自动化的方法来修改这些属性,就可以基本上满足只录制一次的需求。

1、如果对象的定义保存在GUI文件中

假如在英文下录制了一套脚本,该套脚本公用一个GUI文件global.gui,我们要找到一个自动化的方法,生成该GUI文件在其他Locale下对应的GUI文件,如global_zh_CN.gui和global_fr.gui等。这样,在不同Locale下,通过使用不同的GUI文件就可以用同一套脚本运行了。这样看来虽然有多个GUI文件,但是脚本只有一套,其他的GUI文件又是自动生成的,基本上满足了COFAL的要求。 2、如果对象的定义保存在script中

假如在英文下录制了一套脚本,脚本都保存在tina目录下,对象的定义都保存在script中。我们要找到一个自动化的方法,转化该script中对象的定义到不同的Locale下的定义,并把转化的结果保存在新的目录下,如tina_zh_CN和tina_fr目录等。这样,在不同的Locale下,通过使用不同目录下的脚本就可以了。这样看来虽然有多套脚本,但是只录制了一次,其他的都是自动生成的,也基本上满足了COFAL的要求。

9

下面我们会把转化对象定义统一称为“翻译”,接下来要介绍的就是以COFAL命名的一个实现自动化翻译的小工具。

3. 自动翻译工具COFAL简介

CORAL是Code Once Fit All Language的缩写,它是专门为配合WinRunner的全球化测试而开发一个工具,code once fit all language的意思是只需要在一种语言下编写脚本,就可以在所有语言下运行。用COFAL来实现script和GUI文件的自动翻译。

3.1 技术原理

3.1.1 Java应用程序级数据翻译

Oracle AS是一个基于J2EE架构的应用程序,它是通过我们在1.2节中介绍的java数据绑定机制来实现国际化的,也就是说那些需要翻译的属性值其实都是保存在ResourceBundle中。除了前面说过的ListResourceBundle和PropertyResourceBundle外,Oracle AS还把部分ResourceBundle保存在数据库的表中,在运行时根据不同的语言环境用绑定的key动态的从表中检索出对应的值。

由此可知,程序本身是通过关键字(key)结合指定的locale来获得值(value)的;而现在是想在已知值(value)和指定的locale的情况下,获得该key在其他locale下的值(value),这是一个逆向的过程。

为了描述方便,我们用key代表关键字,用prevalue代表当前可得的值,用postvalue代表翻译后的值。

自动翻译的原理是:

(1) 事先定位好resourcebundle的保存位置。

(2) 翻译时,从script或GUI文件中提取出prevalue,然后用prevalue在

ResourceBundle中查询出key,再用key从ResourceBundle中查询出postvalue。

(3) 用postvalue替换prevlaue,把替换的结果保存成新的语言版本。

在COFAL中,我们把Oracle AS用到的ResourceBundle统一保存在一张Oracle数据库表GLOBALRES中。翻译时通过JDBC,用prevalue从表中select出key,再用key去select出postvalue。

GLOBALRES表的结构如下: 列 Component Version

类型 varchar2(60) varchar2(60) 描述 Key所属的组件 组件的版本 10

Prolang varchar2(60) 从ResourceBundle文件名中提取出来的表示语言的串,如从TestBundle_zh_CN.properties中提取出的zh_CN 从ResourceBundle文件 内容中提取出来的(key-value)对中的key Key value varchar2(400) Value1 location nvarchar2(400) 从ResourceBundle文件 内容中提取出来的(key-value),因为有的value非常长,已经超出了4000个字节的字段长度限制,所以如果value超过4000个字节,提取vlaue中前400个字节否则保留全部字节。注意是400个字节不是4000个字节,因为在WinRunner中完全可以通过正则表达式的使用将字符串截短,不用保留那么长的串。 clob 这是一个备份字段,当value超过4000个字节时把整个value备份到这里,否则为空 varchar2(1200) 保留(key-value)对的出处,即它来自于哪个ResourceBundle 注意:component和version字段是为了能更有效的翻译而引入的,在导入resourcebundle时应该确定它属于哪个component的哪个version,这样在翻译时就可以通过增加where判断条件来更具体化一个查询。

抛开如何获得prevalue先不说,最终要进行的select查询就是以下两种 ● SQL精确查询

☆ 获得key的SQL语句

select key from GLOBALRES where value=’Add Another Row’ and prolang=’en’ and component=’UIX’ and version=’10.1.2.0.2’

☆ 获得postvalue的SQL语句

假设上面的SQL语句查询出来的key是TABLE_ADD_ROW_SINGLE_TEXT,则获得postvalue的语句为: select value from GLOBALRES where key=’TABLE_ADD_ROW_SINGLE_TEXT’ and prolang=’zh_cn’ and component=’UIX’ and version=’10.1.2.0.2’ ● SQL模糊查询

☆ 获得key的SQL语句

select key from GLOBALRES where value like 'Certificate Mana%') and prolang=’en’ and component=’oca’ and version=’10.1.2.0.2’

☆ 获得postvalue的SQL语句

假设上面的SQL语句查询出来的key是OCAUIAdminTabText,则获得postvalue的语句为:

select value from GLOBALRES where key=’OCAUIAdminTabText’ and prolang=’zh_cn’ and component=’oca’ and version=’10.1.2.0.2’

看到这里,您也许会有一个疑问:从key到postvalue是一对一的关系,但是从prevalue到key则是多对一的关系,比如可能有多个key在英文下的value都是OK,这就是所谓的对象多翻译的情况,我们将在3.2.4小节说明如何处理这种情况。

11

3.1.2 操作系统级数据翻译

有时测试要打开一些操作系统级的窗口使用里面的一些对象,由于我们不知道如何获得它们的ResourceBundle,所以只好用一种最笨的办法: (1) 第一次将用到的操作系统级的对象手动搜集(可以使用WinRunner的Spy来录制)

在一起,保存成在一个单独的resourcebundle中;

(2) 以后再用到时,从这个resourcebundle里找。

在COFAL中,我们单独定义了一张表SYSRES来保存操作系统级的resourcebundle,表的结构如下: 字段名 win obj value lang 这张表的结果完全是按照WinRunner中“窗口和子对象”的模式定义的,我们规定: ● win字段和obj字段都只能是英文字符串,取对象在英文环境下的名字。如“Security

Alert”窗口中的“OK”按钮对应的win字段为“Security Alert”,ob字段为“OK”。 ● value字段实际上就是对象在不同语言环境下的名字。如“Security Alert”窗口

在英文下的value是“Security Alert”,在简体中文下的value是“安全警报”。

由于我们作出了这样的规定,操作系统级数据只能从英文翻译到其他语言,且prevalue等于key,这样就可以用key直接查找postvalue,省略了从prevalue到key的过程。

另外,在SYSRES中没有象GLOBALRES中的component和version字段,这是因为操作系统的版本比较固定,不象产品那样会有很多个release,同时获得component对我们来说意义也不大。当然,您也可以根据您的实际情况添加这两个或其他字段。

字段类型 varchar2(120) varchar2(120) 描述 窗口的绝对逻辑名 对象的相对逻辑名,当对象是窗口是该字段那为null nvarchar2(240) 对象的需要翻译的属性值 varchar2(10) 语言 3.2 翻译策略

需要翻译的prevalue来自于对象的属性值,但并不是所有的对象都需要翻译,即使需要

翻译也不是所有的属性都需要翻译,即使找到了需要翻译的属性,它的值也一定都可以直接翻译,可能要经过一些特殊处理才能够翻译。下面我们就来一一说明。

3.2.1 通过class属性来判断object是否需要翻译

每个object的定义里都肯定要包含它的class属性,通过class属性可以判断出该object是否需要翻译。

12

3.2.1.1 不需要翻译的class

以下class类型一般不需要翻译:

● edit

● combobox

● check_button ● list

● radio_button

3.2.1.2 需要翻译的object

除了以上那些不需要翻译的class外,其他的class类型基本上都需要翻译。

注意,以上我们所说的class都是WinRunner能够理解的标准的web class,如果您自定义了一些新的class类型,是否需要翻译要由实际情况而定。

在Oracle AS中我们没有定义新的class类,一些非标准的object也可以用标准的class类型定义,如Oracle AS中的某一按钮的定义如下:

\{

MSW_class: html_rect, class: object, html_name: \ location: 0 }

建议,尽量用WinRunner Spy来录制应用程序中的object,不要一开始就自己手动定义。这样你才能发现WinRunner是如何识别你的object的。

3.2.1.3 需要翻译的属性

一般情况下,对于那些需要翻译的object,下列属性需要翻译: ● label

● html_name

● attached_text

注意:一个object一般只具有上列三个属性中的一个,有哪个就翻译哪个。另外,需要翻译的属性可能不只是这三个,但是在我们的测试中这三个属性就足够了。

13

3.2.2 判断是Java应用程序级对象还是操作系统级对象

由3.1.1和3.1.2两个小节可以看出,Java应用程序级对象和操作系统级对象的处理是不一样的。如果一个GUI文件或script文件中同时包含这两种类型的对象定义时,该怎么办呢?由于操作系统级对象的数量比较少,所以每次我们尝试把对象作为操作系统级对象进行翻译,如果不成功作为Java应用程序级对象进行翻译,也就是说先SYSRES中查找,不成功再在GLOBALRES中查找。

3.2.3 翻译规则及其优先级

把从GUI文件中提取出的属性值看作是prevalue,配合其他查询条件最好的情况是可以找到value字段值就等于prevalue的行,进而取出key字段。但有时没有这么幸运,那么是否就要开始模糊查询了,要知道对value字段使用like查询可能会找到很多行,也就是说很多key。无论如何这应该是最后一招,在这之前我们还应该再做些什么的。在实践中我们发现,WinRunner在学习对象的时候可能会对得到的属性值做一定处理,而且java程序在绑定数据时也可能对绑定的key返回的value一定的处理。而我们只要找到这些规则,然后通过反向运用,就可以得到一些更纯粹的子prevlaue,翻译这些子prevalue再把翻译的结果按规则正向组合起来作为最终的postvalue。

下面要介绍的这些语法规则是在我们的测试中用到的。

3.2.3.1 WinRunner的语法规则

WinRunner有许多语法规则,我们用到的就是“!.*”。 使用spy的朋友都知道,如果串过长,WinRunner会自动把它截短并在串的头和尾分别加上“!”和“.*”。其中:“!”表示省略,必须放在串首;“.*”表示任意字符串,可以放在除串首外任何位置,一般放在串尾。

3.2.3.2 SQL语法规则

在SQL语句中,用单引号作为字符串的边界符,所以不论是做select精确查询还是select模糊查询,都要把prevalue中的单引号escape掉,escape符号是SQL中的escape符:“’”(单引号)。

注意:java中字符串的边界符是双引号,escape符号是:“\\”(反斜杠)

3.2.3.3 Oracle AS绑定数据时的语法规则

在我们的测试中用到的规则有以下4条:

14

● 全串匹配

如: “submit”翻译成中文就是“提交” ● 嵌套串 如“Edit Policy Result: UniqueCertificateCo”就是由“Edit Policy Result: {0}”嵌套“UniqueCertificateCo”组成的,也要分别绑定后再组合在一起。 ● 多串连接

如”OracleAS Certificate Authority-Advanced Search”就是由”OracleAS Certificate Authority”和”Advanced Search”用”-”连接组成的,分别绑定后用”-”连接在一起。

注意:OracleAS中只存在连接两个串的情况,也就是说即使prevalue中有多个”-”,也只有一个是其连接作用的,其他的都是子串内部的。

3.2.3.3 翻译规则的优先级

根据上面的语法规则,我们制定了以下的三种翻译规则类别,优先级由高到低: 1、 准备类别

准备类别的优先级最高,是在翻译前必须要判断的,它包括以下两条: ● winrunner的省略符规则 如果在prevalue的首尾发现有“!”和“.*”,则要先去掉“!”和“.*”作为新的prevalue;然后如果对象的绝对逻辑名包含prevalue,则用对象的绝对逻辑名作为新的prevalue ● Escape掉prevalue中所有的单引号 因为最终要用prevalue在表的value字段上“=”或like的select查询,而select语句中是用单引号作为字符串的边界符的,所以要escape掉prevalue内部中的单引号,也就是说在prevalue内部的每个单引号前再加一个单引号。

注意:这两条规则没有优先级,哪条先执行都可以。

2、 精确翻译类别

准备类别后,就是精确翻译类别。包括以下4条,优先级从高到低: ● 常量规则

指prevalue在常量列表中。 ● 精确匹配规则

指用prevalue做select精确查询成功。 ● 嵌套匹配规则

把GLOBALRES表中所有满足条件的value字段包含有“{0}”的所有值取出来,把每个值中的“{i}”用“(.*)”代替后做成pattern,用prevalue与每个pattern匹配,分别解析出被嵌套的串outer和嵌套的串inner,这样可能有多个解析的结果。要求在至少一种解析结果中,outer满足精确匹配规则表示成功,而对于每个inner串,要先进行常量规则判断和精确匹配规则判断,在不满足这两个规则的情况下,取inner串本身。 ● 连接串全精确匹配规则 如果prevalue中包含“-”,则用不同的”-”解析出所有不同的前后段tmpfir和tmplas。要求在至少一种解析下,满足如下条件时表示成功:

☆ tmpfir满足常量规则或精确匹配规则或嵌套匹配规则

15

☆ tmplas满足常量规则或精确匹配规则或嵌套匹配规则

注意:优先级高的规则先执行,如果成功的话就不再执行优先级低的规则,否则执行优先级低的规则。

3、 模糊翻译类别

精确翻译规则失败后,就到了最后的模糊翻译规则。包括以下条规则,没有优先级,都要执行:

● 模糊匹配规则

指prevalue做select模糊查询成功 ● 连接串单精确匹配规则

在多种解析中,至少有一种满足如下条件时表示成功:tmpfir或tmplas中有一个满足精确翻译类别中的任一规则,另一个满足模糊匹配规则或取原值。 ● 连接串全模糊匹配规则

在多种解析中,至少有一种满足如下条件时表示成功:

☆ tmpfir满足模糊匹配规则或取tmpfir本身 ☆ tmplas满足模糊匹配规则或取tmplas本身 ☆ 不能同时取tmpfir和tmplas本身

注意:翻译规则及其优先级是可以补充修改和删除的,您完全可以根据您的实际情况自己来指定。

3.2.4 对象多翻译的处理

在3.1.1小节我们指出了“对象多翻译”情况的存在,如果处理呢?翻译时会把这些对象的所有可能的翻译结果都保存下来,等到输出时再决定取哪个翻译。至于取哪个翻译我们提供了以下两种模式: ● 自动模式

会自动取第一个获得的翻译输出 ● 手动模式

☆ GUI文件

将多翻译的对象单独输出到一个文件中,让用户自己选择。一个典型的输出如下: \{

class: object,

MSW_class: html_rect, html_name: 前进 html_name: 下一步 }

☆ Script文件

不论是单一翻译还是多翻译都输出到一个文件中,对于多翻译的情况,把除第一个翻译外的其他翻译行都用“#”注释掉,让用户觉得以后打开哪个翻译。一个典型的输出如下:

global_image_click(\class: object, MSW_class: html_rect, html_name:

16

结束, location:0} \#global_image_click(\class:

object, MSW_class: MSW_class:

html_rect, html_rect,

html_name: 完成, location:0} \#global_image_click(\class: object, html_name: 提交, location:0} \

3.2.5 多种语言同时翻译的处理

有时我们想从一种语言同时翻译到多种语言,最简单的办法是一种一种的翻译,这样做虽然可行,但是却浪费了时间和资源。事实上,在每种语言下,从prevalue到key的过程是一样的,结果也是一样的,所以只需要在翻译第一种语言时执行从prevalue到key的过程就可以了,然后把key保存在内存中,在翻译其他语言时直接使用就可以了。这样可以节省很多时间。

3.3 COFAL的版本

到目前为止,COFAL有两个版本。

3.3.1 COFAL1.0

COFAL1.0具有以下特点:

● Client-Server两层结构的应用程序,使用者要在本地运行; ● 把所有的ResourceBundle打包到jar文件中 ● 用jar包直接翻译

3.3.2 COFAL2.0

COFAL2.0具有以下特点:

● 是J2EE架构的web应用程序,使用者通过浏览器即可访问; ● 把所有的ResourceBundle都导入到数据库中; ● 通过JDBC用数据库进行翻译;

与1.0相比2.0有以下优点:

● 通过浏览器即可翻译,不用自己在本地运行; ● 增加了翻译策略,提高了翻译的成功率;

● 增加了翻译单个value的功能,能给出value对应的key和该key在其他语言下的

value,以及这个“key-value”对的出处; ● 增加了翻译script脚本的功能

与1.0相比2.0有以下缺点 ● 翻译速度上有一定损失

17

3.4 COFAL2.0的使用简介

我们把COFAL2.0打成一个ear包,部署到一个OC4J服务器上,就可以通过浏览器访问COFAL2.0了。

3.4.1 翻译script或gui文件

● 第一步

访问下面这个页面可以开始翻译script或gui文件:

http://:8990/tina/oracle/cdc/sgt/coral/Trans-step1.uix

在File Location中输入要翻译的script或gui文件,file description是可选项,点击下一步会把这个文件上载到服务器上。

● 第二步 必选项:

☆ 文件的类型(script或gui)

☆ 文件当前的语言和将要翻译成的语言(可多选) 可选项:

☆ 文件涉及的组件(可多选) ☆ 组件的版本(单选)

18

建议指定组件和版本,这样查询速度会快一些,结果会更准确一些。 ● 第三步

翻译前有一个confirmation页面,如果选择“yes”则马上开始翻译,否则回到上一页

开始翻译后,会出现一个等待页面,里面有一个小时钟在不停的转动,真正的翻译通过多线程在后台进行。

19

翻译结束后,会有一张下载文件的table显示出来,选中一个文件,点击“save”按钮就可以把文件保存在本地。

● 第四步

下载文件后,可以选择是否删除原始的和翻译的文件,如果不选择删除的话,可以在当前session结束前,翻译其他语言或下载。

20

● 返回

在这个页面中列出了当前session中所有已经上载的原始文件,可以选择上载新的原始文件,也可以选择已有的原始文件进行新的翻译,还可以选择下载已有的翻译文件。

3.4.2 翻译单独的串

访问下面这个URL翻译串:

http://:8990/tina/oracle/cdc/sgt/coral/StringSearch.uix

● 在“search for”中输入要翻译的串,可以为任何COFAL支持的语言,对于每种语

21

言我们在后台会给它一个缺省的encoding。 ● 在“from lang”中指定串当前的语言

● 在“to lang”中指定要翻译成的语言,缺省为翻译到所有COFAL支持的语言。 ● 选择在查询范围内的component和release等,这些都不是必选项

● 如果想把翻译的结果保存在文件中,支持UTF8和native两种编码方式。

查询结果如下图所示:

4. 利用WinRunner做日期格式等本地化测试

日期等格式的本地化测试是全球化测试的一个重要部分,界面上的日期等格式由客户端或客户端浏览器的当前locale决定,也就是说在不同的locale下日期等都应该有正确的格式。现在的问题是如何在WinRunner中实现日期等格式的本地化测试。答案是正则表达式。

下面我们先从定义正则表达式说起。

4.1 定义正则表达式

Oracle提供的locale有142个,通常用在以Oracle数据库为中心的应用程序中,如Oracle Locale Builder和SQLPLUS等。

Java提供的locale有134个,通常使用JSP/UIX页面技术的Oracle web应用程序会用到,如Oracle AS。

下面就给出java提供的简体中文locale下的一些常用的格式和部分正则表达式。

22

Date Format [Date Format] Short 05-6-1 Medium 2005-6-1 Long 2005年6月1日 Full 2005年6月1日 星期三 统一的正则表达式: (\\d{2}|\\d{4})-\\d{1,2}-\\d{1,2}|\\d{4}年\\d{1,2}月\\d{1,2}日\\s*(星期[一二三四五六七])? 注意:也可以给每种格式分别定义一个正则表达式 [Date/Time Format] Short 05-6-1 上午2:03 Medium 2005-6-1 2:03:04 Long 2005年6月1日 上午02时03分04秒 Full 2005年6月1日 星期三 上午02时03分04秒 IST 统一的正则表达式: (\\d{2}|\\d{4})-\\d{1,2}-\\d{1,2} [上下]午 \\d{1,2}:\\d{1,2}(\\d{1,2})|\\d{4}年\\d{1,2}月\\d{1,2}日\\s*(星期[一二三四五六七]) [上下]午 \\d{1,2}时\\d{1,2}分\\d{1,2}妙 (IST)? [Time Format] Short 上午2:03 Medium 2:03:04 Long 上午02时03分04秒 Full 上午02时03分04秒 IST [Date Symbols] Months(From Jan.) 一月 , 二月 , 三月 , 四月 , 五月 , 六月 , 七月 , 八月 , 九月 , 十月 , 十一月 , 十二月 , Short Months(From Jan.) 一月 , 二月 , 三月 , 四月 , 五月 , 六月 , 七月 , 八月 , 九月 , 十月 , 十一月 , 十二月 , Weekdays(From Sun.) , 星期日 , 星期一 , 星期二 , 星期三 , 星期四 , 星期五 , 星期六 Short Weekdays(From Sun.) , 星期日 , 星期一 , 星期二 , 星期三 , 星期四 , 星期五 , 星期六 AM/PM(From AM) 上午 , 下午 Eras(BC, AD) 公元前 , 公元 Currency Currency Symbol:CNY Currency Name(ISO4217):CNY 23

Currency Code:CNY Currency Example ¥123,456,789.00 -¥123,456,789.00 -¥123,456,789.55 正则表达式如下: -?¥[1-9]{1,3}(,[0-9]{3})*(.[0-9]+)? Number Example 123,456,789 123,456,789.123 -123,456,789 正则表达式如下: -?[1-9]{1,3}(,[0-9]{3})*(.[0-9]+)? Integer Example 123,456,789 -123,456,789 Percentage Example \\\Decimal Separator 。 Grouping Separator , Zero Digit 0 Percent % Pattern Separator ; [Asia/Shanghai] Display Name: (UTC+08:00) 北京, 上海 Short Name CST Long Name(English) China Standard Time Long Name(Native) 中国标准时间 [Asia/Hong_Kong] Display Name: (UTC+08:00) 香港 Short Name HKT Long Name(English) Hong Kong Time Long Name(Native) 香港时间 有一点需要特别说明,我们下面给出的这些格式只涵盖了简体中文locale下的部分情况,具体要用到哪些格式需要定义哪些正则表达式,要由您要测的应用程序来定。

Number format Timezone 4.2 自定义re_match函数

WinRunner自带了一个叫做match的函数,用来判断一个串是否符合正则表达式。但是,WinRunner7.5中的match函数对过于复杂的正则表达式的支持不是很好,鉴于日期等的正则表达式的复杂度比较高,我们使用了一个由EMOS Framework提供的已编译过的函数

24

re_match()。

这个新的函数实现了一个类似于perl语言中正则表达式查询和匹配功能,弥补了原来match函数的不足。

public extern._int re_match(in._string str, in._string re, out._int m_pos, out._int m_len,

inout._string detail)

说明:

将串与正则表达式做匹配。输出detail中的子匹配结果可以通过另外两个函数re_get_details()和re_get_match()获得。 参数:

str – 要匹配的串 re – 正则表达式

m_pos – 匹配发生的开始位置 m_len – 匹配的长度 detail – 匹配的细节 返回值:

0 = 不匹配, 1 =匹配,m_pos和m_len分别表示匹配的开始位置和匹配的长度

下面是一段使用该函数的代码:

input_string=\2005年6月1日\

pattern = \年\\\\d{1,2}月\\\\d{1,2}日\\\\s*(星期[一二三四五六七])?\

if (re_match(input_string, pattern, m_pos, m_len, detail)){ = tl_step(\sensitive date format check\0 , \format is OK\

treturn(\}else {

tl_step(\incorrect\

treturn(\}

注意:这只是一个简单的例子。实际应用中,input_string和pattern都可以参数化到文件,在不同的locale下读取不同的文件动态获得,以保证脚本的通用性。

关于EMOS Framework,它以区别与其他Framework的独特方式实现了一个WinRunner自动化脚本开发的简单但却强大的框架,EMOS是专门为WinRunner设计的,整个EMOS几乎都是用WinRunner自己的TSL语言实现的。关于EMOS Framework的详细介绍请参考http://emos-framework.sourceforge.net/。

小节

25

至此,您应该对用WinRunner实现软件的全球化测试有了一定的了解。我想强调的是:本文的重点不是想象您推荐我们开发的COFAL,而是提供一种思路。这种思路的意义不仅在于它部分地实现了自动化全球化测试的目标,更在于它为测试人员打开了一扇门,工具是死的,关键在于使用工具的人,如果工具做不到的,我们可以想办法让它做到。也许在寻找过程中您会收获到对软件更全局化的理解,收获开发人员对我们的尊敬和咨询,最重要的是收获您自己对这份工作的肯定和信心。

参考文献

● Sun 关于 Internationlization 在 JDK 里面的说明

http://java.sun.com/j2se/1.3/docs/guide/intl/intlTOC.doc.html ● SUN的国际化教程

http://java.sun.com/docs/books/tutorial/i18n/index.html ● WinRunner的用户手册

作者简介

真名王宝蕾,笔名月白。曾从事过软件开发、配置管理和软件测试工作,现专注于软件测试,重点研究测试工具的使用和辅助测试的软件的开发。

26

至此,您应该对用WinRunner实现软件的全球化测试有了一定的了解。我想强调的是:本文的重点不是想象您推荐我们开发的COFAL,而是提供一种思路。这种思路的意义不仅在于它部分地实现了自动化全球化测试的目标,更在于它为测试人员打开了一扇门,工具是死的,关键在于使用工具的人,如果工具做不到的,我们可以想办法让它做到。也许在寻找过程中您会收获到对软件更全局化的理解,收获开发人员对我们的尊敬和咨询,最重要的是收获您自己对这份工作的肯定和信心。

参考文献

● Sun 关于 Internationlization 在 JDK 里面的说明

http://java.sun.com/j2se/1.3/docs/guide/intl/intlTOC.doc.html ● SUN的国际化教程

http://java.sun.com/docs/books/tutorial/i18n/index.html ● WinRunner的用户手册

作者简介

真名王宝蕾,笔名月白。曾从事过软件开发、配置管理和软件测试工作,现专注于软件测试,重点研究测试工具的使用和辅助测试的软件的开发。

26

本文来源:https://www.bwwdw.com/article/gk46.html

Top