持续集成实践:使用Visual Studio 2010 Coded UI Test 制作能自动安装/卸载UI应用的程序
前言
Coded UI Test是Visual Studio 2010对于Testing Project(测试工程)提供的关于UI自动化测试的框架,支持Win32/Web/WPF等UI的自动化测试,在介绍它之前,先简单介绍一下持续集成。大家如果对持续集成不感兴趣的话,可以直接跳到第3节。
1:持续集成
持续集成由软件工程大师Martin Fowler提出,他对技术集成下的定义是:持续集成是一种软件开发实践,即团队开发成员经常集成它们的工作,通常每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽快地发现集成错误。
按照持续集成的思想,代码可以也应该能够在一天里可以多次通过“构建”,从而能在一天之内提供多个可供测试的版本。
这里面讲的构建不单单是代码的编译通过,它应该包含下面的步骤:
- 所有最新代码从配置管理工具中取出.
- 所有的代码从干净的状态开始编译。
- 将编译结果链接并部署,以备执行。
- 执行部署的应用并运行测试套件。
如果上述所有操作没有任何错误,没有人工干预,并通过了所有测试,才认为这是一次成功的构建。
对于第4步而言,如果应用程序是一个需要安装到桌面的UI应用,那么就需要保证它可以成功的部署,这样才能提供可以测试的环境。
2:我的持续集成实践
我公司使用敏捷开发,使用CruiseControl进行代码控制,当代码被Check In 后, 会自动编译,并生成一个压缩后的exe文件,然而而当需要测试该exe文件时,需要手工从文件服务器下载,然后手工卸载已有的程序,再运行该exe安装新的程序,确保安装后的程序/服务正确运行后,方能进行软件的测试。
也就是说,我们已经实现了前三步的自动化,而最后一步,由于涉及UI界面、服务卸载,一直没有能够自动化,这其中的一个难点就是该exe是一个较庞大且复杂的压缩程序,在安装时可以使用十分灵活多样的配置,每一样配置都会导致不同的安装结果,如果要把所有常用的安装方式自动化,编程的代价比较大。
在了解了Visual Studio 2010提供的Coded UI test功能后,以上问题初步得以解决,从而在技术层面,使用较小的C#代码就完成了UI界面安装、服务卸载等问题,从而将上述第四步与前面的三步串联起来,初步满足了持续集成的要求。
最后形成的大致步骤是
1:开发人员提交代码
2:编译服务器开始编译,并在文件服务器上生成installer,并发出通知
3:C#程序去文件服务器下载installer,拷贝至测试服务器
4:C#程序卸载测试服务器上的原程序/服务
5:C#程序根据测试需要/测试参数安装installer,直到完成部署进行
6:C#程序调动自动化脚本(QTP/SilkTest/Seleium),进行自动化测试
7:检查测试结果
第3-6步都是由一个C#程序完成的,下面我主要介绍一下第5步,也就是软件自动安装的实现原理,在掌握了自动安装之后,第4步,也就是软件的自动卸载也就同样得到解决了。
3: Coded UI test使用
Coded UI Test是对UI进行的测试,使用方法和很多支持UI自动化测试的工具(QTP、SilkTest)一样,都支持UI的录制、回放、识别、断言,与这类工具相比,它主要还有如下的好处:
1:基于.Net framework,且同时支持Win32/Web/WPF,利于代码的扩展和复用
2:可以编译成exe文件,脱离Visual Studio运行。
3:除了支持Web/Win应用外,还支持WPF(很多自动化工具对WPF的支持并不是太好)。
3.1 录制一个Coded UI test测试
一个复杂的installer,除了有复杂的安装配置之外,UI界面往往也比较复杂,在不了解Coded UI test这个办法之前,如果专门为installer写一个控制安装程序会是一件比较费时费力的工作,特别是当这个installer有多个设置窗口和控件时。而使用Coded UI test则可以非常轻松的解决这些问题,代码也便于扩展。
下面以notepad++这个大家常用的小工具的安装来说明如果建立一个Coded UI Test(由于我的Visual Studio 2010是英文版的,所以只能提供英文截图和英文名称),在进入下文之前,建议大家再实际下载、运行一下notepad++的安装程序,体验它每一个窗口的功能,以及支持的多种参数设置,并思考如果不使用自动化工具,如何编程实现程序的安装。
我在示例中使用的版本是5.9.6,大家可以去其官方主页http://notepad-plus-plus.org/ 下载5.9.6的版本npp.5.9.6.Installer.exe。
下面是具体的步骤
1:打开Visual Studio 2010,新建一个类型是Test的工程,如下图
2:删掉自动生成的第一个默认类
3:右击工程,选择Add,然后选择Coded UI Test,这时会弹出一个窗口,在此选择第一项“录制一个新测试”,点击OK按钮
4:此时,在窗口的右下角会弹出一个名为Coded UI Test Builder的窗口,点击第一个红色圆形按钮后,便可以进行一个UI测试的录制,如下图
5:在资源管理器中运行notepad++的安装程序,任意设置安装参数,逐个点击Next按钮,最后直至安装完成。
6:点击窗口右下侧Coded UI Test Builder窗口中第4个按钮,在弹出的窗口中将方法名称修改为DoInstall,然后点击Add and Generate按钮,稍等片刻后,整个程序便会生成了,这时可以关闭Coded UI Test Builder窗口。
7:生成后的工程结构如下图所示:
其中CodedUITest1.cs是测试类,而UIMap.uitest则包含了notepad++每个窗口的声明,以及安装的具体步骤,例如DoInstall的主体部分便是具体的每一步操作:
// Click 'OK' button
Mouse.Click(uIOKButton, new Point(40, 10));
// Click '&Next >' button
Mouse.Click(uINextButton, new Point(40, 7));
// Click 'I &Agree' button
Mouse.Click(uIIAgreeButton, new Point(40, 7));
// Click '&Next >' button
Mouse.Click(uINextButton, new Point(40, 7));
// Click '&Next >' button
Mouse.Click(uINextButton, new Point(40, 7));
// Select 'Create Shortcut on Desktop' check box
uICreateShortcutonDeskCheckBox.Checked = this.DoInstallParams.UICreateShortcutonDeskCheckBoxChecked;
// Click '&Install' button
Mouse.Click(uIInstallButton, new Point(40, 10));
// Clear '&Run Notepad++ v5.9.6' check box
uIRunNotepadv596CheckBox.Checked = this.DoInstallParams.UIRunNotepadv596CheckBoxChecked;
// Click '&Finish' button
Mouse.Click(uIFinishButton, new Point(41, 6));
8:如果现在按F5,程序无法运行,原因是这段代码里没有运行notepad++安装程序的代码,只是假设安装程序已经运行了,所以我们要在第一个Click动作前面加上下面的代码
string installer = @"c:\share\npp.5.9.6.Installer.exe";
ApplicationUnderTest InstallerWindow = pplicationUnderTest.Launch(installer);
现在再按F5试试?应该可能运行一个完整的安装了。
程序说明:
1:在录制第一个操作时,系统已经自动将每一个涉及到的UI界面及其包含的元素加以识别,并记录每一次的操作(点击、键入等),当生成代码时,会把这些东东全部输出下来。
要想查看每一个界面元素的定义,大家可以选择任意一个元素,然后按F12,查看它的声明,并进一步查看它所成的窗口的定义。
例如第一个被点击的按钮uIOKButton,它位于UIInstallerLanguageWindow中,而UIInstallerLanguageWindow则是依靠SearchProperties属性具体定位的。
2:我们点击按钮、选中CheckBox,对应的操作就是Mouse.Click或者某CheckBox.Checked,如果我们有复杂的安装需求,可以按照这样的思路进行定制。
3:在实际的安装或者参数的设置时,往往有某些控件不可见/不可用,只有满足了某种条件才会可见/ 可用。就象本文的例子中,对于正在进行安装的窗口,其Next按钮是不可用的,见下图:
该按钮会在安装完成后可用,如果程序在这时要点击这个Next按钮,会导致程序报错,这时怎么办呢?
按照很多人的编程习惯,往往会用sleep(5)来解决,但这也有问题,不同的计算机性能不同, 在一台计算机上设置好的时间,在另外一台上可能过短,如果把时间设足够长,又会导致效率下降。
Coded UI Test提供了一系列方法处理这类问题,如下:
WaitForControlCondition():控件满足某种条件后再往下执行
WaitForControlEnabled():控件有效后再往下执行
WaitForControlExist():控件可以被找到后再往下执行
WaitForControlNotExist():控件不存在时再往下执行
WaitForControlPropertyEqual():控件的某个属性等于等值后再往下执行
WaitForControlPropertyNotEqual():控件的某个属性不等于等值后再往下执行
WaitForControlReady():控件准备就序后再往下执行
这样,对上同样例子中的倒数第二行代码,在程序安装时,由于要花费一定的时间,uIRunNotepadv596CheckBox所处的窗口还没有显现,uIRunNotepadv596CheckBox自然还无效,因此,对于性能较的计算机,执行到这句话时可能出错,为了保险,可以在之前增加一行代码:
uIRunNotepadv596CheckBox. WaitForControlReady();
然后再执行后面的:
uIRunNotepadv596CheckBox.Checked = this.DoInstallParams.UIRunNotepadv596CheckBoxChecked;
就可以保证该控件是在有效的情况下执行后面的操作了。
4:控件的名称、窗口的名称都是程序自动生成的,如果觉得命名不好,可以用Visual Studio 提供的重构-改名功能进行替换。
5:程序的入口是public void CodedUITestMethod1(),默认是无参数的,如果需要在安装中设置复杂的参数,以及把安装程序的路径传递进去,可以在此增加参数,然后把参数传递到具体的执行方法DoInstall()
3.2 让程序脱离Visual Studio执行
以上的代码只能Visual Studio中运行,要想让它脱离Visual Studio也能运行,需要做如下操作。
1:增加一个类,假设名称是TestMagager,加入如下代码
public static void Init()
{
if (!Playback.IsInitialized)
{
Playback.Initialize();
}
}
2:新建另一个工程(可以是Windows,也或以是类库),引用上述的测试工程,然后在代码先中调Init(),然后直接调用安装的主程序,如下:
TestMagager.Init();
CodedUITest1 t = new CodedUITest1();
t.CodedUITestMethod1();
3:这个新建的工程编译成功后,理论上调用上述的代码可以进行软件的安装,但此时会报错误,提示所需要的DLL文件不存在,其原因是:
对于Test类工程,Visual Studio 可以找到依赖的DLL文件,然而被引用由其它的程序调用后,便不能找到这些文件,只要手工把它们拷贝到一个统一的目录,然后引用到新建的工程就可以了,这些文件是:
Microsoft.VisualStudio.QualityTools.CodedUITestFramework.dll
Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll
Microsoft.VisualStudio.QualityTools.UnitTestFramework.xml
Microsoft.VisualStudio.TestTools.TestSettings.Common.dll
Microsoft.VisualStudio.TestTools.TestSettings.dll
Microsoft.VisualStudio.TestTools.UITest.CodeGeneration.dll
Microsoft.VisualStudio.TestTools.UITest.CodeGeneration.xml
Microsoft.VisualStudio.TestTools.UITest.Common.dll
Microsoft.VisualStudio.TestTools.UITest.Common.xml
Microsoft.VisualStudio.TestTools.UITest.Extension.dll
Microsoft.VisualStudio.TestTools.UITest.Extension.IE.Communication.Interop.dll
Microsoft.VisualStudio.TestTools.UITest.Extension.IE.dll
Microsoft.VisualStudio.TestTools.UITest.Extension.MSAA.dll
Microsoft.VisualStudio.TestTools.UITest.Extension.Uia.dll
Microsoft.VisualStudio.TestTools.UITest.Extension.xml
Microsoft.VisualStudio.TestTools.UITest.Framework.dll
Microsoft.VisualStudio.TestTools.UITest.Playback.dll
Microsoft.VisualStudio.TestTools.UITest.Recorder.dll
Microsoft.VisualStudio.TestTools.UITesting.dll
Microsoft.VisualStudio.TestTools.UITesting.dll
在Visual Studio的安装目录下搜索,可以找到这些文件,它们分别存储在\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies和
\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\PublicAssemblies目录下,把它们拷到一个目录中,然后在应用中全部引用,便可以运行新建的这个工程了。
3.3 示例程序
Coded UI Test程序地址是:点击这里
解压缩后,一共有两个文件夹,第一个是Coded UI Test工程,第二个是Winform对它的调用。
因为偷懒,所有Project的文件全是系统默认的,生成的代码也没有重构,Coded UI Test工程用硬代码的方式运行Notepad++的安装程序(c:\share\ npp.5.9.6.Installer.exe),建议大家以参考代码结构为主,自己动手来建立一个类似的运行程序。
如果大家真的要运行示例程序,需要c:\share\ npp.5.9.6.Installer.exe这个程序存在,而且在安装Visual Studio 2010时,安装对测试工程的支持。
最后再说明,我已经把英文Visual Studio 2010的dll文件拷贝到了WindowsFormsApplication1的bin\debug目录下,并且在XP环境下测试通过。
使用上面的思路,还可以实现程序的自动卸载。
后记:按照上述方法,我实现了几个应用程序(包括服务)的自动安装、卸载,从而实现了上文提到的自动部署、测试,初步实现持续集成。
本人对Coded UI Test了解也仅限于此,如有不正确的地方,欢迎批评指正,多谢!