Generating Test Data with Faker and friends

During my recent endeavours to build a REST API, I wanted to test the bulk upload feature of the API which required a large set of test data. I was looking for a quick way to create a fake test data set and found an interesting Ruby library called Faker. This a port of Perl’s Data::Faker library.

Faker is a popular choice in Rails community. It is also ported to Java, Python and JavaScript.

Faker provides a number of categories for test data generation. For example Names, Addresses, Pictures, Business & Finance (Credit Card Numbers, IBAN numbers, Swift Codes etc.), Text placeholders and much more.

Let’s say we want to create a list of records on the fly. We want a list of names and contact phone number. In Ruby, all we would have to do is:

First install Faker Gem with:


gem install faker

and create a simple script to generate records:


require 'faker'
require 'json'

landlords = []

100.times do
  landlord = Hash.new
  landlord["name"] = Faker::Name.name
  landlord["contact_number"] = Faker::PhoneNumber.cell_phone
  landlords.push(landlord)
end

puts JSON.pretty_generate(landlords)

This will create records similar to below output. You can copy or store the output and use it seed to database or during the testing


[
  {
    "name": "Ms. Adelia Ortiz",
    "contact_number": "1-443-107-3897"
  },
  {
    "name": "Delores Cassin",
    "contact_number": "868.775.6054"
  },
  {
    "name": "Rose Klocko",
    "contact_number": "759-090-9777"
  },
  {
    "name": "Josiah Langworth I",
    "contact_number": "1-308-497-4606"
  },
  {
    "name": "Kattie Hamill",
    "contact_number": "266-980-1233"
  },
]

We can also use Faker in automated tests. For example here’s Capybara test using a fake user data to test Sign-Up feature:


name = Faker::Name.name
email =  Faker::Internet.email

visit("/signup")

fill_in('account_name', with: name)
fill_in('account_email', with: email)
click_button('Sign Up')

page.has_content?("Dear ${name}")
page.has_content?('Verify Your Email Address')

Here’s JavaScript version of the Ruby script made with Faker.js


var faker = require('faker')

landlords = []
for(i=0; i<100; i++) {
  var user = {
    name: faker.name.findName(),
    email: faker.phone.phoneNumber(),
  };
  landlords.push(user)
}

console.log(landlords);

By default, these libraries generate values which may not be unique. However, you can set options to generate unique values. You can also extend/customise the output.

You can find Java port of the Faker called Java Faker
There is also Python port available at https://github.com/joke2k/faker

Faker and friends are must have power tool for Developers and testers.


Adding Swagger UI support to Spring Boot REST API Project

Recently I was working on a project to build REST API using Spring Boot framework. I was looking for a way to document the service and all the operations supported by the service in an easy way. I used Swagger to document the API with really simple configurations.

Swagger does an awesome job to document your APIs directly from the source code.

The documentation and Swagger’s interactive Web UI helps users to explore the API, try supported operations with different input values and look at the output from the operation or any validations that are configured for the operation. My tester colleagues really liked this API playground.

Let’s explore steps to configure Swagger UI on an existing project.

In order to setup Swagger UI with the project, we will use Springfox library. The Springfox library enables Swagger by scanning the application, at runtime to infer API semantics based on Spring configurations, class structure and various compile time java Annotations. To get started with Springfox, we need to add following dependencies to POM (I’m using Maven for this project):

<dependency>
  <groupId>io.springfox</groupId>
  <artifactId>springfox-swagger2</artifactId>
  <version>2.6.1</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>io.springfox</groupId>
  <artifactId>springfox-swagger-ui</artifactId>
  <version>2.6.1</version>
  <scope>compile</scope>
</dependency>

Next, we need to configure Docket bean in the Application class which will do the rest of the magic:

@Bean
public Docket simpleDiffServiceApi() {
  return new Docket(DocumentationType.SWAGGER_2)
  .groupName("calculator")
  .apiInfo(apiInfo())
  .select()
  .apis(RequestHandlerSelectors.any())
  .paths(PathSelectors.any())
  .build()
  .pathMapping("/");

}

This will scan the service (in this example the Calculator service request handlers). We also need to pass the API info object which is used to configure API details like Tile, Description, Version, Developer Information etc. See the Springfox docs for more configuration options.

