can';当自动项目从jenkins调用时,不能在testcomplete中运行它

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

当来自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: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进程,但没有活动窗口?您是作为命名用户还是作为系统用户(例如本地系统)运行?