NUnit Selenium Structure - selenium

I'm trying to write some Selenium tests with NUnit and doing my best to keep a clean test design (testing one thing for each test). So I got something like this
[TestFixture]
public class SomeTest
{
IWebDriver driver;
[Setup]
public void Setup()
{
driver = new InternetExplorerDriver();
}
[Test]
public void Test1()
{
}
[Test]
public void Test2()
{
}
[Teardown]
public void Teardown()
{
driver.Close();
}
}
Now this is fine, but things get insanely slow as the number of tests increase. Starting and stopping the entire browser for each test is a bottleneck.
Any way to keep the browser open until the last test? Or perhaps a better approach/design?

In order to only bring up one browser per fixture you can use [TestFixtureSetUp] [TestFixtureTearDown] instead of [SetUp] and [TearDown]:
[TestFixture]
public class SomeTest
{
IWebDriver driver;
[TestFixtureSetUp]
public void Setup()
{
driver = new InternetExplorerDriver();
}
[Test]
public void Test1()
{
}
[Test]
public void Test2()
{
}
[TestFixtureTearDown]
public void Teardown()
{
driver.Close();
}
}
Of course this does not help across fixtures, but could still give some performance gain.

You can make just one method with 'test' in its name. This test method will contain calling other methods (without 'test' in its name). Those other methods will be your tests cases.
Every method with 'test' in its name causes opening and closing browser. By using above solution you will open browser only one time and you will do all your tests cases one by one, at once.

Related

Standard approach for multi browser test execution in Selenium Jupiter

I went through Selenium Jupiter manual and still cannot get the idea of how I can set multiple
browsers in Selenium Jupiter to run every test in every browser.
Should use Test Template for that purpose?
Again I did not see an example of how can I do it in Selenium Jupiter?
p.s. An example with RemoteDrivers on Selenium Grid.
Here is my attempt to do it:
public class BaseTestWithRemoteDrivers {
#RegisterExtension
static SeleniumExtension extension = new SeleniumExtension();
#BeforeAll
public static void setupAll() {
extension.getConfig().setSeleniumServerUrl("http://localhost:4444/wd/hub");
Browser chrome = BrowserBuilder.chrome().build();
Browser firefox = BrowserBuilder.firefox().build();
extension.addBrowsers(chrome, firefox);
}
#Test
public void testWithBrowser(WebDriver driver) {
driver.get("https://www.google.com");
}
#AfterAll
public static void tearDownAll(WebDriver driver) {
driver.quit();
}
Unfortunately, only the Chrome browser will open.
Upd: I also found that there is a message saying:
Browser list for context id is not found. Not sure how to set up Browsers List if it is needed.
So far I did not find multi browsers support except by explicitly putting the browsers type into mvn command like below:
mvn verify -Dtest=BaseTest
-Dsel.jup.selenium.server.url=http://localhost:4444/wd/hub
-Dsel.jup.default.browser=chrome
-Dsel.jup.default.version=80.0.3987.106
#ExtendWith(SeleniumExtension.class)
public class BaseTest {
#Test
public void testNumber1(RemoteWebDriver driver) throws {
driver.get("https://www.google.com/");
}
#AfterAll()
public static void tearDown(RemoteWebDriver driver) {
driver.quit();
}
}
Update:
I figured out the way I can do it with Test Template too.
Below is the working example:
public class MultiBrowserTestTemplate {
#RegisterExtension
static SeleniumExtension extension = new SeleniumExtension();
#BeforeAll
static void setup() {
String browsersList = System.getProperty("prop.browsers.list");
List<String> browsers = Arrays.asList(browsersList.split(","));
if (browsers.contains("chrome")) {
extension.addBrowsers(BrowserBuilder.chrome().version("80.0.3987.106").build());
}
if (browsers.contains("firefox")) {
extension.addBrowsers(BrowserBuilder.firefox().version("73.0").build());
}
}
}
public class MultiBrowserDemoTest extends MultiBrowserTestTemplate {
#TestTemplate
public void testInMultipleBrowsers(WebDriver driver) {
driver.get("https://www.google.com/");
WebElement search = driver.findElement(By.name("q"));
search.sendKeys("JUnit5 extensions");
search.submit();
}
And the maven command goes like this:
mvn verify -DMultiBrowserDemoTest
-Dsel.jup.selenium.server.url=http://localhost:4444/wd/hub
-Dprop.browsers.list=chrome,firefox

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();
}
}