private ApiInfo apiInfo() {
  return new ApiInfoBuilder()
  .title("A simple calculator service")
  .description("A simple calculator REST service made with Spring Boot in Java")
  .contact(new Contact("Unmesh Gundecha", "http://unmesh.me", "upgundecha@gmail.com"))
  .version("1.0")
  .build();
}

Here is the Controller class for the Calculator Service with request handler for the add operation:

@RestController
@RequestMapping("api/v1/")
public class CalculatorController {

  @Autowired
  private Calculator calculatorService;

  @RequestMapping(value = "calculator/add", method = RequestMethod.POST)
  public Result add(@RequestBody Values values) {
  int result = calculatorService.add(values.getFirstNumber(),
  values.getSecondNumber());
  return new Result(result);
  }
}

That’s it. Let’s run this service using

mvn spring-boot:run

This will launch the application. Navigate to http://localhost:8080/swagger-ui.html in a Browser window. This will show the Swagger UI with the service details. In this example it will show the Calculator service with add operation as shown in below screenshot:

swagger1

Let’s open the /api/v1/calculator/add operation. This will show details about this operation as shown in below screenshot:

swagger2

Users can try the add operation or any other operation provided by the service by submitting parameters and using the Try it out! button on the form. Here is add operation in action:

calc_service

Operations can also be further explained using various Swagger Annotations like @ApiOperation, @ApiResponse etc.

You can also define a new API from scratch in Swagger format and generate source code in over dozen different frameworks supported by the Swagger. You can play with Swagger Editor and Swagger Codegen for building new APIs at Swagger Editor


Automated Acceptance testing for Mainframe with Cucumber and Jagacy

 

fullsizerender-1I often get questions around Mainframe Automation using Selenium. However Selenium automates browsers, that’s it! Selenium does not automate Mainframe Green screens, and it’s completely different technology.

Automating Mainframe Green screen is primarily needed to test front to back scenarios in complex transaction processing systems with Web and Mobile integration.

There are tools available that can be used to automate Mainframe Green screen interaction. In this post, we will see how to use Jagacy3270 from Jagacy Software along with Cucumber for writing Automated Acceptance Tests on Mainframe Green Screens also known as CICS interface.

About Jagacy3270

Jagacy3270 is a 3270 screen-scraping library written entirely in Java. As described on Jagacy product website it supports SSL, TN3270E, Internationalization, and over thirty languages. This library can be used to create highly reliable and faster screen-scraping applications. However, this tool comes with a cost and details are available on the website.

We can use this same screen-scraping capability to create automated tests on Mainframe Green screens.

Jagacy provides Session3270 class through which we can connect to a Mainframe host and read or write to screens to perform actions.

Writing Automated Acceptance Tests for Green Screens

We can use Jagacy along with testing frameworks like Cucumber in Agile Software development to automate acceptance criteria for Mainframe user stories involving Green screen interaction. These tests can be integrated into CI/CD pipeline and run in headless mode (Jagacy provides an Emulator screen mode or headless mode).

In this post, we will use a Mainframe host used in Jagacy examples to create a simple Automated Acceptance test for a Phonebook application. Here is our example user story

As I university mainframe user
I should be able to search faculty members in Phonebook
So I can contact them for help

Here is Feature file with one of the acceptance criteria or scenario that searches for Faculty phone number on Phonebook application:

Feature: Phonebook

  As I university mainframe user
  I should be able to search faculty members in Phonebook
  So I can contact them for help

  Scenario: Search faculty phone number using name
    Given I start a new emulator session
    When I open phonbook application
    And search for faculty name "NAME"
    Then I should see the results matching with my search criteria
      |NAME1              111-111-1111  LIBRARIES                    5000|
      |NAME2             UNAVAILABLE  MARY KAY O'CONNOR PROCESS    3122|

To automate Screen entry and retrieve values, we need to use screen coordinates by using Row and Column numbers (Typically 3270 sessions are 24×80 rows and columns long).

We can use PageObject Pattern to abstract Mainframe Green screens and provide screen actions and state to tests. For example, here is HomeScreen object which provides feature on the Home Screen:

package com.example.screens;

import com.example.Fields.EntryField;
import com.example.session.Session;
import com.example.Fields.LabelField;
import com.jagacy.Key;
import com.jagacy.util.JagacyException;

/**
 * Created by upgundecha on 14/10/16.
 */
public class HomeScreen {

    private Session session;
    private String screenCrc = "0xb0c10358";

