这可能不是您想要的,但我的 WPF 应用程序及其编码的 UI 测试也有类似的问题。就我而言,我使用的是 TFS 构建(通过 Lab 模板),它的部署获取我们构建的输出;MSI 并将其安装在目标上,然后针对已安装的软件运行测试。
现在因为我们想要针对已安装的软件进行测试,我们添加了测试初始化方法来启动我们测试的 GUI,方法是调用 MSI API 来获取安装程序中产品/组件 GUID 的安装文件夹。
这是一个代码摘录,请记住从您的安装程序中替换您的产品和组件 GUIDS)
/// <summary>
/// Starts the GUI.
/// </summary>
public void StartGui()
{
Console.WriteLine("Starting GUI process...");
try
{
var path = this.DetectInstalledCopy();
var workingDir = path;
var exePath = Path.Combine(path, "gui.exe");
//// or ApplicationUnderTest.Launch() ???
Console.Write("Starting new GUI process... ");
this.guiProcess = Process.Start(new ProcessStartInfo
{
WorkingDirectory = workingDir,
FileName = exePath,
LoadUserProfile = true,
UseShellExecute = false
});
Console.WriteLine("started GUI process (id:{0})", this.guiProcess.Id);
}
catch (Win32Exception e)
{
this.guiProcess = null;
Assert.Fail("Unable to start GUI process; exception {0}", e);
}
}
/// <summary>
/// Detects the installed copy.
/// </summary>
/// <returns>The folder in which the MSI installed the GUI feature of the cortex 7 product.</returns>
private string DetectInstalledCopy()
{
Console.WriteLine("Looking for install directory of CORTEX 7 GUI app");
int buffLen = 1024;
var buff = new StringBuilder(buffLen);
var ret = NativeMethods.MsiGetComponentPath(
"{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}", // YOUR product GUID (see WiX installer)
"{YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY}", // The GUI Installer component GUID
buff,
ref buffLen);
if (ret == NativeMethods.InstallstateLocal)
{
var productInstallRoot = buff.ToString();
Console.WriteLine("Found installation directory for GUI.exe feature at {0}", productInstallRoot);
return productInstallRoot;
}
Assert.Fail("GUI product has not been installed on this PC, or not for this user if it was installed as a per-user product");
return string.Empty;
}
/// <summary>
/// Stops the GUI process. Initially by asking nicely, then chopping its head off if it takes too long to leave.
/// </summary>
public void StopGui()
{
if (this.guiProcess != null)
{
Console.Write("Closing GUI process (id:[{0}])... ", this.guiProcess.Id);
if (!this.guiProcess.HasExited)
{
this.guiProcess.CloseMainWindow();
if (!this.guiProcess.WaitForExit(30.SecondsAsMilliseconds()))
{
Assert.Fail("Killing GUI process, it failed to close within 30 seconds of being asked to close");
this.guiProcess.Kill();
}
else
{
Console.WriteLine("GUI process closed gracefully");
}
}
this.guiProcess.Close(); // dispose of resources, were done with the object.
this.guiProcess = null;
}
}
这是 API 包装器代码:
/// <summary>
/// Get the component path.
/// </summary>
/// <param name="product">The product GUI as string with {}.</param>
/// <param name="component">The component GUI as string with {}.</param>
/// <param name="pathBuf">The path buffer.</param>
/// <param name="buff">The buffer to receive the path (use a <see cref="StringBuilder"/>).</param>
/// <returns>A obscure Win32 API error code.</returns>
[DllImport("MSI.DLL", CharSet = CharSet.Unicode)]
internal static extern uint MsiGetComponentPath(
string product,
string component,
StringBuilder pathBuf,
ref int buff);