Acceptance testing with Cucumber and Selenium(Java)

In this post, I am going to show how we can write the acceptance test script with Cucumber and Selenium.

Refer my earlier post for Ruby/Cucumber Acceptance testing with Cucumber and Capybara

My objective is to write an acceptance test which opens up the browser and goes to ‘Yelp’ site and search for a restaurant and validate the results.

Refer the below feature file.
java-cucumber-selenium-test/src/test/resources/yelp/test/yelp.feature



Feature: Search Restaurants

  Scenario: Go to yelp and search for valid restaurant
    Given a user goes to Yelp
    When Search for taco bell
    Then See the List of taco bell Restaurants and confirm results contains Lower Greenville

  Scenario: Go to yelp and search for restaurant
    Given a user goes to Yelp
    When Search for Qboba
    Then See the List of Qboba Restaurants

  Scenario: Go to yelp and search for restaurant
    Given a user goes to Yelp
    When Search for Chipotle
    Then See the List of Chipotle Restaurants

  Scenario: Go to yelp and search for invalid restaurant
    Given a user goes to Yelp
    When Search for hhahsdahsdhasd
    Then See No Results found error message

  Scenario Outline:Go to yelp and search for <searchText>
    Given a user goes to Yelp
    When Search for <searchText>
    Then See the List of  Restaurants
    Examples:
      | searchText               |
      | Scardello                |
      | Roti Grill               |
      | Mughlai Restaurant       |
      | Spice In The City Dallas |


Refer the below Junit test file
java-cucumber-selenium-test/src/test/java/yelp/test/YelpTest.java



package yelp.test;

import org.junit.runner.RunWith;
import cucumber.api.junit.Cucumber;

@RunWith(Cucumber.class)
public class YelpTest {
}

Refer the below Step definitions file.

java-cucumber-selenium-test/src/test/java/yelp/test/definitions/YelpStepDefinition.java



package yelp.test.definitions;

import cucumber.api.java.After;
import cucumber.api.java.Before;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.util.concurrent.TimeUnit;

import static org.junit.Assert.assertEquals;

public class YelpStepDefinition {

    protected WebDriver driver;

    @Before
    public void setup() {
        driver = new FirefoxDriver();
        //Loading the driver
        System.setProperty("webdriver.gecko.driver", "/usr/local/bin/geckodriver");
    }

    @Given("^a user goes to Yelp$")
    public void goToYelp() {
        //Get the Yelp home page
        driver.get("https://www.yelp.com/dallas");
    }

    @When("^Search for (.*?)$")
    public void doSearch(String searchTerm) throws InterruptedException {
        WebElement searchDescElement = driver.findElement(By.id("find_desc"));
        searchDescElement.sendKeys(searchTerm);

        WebElement submit = driver.findElement(By.id("header-search-submit"));
        submit.submit();
    }

    @Then("^See the List of (.*?) Restaurants$")
    public void verifyContents(String restaurant) {

        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        assertEquals(true, isContentAvailable(restaurant));
    }

    @Then("^See the List of (.*?) Restaurants and confirm results contains (.*?)$")
    public void verifyContentsWithLandmark(String restaurant, String landMark) {
        //Create an Explicit wait to make sure that the page is loaded and driver updates the page data.
        WebDriverWait myWait = new WebDriverWait(driver, 10);
        myWait.until(ExpectedConditions.visibilityOfElementLocated(By.id("yelp_main_body")));
        assertEquals(true, isContentAvailable(restaurant, landMark));
    }

    public boolean isContentAvailable(String... contents) {
        WebElement searchResultsElement = driver.findElement(By.id("yelp_main_body"));
        boolean result = false;
        for (String content : contents) {
            result = searchResultsElement.getText().contains(content);
        }
        return result;
    }

    @Then("^See No Results found error message")
    public void verifyContents() {
        //Create an Explicit wait to make sure that the page is loaded and driver updates the page data.
        WebDriverWait myWait = new WebDriverWait(driver, 10);
        myWait.until(ExpectedConditions.visibilityOfElementLocated(By.id("yelp_main_body")));
        assertEquals(true, driver.getPageSource().contains("No Results"));
    }

