Please post your Web Driver questions in official Web Driver forum

Saturday, October 29, 2016

Are your selenium element locators static ?

I usually declare element locator static as well as the helper method using them, since element locators is a class variable or constant and is not dependent on a specific instance of class. For example in the following code snippet, element locators - imageElement and teamDeletionSucessMessage are static. Also, method - isTeamDeletionSucessMessageDisplayed is static -


Screenshot from 2016-04-19 15:59:39.png


From one of the SO answer, following can be the requirement to make method static -

  1. If you are writing utility classes and they are not supposed to be changed.
  2. If the method is not using any instance variable(s) or instance method(s). {some thing I consider most important when declaring a variable static}
  3. If any operation is not dependent on instance creation.
  4. If there is some code that can easily be shared by all the instance methods, extract that code into a static method.
  5. If you are sure that the definition of the method will never be changed or overridden. As static methods can not be overridden.
What is your take on this? Are your element locators also static (or even static final)?

Sunday, October 23, 2016

Processing JMeter Results using awk

awk is Pattern scanning and processing language. Its name is derived from its authors “Aho, Weinberger, and Kernighan”.
Some of its features are:
  • Awk views a text file as records and fields
  • Awk has variables, conditionals and loops
  • Awk has arithmetic and string operators
  • Awk can generate formatted reports
Syntax:
awk '/search pattern1/ {Actions}
    
/search pattern2/ {Actions}' file
Herein :
  • search pattern is a regular expression.
  • Actions – statement (s) to be performed.
  • several patterns and actions can be used in Awk.
  • file is the Input file.
  • Single quotes around program avoids shell interpreting any special characters.


Let’s Consider following jmeter summary file -


summary +    41 in  15.4s =    2.7/s Avg:  2234 Min:   383 Max:  6974 Err: 0 (0.00%)
summary +    57 in  21.5s =    2.6/s Avg:  2548 Min:   618 Max:  4528 Err: 0 (0.00%)
summary =    98 in  32.5s =    3.0/s Avg:  2416 Min:   383 Max:  6974 Err: 0 (0.00%)
summary +   108 in  21.8s =    5.0/s Avg:  1291 Min:   229 Max:  6317 Err: 0 (0.00%)
summary =   206 in  52.5s =    3.9/s Avg:  1827 Min:   229 Max:  6974 Err: 0 (0.00%)


Let’s assume that we want to print lines where avg response time is more than 2500ms
awk '{if($9>2500){print $0}}' file.txt


Herein $9 is the the 9th field in log file and $0 denotes all of record


Hence we would get following output -
summary +    57 in  21.5s =    2.6/s Avg:  2548 Min:   618 Max:  4528 Err: 0 (0.00%)


Or printing the records with avg response time more than 2400ms


awk '{if($9>2400){print $0}}' file.txt


And we would get following output -


summary +    57 in  21.5s =    2.6/s Avg:  2548 Min:   618 Max:  4528 Err: 0 (0.00%)
summary =    98 in  32.5s =    3.0/s Avg:  2416 Min:   383 Max:  6974 Err: 0 (0.00%)


Find the total number of record in jmeter.log file -


wc file.txt | awk ‘{print $0}’


Consider that you are logging custom variables on Jmeter log file (i.e. email address etc) and now you want to figure out which email address caused higher latency. Can you guess how you can achieve it?

Sunday, October 9, 2016

When Test Automation Fails and exploratory Testing rocks

This post describes how I discovered a defect which allowed me to gain higher privilege than I was supposed to as a normal user. When testing an application I came across a use case when a privileged user would be allowed to delete a team and non privileged user would not be. Delete operation is controlled by displaying of a link. This is how it looks like for a privileged user -


Screenshot from 2016-05-30 15:37:05.png


And this is how it look for a non privileged user -


Screenshot from 2016-05-30 15:38:02.png


Here “Delete team” link is missing for non privileged user.

Having a look at html source code, I found following for the privileged user -


<a class="delete right" data-bind="if: teamProfile().type() != 'official', click: deleteTeam" href="https://test.com/" title="Delete this team">Delete team...</a>


And following for the non privileged user -


         <a class="delete right" data-bind="if: teamProfile().type() != 'official', click: deleteTeam" href="https://test.com/" title="Delete this team"></a>


The only difference is the missing inner text for delete link for non privileged user. Hence I modified the delete link of non privileged user as -


<a class="delete right" data-bind="if: teamProfile().type() != 'official', click: deleteTeam" href="https://draft.blogger.com/null" title="Delete this team">Delete</a>


This brought the Delete link on front end which was missing on previous snapshot -


Screenshot from 2016-05-30 15:45:21.png


