6 things to avoid when learning selenium automation

dontdoit-1

1. Aiming at becoming a Selenium automation expert

This goal is so high that you will probably fail.

You should replace it with something more achievable like “i want to get a test automation job in 1 year”.

 

2. Selenium WebDriver certifications

Selenium WebDriver certifications are scams. Even if they would be good, they wont help you getting hired. When studying for a certification, you study for the exam that you will take and not for the subject.

Passing an exam is a very poor way of measuring your programming skills.

 

I met people who passed with 90% grades TOEFL (test of english as a foreign language) and TWE (test of written english) but speak and write very bad english.

 

3. Jumping into writing Selenium WebDriver tests before learning a programming language

Test automation with Selenium WebDriver is basically programming.

Without knowing a programming language well, you will always have big obstacles in writing automation code. Selenium WebDriver is just a library that can be used through multiple languages.

Jumping to Selenium tests with no programming is similar with trying to cook lasagna with no cooking skills.

Shortcuts never work. There are no shortcuts to math, to learning french, to getting fit, to anything. You have to put the effort in and follow a process that takes time.

 

4. Looking for the best selenium book or online course

There is no such thing. You will find though many great books and online courses.

The best book for Selenium should include everything about Selenium, everything about the programming language (lets say Java), everything about an IDE (example: Eclipse), everything about unit testing, maven, code design, code refactoring, maven, etc.

Do you really think that it exists?

It does not.

To learn test automation with Selenium, you need to use a multitude of resources, books, blogs, youtube videos, online courses, webinars, etc.

Because the amount of information needed for an automation job is very high.

 

5. Learning by yourself

If you attempt learning by yourself, chances are high that you wont make it.

Find other people with the same goal, take instructor-led courses, find developers willing to help you, go to meetups, anything but being by yourself.

 

6. Selenium IDE

Record and play is not test automation

 

Advertisements

What is a selenium tester doing in real time

If you missed the previous day, you can find it here.

Morning of January 18

I start the day with something to bring my mood and energy up.
One cup of hot, strong coffee (no sugar, no milk) for the energy and Rammstein music for the mood.

Today, I need to focus on test stability issues.

I have around 20 Jenkins jobs that run daily automated tests related to various site features.

Some jobs pass consistently but a few fail from time to time.

The first one that I will look at is for the ChangePassword feature.

It runs all tests from the ChangePassword test class using a Maven command:

mvn clean -Dtest=automatedtests.changePassword.ChangePasswordTests test

Out of 5 job runs, there are 2 failures. The Jenkins console log says that assertions are failing. I will run the test class locally to see what is going on.

 

15 minutes later

From all change password tests, the one that changes the password successfully works. All other negative tests that verify that the password cannot be changed (if it is too short or if it includes special characters) fail. Each negative test attempts changing the password and then checks if an error message is displayed.

 

But the error message is all the time the same. It should say that the password is too short or that the password cannot include special characters. Instead, it always says that the passwords are not identical.

 

This seems like an application bug so I should speak to the developers. I will record a video with the tests execution and send it in an email asking for their opinion. Maybe there is a good explanation for it. I better get their opinion first and then, if they agree, log a bug to Jira.

 

10 minutes later

The email is out so I can look into the second failing Jenkins job. This one is about the user acount security questions.

The Jenkins console log points to timeout issues for different page elements.

There are a few possible reasons:

  • The site is very slow.
  • The test does not navigate from a page to the next one. Maybe the test executes the code for clicking a button and the button is not clicked.
  • The ids of the elements changed again.

The html of the site is pretty bad with many elements having either no ids or dynamic ids.

I will have to run these tests locally as well, then confirm which elements cannot be found, get their ids and compare them to the page element ids from Chrome Inspector.

So booooriiiing, does anyone like to do this part?

Anyways, as Maximus’s servant said it in Gladiator  (what a terrific movie! looking forward to watch it again) when asked if he likes what he does:

Maximus: Do you find it hard to do your duty?
Cicero: Sometimes I do what I want to do. The rest of the time, I do what I have to.

I will do as well what I have to.

Reluctantly 😦

 

Later in the day

I am really upset now. All elements from the security questions page have different ids. I need to modify all locators from the SecurityQuestions.java class and retest all tests that use it.

This is such a waste of effort, modifying page element locators over and over and over.

Starting from scratch 🙂

Too bad that the developers are so busy with the new features that no one has time to add the custom ids that I keep asking for.

I am so looking forward to the end of the sprint. Maybe after it, I will be able to pair with a developer and go through all pages and add custom ids to all elements.

Fingers crossed!

 

Finally, the last failing Jenkins job.

This one is for the user registration tests.

The console log shows stale element exceptions for a few elements. This is weird since I am sure that these tests were running very well.

Maybe the developers enabled the auto postback setting for the page elements which makes the element regenerate every time it is interacted with. I solved this before for other pages by retrying a method on exception a few times so I can do the same here. But since it is later in the day, it will have to wait until tomorrow.

 

4 pm already?

Before I go home, someone mentioned on LinkedIn that page factory should not be used any longer.

It is the video of the keynote of a Selenium conference from 2016. I better watch it to get more details.

 

4.30 pm

Yes, Simon Stewart says that no one is using Page Factory and that its design could have been better.

But apparently, no one uses it correctly either and many people try to generate page objects automatically while using page factory.

Wow, never crossed my mind to generate page objects automatically!

So Page Factory works if you use it as it is supposed to be used.

I should watch this video again.

I laughed so much during it, Simon has a great sense of humor 🙂

Use a custom driver class instead of utility classes

How can I create my own driver class in Selenium?
When learning test automation, you will want your test methods to be executed in multiple browsers such as Firefox and Chrome.

A Firefox driver is created with the FirefoxDriver class:

WebDriver driver = new FirefoxDriver();

A Chrome driver is created with the ChromeDriver class:

WebDriver driver = new ChromeDriver();

Both driver objects use the WebDriver type but are instantiated by different classes.

Now, you dont want to change the class from FirefoxDriver to ChromeDriver and back every time you want to run the tests in another browser.

Instead, you would like to create the driver based on the browser name:

WebDriver driver = new BrowserDriver(browserName);

How do we do this?

We create a custom driver class that implements the WebDriver interface and overrides its methods.

public final class BrowserDriver implements WebDriver {  

   private WebDriver driver;
   private final String browserName;
   private final int timeout = 30; 
   private final String chromeDriverPath = "./src/chromedriver.exe";  

   public BrowserDriver(String browserName) { 
      this.browserName = browserName; 
      this.driver = createDriver(browserName); 
   }  

   private WebDriver createDriver(String browserName) { 
      if (browserName.toUpperCase().equals("FIREFOX") 
         return firefoxDriver(); 

      if (browserName.toUpperCase().equals("CHROME") 
         return chromeDriver();  

      throw new RuntimeException ("invalid browser name"); 
   } 

   private WebDriver chromeDriver() { 
      if (!new File(chromeDriverPath).exists()) 
        throw new RuntimeException
                    ("chromedriver.exe does not exist!"); 

      try { 
        System.setProperty("webdriver.chrome.driver", 
                           chromeDriverPath); 
        return new ChromeDriver(); 
      } 

      catch (Exception ex) { 
        throw new RuntimeException
              ("couldnt create chrome driver"); 
      } 
   } 

   private WebDriver firefoxDriver() { 
      try { 
         return new FirefoxDriver(); 
      } 
      catch (Exception ex) {         
         throw new RuntimeException
              ("could not create the firefox driver"); 
     } 
   } 

   @Override 
   public String toString() { 
      return this.browserName; 
   } 

   public WebDriver driver() { 
      return this.driver; 
   }  

   @Override 
   public void close() { 
      driver().close();   
   }  

   @Override 
   public WebElement findElement(By locator) { 
      return driver().findElement(locator); 
   }  

   @Override 
   public List findElements(By arg0) { 
      return driver().findElements(arg0); 
   }  

   @Override 
   public void get(String arg0) { 
      driver().get(arg0); 
   }  

   @Override 
   public String getCurrentUrl() { 
      return driver().getCurrentUrl(); 
   }  

   @Override 

   public String getPageSource() { 
      return driver().getPageSource(); 
   }  

   @Override 
   public String getTitle() { 
      return driver().getTitle(); 
   }  

   @Override 
   public String getWindowHandle() { 
      return driver().getWindowHandle(); 
   }  

   @Override 
   public Set getWindowHandles() { 
     return driver().getWindowHandles(); 
   }  

   @Override 
   public Options manage() { 
      return driver().manage(); 
   }  

   @Override 
   public Navigation navigate() { 
      return driver().navigate(); 
   }  

   @Override 
   public void quit() { 
     driver().quit(); 
   }  

   @Override 
   public TargetLocator switchTo() { 
      return driver().switchTo(); 
   }  

   @Override 
   public  X getScreenshotAs(OutputType target
   throws WebDriverException { 
      return ((TakesScreenshot) driver())
                    .getScreenshotAs(target);
   } 

}

 

The only method that is not defined in the WebDriver interface is createDriver().
createDriver() creates a driver object based on the browser name and stores it in the driver variable.

All other methods just override the WebDriver interface methods.

In the test method, you can now use the new BrowserDriver class instead of FirefoxDriver and ChromeDriver:

WebDriver driver = new BrowserDriver(“CHROME”);

driver.get(“http://www.bestbuy.com”);

WebElement searchBox = driver.findElement(searchBoxLocator);

 

The custom driver class can add as well new methods.

 

Lets say that you want to have find element methods that use the WebDriverWait and ExpectedConditions classes:

public WebElement findVisibleElement(By locator) {
   WebElement element = new WebDriverWait(driver(), timeout)
                .until( visibilityOfElementLocated (locator));
   return element;
}

public WebElement findClickableElement(By locator) {
   WebElement element = new WebDriverWait(driver(), timeout)
               .until( elementToBeClickable (locator));
   return element;
}

public WebElement findHiddenElement(By locator) {
   WebElement element = new WebDriverWait(driver(), timeout)
              .until( presenceOfElementLocated (locator));
   return element;
}

You may be tempted to create a utility class, move these methods there and then use the utility class as a parent for the page classes.

Resist this temptation as it leads to bad things 🙂

Avoid utility classes in your automation projects.

More about utility classes very soon on this blog.

Instead of the utility class, you can move these methods to your custom driver class.

public final class BrowserDriver implements WebDriver {  

   private WebDriver driver; 
   private final String browserName; 
   private final int timeout = 30; 
   private final String chromeDriverPath = "./src/chromedriver.exe"; 

   public BrowserDriver(String browserName) { 
      this.browserName = browserName; 
      this.driver = createDriver(browserName); 
   }  

......................................................................

   @Override 
   public WebElement findElement(By locator) { 
     WebElement element = new WebDriverWait(driver(), timeout) 
                        .until( visibilityOfElementLocated(locator)); 
     return element; 
   }  

   @Override 
   public List findElements(By arg0) { 
     return driver().findElements(arg0); 
   }

   public WebElement findClickableElement(By locator) { 
      WebElement element = new WebDriverWait(driver(), timeout) 
                       .until( elementToBeClickable(locator)); 
      return element; 
   } 

   public WebElement findHiddenElement(By locator) { 
      WebElement element = new WebDriverWait(driver(), timeout) 
                      .until( presenceOfElementLocated(locator)); 
      return element; 
 }

}