我们使用WatiN进行测试,我们希望在CruiseControl.NET服务器上运行。我们已经使用一个单独的构建。当我们在其他构建中启用这些测试时,它们会在同时运行时失败。我们希望避免将所有运行这些测试的构建放在同一个cc.net队列中,因为这些测试只是整个构建时间的一小部分。我们还希望避免为这些测试建立单独的构建项目,因为这会使cc.net设置中的构建量翻倍。
我们有哪些选择?
如果我们找不到任何现有的解决方案,我们可能会自己构建一些东西,如果是的话,建议使用哪种解决方案?
修改: 这是我对互斥锁的最终实现:
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();
}
}
}
答案 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();
}
}
}