最近又开始弄一些自动化测试的东西,所以在这总结一下。
其实以前也零零散散做过一些自动化的测试,但是基本上都是在一套现有的框架上面做一些相对来说比较简单的开发,但这一次没有框架,没有任何技术支持。还好,要做的东西不难,所以一个人应付下来了。
自动化测试核心部分之一就是要模拟用户的输入,主要有三个方面:
模拟键盘输入
键盘输入其实就是调用系统的API函数
VOID keybd_event( BYTE bVk, BYTE bScan, DWORD dwFlags, DWORD dwExtraInfo);
有了这个函数,只要我们知道你想模拟的键的Virtual Code,你就可以模拟敲键了,具体的Virtual Code可以查阅MSDN手册。这其中有一点点小问题,那就是对PC来说,Virtual Code很容易一一确定,但是在Windows Mobile来说,就不那么显而易见了,比如说那两个软件分别是VK_F1和VK_F2,而那个Center键则是VK_RETURN。当时我就是琢磨了不少时间才确定这些虚拟码,最简洁的办法就是自己写一个程序捕捉一下这些键到底是啥,不要瞎猜,嘿嘿~
模拟文本输入
上面说的模拟键盘输入确实可以模拟输入一些ASCI码值,比如你要输入英文,那绝对没有问题,只需一个一个的发送Virtual Code就行了,但是如果要输入Unicode比如中文什么的,那就不行了,因为keybd_event中的bVk参数本身就是BYTE类型的,应该不可能传送Unicode,所以只能用另外一个办法,就是向你想输入的窗口发送WM_CHAR消息,所以问题就是我们如何得到目标窗口的句柄。由于所测App与我们的自动化测试程序不在同一个线程,所以我们没法直接找到那些窗口,这里我采用了另外一种方法,因为通常情况下目标窗口都是当前的Focused的窗口,所以只要我们能用GetFocus这个API那就可以得到句柄了,但是不同线程之间是没有共享Input Status的,所以我们首先要通过AttachThreadInput这个API来把测试程序所在的Thread attach到Focused窗口所在的Thread,然后再调用GetFocus就可以达到我们的目的了。下面是一段C代码:
Code
// Get the fore ground window.
HWND foreWindow = GetForegroundWindow();
// Get the id of the thread the foreground window belongs to.
DWORD focusedThreadID = GetWindowThreadProcessId(foreWindow, NULL);
// Get the current thread id, our test program.
DWORD currentThreadID = GetCurrentThreadId();
// Attach our test thread to the thread the focused window belongs to.
AttachThreadInput(currentThreadID, focusedThreadID, TRUE);
// Get the handle of the focused window.
HWND focusedWindow = GetFocus();
// Now you can send the wide char to the focused window.
const wchar_t text = L'捕';SendMessage(focusedWindow, WM_CHAR, LPARAM(text), NULL);
需要说明的是,在Windows Mobile上面你不能这么做,因为WinMobile不支持AttachThreadInput这个函数。于是我找到了另外一个API
BOOL WINAPI GetForegroundInfo( GET_FOREGROUND_INFO* pgfi);
通过这个函数可以得到一个GET_FOREGROUND_INFO结构体,里面包含了很多有用的信息
Code
typedef struct tagGetForegroundInfo {
HWND hwndActive;
HWND hwndFocus;
HWND hwndMenu;
HWND hwndKeyboardDest;
DWORD fdwConversion;
DWORD fdwSentence;
BOOL fOpen;
DWORD dwCompStrLen;
HKL KeyboardLayoutHandle;
}GET_FOREGROUND_INFO;
其中hwndFocus就是我们想要的,但是不能高兴太早,这个函数似乎我们用不了,因为MSDN告诉我们“This function is only available to OEMs.”。无情的打击啊,不过柳暗花明的是在Windows Mobile Test Frameworkh中,微软提供了一个.NET DLL封装了这个函数,所以……嘿嘿~对了,那个DLL叫做Microsoft.WindowsCE.Win32API.dll,下面是一段C#代码
Code
1 public static void Input(string text){
2 GET_FOREGROUND_INFO info = new GET_FOREGROUND_INFO();
3 Win32.GetForegroundInfo(out info);
4 IntPtr focusedWindowHandle = new IntPtr(info.hwndFocus);
5 char[] txt = text.ToCharArray();
6 foreach (char c in txt){
7 SendChar(focusedWindowHandle, WM_CHAR, c, 0);
8 }
9 }
10 [DllImport("coredll.dll", SetLastError = true)]
11 private static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
12 [DllImport("coredll.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
13 private static extern int SendChar(IntPtr hwnd, int msg, int c, int lParam);
14 private const int WM_CHAR = 0x0102;
模拟鼠标输入
同键盘输入类似,模拟鼠标输入也有一个非常好的API
VOID mouse_event( DWORD dwFlags, DWORD dx, DWORD dy, DWORD dwData, DWORD dwExtraInfo );用法也非常简单,只是有一点需要注意的是鼠标有自己的坐标,X,Y轴都是从0到65535,所以,如果你想在某个像素位置点击的话,别忘了转换一下坐标,下面是一个模拟鼠标拖拽的C#方法
Code
public static void Drag(int fromX, int fromY, int toX, int toY)
{
if (fromX < 0 || fromX > (SCREEN_WIDTH - 1))
{
return;
}
if (fromY < 0 || fromY > (SCREEN_HEIGHT - 1))
{
return;
}
if (toX < 0 || toX > (SCREEN_WIDTH - 1))
{
return;
}
if (toY < 0 || toY > (SCREEN_HEIGHT - 1))
{
return;
}
Point from = ScreenToMouse(fromX, fromY);
Point to = ScreenToMouse(toX, toY);
MouseEvent(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE, from.X, from.Y, 0, 0);
MouseEvent(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
MouseEvent(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE, to.X, to.Y, 0, 0);
MouseEvent(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
}
private static Point ScreenToMouse(int x, int y)
{
x = x < 0 ? 0 : x;
x = x > (SCREEN_WIDTH - 1) ? (SCREEN_WIDTH - 1) : x;
y = y < 0 ? 0 : y;
y = y > (SCREEN_HEIGHT - 1) ? (SCREEN_HEIGHT - 1) : y;
Point mouse = new Point();
mouse.X = x * 65535 / SCREEN_WIDTH;
mouse.Y = y * 65535 / SCREEN_HEIGHT;
return mouse;
}
[DllImport("coredll.dll", EntryPoint = "mouse_event")]
private static extern int MouseEvent(int dwFlags, int dx, int dy, int dwData, int dwExtraInfo);
private const int MOUSEEVENTF_LEFTDOWN = 0x0002;
private const int MOUSEEVENTF_LEFTUP = 0x0004;
private const int MOUSEEVENTF_MOVE = 0x0001;
private const int MOUSEEVENTF_ABSOLUTE = 0x8000;
private const int SCREEN_WIDTH = 240;
private const int SCREEN_HEIGHT = 320;
知道了怎么拖拽,要实现点击啥的就简单了吧,哈哈~
总结完了~
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/Joey_ZengChen/archive/2008/04/09/2269037.aspx