How to use WireMock for stubbing web services

WireMock is a library for stubbing and mocking REST Web services. This will be a handy one if we want to test external web services. When we use this, it will start a mock http server on the given port number so it looks like we are connecting to the actual web services.

Lets see how we can use this for writing JUnit test cases. Consider that you have two web services. one if for creating the user and another one is for fetching it. We don’t worry about the actual services. Let’s see how we can stub these services with WireMock.

I am going to use JUnit Rule for this example. Add the below dependencies in the maven pom.xml file.


<dependencies>
        <dependency>
            <groupId>com.github.tomakehurst</groupId>
            <artifactId>wiremock</artifactId>
            <version>2.7.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.core</groupId>
            <artifactId>jersey-client</artifactId>
            <version>2.18</version>
        </dependency>
        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-all</artifactId>
            <version>1.3</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

Now my test code is given below,


package com.wiremock;

import com.github.tomakehurst.wiremock.junit.WireMockRule;
import org.glassfish.jersey.client.JerseyClient;
import org.glassfish.jersey.client.JerseyClientBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;

import javax.ws.rs.core.Response;

import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.get;
import static com.github.tomakehurst.wiremock.client.WireMock.matching;
import static com.github.tomakehurst.wiremock.client.WireMock.post;
import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching;
import static javax.ws.rs.client.Entity.entity;
import static javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE;
import static org.junit.Assert.assertEquals;

public class WireMockTest {

    @Rule
    public WireMockRule rule = new WireMockRule(8080);

    private static String GET_USERS = "http://localhost:8080/users/12345";
    private static String POST_USER = "http://localhost:8080/users";
    private static String USER_CONTENT = "12345bala";

    JerseyClient client;

    @Before
    public void setUp() {
        client = JerseyClientBuilder.createClient();
    }

    @After
    public void tearDowm() {
        rule.shutdown();
    }

    private void stubFor(){
      rule.stubFor(post(urlEqualTo("/users")).willReturn(aResponse().withStatus(200));
rule.stubFor(get(urlEqualTo("/users/12345")).willReturn(
                aResponse().withHeader("Content-Type", "application/xml")
                        .withBody(USER_CONTENT)));
    }

    @Test
    public void testAddUser() {
        stubFor();
        client.target(POST_USER).request().post(entity(USER_CONTENT, APPLICATION_XML_TYPE));
        rule.verify(postRequestedFor(urlMatching("/users"))
                            .withRequestBody(matching(USER_CONTENT))
                            .withHeader("Content-Type", matching("application/xml")));

    }

    @Test
    public void testGetUser() {
        stubFor();
        Response response = client.target(GET_USERS).request().get();
        String output = response.readEntity(String.class);
        System.out.println("output: "+output);
        assertEquals(200, response.getStatus());
        assertEquals(USER_CONTENT, output);
    }
}

Explanation:
The first step is to add the WireMockRule and pass the port number on which the mock server is going to be run. You can specify any port number. By default its 8080.

Now the next step is to add the stubFor for both services(getUser, addUser)
For adding user service, the method is POST and it will return the response status as 200. For getting the user service, the method is GET and it will the return the static user response XML.

The next step is to call the services with the REST client object.
The final step is to do the verification. We can do the same kind of verification as such verifying the actual response.

Refer the code @https://github.com/dkbalachandar/java-wiremock-tester

How to use Mockito ArgumentCaptor

In this post, I am going to explain how we can use ArgumentCaptor to test out an internal object which is getting passed to some other class.

Consider that you have a Main class which has a method called “populateAndSavePersonData” which is used to construct the Person details(Person Object) and calls the “savePersonData” method from Dao class to populate the data into DB.  Now you want to test out the Person object and its values since it’s not getting returned from this class. So we have to either update the class to return the person object or we can use ArgumentCaptor to capture that object.

Refer the below example to know how we can do that.

Person.java


import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;

import java.io.Serializable;


public class Person implements Serializable {

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

    public String toString() {
        return ToStringBuilder.reflectionToString(this);
    }

    @Override
    public boolean equals(Object o) {
        return EqualsBuilder.reflectionEquals(this, o);
    }

    @Override
    public int hashCode() {
        return HashCodeBuilder.reflectionHashCode(this);
    }

}

Main.java and Dao.java


public class Main {

    private Dao dao;
    public Main(Dao dao){
        this.dao = dao;
    }
    public void populateAndSavePersonData(String firstName, String lastName) {

        Person person = new Person();
        person.setFirstName(firstName);
        person.setLastName(lastName);
        dao.savePersonData(person);
    }

    public class Dao {

        public void savePersonData(Person person) {
            // Code to save the data into DB
        }
    }
}

MainTest.java
In our test method, We have to create an ArgumentCaptor object and pass the appropriate object which you want to capture(Person). Then you have to call the actual method with the appropriate arguments. After that call “verify” method on Mockito object and pass the dao object and call the appropriate method(“savePersonData”) which gets called in the “populateAndSavePersonData” method. Finally, we have to get the value from ArgumentCaptor and check the value in it.


import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;

public class MainTest {

    @Test
    public void populateAndSavePersonData(){
        Main.Dao dao = Mockito.mock(Main.Dao.class);
        Main main = new Main(dao);
        ArgumentCaptor personArgumentCaptor = ArgumentCaptor.forClass(Person.class);
        main.populateAndSavePersonData("Bala","Samy");
        Mockito.verify(dao).savePersonData(personArgumentCaptor.capture());
        Person person = personArgumentCaptor.getValue();
        assertEquals("Bala",person.getFirstName());
        assertEquals("Samy",person.getLastName());
        System.out.println(person);
    }
}

 

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.

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

Build Operate Check – Acceptance Pattern

Build operate Check is one of the acceptance pattern. So its good that to follow this pattern while creating the Junit test cases.

The first step is to build the input data and hold it in memory, then execute it on the actual code which means call/invoke the code to operate on that data. Finally check the results of that operation.

Please refer the below example.


package com.dao.test;

import org.junit.Test;
import static org.junit.Assert.assertNotNull;
import com.dao.ContactDAO;
import com.model.Contact;

public class ContactDAOTest{
    @Test
    public void testCreateContactData() throws Exception {
        //Build the test data
        Contact contact = buildContactData("bala","dublin");
        //Call the ContactDAO to create the contact information. Assume that 
        //Create() returns an id after the successful creation of the contact in DB
        String id = new ContactDAO().create(contact);
        //check the id and make sure that its not null/blank
        assertNotNull(id);
    }

    private Contact buildContactData(String name, String city) {
        Contact contact = new Contact();
        contact.setName(name);
        contact.setCity(city);
        return contact;
    }
}



package com.model;
public static class Contact {

        private String id;
        private String name;
        private String city;

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getCity() {
            return city;
        }

        public void setCity(String city) {
            this.city = city;
        }
    }