when using chromedriver, with specflow, a new browser instance open per step - c#

I'm having an issue with Specflow. For some reason, a new instance of chrome is started per step.
can you help with this?
For follow test, 3 steps, 3 chrome instance are started.
Feature: Home
Background:
Given The QA Department site
Scenario: QA Department title
When QA site open
Then QA site tile must be "UI Testing Site"
The first instance has the content i want but the other two, that i don´t know why are started, are empty.
namespace QAtests.SpecFlow_Steps.Home
{
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TechTalk.SpecFlow;
[Binding]
class HomeTestSteps
{
private readonly MainPage mainPage = new MainPage();
private readonly PageHelper pageHelper = new PageHelper();
public HomeTestSteps()
{
}
[When(#"QA Department site open")]
public void GivenQADepartmentSiteOpen()
{
var url = this.mainPage.ValiteSiteAddress();
Assert.AreEqual(url, this.mainPage.siteURL);
}
[Then(#"QA Department site tile must be ""(.*)""")]
public void ThenQADepartmentSiteTileMustBe(string pageTile)
{
var title = this.pageHelper.GetElementTitle();
Assert.AreEqual(pageTile, title);
}
}
}
The main page class just sets the url and checks elements
namespace QAtests.Pages.Main
{
public class MainPage
{
private ChromeDriver driver = new ChromeDriver();
private readonly string elementTitle = "//title";
public readonly string siteURL = "http://uitest.duodecadits.com/";
public MainPage()
{
}
public void StartSite()
{
try
{
this.driver.Navigate().GoToUrl(siteURL);
}
catch (Exception e)
{
throw new Exception("Can´t set address.", e);
}
}
public void Close()
{
this.driver.Close();
}
public string ValiteSiteAddress()
{
return this.driver.Url;
}
public IWebElement ElementTitleisVisible()
{
try
{
return this.driver.FindElement(By.XPath(elementTitle));
}
catch(Exception e){
throw new Exception("Element tile not found.", e);
}
}
}
}
I think that is related with the declaration of
private ChromeDriver driver = new ChromeDriver();

You are instantiating a new ChromeDriver instance each time you instantiate a page.
As suggested, you will want to setup your webdriver in a BeforeScenario step.
Also, you could make use of the built in IOC container and register your web driver instance. Then that instance can be injected into any of your page objects, as and when they are needed.
Something like...
[Binding]
public class BaseScenarioHooks
{
protected IObjectContainer Container;
public BaseScenarioHooks(IObjectContainer container)
{
Container = container;
}
[BeforeScenario(Order = 3)]
public void SetupDrivers()
{
var webDriver = new WebDriver(browser, seleniumHub, url, Context.ScenarioInfo.Title,
Context["UniqueTestName"].ToString(), FrameworkConfiguration.VideoRecording);
Container.RegisterInstanceAs<WebDriver>(webDriver);
}
}
Have a look at https://github.com/techtalk/SpecFlow/wiki/Context-Injection.
Also have a look here for ideas on how to organize your driver class

Not seeing your thread get a lot of love here. In all honesty, I would look for a SpecFlow framework online and then start building yours out from there. SpecFlow uses hooks so you are probably going to want to invoke your browser with a BeforeScenario so that it is called once for each test. Put your cleanup in an AfterScenario hook.
If you use the nuget chromedriver and have it set always output to your bin debug folder, you can use the GetBasePath call so it always calls from that directory. You can remove the call and hard code the chromedrive.exe path though. This just makes it easier if it is going into source control.
Hopefully this will help you get started.
ex.
MyFile.cs
[BeforeScenario]
public static void Startup()
{
Browser.StartWebDriver();
}
Browser.cs
public class Browser
{
static IWebDriver _Driver;
static WebDriverWait _wait;
public static void StartWebDriver()
{
ChromeDriverService service = ChromeDriverService.CreateDefaultService(Path.Combine(GetBasePath, #"bin\Debug\"));
ChromeOptions options = new ChromeOptions();
options.AddArguments("--disable-extensions");
options.AddAdditionalCapability("useAutomationExtension", false);
options.AddExcludedArgument("enable-automation");
_Driver = new ChromeDriver(service, options);
_wait = new WebDriverWait(_Driver, TimeSpan.FromSeconds(10));
}
public static string GetBasePath
{
get
{
var basePath =
System.IO.Path.GetDirectoryName((System.Reflection.Assembly.GetExecutingAssembly().Location));
basePath = basePath.Substring(0, basePath.Length - 10);
return basePath;
}
}
}

Yes. This line
private ChromeDriver driver = new ChromeDriver();
is definitely your problem. Every time you access this property you are creating a new driver.
Here's a web hook class i use in my tests.
[Binding]
internal sealed class WebHooks
{
private readonly IObjectContainer _objectContainer;
public WebHooks(IObjectContainer objectContainer)
{
_objectContainer = objectContainer;
}
[BeforeScenario("web")]
public void BeforeWebScenario()
{
var options = new ChromeOptions();
options.AddArgument("--start-maximized");
options.AddAdditionalCapability("useAutomationExtension", false);
options.AddArgument("no-sandbox");
//HACK: this fixes issue with not being able to find chromedriver.exe
//https://stackoverflow.com/questions/47910244/selenium-cant-find-chromedriver-exe
var webDriver = new ChromeDriver(".", options);
webDriver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
_objectContainer.RegisterInstanceAs<IWebDriver>(webDriver);
}
[AfterScenario("web")]
public void AfterWebScenario()
{
var webDriver = _objectContainer.Resolve<IWebDriver>();
if (webDriver == null) return;
webDriver.Close();
webDriver.Dispose();
}
}
So this registers the webdriver with the internal SpecFlow DI container so that it can now be called in you step definitions.
Then modify your step definition class to access the webdriver as a constructor parameter
[Binding]
public class YourSteps
{
private readonly IWebDriver _webDriver;
public CanvasSteps(IWebDriver webDriver)
{
_webDriver = webDriver;
}
}
Specflow's internal DI automagically wires everything up and you should now have 1 webdriver instance per scenario. It also creates a better design because your cross-cutting concern of a webdriver instance has been extracted from your steps and placed in a Hook where is belongs. Just tag your scenario with the #web hook

Related

Migrating to NUnit from SpecRunner - Parallels Execution with Selenium

I am migrating my test framework to NUnit from SpecRunner since SpecRunner is not longer maintained.
So far i am able to run the tests in parrallel by using the assembly code [assembly: Parallelizable(ParallelScope.Fixtures)]
However I am using Selenium to run my UI tests, currently when i run the tests only one browser instance in open (just testing on Chrome) for the two tests causing one of them to fail.
In SpecRunner I could specify the number of threads by specifying them in the default.srprofile file using the testThreadCount attribute.
<Execution stopAfterFailures="0" retryFor="Failing" testThreadCount="3" testSchedulingMode="Sequential" />
And that would open 3 instances of Chrome locally on my machine, and on the CI machine.
My question is : Can I do something similar in NUnit3 to run a chrome instance per thread?
UPDATE
GetWebDriver.cs
public class GetWebDriver
{
private static TestContextModified context;
public static string url;
public static IWebDriver WebDriver(string browserName)
{
IWebDriver driver;
context = TestContextModified.GetContextInstance();
url = context.AppSetting["url"];
var seleniumHubURL = context.AppSetting["seleniumGridServer"];
switch (browserName)
{
case "IE":
try
{
if (context.AppSetting["REMOTE"] == "true")
{
InternetExplorerOptions options = new InternetExplorerOptions();
options.AddAdditionalCapability("ignoreProtectedModeSettings", true);
options.AddAdditionalCapability(CapabilityType.AcceptSslCertificates, true);
options.AddAdditionalCapability(CapabilityType.IsJavaScriptEnabled, true);
options.AddAdditionalCapability(CapabilityType.Platform,
new Platform(PlatformType.Windows));
driver = new RemoteWebDriver(
new Uri(seleniumHubURL), options.ToCapabilities(), TimeSpan.FromSeconds(600))
{ Url = url};
}
else
{
return new InternetExplorerDriver(new InternetExplorerOptions { IgnoreZoomLevel = true }) { Url = url};
}
return driver;
}
catch
{
string strCmdText;
strCmdText = #"/C cd bin\Debug&taskkill /im IEDriverServer.exe /f";
System.Diagnostics.Process.Start("CMD.exe", strCmdText);
Console.WriteLine("Deleted Chromedriver becouse Exception was raised");
return null;
}
case "Chrome":
try
{
if (context.AppSetting["REMOTE"] == "true")
{
ChromeOptions options = new ChromeOptions();
options.AddArguments("--window-size=1920,1080");
options.AddArguments("--start-maximized");
options.AddArguments("--headless");
options.AddArgument("--disable-gpu");
driver = new RemoteWebDriver(
new Uri(seleniumHubURL), options)
{ Url = url};
}
else
{
return new ChromeDriver { Url = url};
}
return driver;
}
catch
{
string strCmdText;
strCmdText = #"/C cd bin\Debug&taskkill /im chromedriver.exe /f";
System.Diagnostics.Process.Start("CMD.exe", strCmdText);
Console.WriteLine("Deleted Chromedriver becouse Exception was raised");
return null;
}
case "Firefox":
try
{
if (context.AppSetting["REMOTE"] == "true")
{
FirefoxOptions options = new FirefoxOptions();
driver = new RemoteWebDriver(
new Uri(seleniumHubURL), options);
return driver;
}
else
{
return new FirefoxDriver { Url = url};
}
}
catch
{
string strCmdText;
strCmdText = #"/C cd bin\Debug&taskkill /im geckodriver.exe /f";
System.Diagnostics.Process.Start("CMD.exe", strCmdText);
Console.WriteLine("Deleted Chromedriver becouse Exception was raised");
return null;
}
case string browser: throw new NotSupportedException($"{browser} is not a supported browser");
default: throw new NotSupportedException("not supported browser: <null>");
}
}
}
}
IntiliazeWebdriver.cs
public class IntializeWebdriver
{
public static IWebDriver driver;
public IntializeWebdriver()
{
}
public static IWebDriver webDriver()
{
if (driver == null)
{
driver = GetWebDriver.WebDriver("Chrome");
return driver;
}
else
{
return driver;
}
}
}
And then in my steps:
public class Steps: IntializeWebdriver
{
public Steps stepsTest;
private ScenarioContext scenarioContext;
public Steps(ScenarioContext _scenarioContext)
{
scenarioContext = _scenarioContext;
stepsTest= new Step(webDriver());
}
...
Kumar's answer leads you in the right direction. The web driver cannot be static, because then multiple threads (hence multiple tests) share the same instance of web driver. Instead, each scenario needs to create its own web driver instance and register it with the dependency injection framework. Unfortunately with how your code is currently, this will involve a good amount of refactoring. Despite this being a moderate amount of work, it is worth the effort.
Initialize web driver in a [BeforeScenario] hook (see SpecFlow docs):
[Binding]
public class SpecFlowHooks
{
private readonly IObjectContainer container;
public SpecFlowHooks(IObjectContainer container)
{
this.container = container;
}
[BeforeScenario]
public void CreateWebDriver()
{
// Initialize whichever web driver you want to use, however
// you want to initialize it
var driver = new ChromeDriver(...);
// Register the web driver with SpecFlow's dependency injection framework
container.RegisterInstanceAs<IWebDriver>(driver);
}
}
Refactor step definition classes to accept an IWebDriver object as a constructor parameter:
[Binding]
public class YouStepDefinitions
{
private readonly IWebDriver driver;
public YouStepDefinitions(IWebDriver driver)
{
this.driver = driver;
}
[Given("...")]
public void GivenX()
{
driver.FindElement(...)
}
}
This ensures you initialize one web driver per scenario, which should allow your tests to run in parallel.
At the end of the test, you can use an [AfterScenario] hook to destroy the driver and even take a screenshot:
[Binding]
public class SpecFlowHooks
{
private readonly IObjectContainer container;
...
[AfterScenario]
public void CreateWebDriver()
{
var driver = container.Resolve<IWebDriver>();
var photographer = (ITakeScreenShot)driver;
// take screenshot with 'photographer' variable
driver.Quit();
driver.Dispose();
}
}
Looks like this line is causing issue :-
public static IWebDriver driver;
Can you try by not making this static? I remember that I faced issue in parallel execution via Nunit when the driver was static.

From a LightBDD Decorator, how to retrieve the scenario's current ChromeDriver from the DependencyResolver?

I'm using LightBDD to run Selenium tests and I'm trying to automatically take a screenshot whenever a scenario fails. I wrote a class-level LightBDD Decorator to do this but I retrieve a new instance of the ChromeDriver from the ResourcePool instead of retrieving the current ChromeDriver.
How can retrieve the scenario's current ChromeDriver instead of a new instance?
More Details
I'm registering the ChromeDriver as in the provided example, i.e.:
private void ConfigureContainer(ContainerConfigurator config)
{
config.RegisterInstance(
new ResourcePool<ChromeDriver>(CreateDriver),
new RegistrationOptions());
}
private ChromeDriver CreateDriver()
{
var driver = new ChromeDriver();
driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromMilliseconds(0);
return driver;
}
My Decorator:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class TakeScreenshotOnErrorAttribute : Attribute, IScenarioDecoratorAttribute
{
public async Task ExecuteAsync(IScenario scenario, Func<Task> scenarioInvocation)
{
try {
await scenarioInvocation();
}
catch (Exception ex) {
await TakeScreenshot(scenario);
}
}
public int Order { get; set; }
private static async Task TakeScreenshot(IScenario scenario)
{
try {
var driverHandle = scenario.DependencyResolver.Resolve(typeof(ResourceHandle<ChromeDriver>));
var driver = await ((ResourceHandle<ChromeDriver>) driverHandle).ObtainAsync();
var screenshot = driver.GetScreenshot();
screenshot.SaveAsFile(#"c:\temp\error.png");
}
catch {
/* Ignore */
}
}
}
The debugger clearly shows that a second instance is created:
Version: LightBDD 3.0.1 with NUnit3
The default behavior of LightBDD DI container is to provide a new instance of the requested dependency every time Resolve() method is called.
To make it working as expected a more advanced DI has to be used (like LightBDD.Autofac package) and ResourceHandle<ChromeDriver> has to be registered with a scope lifetime:
public class ConfiguredLightBddScopeAttribute : LightBddScopeAttribute
{
protected override void OnConfigure(LightBddConfiguration configuration)
{
configuration.DependencyContainerConfiguration()
.UseAutofac(ConfigureContainer());
}
private ContainerBuilder ConfigureContainer()
{
var builder = new ContainerBuilder();
builder.RegisterInstance(new ResourcePool<ChromeDriver>(CreateDriver));
builder.RegisterType<ResourceHandle<ChromeDriver>>().InstancePerLifetimeScope();
// ^-- this makes the difference
return builder;
}
private ChromeDriver CreateDriver()
{
var driver = new ChromeDriver();
driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromMilliseconds(0);
return driver;
}
}
It would mean that while each scenario will get own copy of the handle, the scenario code and the decorator code will get the same instance.
I have provided the working example in a response on the LightBDD issues page: https://github.com/LightBDD/LightBDD/issues/186

Why am I unable to create an object of my class outside stepdefinition

I am just automating a website using SpecFlow+Selenium+pageObject.
When i initialize an object of my SignIn class then i am getting null pointer exception. I tried inside constructor of LoginTest Class(Step definition file) but same error then i moved to first step definition then it is working. The new issue is that i cant use the same object in 2nd step definition since it is initialized locally.
I am adding my code , please tell me what mistake i am making in over all script.
namespace UnitTestProject5.Pages
{
public class SignIn
{
public IWebDriver driver;
[FindsBy(How = How.XPath, Using ("//nav[#role='navigation']/div[3]/div[1]/div/div/div/ul/li[5]/a"))]
public IWebElement Login { get; set; }
public IWebElement Username;
public IWebElement Password;
public IWebElement Signin;
public SignIn(IWebDriver driver)
{
this.driver = driver;
}
public void LoginToMyAccount(String username,String password)
{
Username.SendKeys(username);
Password.SendKeys(password);
Signin.Submit();
}
//...
}
}
And..
namespace UnitTestProject5
{
[Binding]
public class LoginTest
{
IWebDriver driver = null;
// constants con = new constants();
[Given(#"Go to website")]
public void GivenGoToWebsite()
{
driver =new FirefoxDriver();
driver.Navigate().GoToUrl("https://xero.com");
SignIn sin = new SignIn(driver);
PageFactory.InitElements(driver, sin);
sin.Clicklogin();
}
[Given(#"Enter user name & password")]
public void GivenEnterUserNamePassword()
{
sin.
}
[When(#"I press submit")]
public void WhenIPressSubmit()
{
Console.WriteLine("hello");
}
[Then(#"i should be my landing page")]
public void ThenIShouldBeMyLandingPage()
{
Console.WriteLine("hello");
}
}
}
Feature / Scenario:
Feature: Successful Login
Scenario: Successful Login
Given Go to website
And Enter user name & password
When I press submit
Then i should be my landing page
I believe that you're losing the variable between each given-when-then scenario contexts. Each of the methods "Given-When-Then" are executed in a static context and any variables you may have defined in the class are lost between the calls to them. The proper way to adress this is to use the ScenarioContext and FeatureContext objects. Pseudo example below:
:
[Given("Something nice")]
public void WhenIStartSomething()
{
// Add an inspector to the current context
var currentPageInspector = ScenarioContext.Current.Set("PageInspector", new PageInspector());
// Construct other stuff
ScenarioContext.Current.Add("signInInstance", SignIn(...));
}
[When("I do something planned")]
public void WhenIDoSomethingPlanned()
{
var signIn = ScenarioContext.Current.Get<SignIn>();
// do the action with signIn
}
[Then("I should see the following result")]
public void ThenIShouldSeeTheFollowingResult()
{
var currentPageInspector = ScenarioContext.Current.Get<PageInspector>();
currentPageInspector.CurrentPage.Title.ShouldEqual("My Landing Page");
}
What you're basically doing is creating a static instance of your PageInspector and SignIn objects that ONLY EXIST as part of the scenario that they are running in. If you have a different scenario where you repeat any of the steps, the ScenarioContext will ensure that you have a different static context for the objects there.

How do I start kestrel from a test?

I'm setting up regression testing for my ASP.NET 5 project using beta8. When I setup the test fixtures I want to fire up kestrel so that I could run selenium tests against it without the need for any external web server. How do I do this?
It's basically something like this:
public class RegressionTests : IDisposable
{
public RegressionTests()
{
// Start kestrel
}
[Fact]
public void Test1()
{
Assert.True(true);
// more tests...
}
public void Dispose()
{
// Shutdown kestrel
}
}
This is what I've tried so far but I couldn't get it to work. It doesn't pick up the project.json file. Well, to be honest, I don't know what to pass to it since I can't find anywhere what command args I can pass to Microsoft.AspNet.Hosting.Program.
new Microsoft.AspNet.Hosting.Program(CallContextServiceLocator.Locator.ServiceProvider).Main(
new[]
{
"--server",
"Microsoft.AspNet.Server.Kestrel",
"--project",
"../Web/project.json",
"--port",
"5001",
});
Thanks #Victor Hurdugaci. For the google folks of the future, this is what I ended up having. This is a test fixture that I use for xunit. The TestConfiguration class is missing but you should get the idea. You need to add a dependency on Microsoft.AspNet.Server.Testing.
public class WebTestsFixture : IDisposable
{
private readonly IApplicationDeployer _deployer;
private readonly IDisposable _loggerScope;
public WebTestsFixture()
{
var logger = new LoggerFactory()
.AddConsole(LogLevel.Information)
.CreateLogger("Regression");
_loggerScope = logger.BeginScope("RegressionTestSuite");
var deploymentParameters = new DeploymentParameters(
TestConfiguration.Configuration.Get<string>("Settings:ApplicationPath"),
(ServerType)Enum.Parse(typeof(ServerType), TestConfiguration.Configuration.Get<string>("Settings:ServerType")),
RuntimeFlavor.Clr,
RuntimeArchitecture.x86)
{
ApplicationBaseUriHint = TestConfiguration.Configuration.Get<string>("Settings:ApplicationUri"),
EnvironmentName = TestConfiguration.Configuration.Get<string>("Settings:EnvironmentName"),
PublishWithNoSource = false
};
_deployer = ApplicationDeployerFactory.Create(deploymentParameters, logger);
DeploymentResult = _deployer.Deploy();
}
public DeploymentResult DeploymentResult { get; private set; }
public void Dispose()
{
_loggerScope.Dispose();
_deployer.Dispose();
}
}
#mardoxx points out that a more modern and much simpler approach to testing is documented here.

Run Selenium tests in multiple browsers with C#

I have a method that creates 2 remote web drivers. one with chrome and another with firefox:
Driver.cs
public class Driver
{
public static IWebDriver Instance { get; set; }
public static void Initialize()
{
DesiredCapabilities[] browsers = {DesiredCapabilities.Firefox(),DesiredCapabilities.Chrome()};
foreach (DesiredCapabilities browser in browsers)
{
if (browser == DesiredCapabilities.Chrome())
{
var browser = DesiredCapabilities.Chrome();
System.Environment.SetEnvironmentVariable("webdriver.chrome.driver", "C:/Users/jm/Documents/Visual Studio 2013/Projects/VNextAutomation - Copy - Copy (3)/packages/WebDriverChromeDriver.2.10/tools/chromedriver.exe");
ChromeOptions options = new ChromeOptions() { BinaryLocation = "C:/Users/jm/AppData/Local/Google/Chrome/Application/chrome.exe" };
browser.SetCapability(ChromeOptions.Capability, options);
Console.Write("Testing in Browser: " + browser.BrowserName);
Instance = new RemoteWebDriver(new Uri("http://127.0.0.1:4444/wd/hub"), browser);
} else {
Console.Write("Testing in Browser: "+ browser.BrowserName);
Instance = new RemoteWebDriver(new Uri("http://127.0.0.1:4444/wd/hub"), browser);
}
}
Instance.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(15));
}
Then I have a Test class:
[TestClass]
public class LoginTests
{
[TestInitialize]
public void Init()
{
Driver.Initialize();
}
[TestMethod]
public void Failed_login()
{
LoginPage.GoTo();
LoginPage.LoginAs("user").WithPassword("pass").WithDatasource("db").Login();
Assert.IsTrue(LoginFail.IsAt, "Login failure is incorrect");
}
[TestMethod]
public void Admin_User_Can_Login()
{
LoginPage.GoTo();
LoginPage.LoginAs("user").WithPassword("pass").WithDatasource("db").Login();
Assert.IsTrue(HomePage.IsAt, "Failed to login.");
}
[TestCleanup]
public void Cleanup()
{
Driver.Close();
}
}
}
The problem is when Driver.Intialize gets called it doesn't run both chrome and firefox. What I want to happen is that when the Init method gets called it starts both browsers and runs the Test Methods in each browser.
The way I am currently doing this is with NUnit.
I had the same problem and could not find a good way to do it with MSTest.
What I am doing would be:
As you can see I just create a new TestFixture for each browser.
[TestFixture(typeof(ChromeDriver))]
[TestFixture(typeof(InternetExplorerDriver))]
[TestFixture(typeof(FirefoxDriver))]
public class LoginTests<TWebDriver> where TWebDriver : IWebDriver, new()
{
[SetUp]
public void Init()
{
Driver.Initialize<TWebDriver>();
}
[Test]
public void Failed_login()
{
LoginPage.GoTo();
LoginPage.LoginAs("user").WithPassword("pass").WithDatasource("db").Login();
Assert.IsTrue(LoginFail.IsAt, "Login failure is incorrect");
}
[Test]
public void Admin_User_Can_Login()
{
LoginPage.GoTo();
LoginPage.LoginAs("user").WithPassword("pass").WithDatasource("db").Login();
Assert.IsTrue(HomePage.IsAt, "Failed to login.");
}
[TearDown]
public void Cleanup()
{
Driver.Close();
}
}
}
Driver Class
public class Driver<TWebDriver> where TWebDriver : IWebDriver, new()
{
public static IWebDriver Instance { get; set; }
public static void Initialize()
{
if (typeof(TWebDriver) == typeof(ChromeDriver))
{
var browser = DesiredCapabilities.Chrome();
System.Environment.SetEnvironmentVariable("webdriver.chrome.driver", "C:/Users/jm/Documents/Visual Studio 2013/Projects/VNextAutomation - Copy - Copy (3)/packages/WebDriverChromeDriver.2.10/tools/chromedriver.exe");
ChromeOptions options = new ChromeOptions() { BinaryLocation = "C:/Users/jm/AppData/Local/Google/Chrome/Application/chrome.exe" };
browser.SetCapability(ChromeOptions.Capability, options);
Console.Write("Testing in Browser: " + browser.BrowserName);
Instance = new RemoteWebDriver(new Uri("http://127.0.0.1:4444/wd/hub"), browser);
} else {
Console.Write("Testing in Browser: "+ browser.BrowserName);
Instance = new RemoteWebDriver(new Uri("http://127.0.0.1:4444/wd/hub"), browser);
}
}
Instance.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(15));
}
}
I have tried to fit it around your code.
If you wanted to be able to specify a browser to run a test on an adhoc basis rather than all of them every time using TestFixtures, Richard Bradshaw has an excellent tutorial here.
The idea is to use an app config file (and Factory Pattern) that houses values such as the browser, version, platform, selenium hub and port information (as well as any other data you might require in your Hub/Node implementation on Grid) and pull it in at the time of testing to create a WebDriver instance. You can then modify this file in between tests to spin up a WebDriver of a different type if necessary.
We use this to run tests sequentially with NUnit and it has proven quite effective.
an easier and a little bit more straight forward solution using NUnit:
namespace Test
{
//add all browser you want to test here
[TestFixture(typeof(FirefoxDriver))]
[TestFixture(typeof(ChromeDriver))]
public class SkillTest<TWebDriver> where TWebDriver : IWebDriver, new()
{
private IWebDriver _driver;
private string driverPath;
[SetUp]
public void Init()
{
_driver = new TWebDriver();
_driver.Navigate().GoToUrl("https://localhost:5001/");
}
[Test]
public void your_test_case()
{
//some test logic
} 
[TearDown]
public void CleanUp()
{
_driver.Quit();
_driver.Dispose();
}
}
}

Categories

Resources