SpecFlow + Selenium-WebDriver: Sharing a WebDriver Across Steps? - selenium

Say I have a scenario that uses steps that are contained in two different classes. Is there a way for both of them to have a handle to the same IWebDriver instance without going through ScenarioContext.Current["webdriverVariableName"]?
That's so ugly. Is there a cleaner way?
I was going to make a class with a public static IWebDriver property that gets assigned at the start of every scenario, so that all my steps could refer to it, but I don't think that will work when I start to run them in parallel, as each scenario would overwrite the global driver.

Specflow offers a Dependency Injection mecanism, so you could get your web driver instance injected in your steps.
See https://github.com/techtalk/SpecFlow/wiki/Context-Injection
See the "Avanced options" section.

I have just started using Specflow but this appears to work;
Create a class which takes IObjectContainer as a constructor and has a BeforScenario method to create the WebDriver instance;
[Binding]
public class WebDriverSupport
{
private readonly IObjectContainer _objectContainer;
public WebDriverSupport(IObjectContainer objectContainer)
{
_objectContainer = objectContainer;
}
[BeforeScenario]
public void InitializeWebDriver()
{
var webDriver = DriverFactory.CreateDriver();
_objectContainer.RegisterInstanceAs<RemoteWebDriver>(webDriver);
}
}
Create your step classes with a constructor which take RemoteWebDriver;
[Binding]
public class POCSteps
{
private readonly IdlWebDriver _driver;
public POCSteps(IdlWebDriver driver)
{
_driver = driver;
}
}
Your steps steps will now have access to a fully instantiated WebDriver object

