[英]How can I make the C# .net POCO thread safe?
I am new in C# .net and I'm currently working on a Selenium C# Project that have the BrowserFactory class and have POCO named Driver.
InitBrowser 方法设置它的值。
当尝试在具有 2 个并行测试的 NUnitFramework 中使用 Parallel Test 运行测试时,它肯定会出错,因为您可以看到代码不是线程安全的,因此它无法在并行测试环境中工作。
下面是代码:
namespace SeleniumAutomationFramework.WrapperFactory {
class BrowserFactory
{
private static readonly IDictionary<string, IWebDriver> Drivers = new Dictionary<string, IWebDriver>();
private static IWebDriver driver;
public static IWebDriver Driver
{
get
{
if (driver == null)
throw new NullReferenceException("The WebDriver browser instance was not initialized. Try to call the method InitBrowser instead.");
return driver;
}
private set
{
driver = value;
}
}
public static void InitBrowser(string browserName)
{
switch(browserName.ToLower())
{
case "firefox":
driver = new FirefoxDriver();
Drivers.Add("Firefox", Driver);
break;
case "chrome":
var options = new ChromeOptions();
options.AddArguments(
"--headless",
"--no-sandbox",
"--disable-dev-shm-usage"
);
driver = new ChromeDriver(options);
Drivers.Add("Chrome", Driver);
break;
case "ie":
driver = new InternetExplorerDriver();
Drivers.Add("IE", Driver);
break;
//case "chromium":
// driver = new ChromeDriver();
// break;
default:
driver = new ChromeDriver();
Drivers.Add("Chrome", Driver);
break;
}
}
public static void LoadApplication(string url)
{
Driver.Navigate().GoToUrl(url);
}
public static void CloseAllDrivers()
{
foreach (var key in Drivers.Keys)
{
Drivers[key].Close();
Drivers[key].Quit();
}
}
} }
页面生成器 class 正在调用 Driver 属性。
namespace SeleniumAutomationFramework.PageObjects
{
public static class Page
{
private static T GetPage<T>() where T : new()
{
var page = new T();
PageFactory.InitElements(BrowserFactory.Driver, page);
return page;
}
public static HomePage Home
{
get { return GetPage<HomePage>(); }
}
public static LoginPage Login
{
get { return GetPage<LoginPage>(); }
}
}
}
我认为最好的方法是使用 Lazy class 和 ConcurrentDictionary。
但是拥有 Driver 属性的原因是什么? 如果它并行运行,则您只有最后加载的驱动程序。 因此,对于所有测试,您将使用一个驱动程序。 我认为你应该只使用 ConcurrentDictionary 并这样做
更新以更好地适应需求
我会使用的代码
class BrowserFactory
{
private static readonly ConcurrentDictionary<string, IWebDriver> Drivers = new ConcurrentDictionary<string, IWebDriver>();
private static IWebDriver InitDriver(string browserName)
{
switch (browserName.ToLower())
{
case "firefox":
return new FirefoxDriver();
case "chrome":
var options = new ChromeOptions();
options.AddArguments(
"--headless",
"--no-sandbox",
"--disable-dev-shm-usage"
);
return new ChromeDriver(options);
case "ie":
return InternetExplorerDriver();
default:
return new ChromeDriver();
}
}
public static IWebDriver GetDriver(string browserName)
{
if (!Drivers.ContainsKey(browserName))
{
var driver = InitDriver(browserName);
Drivers.TryAdd(browserName, driver);
}
return Drivers[browserName];
}
public static void LoadApplication(string browserName, string url)
{
Drivers[browserName].Navigate().GoToUrl(url);
}
// close should be called explicit by browserName or driver directly
// by closing all drivers you will broke all other still running tests
/*
public static void CloseAllDrivers()
{
foreach (var key in Drivers.Keys)
{
Drivers[key].Close();
Drivers[key].Quit();
}
}
*/
}
public abstract class PageBase
{
protected PageBase(IWebDriver driver)
{
Driver = driver;
}
protected IWebDriver Driver { get; private set; }
}
public class HomePage : PageBase
{
public HomePage(IWebDriver driver) : base(driver)
{
}
public IWebElement SomeElement => Driver.FindElement(By.CssSelector("selector"));
}
然后像这样创建页面
var page = new HomePage(BrowserFactory.GetDriver("chrome"));
我首选的解决方案是停止使用全局字段(即 static 属性/方法),而是创建一个 object 来处理所有需要此功能的组件。 您可能还想为此 object 创建一个接口。 这将允许您的单元测试使用模拟 object 而不是真实的东西。 这将避免在您运行单元测试时弹出一堆网络浏览器。
更糟糕的解决方案是在所有公共方法中添加锁定语句,
static object lockObj = new object();
public static MyPublicMethod(){
lock(lockObj){
// Logic
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.