在单个CruiseControl.NET服务器上使用WatiN测试运行并行构建

时间:2011-09-05 08:14:51

标签: cruisecontrol.net watin

我们使用WatiN进行测试,我们希望在CruiseControl.NET服务器上运行。我们已经使用一个单独的构建。当我们在其他构建中启用这些测试时,它们会在同时运行时失败。我们希望避免将所有运行这些测试的构建放在同一个cc.net队列中,因为这些测试只是整个构建时间的一小部分。我们还希望避免为这些测试建立单独的构建项目,因为这会使cc.net设置中的构建量翻倍。

我们有哪些选择?

  1. 有没有办法将这些测试放在自己的cc.net任务中并将该任务放在队列中?
  2. 是否有任何msbuild / nant / ccnet任务或处理排队的任何事情?
  3. 是否有任何命令行工具可以从我们的msbuild脚本运行,该脚本处理命令行任务的排队,以便我们可以使用nunit命令行调用来运行我们的测试?
  4. 这个问题还有其他智能解决方案吗?
  5. 如果我们找不到任何现有的解决方案,我们可能会自己构建一些东西,如果是的话,建议使用哪种解决方案?

    修改: 这是我对互斥锁的最终实现:

    public class SystemLevelLock : IDisposable
    {
        private readonly string _id;
        private bool _isAquired;
        private Mutex _mutex;
    
        public SystemLevelLock(string id)
        {
            _id = id;
            Aquire();
        }
    
        public SystemLevelLock() : this(GetApplicationId()) { }
    
        private void Aquire()
        {
            try
            {
                var mutex = GetMutex();
                _isAquired = mutex.WaitOne(TimeSpan.FromMinutes(1), false);
                if (!_isAquired)
                    throw new Exception("System level mutex could not be aquired");
            }
            catch (AbandonedMutexException)
            {
                // Mutex was abandoned by another process (it probably crashed)
                // Mutex was aquired by this process instead
            }
        }
    
        private Mutex GetMutex() { return _mutex ?? (_mutex = MakeMutex()); }
    
        private Mutex MakeMutex()
        {
            var mutexId = string.Format("Global\\{{{0}}}", _id);
            var allowEveryoneRule = new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow);
            var securitySettings = new MutexSecurity();
            securitySettings.AddAccessRule(allowEveryoneRule);
            var mutex = new Mutex(false, mutexId);
            mutex.SetAccessControl(securitySettings);
            return mutex;
        }
    
        private void Release()
        {
            if (_isAquired)
                _mutex.ReleaseMutex();
        }
    
        public void Dispose() { Release(); }
    
    }
    

    这是使用互斥锁的Browser类实现。这也是使用SpecFlow scenariocontext存储浏览器实例并锁定此场景。

    public static class Browser
    {
    
        public static IE Current
        {
            get
            {
                if (!IsStarted())
                    Start();
                return ScenarioBrowser;
            }
        }
    
        private static IE ScenarioBrowser
        {
            get
            {
                if (ScenarioContext.Current.ContainsKey("browser"))
                    return ScenarioContext.Current["browser"] as IE;
                return null;
            }
            set
            {
                if (value == null)
                {
                    if (ScenarioContext.Current.ContainsKey("browser"))
                        ScenarioContext.Current.Remove("browser");
                }
                else
                    ScenarioContext.Current["browser"] = value;
            }
        }
    
        private static IDisposable BrowserLock
        {
            get
            {
                if (ScenarioContext.Current.ContainsKey("browserLock"))
                    return ScenarioContext.Current["browserLock"] as IDisposable;
                return null;
            }
            set
            {
                if (value == null)
                {
                    if (ScenarioContext.Current.ContainsKey("browserLock"))
                        ScenarioContext.Current.Remove("browserLock");
                }
                else
                    ScenarioContext.Current["browserLock"] = value;
            }
        }
    
        private static void LockBrowser()
        {
            BrowserLock = MakeBrowserLock();
        }
    
        private static void ReleaseBrowser()
        {
            BrowserLock.Dispose();
            BrowserLock = null;
        }
    
        private static SystemLevelLock MakeBrowserLock() { return new SystemLevelLock("WatiNBrowserLock"); }
    
        private static void Start()
        {
            LockBrowser();
            var browser = new IE();
            ScenarioBrowser = browser;
        }
    
        public static bool IsStarted() { return ScenarioBrowser != null; }
    
        public static void Close()
        {
            try
            {
                var browser = ScenarioBrowser;
                ScenarioBrowser = null;
                browser.Close();
                browser.Dispose();
            }
            finally
            {
                ReleaseBrowser();
            }
        }
    
    }
    