    // Screen fields
    private LabelField waitForLabel =
            new LabelField(17, 6, "TEXAS A & M UNIVERSITY");
    private EntryField applicationEntryField = new EntryField(23, 1);

    public HomeScreen(final Session s) throws JagacyException {
        this.session = s;
        if (!session.waitForTextLabel(waitForLabel)) {
            throw new IllegalStateException("Not Home screen!");
        }

        if (session.getCrc32() != Long.decode(screenCrc)) {
            throw new IllegalStateException("Home Screen has been changed!");
        }
    }

    /**
     * Open Phonbook Menu screen.
     * @return Phonbook Menu Screen
     * @throws JagacyException JagacyException
     */
    public final PhonbookMenuScreen openPhonbook() throws JagacyException {
        session.setEntryFieldValue(applicationEntryField, "PHONBOOK");
        session.writeKey(Key.ENTER);
        session.waitForChange(10000);
        return new PhonbookMenuScreen(session);
    }
}

We can check if a correct page is displayed in the emulator by using the arbitrary text displayed on the screen. We can also use CRC of the screen to make sure it is not updated otherwise tests might fail as fields or text values on screen are not found at specified locations.

Finally, we will call the PageObjects in step definitions to perform the scenario and validate the output:

package com.example.test;

import com.example.screens.HomeScreen;
import com.example.screens.PhonbookMenuScreen;
import com.example.screens.PhonbookSearchScreen;
import com.example.session.Session;
import com.jagacy.util.JagacyException;
import cucumber.api.Scenario;
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 static org.junit.Assert.*;

import java.util.List;


/**
 * Created by upgundecha on 14/10/16.
 */
public class Stepdefs {

    private Session session;
    private HomeScreen homeScreen;
    private PhonbookMenuScreen phonbookMenuScreen;
    private PhonbookSearchScreen phonbookSearchScreen;
    private Scenario scenario;

    @Before
    public void setUp(Scenario scenario){
        this.scenario = scenario;
    }

    @Given("^I start a new emulator session$")
    public void i_start_a_new_emulator_session() throws Throwable {

        session = new Session("test");
        session.open();

    }

    @When("^I open phonbook application$")
    public void i_open_phonbook_application() throws Throwable {

        homeScreen = new HomeScreen(session);
        scenario.embed(session.getScreenshot(), "image/png");
        phonbookMenuScreen = homeScreen.openPhonbook();

    }

    @When("^search for faculty name \"([^\"]*)\"$")
    public void search_for_faculty_name(String q) throws Throwable {

        scenario.embed(session.getScreenshot(), "image/png");
        phonbookSearchScreen = phonbookMenuScreen.openFacultyStaffListing();
        phonbookSearchScreen.searchByFirstOrMiddleName(q);

    }

    @Then("^I should see the results matching with my search criteria$")
    public void i_should_see_the_results_matching_with_my_search_criteria(List<String> records) throws Throwable {

        scenario.embed(session.getScreenshot(), "image/png");
        assertEquals(records, phonbookSearchScreen.getResults());

    }

    @After
    public void tearDown() throws JagacyException {
        session.close();
    }
}

We can also get the screenshot (not available as part of Jagacy API) embedded in the reports.

And if you already have a well established Selenium framework (on JVM) and want to automate Mainframe Green screens, you can use above approach with Cucumber or any other xUnit testing framework that you might be using.

The complete source code for this post is available here. Please drop me a message for access with your Github username. I have built this simple framework on top of Jagacy API. If you need any further information or have suggestions, please do reach out to me.


Using Tesseract with Selenium WebDriver for checking text on images using OCR

Recently a team approached me looking for a solution to extract text from an image displayed on a web page and verify it’s contents as part of Selenium tests.

This post explains the solution using Tesseract, Tess4J along with Selenium for checking text displayed on images.

Tesseract is a famous open source OCR engine. It uses the Leptonica Image Processing Library. Tesseract support a wide variety of image formats and convert them to text in over 60 languages.

Tesseract works on Linux, Windows and Mac OSX. Please refer Readme page for installation instructions.

This sample is built on Mac. You can install Tesseract on Mac using homebrew:

brew install tesseract

In addition to Tesseract (written in C++), we need a Java wrapper called Tess4J which provides JNA wrapper for Tesseract OCR API.

Here is a sample page which has a barcode displayed as image. We will extract the barcode number and assert it’s value.

ocr_example

