Reputation: 45
So as we know when you use SpecFlow if you reuse a step from another test it automatically pulls it in and reuses it... however, I have the issue whereby Test A logs me in and test B logs in and confirms the home page is correct but as test A is initialising ChromeDriver when I come to use Test B my Driver wants to open another webpage causing the test to fail as its open an empty webpage.
My question is - How do I use the driver without it opening another instance of Chrome. Here is what I have code wise for my 'generic login:'
private LandingPageCode landingPage;
private HomePageCode HomePage;
[Given(@"I have entered my username, password selected login")]
public void GivenIHaveEnteredMyUsernamePasswordSelectedLogin()
{
driver = new ChromeDriver();
driver.Url = ("my URL");
landingPage = new LandingPageCode(driver);
HomePage = new HomePageCode(driver);
The code I have on test B which validates the homepage once logged in:
{
private ChromeDriver driver;
private HomePageCode HomePage;
private LandingPageCode landingPage;
[Given(@"Successfully log into Cal's website (.*)")]
public void GivenSuccessfullyLogIntoOptix(Decimal p0)
{
driver = new ChromeDriver();
HomePage = new HomePageCode(driver);
landingPage = new LandingPageCode(driver);
driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(5);
Assert.AreEqual("HomePage", driver.Title);
Upvotes: 2
Views: 3510
Reputation: 18868
I see this question or related ones very frequently (How to properly manage and access webdriver instances to avoid problems with parallel execution of tests?). Integrating Selenium and SpecFlow can be tricky. You need to leverage the dependency injection framework that comes with SpecFlow, and use before and after scenario hooks to initialize the web driver, then register it with the dependency injection container. Later on in your step definition classes, you need to specify a constructor for those classes that accepts an IWebDriver
object as a constructor parameter, and assign it to a field on each step definition class.
[Binding]
public class WebDriverHooks
{
private readonly IObjectContainer container;
public WebDriverHooks(IObjectContainer container)
{
this.container = container;
}
[BeforeScenario]
public void CreateWebDriver()
{
// or new FirefoxDriver or new WhateverDriver as long as it implements
// the IWebDriver interface
ChromeDriver driver = new ChromeDriver();
// Make 'driver' available for DI
container.RegisterInstanceAs<IWebDriver>(driver);
}
[AfterScenario]
public void DestroyWebDriver()
{
var driver = container.Resolve<IWebDriver>();
if (driver != null)
{
driver.Quit();
driver.Dispose();
}
}
}
And a sample step definition file:
[Binding]
public class LoginSteps
{
private readonly IWebDriver driver;
private readonly LoginPage loginPage;
public LoginSteps(IWebDriver driver)
{
// Assign 'driver' to private field or use it to initialize a page object
this.driver = driver;
// Initialize Selenium page object
this.loginPage = new LoginPage(driver);
}
[When(@"I go to the login page")]
public void WhenIGoToTheLoginPage()
{
// Use 'driver' in step definition
driver.FindElement(By.LinkText("Sign In")).Click();
}
[When(@"I log in")]
public void WhenILogIn()
{
// Use Selenium page object in step definition
loginPage.LogIn("testUser", "testPassword");
}
}
This not only allows you to share web driver instances across step definition files, but it centralizes the logic of creating and disposing of these objects, and brings you one step closer allowing parallel tests execution.
See also: Context Injection on SpecFlow.org.
Upvotes: 2
Reputation: 125
You could remove your driver code from your tests and set up a framework for your code to run on. Using NUnit, you could develop a framework for yourself to run the tests in parallel. There are tones of online tutorials for this. [https://nunit.org/][1]
You could create a driver.cs class that looks like this which pulls the base URL from a config class.:
public static class Driver
{
public static IWebDriver driver = new ChromeDriver();
public static void InitializedDriver()
{
Driver.driver.Navigate().GoToUrl(Config.BaseURL);
Driver.driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(5);
}
}
Then in your test class, you can use OneTimeSetUp to initialise your web driver:
[OneTimeSetUp]
public void Initialize()
{
Driver.InitializedDriver();
}
After your test codes, you can then tear down using:
[OneTimeTearDown]
public void CleanUp()
{
Driver.driver.Quit();
}
This would allow your tests to run on the same Chrome instance.
Upvotes: 0