1 个答案:

答案 0 :(得分:1)

看起来您的测试并非孤立。您需要确保在自己的隔离环境中设置和运行测试。测试是否依赖于共享资源?测试/服务器/网址等?

由于您的IE是共享资源(您确定它不是网站)。也许您可以使用在名为mutex的系统级别上等待的自定义任务暂停该过程。

编辑: 这是我(MatteS)最终实现的互斥体:

public class SystemLevelLock : IDisposable
{
    private readonly string _id;
    private bool _isAquired;
    private Mutex _mutex;

    public SystemLevelLock(string id)
    {
        _id = id;
        Aquire();
    }

    public SystemLevelLock() : this(GetApplicationId()) { }

    private void Aquire()
    {
        try
        {
            var mutex = GetMutex();
            _isAquired = mutex.WaitOne(TimeSpan.FromMinutes(1), false);
            if (!_isAquired)
                throw new Exception("System level mutex could not be aquired");
        }
        catch (AbandonedMutexException)
        {
            // Mutex was abandoned by another process (it probably crashed)
            // Mutex was aquired by this process instead
        }
    }

    private Mutex GetMutex() { return _mutex ?? (_mutex = MakeMutex()); }

    private Mutex MakeMutex()
    {
        var mutexId = string.Format("Global\\{{{0}}}", _id);
        var allowEveryoneRule = new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow);
        var securitySettings = new MutexSecurity();
        securitySettings.AddAccessRule(allowEveryoneRule);
        var mutex = new Mutex(false, mutexId);
        mutex.SetAccessControl(securitySettings);
        return mutex;
    }

    private void Release()
    {
        if (_isAquired)
            _mutex.ReleaseMutex();
    }

    public void Dispose() { Release(); }

}

这是使用互斥锁的Browser类实现。这也是使用SpecFlow scenariocontext存储浏览器实例并锁定此场景。

public static class Browser
{

    public static IE Current
    {
        get
        {
            if (!IsStarted())
                Start();
            return ScenarioBrowser;
        }
    }

    private static IE ScenarioBrowser
    {
        get
        {
            if (ScenarioContext.Current.ContainsKey("browser"))
                return ScenarioContext.Current["browser"] as IE;
            return null;
        }
        set
        {
            if (value == null)
            {
                if (ScenarioContext.Current.ContainsKey("browser"))
                    ScenarioContext.Current.Remove("browser");
            }
            else
                ScenarioContext.Current["browser"] = value;
        }
    }

    private static IDisposable BrowserLock
    {
        get
        {
            if (ScenarioContext.Current.ContainsKey("browserLock"))
                return ScenarioContext.Current["browserLock"] as IDisposable;
            return null;
        }
        set
        {
            if (value == null)
            {
                if (ScenarioContext.Current.ContainsKey("browserLock"))
                    ScenarioContext.Current.Remove("browserLock");
            }
            else
                ScenarioContext.Current["browserLock"] = value;
        }
    }

    private static void LockBrowser()
    {
        BrowserLock = MakeBrowserLock();
    }

    private static void ReleaseBrowser()
    {
        BrowserLock.Dispose();
        BrowserLock = null;
    }

    private static SystemLevelLock MakeBrowserLock() { return new SystemLevelLock("WatiNBrowserLock"); }

    private static void Start()
    {
        LockBrowser();
        var browser = new IE();
        ScenarioBrowser = browser;
    }

    public static bool IsStarted() { return ScenarioBrowser != null; }

    public static void Close()
    {
        try
        {
            var browser = ScenarioBrowser;
            ScenarioBrowser = null;
            browser.Close();
            browser.Dispose();
        }
        finally
        {
            ReleaseBrowser();
        }
    }

}