Since I am using Maven for this project, I added Tess4j dependency to my pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>me.unmesh</groupId>
    <artifactId>selenium-ocr-example</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>net.sourceforge.tess4j</groupId>
            <artifactId>tess4j</artifactId>
            <version>2.0.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>2.46.0</version>
        </dependency>
    </dependencies>
</project>

Here’s JUnit test which navigates to the sample page and checks the number displayed on the barcode image:

package me.unmesh.selenium.ocr.example;

import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.By;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;

import net.sourceforge.tess4j.*;
import java.io.File;

/**
 * A demo test to verify text from an image using Tesseract OCR API
 *
 * @author  upgundecha
 *
 */
public class BarcodeTest {
    private WebDriver driver;

    @Before
    public void setUp() {
        driver = new FirefoxDriver();
        // navigate to the dummy page with a barcode image
        driver.get("https://dl.dropboxusercontent.com/u/55228056/barcode.html");
    }

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

    @Test
    public void testBarcodeNumber() throws Exception {
        // get and capture the picture of the img element used to display the barcode image
        WebElement barcodeImage = driver.findElement(By.id("barcode"));
        File imageFile = WebElementExtender.captureElementPicture(barcodeImage);

        // get the Tesseract direct interace
        Tesseract instance = new Tesseract();

        // the doOCR method of Tesseract will retrive the text
        // from image captured by Selenium
        String result = instance.doOCR(imageFile);

        // check the the result
        assertEquals("Application number did not match", "123-45678", result.trim());
    }
}

Instead of capturing screenshot of the entire page using Selenium, I captured screenshot of the image element where the barcode is displayed on the page.

<html>
  <head>
    <title>Barcode Sample</title>
   </head>
  <body>
    <table>
      <tr>
        <td style="padding:10px; font-size:15px; font-family:Arial, Helvetica; text-align:center;">
          <p> Please write down your application id</p>
        <td>
          <img id="barcode" src="barcode.png" />
        </td>
      </tr>
  </table>
  </body>
 </html>

The captured image is then passed to doOCR() method of Tesseract instance to retrieve the text.

To capture the image of a WebElement I used captureElementPicture() method from WebElementExtender class which is described in my book Selenium Testing Tools Cookbook:

package me.unmesh.selenium.ocr.example;

import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.ImageIO;

import org.openqa.selenium.OutputType;
import org.openqa.selenium.Point;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.internal.WrapsDriver;

/**
 * This class provides various additional helper methods on elements
 *
 * @author upgundecha
 *
 */

public class WebElementExtender {

    /**
     * Gets a picture of specific element displayed on the page
     * @param element The element
     * @return File
     * @throws Exception
     */
    public static File captureElementPicture(WebElement element)
            throws Exception {

        // get the WrapsDriver of the WebElement
        WrapsDriver wrapsDriver = (WrapsDriver) element;

        // get the entire screenshot from the driver of passed WebElement
        File screen = ((TakesScreenshot) wrapsDriver.getWrappedDriver())
                .getScreenshotAs(OutputType.FILE);

        // create an instance of buffered image from captured screenshot
        BufferedImage img = ImageIO.read(screen);

        // get the width and height of the WebElement using getSize()
        int width = element.getSize().getWidth();
        int height = element.getSize().getHeight();

        // create a rectangle using width and height
        Rectangle rect = new Rectangle(width, height);

        // get the location of WebElement in a Point.
        // this will provide X & Y co-ordinates of the WebElement
        Point p = element.getLocation();

        // create image  for element using its location and size.
        // this will give image data specific to the WebElement
        BufferedImage dest = img.getSubimage(p.getX(), p.getY(), rect.width,
                rect.height);

        // write back the image data for element in File object
        ImageIO.write(dest, "png", screen);

        // return the File object containing image data
        return screen;
    }
}

Tesseract is clean, fast and accurate for OCR testing needs. Similar approach can be followed for .NET using Emgu library


iOS Automation with Appium & Selenium

Note: This post is not up to date with latest release of Appium. An update coming soon…

Yesterday I saw a tweet on Appium release from Sauce Labs and immediately started exploring it. This post summarizes my initial experience with Appium.