When clicked on Delete link then voila, I got the confirmation prompt message of team deletion -


Screenshot from 2016-05-30 15:45:50.png

I was automating this use case by verifying the absence of delete link for non privileged user. Which would run perfect without reporting any bug. But we can see from example above that doing a little exploratory testing helped uncovered a defect which would have been missed from automated tests :-)


Do you have a similar story to share when automated testing helped you uncover a defect?

JMeter and Patch Request

I was using PATCH request with JMeter and I get following error -


########################################################
java.net.ProtocolException: Invalid HTTP method: PATCH
at java.net.HttpURLConnection.setRequestMethod(HttpURLConnection.java:428)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.setRequestMethod(HttpsURLConnectionImpl.java:374)
#########################################################

The problem lies with HTTP Request implementation being used here. Java implementation of HTTP request does not support PATH request and you should be using HTTPClient 4 implementation to get rid of this error

Monday, October 3, 2016

Is page object returning another page object a bad practice?

I have come across few articles which talk of page object returning another page object being bad practice. The reason cited are following -

  • Tight coupling between page objects and less flexibility
  • Duplication of code as two variant of a method need to be created returning two different page object depending on if operation was valid or not, i.e. -
loginAs‘ and ‘loginAsExpectingError

Let’s see following example of page objects wherein a page object class does not return another page object. For the sake of simplicity, I have consider three page object classes -


  • LoginPage class which lets user login
  • LoggedInUserHomePage class which provides services when user is logged in
  • InvoiceDetailPage class using which user invoice details

A simplified version of classes would be -

public class LoginPage {

  public LoginPage() {
      if(!WebUIDriver.getWebDriver().getTitle().equalsIgnoreCase("login page")) {
          throw new IllegalStateException("Not Login Page");
      }
  }

private TextFieldElement loginTextBox = new TextFieldElement("login text box", Locator.locateById("login"));

private TextFieldElement passwordTextBox = new TextFieldElement("password text box", Locato.locateById("password"));

private ButtonElement submitButton = new ButtonElement("password text box", Locator.locateById("password"));


public void login(User user) {
      loginTextBox.sendKeys(user.getUserName());
      passwordTextBox.sendKeys(user.getPassword());
      submitButton.click();
  }
}

public class LoggedInUserHomePage {

  public LoggedInUserHomePage() {
      if(!WebUIDriver.getWebDriver().getTitle().equalsIgnoreCase("logged in user page")) {
          throw new IllegalStateException("not logged in user page");
      }
  }

  public void getInvoiceDetailsOfOrderNumber(Object orderNumber) {
  }
}

And

public class InvoiceDetailPage {

public InvoiceDetailPage() {
      if(!WebUIDriver.getWebDriver().getTitle().equalsIgnoreCase("invoice detail page")) {
          throw new IllegalStateException("Not invoice detail Page");
      }
  }

public BigDecimal getOrderAmount(Object orderNumber) {
      return orderAmount;
  }
}


A test method may look as -

@Test
public void shouldDisplayOrderAmountOfGivenOrderNumber() {
  int orderNumber = 12345;
  BigDecimal expectedOrderAmount = new BigDecimal(50.0);

  LoginPage loginPage = new LoginPage();
  loginPage.login(new User());

LoggedInUserHomePage loggedInUserHomePage = new LoggedInUserHomePage();
  loggedInUserHomePage.getInvoiceDetailsOfOrderNumber(orderNumber);

  InvoiceDetailPage invoiceDetailPage = new InvoiceDetailPage();
  BigDecimal orderAmount = invoiceDetailPage.getOrderAmount(orderNumber);

  assertThat("Wrong order amount", orderAmount, is(expectedOrderAmount));
}


Notice that how each page object class had to be instantiated each time before being able to use the corresponding page object. That’s because none of our page object method return a page object.
Now let’s consider the old page object approach wherein each page object method return object of another page if it brings control on it. In this case test method would looks as -


@Test
public void shouldDisplayOrderAmountOfGivenOrderNumber() {
  int orderNumber = 12345;
  BigDecimal expectedOrderAmount = new BigDecimal(50.0);

  BigDecimal orderAmount = new LoginPage()
                              .login(new User())
                              .getInvoiceDetailsOfOrderNumber(orderNumber)
                              .getOrderAmount(orderNumber);
  assertThat("Wrong order amount", orderAmount, is(expectedOrderAmount));
}

You can see how succinct and comprehensible test is when page object method return other objects. This is an example of just three page objects but real world applications have more deep linked pages than this. And the advantages I cited earlier begin to diminish when pages are deep linked. Do you page object methods also return other page objects? What is your opinion about this?
Fork me on GitHub