SAP是当前知名且领先的ERP系统,在对与 SAP 有交互的软件系统进行测试时,经常需要使用 SAP GUI Client 完成一定的常规操作,例如创建测试数据等。这些操作具备如下特点:需要一定的 SAP 知识和技能;步骤冗长;耗时耗力;重复性强等。为了提高工作效率,降低测试人员和开发人员的工作量,通过自动化的方式来完成数据准备是我们首先想到的方法。Script Center是我们自主开发的一款基于 AutoIt 的 SAP 自动化测试工具,通过它执行操作 SAP 的 VBS 脚本,可快速完成测试数据的准备。用户也可以通过Script Center方便的编辑要创建的数据值,以便创建若干不同的测试数据。
笔者所在的部门是负责开发和测试一个电子商务应用系统,这个系统和SAP交互频繁。我们往往需要在SAP中准备一些测试数据。以前,这些数据的准备工作,通常是手动的在SAP GUI Client中进行操作,参考帮助文档,一步一步执行完成。整个过程耗时耗力,且重复性强,很无趣。另外,这些操作往往比较复杂,通常是由熟悉SAP操作且了解电子商务应用系统的业务逻辑的少数人帮助大家来完成。在任务比较多的阶段,测试数据的需求也多,这些人本来的工作量就很大,所以对于其他人关于创建测试数据的请求有时会延迟处理。所以,项目组迫切需要一种方便、快捷的方式来在SAP中准备测试数据,减轻大家的工作压力,提高工作效率。
自动化准备数据是我们首先想到的解决方法,SAP自带了录制和回放功能。最后录制形成的脚本是VBS格式,双击这个VBS文件即可回放。但是单纯的回放脚本并不能满足用户对数据的要求,我们需要参数化这些数据,用户可以根据自己的需要来填写自己想要的数据。因为XML编辑起来没有对软件的特殊要求,可以很方便的进行编辑,最终决定用XML格式来保存这些数据。鉴于用户直接编辑XML可能会导致错误,我们用AutoIt研发出的script center可以对这些数据字段进行友好访问及编辑。Script center还可以对脚本进行集中管理,使得用户有更易用的界面来运行自己需要的脚本。
图1. 架构图
从架构图可以看到我们Script Center的设计思路,下面从工作流的角度来解释该结构图:
前提:
AutoIt 是用以编写并生成具有 BASIC 语言风格的脚本程序的免费软件,用来在Windows下实现各种自动化任务(比如自动安装目标程序、完成各种自动化操作等)。 通过它可以组合使用模拟键盘按键,鼠标移动和窗口/控件操作等来实现自动化任务, 而且可以利用它开发自己的GUI,以便获得更好的交互效果,另外,它可以把它的Script语言转换成exe可执行程序。
考虑到Script Center的主要功能比较简单,所以选择轻量级的AutoIt来开发主界面,而且AutoIt可以把脚本文件编译为独立的可执行文件,方便 Script Center在不同客户机上运行。 Script Center主界面主要是用于展示脚本文件,然后选择对应的脚本文件配置数据文件, 最后点击运行执行自动化脚本调用SAP GUI Client进行SAP自动化操作。
图2. Script Center主界面
Script Center GUI创建的代码片段,前半部分完成控件的创建,后半部分通过消息循环机制实现操作部分。
Local $mainwindow = GUICreate("ScriptCenter", 900, 600) GUISetIcon("Config/scriptcenter.ico") $label_Title = GUICtrlCreateLabel("Script Center v1", 10, 20, 900, 50) GUICtrlCreateTab(10, 70, 880, 450) ;;;;;;;;;;;;;;;;;;;;;;;;;;Tab1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; $tab1 = GUICtrlCreateTabItem("Execution") GUICtrlCreateLabel("Script Type", 30, 108, 60, 20) $comb_tab1_type = GUICtrlCreateCombo("", 95, 105, 80, 20,0x0003) GUICtrlSetData(-1, "SAP|Web|Other", "SAP") $bt_tab1_EditDataSource = GUICtrlCreateButton("Edit Data Source", 740, 105, 100, 25) $listview_tab1_Script = GUICtrlCreateListView("| Script Name| Key Info| Last Run| Author", 30, 140, 830, 320) GUICtrlListView_SetExtendedListViewStyle($listview_tab1_Script, BitOR ($LVS_NOCOLUMNHEADER, $LVS_SHOWSELALWAYS, $LVS_SINGLESEL)) $bt_tab1_Execute = GUICtrlCreateButton("Execute", 610, 470, 80, 25) $bt_tab1_Refresh = GUICtrlCreateButton("Refresh", 740, 470, 100, 25) ;;;;;;;;;;;;;;;;;;;;;;;;;;Tab1 End;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; GUI MESSAGE LOOP GUISetState() LoadViewList() While 1 $msg1 = GUIGetMsg() Switch $msg1 Case $GUI_EVENT_CLOSE Exit Case $bt_tab1_Execute Local $isselected = 0 ;$typeitem = ControlCommand ("ScriptCenter", " ",$comb_tab1_type,"GetCurrentSelection") For $item = 0 To $count $fielitem = $item + 1 $file = $FileList[$fielitem] $path1 = GetDir() IF $typeitem =="SAP" Then _RunDos("wscript "&$path1&"\script\"&$file) EndIf EndIf Next Case $bt_tab1_EditDataSource For $item = 0 To $count If _GUICtrlListView_GetItemState ($listview_tab1_Script, $item, $LVIS_SELECTED) Then $xmlFile = $path1&"\xml\"&$filedatasource $xmlNodePath = "data/"&$filename[1] RunXMLEditor($xmlFile,$xmlNodePath) GUISetState(@SW_ENABLE) WinActivate("ScriptCenter") EndIf Next If $isselected == 0 Then MsgBox(0,"Message","Please select one item before click button") EndIf Case $bt_tab1_Refresh LoadViewList() EndSwitch WEnd
SAP Client自带脚本录制工具,读者可以通过该工具录制生成vbs脚本。
If Not IsObject(application) Then Set SapGuiAuto = GetObject("SAPGUI") Set application = SapGuiAuto.GetScriptingEngine End If If Not IsObject(connection) Then Set connection = application.Children(0) End If If Not IsObject(session) Then Set session = connection.Children(0) End If If IsObject(WScript) Then WScript.ConnectObject session, "on" WScript.ConnectObject application, "on" End If session.findById("wnd[0]").resizeWorkingPane 156,25,false session.findById("wnd[0]/usr/txtRSYST-BNAME").text = "UserName" session.findById("wnd[0]/usr/pwdRSYST-BCODE").text = "********" session.findById("wnd[0]/usr/pwdRSYST-BCODE").setFocus session.findById("wnd[0]/usr/pwdRSYST-BCODE").caretPosition = 8 session.findById("wnd[0]/tbar[0]/btn[0]").press session.findById("wnd[0]/tbar[0]/okcd").text = "va03" session.findById("wnd[0]/tbar[0]/btn[0]").press
因为SAP录制的脚本只能在手动启动SAP Client以后才能通过脚本开始自动操作,所以我们需要利用AutoIt启动SAP Client,封装OpenSAP方法。
Function OpenSAP720() set autoIt = WScript.CreateObject("AutoItX3.Control") set wsh = createobject("wscript.shell") wsh.run Chr(34)&SAPPath&Chr(34) Log1("Open SAP system list") WScript.sleep 5000 autoIt.WinWaitActive("SAP Logon 720") autoIt.ControlClick "SAP Logon 720","","[CLASS:Button; INSTANCE:7]" if testingEnv="LC0" Then autoIt.ControlSend "SAP Logon 720","","[CLASS:Edit; INSTANCE:1]","lc0" end if if testingEnv="LC2" Then autoIt.ControlSend "SAP Logon 720","","[CLASS:Edit; INSTANCE:1]","lc2[d" end if autoIt.send "{Enter}" If IsObject(WScript) Then WScript.sleep 8000 Set session = connection.Children(0) WScript.ConnectObject session, "on" WScript.ConnectObject application, "on" End If WScript.sleep 5000 session.findById("wnd[0]").maximize End Function
根据总体架构的设计,需要把录制好的脚本进行数据和action分离,数据文件独立存入XML中, vbs脚本启动SAP Client,并从XML获得参数执行自动化。
''' include common functions Dim currentScriptDir currentScriptDir=getDirOfCurrentScript() include currentScriptDir&"\"&"CommonFunctions.vbs" filename = Split(wscript.scriptname, ".") ' initialzie Init(filename(0)) '开始执行脚本,并创建和脚本同名的log文件 xmlNode_this = "/data/"&filename(0)&"/" '定义在DataSource中找相同名节点 ''''''''''''''''''''' common for all scripts'''''''''''''''''''''''' '''''''''''''''''''''''' Login SAP'''''''''''''''''''''''''''''' CurrentRegion = GetTextFromXML(xmlNode_this,"CurrentRegion") '读所选区域 Log1("CurrentRegion:["&CurrentRegion&"]") AccountNode = "/data/Account/"&CurrentRegion&"/" loginUser = GetTextFromXML(AccountNode,"Account1") '读对应用户名 'Log in call Login(loginUser) '登录方法里call了openSAP方法 ''''''''''''''''''''''''''''Login SAP'''''''''''''''''''''''''''' '''''''''''''''''''''''''''Specific part''''''''''''''''''''''''' session.findById("wnd[0]/tbar[0]/okcd").text = "zvd01" session.findById("wnd[0]/tbar[0]/btn[0]").press session.findById("wnd[1]/usr/cmbRF02D-KTOKD").key = "ZCTR" Sales_Org = GetTextFromXML(xmlNode_this,"Sales_Org") Log1("Sales_Org:["&Sales_Org&"]") session.findById("wnd[1]/usr/ctxtRF02D-VKORG").text = Sales_Org Distribution_ Channel = GetTextFromXML(xmlNode_this,"Distribution_Channel") Log1("Distribution_Channel:["&Distribution_Channel&"]") session.findById("wnd[1]/usr/ctxtRF02D-VTWEG").text = Distribution_Channel ''''''''''''''''''''''''''''Specific part''''''''''''''''''''''''' '''''''''''''''''''' common for all scripts'''''''''''''''''''''' KillSAP() ReleaseOjbects() Function getDirOfCurrentScript() Dim scriptName scriptName = wscript.scriptfullname dataDir= left(scriptName,instrrev(scriptName,"\")-8) getDirOfCurrentScript = dataDir End Function Function include(file) ExecuteGlobal CreateObject("Scripting.FileSystemObject").OpenTextFile (file,1).ReadAll End Function '''''''''''''''''''' common for all scripts'''''''''''''''''''''
通过AutoIt生成数据文件(XML)的编辑界面,用户可以通过界面编辑脚本执行所需数据,通过XML的属性来决定在编辑界面上的显示风格。图3是Script Center的数据编辑页面,图4是对应的数据文件格式。
XML格式要求:
XML节点属性值对应的意义:
AutoIt有丰富的函数库,其中包含RunDos的命令, 可以通过命令行直接执行vbs脚本,所以在Execute按钮中包含: _RunDos("wscript "&$path&$file)
根据该解决方案,作者开发了Script center,并且在作者所在的项目组得到广泛的应用,到目前为止,使用状况良好,使用前后生产率的提高也是非常显著的。如下图所示:
图5. 使用前后的效率对比
该解决方案的优势在于:
目前Script Center已经实现了调用VBS脚本在SAP中完成数据创建的操作,使用方便,执行速度快,对笔者所在的项目来说,在SAP中准备测试数据变成了一个简单的工作,不再费时费力。当然,我们也意识到Script Center还有可以提升的空间,例如:一次创建多条类似的数据;可以设置多个脚本的执行顺序,然后依次执行;等等。相信在不久的将来,Script Center会实现这些工作,给使用者带来更多的便利。
本文主要介绍了利用AutoIt开发出来的工具Script Center,以及通过Script Center调用VBS脚本以在SAP中创建各种测试数据的过程,提出了在SAP中准备测试数据的一种新想法,期望对读者有所启发。
兰艳 IBM中国软件开发中心软件工程师。目前主要从事Web Application的自动化测试,功能测试等工作。
张俊 参与IBM软件产品的自动化测试和功能测试。
付荣 参与IBM软件产品的自动化测试和功能测试。