My tests, which are currently working fine running multithreaded webdriver instances, are using a base step definitions class to hold the driver instance. All step definitions inherit from this, so the driver is available to all steps..
namespace Project.StepDefinitions
{
[Binding]
public class BaseStepDefinitions
{
private const string CurrentPageKey = "Current.Page";
public static IWebDriver Driver { get; set; }
protected LogonPageModel LogonPage
{
get { return (LogonPageModel)ScenarioContext.Current[CurrentPageKey]; }
set { ScenarioContext.Current[CurrentPageKey] = value; }
}
protected RegisterPageModel RegisterPage
{
get { return (RegisterPageModel)ScenarioContext.Current[CurrentPageKey]; }
set { ScenarioContext.Current[CurrentPageKey] = value; }
}
}
}
//////////////
namespace SpecDriver.StepDefinitions
{
[Binding]
public class LoginSteps : BaseStepDefinitions
{
[Given(#"I navigate to the homepage")]
public void GivenINavigateToTheHomepage()
{
Driver.Navigate().GoToUrl(SettingsManager.BaseUrl);
}
}
}
etc etc...

Just create a new separated class with a static property that returns driver:
static class DriverProvider
{
private static IWebDriver _driver;
public static IWebDriver Driver
{
get
{
if (_driver == null)
{
_driver = new ChromeDriver();
_driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(40);
_driver.Manage().Window.Maximize();
}
return _driver;
}
}
}
Each time you will need to do something with driver, just call it in a such way:
SomeMethod(DriverProvider.Driver);
//
IWebelement e = DriverProvider.Driver.FindElement(By.XPath("you_XPath"));
e.Click();
// etc etc etc

Related

In Page Class should the action methods have return type as class name or using void return type is a good practice?

public class HomePage {
public HomePage clickAboutUs1Link() {
aboutUs1.click();
return this;
}
public void clickAboutUs1Link() {
aboutUs1.click();
}
}
I will be calling the action method in my Test Class. So is there any advantage or disadvantage of using any one over the other when using Page Object Model with Selenium webdriver?
This question will be more clear if you had more methods. Consider those classes
public class HomePage {
public AboutUsPage clickAboutUsLinkAndGoToAboutUsPage() {
aboutUs1.click();
return new AboutUsPage();
}
public HomePage typeToField() {
aboutUs1.click();
return this;
}
public HomePage clickOnChecbox() {
aboutUs1.click();
return this;
}
}
class AboutUsPage {
public boolean isAboutUsPageDisplayed() {
return someElement.isDisplayed();
}
}
Now you can use method chaining in the test to create a flow
public class TestAboutUsLink {
boolean isDisplayed =
new HomePage()
.typeToField()
.clickOnChecbox()
.clickAboutUsLinkAndGoToAboutUsPage()
.isAboutUsPageDisplayed();
assertTrue(isDisplayed);
}
And if every method didn't return anything
public class TestAboutUsLink {
HomePage homePage = new HomePage();
homePage.typeToField();
homePage.clickOnChecbox();
homePage.clickAboutUsLinkAndGoToAboutUsPage()
AboutUsPage aboutUsPage = new AboutUsPage();
boolean isDisplayed = aboutUsPage.isAboutUsPageDisplayed();
assertTrue(isDisplayed);
}
This is subjective issue, but I find it clearer to have the test flow with implicit page objects creation (as far as the test concern) than breaking it to parts.

Where do Before and After hooks go in Cucumber

I have a fairly simple Cucumber test framework with a feature file, a step definitions file, and a test runner class that looks like this:
#RunWith(Cucumber.class)
#CucumberOptions(features = "src/test/java/com/tests/cucumber/features/ui/ExampleTest.feature",
glue = { "com.tests.cucumber.stepdefinitions" },
)
public class ExampleTestRunner {
}
This runs a scenario in the feature file just fine. Now I want to add a Before and After hook to do some setup and teardown, but I can't for the like of me get the hooks to run. I've tried adding the hooks to the ExampleTestRunner and to the StepDefinition class, but they never run. Where should I put these hooks? At the moment, the hooks just look like this, but I'll add content to them once I've worked this out!
package com.tests.cucumber.stepdefinitions;
import cucumber.api.java.After;
import cucumber.api.java.Before;
public class StepDefinitions {
#Before
public void before() {
System.out.println("starting before()");
}
}
Thanks for any help.
I am a little hesitant to answer this question even though I managed to get this to work. As far as I can tell, the problem was that I had added the Before and After methods in classes that were extended by other classes. In this situation, the tests would not run. I had to add the Before and After methods to a class that was not extended.
It feels like this is similar to the situation in which if you specify a step definition in a class that is extended by another class, then the step definition is considered to have a duplicate definition. Do I have the correct diagnosis here?
I use like this;
Runner Class:
#RunWith(Cucumber.class)
#CucumberOptions(
features = {"src\\test\\features\\ui_features"},
glue = {"com\\base\\tm\\auto_reg\\tests\\ui_tests\\price_features"},
plugin = {"com.cucumber.listener.ExtentCucumberFormatter:"}
)
public class PriceFeatureRunner {
#BeforeClass
public static void setup() {
RunnerUtil.setup(PriceFeatureRunner.class);
}
#AfterClass
public static void teardown() {
RunnerUtil.teardown();
}
}
RunnerUtil.java:
public class RunnerUtil {
public static void setup(Class<?> clazz) {
String reportPath = "target/cucumber-reports/" + clazz.getSimpleName().split("_")[0] + "_report.html";
ExtentProperties extentProperties = ExtentProperties.INSTANCE;
extentProperties.setReportPath(reportPath);
}
public static void teardown() {
UiHooks uiHooks = new UiHooks();
uiHooks.afterScenario();
ExtentReportConfiguration.configureExtentReportTeardown();
}
}
UiHooks.java
public class UiHooks implements HookHelper {
public static final String BASE_URL = "https://www.stackoverfow.com/";
private Scenario scenario;
#Override
#Before
public void beforeScenario(Scenario scenario) {
this.scenario = scenario;
Reporter.assignAuthor(System.getProperty("user.name"));
}
#Override
#After
public void afterScenario() {
if (HookUtil.driver != null) {
HookUtil.driver.quit();
}
if (HookUtil.seleniumBase != null) {
HookUtil.seleniumBase.stopService();
}
}
#Override
#After
public void afterTest() {
if (HookUtil.driver != null) {
HookUtil.driver.quit();
}
if (HookUtil.seleniumBase != null) {
HookUtil.seleniumBase.stopService();
}
}
}
HookHelper.Java
public interface HookHelper {
#Before
void beforeScenario(Scenario scenario);
#After
void afterScenario();
void afterTest();
}

