can';当自动项目从jenkins调用时,不能在testcomplete中运行它
当来自jenkins的调用时,无法在testcomplete中运行自动化项目 在我们的持续集成部分中,项目是使用testcomplete自动化的,它是在bat文件的帮助下通过jenkins调用的can';当自动项目从jenkins调用时,不能在testcomplete中运行它,jenkins,continuous-integration,jenkins-plugins,testcomplete,Jenkins,Continuous Integration,Jenkins Plugins,Testcomplete,当来自jenkins的调用时,无法在testcomplete中运行自动化项目 在我们的持续集成部分中,项目是使用testcomplete自动化的,它是在bat文件的帮助下通过jenkins调用的 "C:\Program Files\Automated QA\TestComplete 7\Bin\TestComplete.exe " "D:\Test Complete7 Projects\ProjectInput_AllSamples\ProjecInputs.pjs" /r /p:Sample
"C:\Program Files\Automated QA\TestComplete 7\Bin\TestComplete.exe " "D:\Test Complete7 Projects\ProjectInput_AllSamples\ProjecInputs.pjs" /r /p:Samples /rt:Main "iexplore" /e
它将打开testcomplete和iexplorer,但不会填充数据(自动化)。
当我们不使用jenkins直接调用bat文件时,它工作得非常好。如果您将jenkins(主或从)作为windows服务运行,是否有任何解决方案,请确保它是作为用户而不是本地系统运行的
我们也按照Gentlesea的建议做了同样的事情,我们在Jenkins Slaves上运行TestExecute,并为设计TestComplete脚本的人员保留TestComplete许可证。根据您的描述,这听起来像是Windows中有什么东西阻止了您的测试应用程序正常工作。第二个用户可能是一个问题,但我不能确认这一点,因为我找不到任何关于它在Windows XP中如何工作的明确解释。我很确定这在WindowsVista、7、8或服务器上都不起作用,但这是因为 听起来最好的解决方案是确保您的自动化UI测试由交互用户启动。当我试图将自动测试添加到构建中时,我们在WindowsXPSP2虚拟机上使用了TestComplete7。为了以交互用户的身份开始我们的测试,我们:
- 在windows启动时让用户登录,这样就始终有一个交互式用户,这意味着有一个实际的桌面会话可以访问键盘/鼠标。我似乎记得(但目前找不到任何链接),没有交互式用户,就没有可以访问键盘/鼠标的活动桌面
- 我们编写了一个小应用程序,当交互用户登录时启动。此应用程序将查看特定文件,当该文件更改/创建时,它将读取该文件并启动应用程序。此应用程序的代码看起来有点像:
using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ApplicationStarter { class Program { // The string used to indicate that the application should quit. private const string ExitString = "exit"; // The path which is being watched for changes. private static string s_LoadFilePath; static void Main(string[] args) { try { { Debug.Assert( args != null, "The arguments array should not be null."); Debug.Assert( args.Length == 1, "There should only be one argument."); } s_LoadFilePath = args[0]; { Console.WriteLine( string.Format( CultureInfo.InvariantCulture, "Watching: {0}", s_LoadFilePath)); } if (File.Exists(s_LoadFilePath)) { RunApplication(s_LoadFilePath); } using (var watcher = new FileSystemWatcher()) { watcher.IncludeSubdirectories = false; watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName; watcher.Path = Path.GetDirectoryName(s_LoadFilePath); watcher.Filter = Path.GetFileName(s_LoadFilePath); try { watcher.Created += OnConfigFileCreate; watcher.EnableRaisingEvents = true; // Now just sit here and wait until hell freezes over // or until the user tells us that it has string line = string.Empty; while (!string.Equals(line, ExitString, StringComparison.OrdinalIgnoreCase)) { line = Console.ReadLine(); } } finally { watcher.Created -= OnConfigFileCreate; } } } catch (Exception e) { Console.WriteLine(e); } } private static void RunApplication(string configFilePath) { var appPath = string.Empty; var arguments = string.Empty; using (var reader = new StreamReader(configFilePath, Encoding.UTF8)) { appPath = reader.ReadLine(); arguments = reader.ReadLine(); } // Run the application StartProcess(appPath, arguments); } private static void StartProcess(string path, string arguments) { var startInfo = new ProcessStartInfo(); { startInfo.FileName = path; startInfo.Arguments = arguments; startInfo.ErrorDialog = false; startInfo.UseShellExecute = true; startInfo.RedirectStandardOutput = false; startInfo.RedirectStandardError = false; } Console.WriteLine( string.Format( CultureInfo.InvariantCulture, "{0} Starting process {1}", DateTime.Now, path)); using (var exec = new Process()) { exec.StartInfo = startInfo; exec.Start(); } } private static void OnConfigFileCreate( object sender, FileSystemEventArgs e) { Console.WriteLine( string.Format( CultureInfo.InvariantCulture, "{0} File change event ({1}) for: {2}", DateTime.Now, e.ChangeType, e.FullPath)); // See that the file is there. If so then start the app if (File.Exists(e.FullPath) && string.Equals(s_LoadFilePath, e.FullPath, StringComparison.OrdinalIgnoreCase)) { // Wait for a bit so that the file is no // longer locked by other processes Thread.Sleep(500); // Now run the application RunApplication(e.FullPath); } } } }
C:\Program Files\Automated QA\TestComplete 7\Bin\TestComplete.exe "D:\Test Complete7 Projects\ProjectInput_AllSamples\ProjecInputs.pjs" /r /p:Samples /rt:Main "iexplore" /e
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ApplicationStarter
{
class Program
{
// The string used to indicate that the application should quit.
private const string ExitString = "exit";
// The path which is being watched for changes.
private static string s_LoadFilePath;
static void Main(string[] args)
{
try
{
{
Debug.Assert(
args != null,
"The arguments array should not be null.");
Debug.Assert(
args.Length == 1,
"There should only be one argument.");
}
s_LoadFilePath = args[0];
{
Console.WriteLine(
string.Format(
CultureInfo.InvariantCulture,
"Watching: {0}",
s_LoadFilePath));
}
if (File.Exists(s_LoadFilePath))
{
RunApplication(s_LoadFilePath);
}
using (var watcher = new FileSystemWatcher())
{
watcher.IncludeSubdirectories = false;
watcher.NotifyFilter =
NotifyFilters.LastAccess
| NotifyFilters.LastWrite
| NotifyFilters.FileName
| NotifyFilters.DirectoryName;
watcher.Path = Path.GetDirectoryName(s_LoadFilePath);
watcher.Filter = Path.GetFileName(s_LoadFilePath);
try
{
watcher.Created += OnConfigFileCreate;
watcher.EnableRaisingEvents = true;
// Now just sit here and wait until hell freezes over
// or until the user tells us that it has
string line = string.Empty;
while (!string.Equals(line, ExitString, StringComparison.OrdinalIgnoreCase))
{
line = Console.ReadLine();
}
}
finally
{
watcher.Created -= OnConfigFileCreate;
}
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
private static void RunApplication(string configFilePath)
{
var appPath = string.Empty;
var arguments = string.Empty;
using (var reader = new StreamReader(configFilePath, Encoding.UTF8))
{
appPath = reader.ReadLine();
arguments = reader.ReadLine();
}
// Run the application
StartProcess(appPath, arguments);
}
private static void StartProcess(string path, string arguments)
{
var startInfo = new ProcessStartInfo();
{
startInfo.FileName = path;
startInfo.Arguments = arguments;
startInfo.ErrorDialog = false;
startInfo.UseShellExecute = true;
startInfo.RedirectStandardOutput = false;
startInfo.RedirectStandardError = false;
}
Console.WriteLine(
string.Format(
CultureInfo.InvariantCulture,
"{0} Starting process {1}",
DateTime.Now,
path));
using (var exec = new Process())
{
exec.StartInfo = startInfo;
exec.Start();
}
}
private static void OnConfigFileCreate(
object sender,
FileSystemEventArgs e)
{
Console.WriteLine(
string.Format(
CultureInfo.InvariantCulture,
"{0} File change event ({1}) for: {2}",
DateTime.Now,
e.ChangeType,
e.FullPath));
// See that the file is there. If so then start the app
if (File.Exists(e.FullPath) &&
string.Equals(s_LoadFilePath, e.FullPath, StringComparison.OrdinalIgnoreCase))
{
// Wait for a bit so that the file is no
// longer locked by other processes
Thread.Sleep(500);
// Now run the application
RunApplication(e.FullPath);
}
}
}
}
C:\Program Files\Automated QA\TestComplete 7\Bin\TestComplete.exe
"D:\Test Complete7 Projects\ProjectInput_AllSamples\ProjecInputs.pjs" /r /p:Samples /rt:Main "iexplore" /e
您应该能够在构建步骤中从Jenkins生成此文件
最后,您可能需要观看TestComplete退出过程,以便在结束时获取结果,但我将把它作为练习留给读者。如果您有浮动许可证,您可能希望使用TestExecute来保存许可证。您运行的是什么操作系统?请注意,在Windows 7/8或Windows server上,作为服务运行(或由服务启动)的进程无法访问交互式桌面(通常)。交互式桌面是唯一可以访问键盘和鼠标的桌面,这意味着虽然TestComplete将启动,但它将无法通过应用程序的UI向应用程序提供数据。在上一份工作中,我们编写了一个帮助我们解决这个问题的工具。@Petrik windows xp SP3是否将Jenkins作为服务运行?在这两种情况下,您是否看到TestComplete和IE窗口在桌面上打开(换句话说,您是否可以使用键盘/鼠标与它们交互)?或者您只是在进程列表中看到TestComplete/IE进程,但没有活动窗口?您是作为命名用户还是作为系统用户(例如本地系统)运行?