Cucumber Junit Testing Code

I tried to work with webdriver to see if the cucumber will open browser with junit. It is recognizing everything except for opening the web browser or even doing what I asked to do. Here is the code snippet:
public class JobSearch {
WebDriver driver;
#Test
public void JobSearchSteps()
{
driver = new FirefoxDriver();
driver.navigate().to("http://www.careerbuilder.com");
}
#Given("^I am on the page Find Jobs$")
public void I_am_on_the_page_Find_Jobs()throws Throwable{
System.out.println("******************************");
System.out.println("#Given -- I am on the page Find Jobs");
}
#When("^I enter \"([a-zA-Z]{1,})\" in the Keywords textbox$")
public void I_enter_QA_in_the_Keywords_textbox(String Job){
driver.findElement(By.id("s_rawwords")).sendKeys(Job);
System.out.println("The search is "+Job);
}
#And("^I enter\"([a-zA-Z]{1,})\" in the Location textbox$")
public void I_enter_my_location_in_the_Location_textbox(String Loc)throws Throwable{
System.out.println("The location is "+ Loc);
driver.findElement(By.id("s_freeloc")).sendKeys(Loc);
}
#And ("^I Select\"([a-zA-Z]{1,})\" from the Careers Category List$")
public void I_Select_from_the_Careers_Category_List(String Option)throws Throwable{
WebElement ListBox =driver.findElement(By.id("s_jobtypes"));
List options = ListBox.findElements(By.tagName(Option));
}
#And ("^I click the button Find Jobs$")
public void I_click_the_button_Find_Jobs()throws Throwable{
driver.findElement(By.id("qsbButton")).click();
}
#Then("^the page Jobs should be shown$")
public void the_page_Jos_should_be_shown()throws Throwable{
}
}
You cannot combine Junit annotations with Cucumber annotations. I suggest you to remove #Test annotation. You should rather write a step to launch the site and implement it. For example put this at the top of your scenario,
Given I navigate to "http://www.careerbuilder.com"
This will translate to a step like,
#Given("^I navigate to \"([^\"]*)\"$")
public void I_navigate_to_site(String url) throws Throwable {
driver = new FirefoxDriver();
driver.navigate().to(url);
}

Capture WebDriver Screenshots When Running Parallel Tests With TestNG

I am currently capturing screenshots on failure and success in TestNG by way of overriding the TestListenerAdapter methods onTestFailure, and onTestSuccess respectively. In order to do this you need to specify which driver you want to take a screenshot of.
My question: Is there a good way to capture screenshots when running tests in parallel on the method level?
In order to run tests in parallel, each individual test needs a unique driver instance. So, at any given time you have x number of driver instances running. When it comes time to capture a screenshot, how do you determine which driver to use?
Code excerpts below:
public class OnFailureListener extends TestListenerAdapter {
#Override
public void onTestFailure(ITestResult tr) {
Screenshots.captureScreenshot(tr);
super.onTestFailure(tr);
}
--
public static void captureScreenshot(ITestResult tr) {
WebDriver driver = TestClass.driver;
if (driver instanceof TakesScreenshot) {
String filename = "path/to/screenshot/file";
try {
File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(scrFile, new File(filename));
} catch (IOException e) { e.printStackTrace(); }
}
If you create a base test class with access to the driver, then that driver will always be the correct driver
The following will achieve this;
All test classes must extend a simple base test class;
public asbtract baseTestCase() {
private WebDriver driver;
public WebDriver getDriver() {
return driver;
}
#BeforeMethod
public void createDriver() {
driver=XXXXDriver();
}
#AfterMethod
public void tearDownDriver() {
if (driver != null){
try{
driver.quit();
}
catch (WebDriverException e) {
System.out.println("***** CAUGHT EXCEPTION IN DRIVER TEARDOWN *****");
System.out.println(e);
}
}
}
In your listener, you need to access the base class:
public class ScreenshotListener extends TestListenerAdapter {
#Override
public void onTestFailure(ITestResult result){
Object currentClass = result.getInstance();
WebDriver webDriver = ((BaseTest) currentClass).getDriver();
if (webDriver != null){
File f = ((TakesScreenshot)webDriver).getScreenshotAs(OutputType.FILE);
//etc.
}
}
}

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!