How to use #DataProvider present in different class

How to use #DataProvider that is present in a different class?
I have created a different package and I have defined data providers next to each test cases. Please share how I may to use that in a different class.
You can use the dataProviderClass attribute of #Test:
public class StaticProvider {
#DataProvider(name = "create")
public static Object[][] createData() {
return new Object[][] {
new Object[] { new Integer(42) }
};
}
}
public class MyTest {
#Test(dataProvider = "create", dataProviderClass = StaticProvider.class)
public void test(Integer n) {
// ...
}
}
Check the documentation for more details.
If you have unique dataProvider method name (createData), and if you choose not to give name after DataProvider annotation as below,
#DataProvider
public Object[][] createData(){
}
Then you can use the method name as below,
#Test(dataProvider = "createData", dataProviderClass = StaticProvider.class)

Parallel execution using POM with PageFactory

I started encountering problems when I use static objects reference for WebDriver and run the tests in parallel.
public static WebDriver driver;
Hence I decided to use non-static object reference for the WebDriver.
private WebDriver driver;
Now when I use POM with Page Factory, my understanding is that everytime I create a Test I will have to be creating a new Object in the test class as shown below.
/* Constructor in the Page Object class */
private WebDriver driver;
public LoginPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
2 testcases as shown below in the same class.
private LoginPage loginPage;
#Test
public void testCase1() {
loginPage = new LoginPage(getDriver());
loginPage.sendkeys("sometext");
}
#Test
public void testCase2() {
loginPage = new LoginPage(getDriver());
loginPage.sendkeys("sometext");
}
My question here is a
Am I right in creating page object for every test cases?
Is there any way I can optimize this? Because One doubt I got is that non-static object reference may be getting overridden and causing problems in one of the methods if I run them in parallel.
Sorry if my query is naive. Any help would be appreciated.
You do not need to initialize it again. Also, initialize the pages in #BeforeTest rather than in test cases.
Here i would like to give you example of Page object model. Hope you can relate this.
My Main test:
#Before
public void SelectBrowser(){
driver = WebUtils.SelectBrowser(driver,"Chrome");
}
#Test
public void LoginToGmail() throws InterruptedException{
//WebDriver driver = new FirefoxDriver();
//MAximize the Screen
driver.manage().window().maximize();
//Go to Gmail Login Page
SignInPage SignInPage = new SignInPage();
WebUtils.GoToSignInPageForPropertyFile(driver, "URL");
//Click on Next
SignInPage.ClickToLogin(driver, By.cssSelector("input[id='next']"));
Now Supporting class:
GoToSignInPageForPropertyFile method will be in WebUtils
Whatever i write in Webutils will be used by each page object class.
For e.g.
public class WebUtils {
public static pageobject.SignInPage GoToSignInPageForPropertyFile(WebDriver driver, String URL) {
ReadFileData File = new ReadFileData();
Properties Values = File.ReadFile();
driver.get(Values.getProperty("URL"));
return PageFactory.initElements(driver, pageobject.SignInPage.class);
}
}
Now the method ClickToLogin is defined under SignInPage class as:
public class SignInPage {
public EmailViewPage ClickToLogin(WebDriver driver, By by) {
WebUtils.Click(driver, by);
return PageFactory.initElements(driver, EmailViewPage.class);
}
}
Which will further be in Webutils
public class WebUtils {
public static void Click(WebDriver driver, By by) {
WebElement Element = driver.findElement(by);
Element.click();
}
}

How can I share one Selenium webdriver instance in NUnit and C#?

I want easy way to launch Selenium webdriver instance and run various tests on it. I'm trying to do this in Suite file, but it doesn't work. Instance is killed instantly. Is there any alternatives on how to do this?
Potentially I want to add more drivers (IE, Chrome) in this suite and if possible launch separately. Any suggestions welcome.
namespace NUnit.Tests
{
public class AllTests
{
private static IWebDriver _Driver;
[TestFixtureSetUp]
public void SuiteSetUp()
{
_Driver = new FirefoxDriver();
}
[TestFixtureTearDown]
public void SuiteTearDown()
{
try
{
_Driver.Quit();
}
catch (Exception)
{
// Ignore errors if unable to close the browser
}
}
[Suite]
public static TestSuite Suite
{
get
{
LoginTest lt = new LoginTest { Driver=_Driver };
suite.Add(lt);
AnotherTest at = new AnotherTest { Driver=_Driver };
suite.Add(at);
return suite;
}
}
}
}
I did this in Java, I made a base class, declared the webdriver as static, put my startup/config methods in this class and then extended it in to each test class i made.
Im sure its the same for C#.
Trying to run this with base class / extended classes failed. As webdriver instance didn't get initialized properly and couldn't be killed properly. Instead I created SetupIE(), SetupChrome(), SetupFirefox() methods in Suite and also created teardown method that would work as last test for suite.
Here is the code:
namespace TestNamespace
{
using System;
using NUnit.Framework;
using NUnit.Core;
using SeleniumTests;
using OpenQA.Selenium;
using OpenQA.Selenium.IE;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
class AllTests
{
public static IWebDriver WebDriver { get; private set; }
[Suite]
public static TestSuite Suite
{
get
{
TestSuite suite = new TestSuite("All Tests");
//Setup a Web driver (see methods below for different browsers) - SetupIE(), SetupChrome(), SetupFirefox()
SetupIE();
// Add tests to suite
suite.Add(new FlashLoadedTest { Driver = WebDriver });
// Tear down a Web driver
suite.Add(new TearDownTest { DriverToTearDown = WebDriver });
// return suite to NUnit
return suite;
}
}
// Method that's initialises FireFox Driver
private static void SetupFireFox()
{
WebDriver = new FirefoxDriver();
}
// Method that's initialises IE Driver
private static void SetupIE()
{
WebDriver = new InternetExplorerDriver();
}
// Can't get this working, but this is how its supposed to work
private static void SetupChrome()
{
WebDriver = new ChromeDriver(#"C:\Users\<user>\AppData\Local\Google\Chrome\Application");
}
// Class with a test that tears down browser instance
[TestFixture]
class TearDownTest
{
public IWebDriver DriverToTearDown;
[Test]
public void TearDownBrowser()
{
if (DriverToTearDown == null)
Assert.Fail("No Browser to Tear Down");
try
{
DriverToTearDown.Close();
DriverToTearDown.Dispose();
}
catch
{
Assert.Fail("Browser failed to tear down");
}
}
}
}
}
I appreciate this is a little late but may prove useful for future readers.
I created a base class containing a firefox driver with the following and it works perfectly for me. You can then simply reference the base class (Driver in this instance) from your derived test class. Worth noting I'm using C# and Nunit.
Code for base class is:
namespace yournamespace
{
public class Driver
{
public IWebDriver driver;
public StringBuilder verificationErrors;
public Driver()
{
driver = new FirefoxDriver(); //replace with required driver
verificationErrors = new StringBuilder();
}
}
}
Then simply called the 'Driver' class from my test class:
[TestFixture]
public class IMSLogin : Driver
{
//.. all the usual bits and bobs!