在上次完成基础的界面测试后,我进行了进一步的探索
首先是官方提供的WinAppDriverUiRecorder,里面使用的函数FindElementByAbsoluteXPath其实是自定义函数
本质是使用循环多次使用FindElementByXPath查找目标
这里给出官方给的类
//******************************************************************************
//
// Copyright (c) 2019 Microsoft Corporation. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//******************************************************************************
using System;
using OpenQA.Selenium.Appium.Windows;
using OpenQA.Selenium.Remote;
namespace test
{
public class DesktopSession
{
protected const string WindowsApplicationDriverUrl = "http://127.0.0.1:4723";
private const string Paint3DAppId = "C:\\Users\\hasee\\source\\repos\\888\\mian\\TrainingSoftware\\bin\\Debug\\TrainingSoftware.exe";
WindowsDriver<WindowsElement> desktopSession;
public DesktopSession()
{
DesiredCapabilities appCapabilities = new DesiredCapabilities();
appCapabilities.SetCapability("app", Paint3DAppId);
appCapabilities.SetCapability("deviceName", "WindowsPC");
desktopSession = new WindowsDriver<WindowsElement>(new Uri(WindowsApplicationDriverUrl), appCapabilities);
}
~DesktopSession()
{
desktopSession.Quit();
}
public WindowsDriver<WindowsElement> DesktopSessionElement
{
get { return desktopSession; }
}
public WindowsElement FindElementByAbsoluteXPath(string xPath, int nTryCount = 100)
{
WindowsElement uiTarget = null;
while (nTryCount-- > 0)
{
try
{
uiTarget = desktopSession.FindElementByXPath(xPath);
}
catch
{
}
if (uiTarget != null)
{
break;
}
else
{
System.Threading.Thread.Sleep(0);
}
}
return uiTarget;
}
}
}
但是实际一点用处也没有,实际测试下来,10次都不一定有一次能获取到目标,运行时间长且获取几率低,建议不要使用
所以获取窗口内控件建议还是使用FindElementByAccessibilityId配合控件name使用
但是这个类可以用来整合初始化变量代码,减少重复代码,所以可以用这个类
然后是遇到弹出输入框后进程阻塞的问题
事实证明课程之间是有关联性的,我在做界面测试的时候,发现点击按钮弹出输入框后程序会阻塞住,不继续往下执行,这时要对输入框操作程序才能继续走下去,但是进程阻塞不动了执行代码,这时我想起了操作系统的多进程的思路,用另外一个进程来操作输入框,但此时出现了一个新的问题,因为主进程阻塞了,所以窗口被占用,无法用WinAppDriver进行操作,这时我想起了Windows编程的思路,通过窗口句柄和消息循环的机制来操作弹出窗口,最终解决弹出窗口这一问题
在开头添加下面代码
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);//获取窗口句柄
[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(int hWnd, int Msg, int wParam, string lParam);//发送消息
[DllImport("User32.dll ")]
public static extern IntPtr FindWindowEx(int parent, int childe, string strclass, string FrmText);//获取控件句柄
const int WM_SETTEXT = 0x000C;
const int WM_LBUTTONDOWN = 0x0201;
const int WM_LBUTTONUP = 0x0202;
const int WM_CLOSE = 0x0010;
const int WM_QUIT = 0x0012;
可查看这篇文章https://blog.csdn.net/bobui/article/details/7896965
然后附上我的使用方法,我写了注释,应该能看的懂
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
using ku;
using mian;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium.Appium.Windows;
using OpenQA.Selenium.Remote;
namespace test
{
[TestClass]
public class InterfaceTest
{
static DesktopSession desktopSession = new DesktopSession();
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(int hWnd, int Msg, int wParam, string lParam);
[DllImport("User32.dll ")]
public static extern IntPtr FindWindowEx(int parent, int childe, string strclass, string FrmText);
const int WM_SETTEXT = 0x000C;
const int WM_LBUTTONDOWN = 0x0201;
const int WM_LBUTTONUP = 0x0202;
const int WM_CLOSE = 0x0010;
const int WM_QUIT = 0x0012;
[TestMethod]
public void TestAddSpaceButtonSuccess()
{
//添加题库
var AddSpaceButtonSuccess = desktopSession.DesktopSessionElement.FindElementByAccessibilityId("AddSpaceButton");
new Thread(SuccessTest) { IsBackground = false }.Start();//创建多线程
Assert.IsNotNull(AddSpaceButtonSuccess);
AddSpaceButtonSuccess.Click();//点击创建,此时会弹出一个输入框,主进程阻塞
}
static void SuccessTest()
{
Thread.Sleep(2000);//先休眠等待主进程弹出输入框
IntPtr HwndFirst = FindWindow(null, "建立题库");//获取输入框窗口句柄,"建立题库"为窗口名字
Assert.IsNotNull(HwndFirst);//判断是否为空
IntPtr HtextBoxFirst = FindWindowEx((int)HwndFirst, 0, null, "");//获取输入框控件句柄,“”为控件名称,可使用inspect.exe进行查看,使用方法为打开inspect.exe然后鼠标移动到控件处就能查看到控件的信息,其中name就是名称
Assert.IsNotNull(HtextBoxFirst);
SendMessage((int)HtextBoxFirst, WM_SETTEXT, 0, "233");//发送信息进行输入
Thread.Sleep(1000);
IntPtr HbuttonFirst = FindWindowEx((int)HwndFirst, 0, null, "确定");//获取确定按钮句柄
Assert.IsNotNull(HbuttonFirst);
SendMessage((int)HbuttonFirst, WM_LBUTTONDOWN, 0, null);//发送信息模拟点击
SendMessage((int)HbuttonFirst, WM_LBUTTONUP, 0, null);
}
}
}
然后是在主窗口弹出另外一个窗口的情况
这个情况下进程不会阻塞但是无法使用WinAppDriver来获取弹出窗口的控件
这时候就使用句柄的方式进行操作就行了
这里放下我的代码,和上方代码类似,只是没使用多线程
using System;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace test
{
[TestClass]
public class OtherWindows
{
static DesktopSession desktopSession = new DesktopSession();
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(int hWnd, int Msg, int wParam, string lParam);
[DllImport("User32.dll ")]
public static extern IntPtr FindWindowEx(int parent, int childe, string strclass, string FrmText);
const int WM_SETTEXT = 0x000C;
const int WM_LBUTTONDOWN = 0x0201;
const int WM_LBUTTONUP = 0x0202;
const int WM_CLOSE = 0x0010;
const int WM_QUIT = 0x0012;
[TestMethod]
public void TestMethod1()
{
//弹出回答问题窗口
var AddSpaceButtonSuccess = desktopSession.DesktopSessionElement.FindElementByAccessibilityId("a0");
Assert.IsNotNull(AddSpaceButtonSuccess);
AddSpaceButtonSuccess.Click();//AnswerQustion
IntPtr HwndFirst = FindWindow(null, "NewQustion");//获取输入框窗口句柄,"NewQustion"为窗口名字
Assert.IsNotNull(HwndFirst);//判断是否为空
IntPtr HbuttonFirst = FindWindowEx((int)HwndFirst, 0, null, "回答问题");//获取回答问题按钮句柄
Assert.IsNotNull(HbuttonFirst);
SendMessage((int)HbuttonFirst, WM_LBUTTONDOWN, 0, null);//发送信息模拟点击
SendMessage((int)HbuttonFirst, WM_LBUTTONUP, 0, null);
Thread.Sleep(4000);
}
}
}