    @After
    public void closeBrowser() {
        driver.quit();
    }
}


Follow the below steps to run the test script

1. Download the repository
2. Download the ‘gecko’ driver from https://github.com/mozilla/geckodriver/releases and copy it into ‘/usr/local/bin/’
3. Do ‘mvn clean install’
4. Maven builds the test class and runs it. We can also run the test case(YelpTest.java) from any IDE as normal Junit test case.

SimpleDateFormat – ISO8601 format

I have done some date format operations in Java and got to know about the Zulu time which is nothing but the UTC time.

Now, I have a date and want to format that into “yyyy-MM-dd’T’HH:mm:ss.SSSZ” format. Here Z stands for zulu timezone.

Refer the below program and the output of those.


import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimeZone;


public class Main {

    public static void main(String[] args) {

        //ISO8601 format
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");

        //EST time
        Calendar calendar1 = Calendar.getInstance();
        System.out.println("calendar1::" + calendar1.getTimeZone());
        System.out.println("\n");
        System.out.println("calendar1.getTime()::" + dateFormat.format(calendar1.getTime()));
        System.out.println("\n");
        //PDT time
        Calendar calendar2 = Calendar.getInstance(TimeZone.getTimeZone("America/Los_Angeles"));
        dateFormat.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
        System.out.println("calendar2::" + calendar2.getTimeZone());
        System.out.println("calendar2.getTime()::" + dateFormat.format(calendar2.getTime()));

    }
}


calendar1::sun.util.calendar.ZoneInfo[id="America/New_York",offset=-18000000,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/New_York,offset=-18000000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]]


calendar1.getTime()::2017-06-02T17:03:04.643-0400


calendar2::sun.util.calendar.ZoneInfo[id="America/Los_Angeles",offset=-28800000,dstSavings=3600000,useDaylight=true,transitions=185,lastRule=java.util.SimpleTimeZone[id=America/Los_Angeles,offset=-28800000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]]
calendar2.getTime()::2017-06-02T14:03:04.645-0700

calendar1 uses the default timezone and in this case its EST time. So when i am doing the format, the output string is “2017-06-02T16:53:24.122-0400”. Here -0400 represents the time difference between the current timezone(EST) and UTC(Zulu) time.

calendar2 uses the PDT time and also set the same timezone to SimpleDateFormat as well. So the output string is “2017-06-02T13:53:24.124-0700”. Here the -0700 represents the time difference between the PDT timezone and UTC(Zulu) time.

Java 8: Create LinkedHashMap with Collectors.toMap

In this article, I will show you how to create a LinkdHashMap with Collectors.toMap() method.

Assume that you have a LinkedHashMap with the key as a string and the value as an Integer. Now you want to iterate this map and modify the value of each key and then create an another map to hold that value.

Refer the below code to know how to do that.



import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;

public class Main {

    public static void main(String[] args) {

        Map map1 = new LinkedHashMap();

        map1.put("key1", 1);
        map1.put("key2", 2);
        map1.put("key3", 3);

        System.out.println(map1);

        Map map2 = map1.keySet()
                .stream()
                .collect(Collectors.toMap(key -> key,
                        key -> (map1.get(key) + 10),
                        (e1, e2) -> e1,
                        LinkedHashMap::new));

        System.out.println(map2);
    }
}


By default, the Collectors.toMap function creates a HashMap but we can override it by specifying the mapSupplier argument. The corresponding function from Collectors class which should be used in this case.


    public static <T, K, U, M extends Map<K, U>>
    Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
                                Function<? super T, ? extends U> valueMapper,
                                BinaryOperator<U> mergeFunction,
                                Supplier<M> mapSupplier) 

So in my code,I am passing the key, updated value, merge function(consider the first key if there is a duplicate key), finally the LinkedHashMap to the Collectors.toMap() function.

The output will be like this,


 map1{key1=1, key2=2, key3=3}
 map2{key1=11, key2=12, key3=13}

How to use ReflectionUtils to retrieve the field value

In this post, I am going to show how we can use the ReflectionUtils to get the field value from an object.

Most of the time, we use Java Reflection to retrieve the value but if the field is in the Super class, then you have to write some boilerplate code to retrieve those. But if you use ReflectionUtils, then you won’t have to worry about that.

