现在的位置: 首页 > 综合 > 正文

.Net软件UI界面测试自动化–Windows API

2014年03月19日 ⁄ 综合 ⁄ 共 6241字 ⁄ 字号 评论关闭

       在目前进行软件测试时,都或多或少的引入了自动化测试的概念,而且市面上也有好多软件自动化方面相关的工具,比如QTP,比如LoadRunner,但是这些工具要么售价不菲,要么对某些方面功能支持的不够全面,那么我们在引入软件自动化测试时,都需要考虑哪些方面呢?当然是最符合自己项目的工具最合适,同时费用也比较低,那么除了市面上这些商业软件外,还有没有哪些方法可以自己动手来做软件的自动化测试呢?答案是肯定的.

      本文将介绍实现软件自动化测试其中一种测试方法------Windows API技术,当然,此种方法仅限于对.Net软件使用,还有一些比较通用的方法,将在后续的文章中进行介绍(使用UIAutomation类).

      反射技术具体是什么原理,本文将不做任何介绍,大家可以去网上搜索一下,有很多这方面的文章介绍,本文只介绍如何使用Windows API技术进行.NET软件的UI界面的自动化测试.

      废话少说,多做实事!(本文所有代码均在VS2008环境下测试通过)

      一. 创建待测试程序

          1. 启动VS2008,建立一个C#的WinForm工程,并将工程文件名命名为AUT(Application Under Test)

          2. 创建的Form上的按钮布局,如下图所示

              

          3. 一个菜单(包含一个以及菜单File以及一个二级菜单Exit),一个TextBox,一个ComboBox,一个Button以及一个ListBox

        private System.Windows.Forms.MenuStrip menuStrip1;  
        private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem;  
        private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem;  
        private System.Windows.Forms.TextBox textBox1;  
        private System.Windows.Forms.ComboBox comboBox1;  
        private System.Windows.Forms.Button button1;  
        private System.Windows.Forms.ListBox listBox1;  

              4. 给Button按钮添加一个消息响应函数    

        private void button1_Click(object sender, EventArgs e)  
        {  
            string tb = textBox1.Text;  
            string cb = comboBox1.Text;  
  
            if (tb == cb)  
            {  
                listBox1.Items.Add("Result is a tie");  
            }  
            else if (tb == "paper" && cb == "rock" ||  
                     tb == "rock" && cb == "scissors" ||  
                     tb == "scissors" && cb == "paper")  
            {  
                listBox1.Items.Add("The TextBox wins");  
            }  
            else  
            {  
                listBox1.Items.Add("The ComboBox wins");  
            }  
        }  

           5. 给Exit菜单添加一个消息响应函数       

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)  
        {  
            Application.Exit();  
        }  

          6.给ComboBox控件添加三个Item,分别为paper,rock,scissions

        7. 编译待测试程序,生成文件名为AUT.exe的待测试程序

      二. 创建测试程序  
        1. 启动VS2008,创建一个C#控制台程序,并命名为WindowsUITest

        2. 在工程中添加以下using语句

      using System;
      using System.Diagnostics;
      using System.Runtime.InteropServices;
      using System.Threading;
      using System.IO;
      using System.Text;

        3. 声明需要使用到的WIndows API

        [DllImport("user32.dll", EntryPoint = "FindWindow", CharSet = CharSet.Auto)]
        static extern IntPtr FindWindow(string lpClassName, string lpWindowsName);

        [DllImport("user32.dll", EntryPoint = "FindWindowEx", CharSet = CharSet.Auto)]
        static extern IntPtr FindWindowEx(IntPtr hwndParent, 
                                          IntPtr hwndChildAfter,
                                          string lpszClass,
                                          string lpszWindow);

        //用于发送WM_CHAR消息
        [DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
        static extern void SendMessage1(IntPtr hWnd, uint Msg, int wParam, int lParam);

        //用于发送WM_COMMAND消息
        [DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
        static extern void SendMessage2(IntPtr hWnd, uint Msg, int wParam, IntPtr lParam);

        //用于发送WM_GETTEXT消息
        [DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
        static extern int SendMessage3(IntPtr hWndControl, uint Msg, int wParam, byte[] lParam);

        //用于发送LB_FINDSTRING消息
        [DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
        static extern int SendMessage4(IntPtr hWnd, uint Msg, int wParam, byte[] lParam);

        //用于发送WM_LBUTTONDOWN和WM_LBUTTONUP消息
        [DllImport("user32.dll", EntryPoint="PostMessage", CharSet=CharSet.Auto)]
        static extern bool PostMessage1(IntPtr hWnd, uint Msg, int wParam, int lParam);

        //菜单函数相关
        [DllImport("user32.dll")]
        static extern IntPtr GetMenu(IntPtr hWnd);
        [DllImport("user32.dll")]
        static extern IntPtr GetSubMenu(IntPtr hMenu, int nPos);
        [DllImport("user32.dll")]
        static extern int GetMenuItemID(IntPtr hMenu, int nPos);

        4. 定义查询窗体的函数

        static IntPtr FindTopLevelWindow(string caption, int delay, int maxTries)
        {
            IntPtr mwh = IntPtr.Zero;
            bool formFount = false;
            int attempts = 0;
            
            do 
            {
                mwh = FindWindow(null, caption);
                if (mwh == IntPtr.Zero)
                {
                    Console.WriteLine("Form not yet found");
                    Thread.Sleep(delay);
                    ++attempts;
                }
                else
                {
                    Console.WriteLine("Form has been found");
                    formFount = true;
                }
            } 
            while (!formFount && attempts < maxTries);

            if (mwh != IntPtr.Zero)
            {
                return mwh;
            }
            else
            {
                throw new Exception("Could not found Main Window");
            }            
        }

        static IntPtr FindMainWindowHandle(string caption, int delay, int maxTries)
        {
            return FindTopLevelWindow(caption, delay, maxTries);
        }

        static IntPtr FindMessageBox(string caption)
        {
            int delay = 100;
            int maxTries = 25;

            return FindTopLevelWindow(caption, delay, maxTries);
        }

        static IntPtr FindWindowByIndex(IntPtr hwndParent, int index)
        {
            if (index == 0)
            {
                return hwndParent;
            }
            else
            {
                int ct = 0;
                IntPtr result = IntPtr.Zero;

                do 
                {
                    result = FindWindowEx(hwndParent, result, null, null);
                    if (result != IntPtr.Zero)
                    {
                        ++ct;
                    }
                } 
                while (ct < index && result != IntPtr.Zero);

                return result;
            }
        }

        5.  定义发送字符串/字符的函数

        static void SendChar(IntPtr hControl, char c)
        {
            uint WM_CHAR = 0x0102;

            SendMessage1(hControl, WM_CHAR, c, 0);
        }

        static void SendChars(IntPtr hControl, string s)
        {
            foreach (char c in s)
            {
                SendChar(hControl, c);
            }
        }

        6. 定义点击鼠标按钮的函数

        static void ClickOn(IntPtr hControl)
        {
            uint WM_LBUTTONDOWN = 0x0201;
            uint WM_LBUTTONUP = 0x0202;

            PostMessage1(hControl, WM_LBUTTONDOWN, 0, 0);
            PostMessage1(hControl, WM_LBUTTONUP, 0, 0);
        }

        7. 编写测试代码

        [STAThread]
        static void Main(string[] args)
        {
            try
            {
                Console.WriteLine("\nLaunching application under test");

                string path = Directory.GetCurrentDirectory() + "\\AUT.exe";
                Process p = Process.Start(path);

                Thread.Sleep(2000);

                Console.WriteLine("\nFinding main window handle");
                IntPtr mwh = FindMainWindowHandle("Form1", 100, 25);
                Console.WriteLine("Main window handle = " + mwh);

                Thread.Sleep(2000);
                
                //因为测试程序是使用C#创建的,所以控件的Class名称会比较奇怪,可以使用SPY++工具来查看
                IntPtr tb = FindWindowEx(mwh, IntPtr.Zero, "WindowsForms10.EDIT.app.0.378734a", "");
                IntPtr cb = FindWindowEx(mwh, IntPtr.Zero, "WindowsForms10.COMBOBOX.app.0.378734a", "");
                IntPtr bt = FindWindowEx(mwh, IntPtr.Zero, null, "button1");
                IntPtr lb = FindWindowEx(mwh, IntPtr.Zero, "WindowsForms10.LISTBOX.app.0.378734a", "");                

                if (tb == IntPtr.Zero || cb == IntPtr.Zero ||
                    bt == IntPtr.Zero || lb == IntPtr.Zero)
                {
                    throw new Exception("Unable to find all controls");
                }
                else
                {
                    Console.WriteLine("All control handles found");
                }

                //设置数据
                SendChars(tb, "paper");
                SendChars(cb, "rock");

                ClickOn(bt);
                Thread.Sleep(1000);

                uint LB_FINDSTRING = 0x018F;
                byte[] bResult = Encoding.ASCII.GetBytes("The TextBox wins");
                int result = SendMessage4(lb, LB_FINDSTRING, -1, bResult);

                //uint WM_GETTEXT = 0x000D;

                if (result >= 0)
                {
                    Console.WriteLine("\nTest scenario result = Pass");
                }
                else
                {
                    Console.WriteLine("\nTest scenario result = Fail");
                }

                Console.WriteLine("\nExiting app in 3 seconds...");
                Thread.Sleep(3000);
                IntPtr hMainMenu = GetMenu(mwh);
                //IntPtr hMainMenu = FindWindowEx(mwh, IntPtr.Zero, "WindowsForms10.Window.8.app.0.378734a", null);
                IntPtr hFile = GetSubMenu(hMainMenu, 0);
                int iexit = GetMenuItemID(hFile, 0);
                uint WM_COMMAND = 0x0111;
                SendMessage2(mwh, WM_COMMAND, iexit, IntPtr.Zero);

                Console.WriteLine("\nDone");
                Console.ReadLine();
            }
            catch (System.Exception ex)
            {
            	
            }
        }

        8.  编译测试程序,OK,大功告成


抱歉!评论已关闭.