我有一个应用程序我正在尝试编写自动UI测试。 这是一个本机C ++ ATL应用程序,它有几个控件和一个MenuBar。用C#编写的自动化客户端应用程序可以看到菜单栏,但没有明显的原因,用IronRuby编写的等效应用程序不能。
我的C#控制台应用程序可以枚举主窗口的子项,它会看到MenuBar ...这是代码
var desktop = AutomationElement.RootElement;
var walker = TreeWalker.RawViewWalker;
var mainWindow = desktop.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "TheWindowName"));
var child = walker.GetFirstChild(mainWindow);
do
{
Console.WriteLine(child.Inspect());
child = walker.GetNextSibling(child);
}
while (child != null);
---- Output ----
<Static Name="view:" AutomationId="4337">
<Static Name="[ALL]" AutomationId="4341">
<Button Name="View" AutomationId="4322">
<AtlAxWinLic100 Name="" AutomationId="1101">
<ATL:msctls_statusbar32 Name="" AutomationId="StatusBar">
< Name="TheWindowName" AutomationId="TitleBar">
< Name="Application" AutomationId="MenuBar">
但是,当我使用IronRuby(v1.1.3)编写等效代码时,不会列出TitleBar和MenuBar控件!
desktop = AutomationElement.RootElement;
walker = TreeWalker.RawViewWalker;
mainWindow = desktop.FindFirst(TreeScope.Children, PropertyCondition.new(AutomationElement.NameProperty, "TheWindowName".to_clr_string));
child = walker.GetFirstChild(mainWindow);
until child.nil? do
Console.WriteLine(Inspect(child));
child = walker.GetNextSibling(child);
end
---- Output ----
<Static Name="view:" AutomationId="4337">
<Static Name="[ALL]" AutomationId="4341">
<Button Name="View" AutomationId="4322">
<AtlAxWinLic100 Name="" AutomationId="1101">
<ATL:msctls_statusbar32 Name="" AutomationId="6872212">
正如您所看到的,ClassName属性为空字符串的项目未显示(并且还注意状态栏上的AutomationId不同)...但为什么????
此处未显示的唯一代码是using namespace stuff ...
任何想法会导致什么?我的C#app和IronRuby都有一个单独的线程,它是STA,就我所知,它都没有调用CoInitializeSecurity。
PS:对这些问题的通常回答是为Windows XP,Vista,server2003等安装MS UI自动化3.0更新。我在Windows 7上运行,据我所知,没有UIA更新对于Windows 7PPS:这是Inspect方法的代码,对于ruby和C#都是相同的(足够接近)
public static string Inspect(this AutomationElement element)
{
var className = element.GetCurrentPropertyValue(AutomationElement.ClassNameProperty);
var name = element.GetCurrentPropertyValue(AutomationElement.NameProperty);
var id = element.GetCurrentPropertyValue(AutomationElement.AutomationIdProperty);
return String.Format("<{0} Name=\"{1}\" AutomationId=\"{2}\">", className, name, id);
}
答案 0 :(得分:1)
预感后,我启用了Fusion日志,并注意到我的C#应用程序正在加载UIAutomationClientSideProviders.dll
,但我的IronRuby应用程序却没有。反射器显示此DLL包含一大堆Windows组件提供程序,因此看起来很可疑。
我的下一步是从IronRuby显式加载该DLL,它没有做任何事情。
然后我查看了ClientSide提供程序的工作方式 - 您需要调用ClientSettings.RegisterClientSideProviderAssembly
来注册包含提供程序的程序集。当我尝试这样做时,我得到以下异常:
UIAutomationClient:0:in `RegisterProxyAssembly': 'UIAutomationClientsideProviders' assembly not found.
(System::Windows::Automation::ProxyAssemblyNotLoadedException)
from UIAutomationClient:0:in `LoadDefaultProxies'
from UIAutomationClient:0:in `RegisterWindowHandlers'
from UIAutomationClient:0:in `RegisterClientSideProviders'
返回反射器以查看LoadDefaultProxies
的代码。我不会复制/粘贴代码,但它基本上是这样做的:
UIAutomationClient
程序集。UIAutomationClientsideProviders
程序集UIAutomationClient
醇>
这解释了它的工作原理:
我的控制台应用程序明确引用UIAutomationClient
,因此获取完整的公钥令牌等,并可以从GAC加载ClientSideProviders dll
IronRuby没有明确的引用,因为它都是动态的,因此它只使用没有公钥令牌等的字符串名称加载,因此无法使用GAC。
一旦我发现了这一点,我就将UIAutomationClientsideProviders.dll
复制到我的IronRuby bin目录中(因此它将在加载路径中),而且确实有效。
您不需要显式加载任何内容,IronRuby只需要能够加载UIAutomationClientsideProviders.dll
而无需公钥令牌或版本信息,而且一切都很好。
为避免复制内容,以下代码使用AssemblyResolve
事件返回正确的程序集
require 'UIAutomationClientSideProviders, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL'
System::AppDomain.current_domain.assembly_resolve do |sender, args|
args.name == "UIAutomationClientsideProviders" ?
UIAutomationClientsideProviders::UIAutomationClientSideProviders.to_clr_type.assembly :
nil
end