Refer the below example,

BaseProfile and Employee are the two value objects. Here the Employee class extends BaseProfile class which has some common fields. Then in ReflectionUtilsMain, I am using Java reflection and also ReflectionUtils to retrieve the value of “firstName” field

Let’s check the code.

BaseProfile.java


import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;


public class BaseProfile {

    private String firstName;

    private String lastName;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;

        if (o == null || getClass() != o.getClass()) return false;

        BaseProfile that = (BaseProfile) o;

        return new EqualsBuilder()
                .append(firstName, that.firstName)
                .append(lastName, that.lastName)
                .isEquals();
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder(17, 37)
                .append(firstName)
                .append(lastName)
                .toHashCode();
    }
}

BaseProfile.java


import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;


public class Employee extends BaseProfile {

    private String empId;

    private String designation;

    public String getEmpId() {
        return empId;
    }

    public void setEmpId(String empId) {
        this.empId = empId;
    }

    public String getDesignation() {
        return designation;
    }

    public void setDesignation(String designation) {
        this.designation = designation;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;

        if (o == null || getClass() != o.getClass()) return false;

        Employee employee = (Employee) o;

        return new EqualsBuilder()
                .appendSuper(super.equals(o))
                .append(empId, employee.empId)
                .append(designation, employee.designation)
                .isEquals();
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder(17, 37)
                .appendSuper(super.hashCode())
                .append(empId)
                .append(designation)
                .toHashCode();
    }

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

Here is our main class
ReflectionUtilsMain.java


import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.lang3.reflect.FieldUtils;

import java.lang.reflect.Field;

public class ReflectionUtilsMain {

    public static void main(String[] args) {

        Employee employee = new Employee();
        employee.setEmpId("1234");
        employee.setFirstName("John");
        employee.setLastName("Turner");
        employee.setDesignation("Manager");
        System.out.println(employee);

        //Now you want to access the First Name from Employee object with Java reflection
        String firstName = null;
        String fieldName = "firstName";
        for (Class aClass = employee.getClass(); aClass != null; aClass = aClass.getSuperclass()) {
            System.out.println("aClass:" + aClass.getSimpleName());
            try {
                Field field = aClass.getDeclaredField(fieldName);
                if (!field.isAccessible()) {
                    System.out.println("Field is found "+field);
                    field.setAccessible(true);
                    firstName = (String) field.get(employee);
                    break;
                }
            } catch (NoSuchFieldException | IllegalAccessException e) {
                System.err.print(ExceptionUtils.getStackTrace(e));
            }
        }
        System.out.println("Using Reflection firstName:" + firstName);
        firstName = null;
        //You can also use ReflectionUtils to get this very easily
        try {
            Field field = FieldUtils.getField(employee.getClass(), fieldName, true);
            firstName = (String) field.get(employee);
        } catch (Exception e) {
            System.err.print(ExceptionUtils.getStackTrace(e));
        }
        System.out.println("Using Reflection Utils firstName:" + firstName);

    }
}

The output will be like this,


java.lang.NoSuchFieldException: firstName
	at java.lang.Class.getDeclaredField(Class.java:2070)
	at org.cas.osd.mp.ReflectionUtilsMain.main(ReflectionUtilsMain.java:29)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
org.cas.osd.mp.Employee@42110406[empId=1234,designation=Manager,firstName=John,lastName=Turner]
aClass:Employee
aClass:BaseProfile
Field is found private java.lang.String org.cas.osd.mp.BaseProfile.firstName
Using Reflection firstName:John
Using Reflection Utils firstName:John

How to get Application HostName and client ip address in Java

Consider the below example,

We have an AngularJs web application and the backend is Java RESTful API.

So the application flow will be like this,
Client ==> AngularJs==> RESTful API

Assume that we have two RESTful services. They are /api/document to retrieve the document details and /api/download to download the document content in a PDF. Assume that we want to generate the download service link in the /api/document service response something like below,

/api/document?docId=1
{
	"docId": "1",
        "data":"",
	"downloadLink": "https://app-dev.com/api/download?type=pdf&docId=1"
}

Here the app-dev.com represents the host name of the application.

So to get the host name, we have to retrieve the ‘x-forward-host’  HTTP header as we can’t depend on the host header as it may be modified by the intermediate proxy server. Refer below the code to retrieve the hostname.