Appium (http://appium.io/) is an open source tool/framework for automating iOS Native and Hybrid Apps. It uses the WebDriver JSON wire protocol to drive iOS apps.

Appium server is written in Node.js and talks to iOS using UIAutomation via Instruments. You can use the Selenium WebDriver API for writing tests which talk to Appium via JSON wire protocol for running the Selenium commands. This also gives you advantage of writing tests in your language of preference.

Installation

I found installing Appium quite easy on a local machine. You need Node.js installed before using Appium.

1. Install Node.js from http://nodejs.org/

2. Install WebDriver package for Node.js with the following command

sudo npm install wd

3. Install Appium with the following command

sudo npm install appium -g

4. Start the Appium server with the following command

appium &

Appium server will start at http://localhost:4723

Implementing test using Selenium WebDriver

I am using a sample BMI Calculator App developed with native iOS SDK for this example

Bmi Calculator App

Bmi Calculator App

Build the app using xcodebuild command (In this example the BmiCalc app)

xcodebuild -sdk iphonesimulator6.1

I am using Maven to setup a Java project for this test and here is pom.xml with the following dependencies added. For this example I have used IntelliJ IDEA. For more information on using Maven for Selenium script development refer bonus Chapter Integration with other Tools from my Selenium Testing Tools Cookbook

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.bmicalc.test</groupId>
    <artifactId>bmi-ios-test</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-java</artifactId>
        <version>LATEST</version>
        <scope>test</scope>
    </dependency>
    </dependencies>
</project>

And here is BmiCalcTest class

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.By;

import java.io.File;
import java.net.URL;
import java.util.List;

import static org.junit.Assert.assertEquals;

public class BmiCalcTest {

    private WebDriver driver;

    @Before
    public void setUp() throws Exception {

        //Appium needs the path of app build
        //Set up the desired capabilities and pass the iOS SDK version and app path to Appium
        File app = new File("/Users/upgundecha/Desktop/AppExamples/BmiCalculator/build/Release-iphonesimulator/BmiCalculator.app");
        DesiredCapabilities capabilities = new DesiredCapabilities();
        capabilities.setCapability(CapabilityType.BROWSER_NAME, "iOS");
        capabilities.setCapability(CapabilityType.VERSION, "6.1");
        capabilities.setCapability(CapabilityType.PLATFORM, "Mac");
        capabilities.setCapability("app", app.getAbsolutePath());

        //Create an instance of RemoteWebDriver and connect to the Appium server.
        //Appium will launch the BmiCalc App in iPhone Simulator using the configurations specified in Desired Capabilities
        driver = new RemoteWebDriver(new URL("http://localhost:4723/wd/hub"), capabilities);
    }

    @Test
    public void testBmiCalc() throws Exception {

        //iOS controls are accessed through WebElement class
        //Locate the Height & Weight textField by their accessibility labels using By.name()
        WebElement heightTextField = driver.findElement(By.name("Height"));
        heightTextField.sendKeys("181");

        WebElement weightTextField = driver.findElement(By.name("Weight"));
        heightTextField.sendKeys("80");

        //Locate and tap on Calculate button using the click() method
        WebElement calculateButton =  driver.findElement(By.name("Calculate"));
        calculateButton.click();

        //Locate all the label elements using By.tagName()
        List<WebElement> labels = driver.findElements(By.tagName("staticText"));

        //Check the calculated Bmi and Category displayed on labels
        //Label with index 8 has value of the Bmi and index 9 has the value for category
        assertEquals("24.42",labels.get(8).getText());
        assertEquals("Normal",labels.get(9).getText());
    }

    @After
    public void tearDown() throws Exception {
        //Close the app and simulator
        driver.quit();
    }
}

I really liked using Selenium WebDriver API for writing iOS tests with Appium. I can add iOS support to my existing Selenium Framework with minimal changes. Appium presently supports locating elements using the tag name (i.e type of iOS control) and accessibility labels.

Running tests in Cloud

You can also run Appium with Sauce Labs Cloud, for more details read http://sauceio.com/index.php/2013/02/announcing-appium-on-sauce-native-hybrid-ios-testing-in-the-cloud/

Overall Appium is a great tool to start with.

References:
Getting Started – http://appium.io/getting-started.html
Appium on GitHub – http://sauceio.com/index.php/2013/02/announcing-appium-on-sauce-native-hybrid-ios-testing-in-the-cloud/
Samples – https://github.com/appium/appium/tree/master/sample-code
Wiki – https://github.com/appium/appium/wiki
Google Group – https://groups.google.com/forum/?hl=en&fromgroups=#!forum/appium-discuss