     public String getHost(HttpServletRequest servletRequest) {
          return servletRequest.getHeader("x-forwarded-host");
    }

To get the client IP address, we have to retrieve the ‘x-forwarded-for’ header. The general format of this field is X-Forwarded-For: client, proxy1, proxy2. So if there are any proxy servers in between the client and application, then those proxies IP address are appended to this header. So always use the first IP address available in this header to know the actual client IP address.


     public String getClientIpAddress(HttpServletRequest servletRequest) {
          return servletRequest.getHeader("X-Forwarded-For").split(",")[0];
    }

Test Secure REST services with Chrome Browser Plugin

Most of us want to test out the REST services via Advanced Rest Client or Postman for some reason or debug an issue.

But if the REST services are secure and protected by Ping Access or SiteMinder or any other tool, then we will get a login page. So we have to hard code the browser cookies to bypass the login page.

There is an another way to do that.

If you are using Advanced Rest Client(https://advancedrestclient.com), then you can use ARC cookie exchange plugin.
So this plugin helps ARC plugin to retrieve the browser cookies and send it in the request.

If you are using Postman(https://www.getpostman.com), then you can use Postman interceptor. So the Postman interceptor plugin helps the Postman plugin to use the browser cookies for each service call.

Mock System class with Mockito + PowerMock

In this post, I am going to show how to mock the System.getenv and System.getProperty methods.

I have used Mockito and PowerMock to do this. Make sure to include the below dependencies in your pom file.


      <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-api-mockito</artifactId>
            <version>1.6.4</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-module-junit4</artifactId>
            <version>1.6.4</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-api-mockito-common</artifactId>
            <version>1.6.5</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-core</artifactId>
            <version>1.6.4</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.powermock.tests</groupId>
            <artifactId>powermock-tests-utils</artifactId>
            <version>1.6.4</version>
            <scope>test</scope>
        </dependency>
 

I have created an another util class which has the getEnv and getProperty methods. So instead of mocking the System class methods explicitly, I have mocked the MockUtils static methods.

MockUtils.java


package com;

import org.apache.commons.lang3.StringUtils;

public class MockUtils {

    public static String getEnv(String name) {
        return StringUtils.defaultIfBlank(System.getenv(name), "");
    }

    public static String getProperty(String name) {
        return StringUtils.defaultIfBlank(System.getProperty(name), "");
    }
}

Here is my test class.

MockTest.java



package com;

import com.MockUtils;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import static junit.framework.Assert.assertEquals;

@RunWith(PowerMockRunner.class)
@PrepareForTest(MockUtils.class)
@PowerMockIgnore("javax.management.*")
public class MockTest {

    @BeforeClass
    public static void setupClass() throws Exception {
        PowerMockito.mockStatic(MockUtils.class);
        PowerMockito.when(MockUtils.getEnv("APP_ENV")).thenReturn("DEV");
        PowerMockito.when(MockUtils.getProperty("username")).thenReturn("bala");
    }

    @Test
    public void testMockUtils() {
        assertEquals("DEV", MockUtils.getEnv("APP_ENV"));
        assertEquals("bala", MockUtils.getProperty("username"));
    }
	

Sometimes the static method might be used in the underlying classes and if those classes are not using the mocked values, then you can initialize the mocked values in the @Before like below,


import static junit.framework.Assert.assertEquals;

@RunWith(PowerMockRunner.class)
@PrepareForTest(MockUtils.class)
@PowerMockIgnore("javax.management.*")
public class MockTest {

    @Before
    public void setupClass() throws Exception {
        PowerMockito.mockStatic(MockUtils.class);
        PowerMockito.when(MockUtils.getEnv("APP_ENV")).thenReturn("DEV");
        PowerMockito.when(MockUtils.getProperty("username")).thenReturn("bala");
    }

    @Test
    public void testMockUtils() {
        assertEquals("DEV", MockUtils.getEnv("APP_ENV"));
        assertEquals("bala", MockUtils.getProperty("username"));
    }