Sunday, 17 May 2020

WireMock: Generate Dynamic response from query parameter

We can generate dynamic response using Response templates.

 

Step 1: Create WireMockRule using ResponseTemplateTransformer.

public WireMockRule wireMockRule = new WireMockRule(WireMockConfiguration.options().port(HTTP_SERVICE_PORT).httpsPort(HTTPS_SERVICE_PORT).notifier(new ConsoleNotifier(true)).extensions(new ResponseTemplateTransformer(true)));

 

Step 2: Create a response json using response template.

queryNameTemplate.json
[
	{
		"id": 1,
		"firstName": "{{request.query.empName}}",
		"lastName": "Ponnam"
	},
	{
		"id": 2,
		"firstName": "Lakshman",
		"lastName": "{{request.query.empName}}"
	}
]

{{request.query.empName}}: Access the value associated with query parameter empName.

 

Step 3: Create a stub that return response from queryNameTemplate.json file.

wireMockRule.stubFor(get(urlPathEqualTo("/api/v1/employees/by-name/")).withQueryParam("empName", equalTo(nameSubStr)).willReturn(aResponse().withStatus(200).withHeader("Content-Type", "application/json").withBodyFile("queryNameTemplate.json")));

 

Find the below working application.

 

Employee.java
package com.sample.app.model;

public class Employee {

	private int id;
	private String firstName;
	private String lastName;

	public int getId() {
		return id;
	}

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

	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 "Employee [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + "]";
	}

}

EmployeeApiException.java

package com.sample.app.exception;

public class EmployeeApiException extends RuntimeException {

	private static final long serialVersionUID = 119874212393098L;

	public EmployeeApiException(String msg) {
		super(msg);
	}

}

EmployeeService.java

package com.sample.app.service;

import java.util.List;

import com.sample.app.model.Employee;

public interface EmployeeService {

	public List<Employee> emps();

	public Employee byId(int id);

	public List<Employee> containsName(String name);

	public Employee addEmployee(Employee emp);

	public Employee updateEmployee(int id, Employee emp);

	public Employee deleteEmployee(int id);

}

EmployeeRestClient.java

package com.sample.app.service.impl;

import java.util.List;

import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import org.springframework.web.util.UriComponentsBuilder;

import com.sample.app.exception.EmployeeApiException;
import com.sample.app.model.Employee;
import com.sample.app.service.EmployeeService;

public class EmployeeRestClient implements EmployeeService {

	private WebClient webClient;

	public EmployeeRestClient(WebClient webClient) {
		this.webClient = webClient;
	}

	@Override
	public List<Employee> emps() {

		return webClient.get().uri("api/v1/employees").retrieve().bodyToFlux(Employee.class).collectList().block();
	}

	@Override
	public Employee byId(int id) {
		try {
			return webClient.get().uri("api/v1/employees/" + id).retrieve().bodyToMono(Employee.class).block();
		}catch(WebClientResponseException e) {
			throw new EmployeeApiException(e.getMessage() + "," + e.getRawStatusCode());
		}
		
	}

	@Override
	public List<Employee> containsName(String name) {
		String uriToHit = UriComponentsBuilder.fromUriString("api/v1/employees/by-name/").queryParam("empName", name)
				.buildAndExpand().toString();

		return webClient.get().uri(uriToHit).retrieve().bodyToFlux(Employee.class).collectList().block();
	}

	@Override
	public Employee addEmployee(Employee emp) {
		return webClient.post().uri("api/v1/employees").syncBody(emp).retrieve().bodyToMono(Employee.class).block();
	}

	@Override
	public Employee updateEmployee(int id, Employee emp) {
		return webClient.put().uri("api/v1/employees/" + id).syncBody(emp).retrieve().bodyToMono(Employee.class)
				.block();
	}

	@Override
	public Employee deleteEmployee(int id) {
		return webClient.delete().uri("api/v1/employees/" + id).retrieve().bodyToMono(Employee.class).block();
	}

}

EmployeeRestClientTest.java

package com.sample.app.service;

import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.anyUrl;
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
import static com.github.tomakehurst.wiremock.client.WireMock.get;
import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
import static com.github.tomakehurst.wiremock.client.WireMock.urlPathMatching;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.web.reactive.function.client.WebClient;

import com.github.tomakehurst.wiremock.common.ConsoleNotifier;
import com.github.tomakehurst.wiremock.common.Json;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import com.github.tomakehurst.wiremock.extension.responsetemplating.ResponseTemplateTransformer;
import com.github.tomakehurst.wiremock.junit.WireMockRule;
import com.sample.app.exception.EmployeeApiException;
import com.sample.app.model.Employee;
import com.sample.app.service.impl.EmployeeRestClient;

public class EmployeeRestClientTest {
	private static final int HTTP_SERVICE_PORT = 8888;
	private static final int HTTPS_SERVICE_PORT = 9999;

	private List<Employee> ALL_EMPLOYEES = new ArrayList<>();

	private EmployeeRestClient empRestClient;
	private String baseURI;

	private static int idCounter = 1;

	private static Employee buildEmployee(String firstName, String lastName) {
		Employee emp = new Employee();
		emp.setId(idCounter);
		emp.setFirstName(firstName);
		emp.setLastName(lastName);

		idCounter++;

		return emp;
	}

	@Before
	public void initializeEmployees() {
		Employee emp1 = buildEmployee("Deepak", "Moud");
		Employee emp2 = buildEmployee("Srinivasa Rao", "Gumma");
		Employee emp3 = buildEmployee("Purna Chandra", "Rao");
		Employee emp4 = buildEmployee("Madhavi Latha", "Gumma");
		Employee emp5 = buildEmployee("Raghava", "Reddy");
		Employee emp6 = buildEmployee("Ramesh Chandra", "Dokku");

		ALL_EMPLOYEES.addAll(Arrays.asList(emp1, emp2, emp3, emp4, emp5, emp6));

	}

	@Before
	public void setup() {
		baseURI = "http://localhost:" + wireMockRule.port() + "/";

		WebClient webClient = WebClient.create(baseURI);
		empRestClient = new EmployeeRestClient(webClient);
	}

	@Rule
	public WireMockRule wireMockRule = new WireMockRule(
			WireMockConfiguration.options().port(HTTP_SERVICE_PORT).httpsPort(HTTPS_SERVICE_PORT)
					.notifier(new ConsoleNotifier(true)).extensions(new ResponseTemplateTransformer(true)));

	@Test
	public void allEmployeeForAnyURL() {

		wireMockRule.stubFor(get(anyUrl()).willReturn(aResponse().withStatus(200)
				.withHeader("Content-Type", "application/json").withBody(Json.write(ALL_EMPLOYEES))));

		List<Employee> resultFromService = empRestClient.emps();

		assertEquals(resultFromService.size(), 6);

	}

	@Test
	public void allEmployeeForEactURLPath() {

		wireMockRule.stubFor(get(urlPathEqualTo("/api/v1/employees")).willReturn(aResponse().withStatus(200)
				.withHeader("Content-Type", "application/json").withBody(Json.write(ALL_EMPLOYEES))));

		List<Employee> resultFromService = empRestClient.emps();

		assertEquals(resultFromService.size(), 6);

	}

	@Test
	public void getEmployeeById() {

		Employee emp = new Employee();
		emp.setId(Integer.MAX_VALUE);
		emp.setFirstName("Chamu");
		emp.setLastName("Gurram");

		wireMockRule.stubFor(get(urlPathMatching("/api/v1/employees/[1-5]")).willReturn(
				aResponse().withStatus(200).withHeader("Content-Type", "application/json").withBody(Json.write(emp))));

		for (int i = 1; i < 6; i++) {

			Employee resultEmp = empRestClient.byId(1);

			assertNotNull(resultEmp);
			assertEquals(Integer.MAX_VALUE, resultEmp.getId());
			assertEquals("Chamu", resultEmp.getFirstName());
			assertEquals("Gurram", resultEmp.getLastName());

		}

	}

	@Test
	public void allEmployeeFromFile() {

		wireMockRule.stubFor(get(urlPathEqualTo("/api/v1/employees")).willReturn(aResponse().withStatus(200)
				.withHeader("Content-Type", "application/json").withBodyFile("allEmployees.json")));

		List<Employee> resultFromService = empRestClient.emps();

		assertEquals(resultFromService.size(), 2);

		Employee emp = resultFromService.get(0);

		if (emp.getId() == 1) {
			assertEquals("Ram", emp.getFirstName());
			assertEquals("Ponnam", emp.getLastName());
		} else if (emp.getId() == 2) {
			assertEquals("Lakshman", emp.getFirstName());
			assertEquals("Gurram", emp.getLastName());
		}

	}

	@Test
	public void getEmployeeByIdUsingResponseTemplate() {

		wireMockRule.stubFor(get(urlPathMatching("/api/v1/employees/3")).willReturn(aResponse().withStatus(200)
				.withHeader("Content-Type", "application/json").withBodyFile("employeeByIdTemplate.json")));

		Employee resultEmp = empRestClient.byId(3);

		assertNotNull(resultEmp);
		assertEquals(3, resultEmp.getId());
		assertEquals("Ram", resultEmp.getFirstName());
		assertEquals("Ponnam", resultEmp.getLastName());

	}

	@Test(expected = EmployeeApiException.class)
	public void getEmployeeByIdNotFound() {

		int empId = 12345;

		wireMockRule.stubFor(get(urlPathMatching("/api/v1/employees/" + empId))
				.willReturn(aResponse().withStatus(404).withHeader("Content-Type", "application/json")));

		empRestClient.byId(12345);

	}

	@Test(expected = EmployeeApiException.class)
	public void getEmployeeByIdNotFoundReturnErrorPayloadFromFile() {

		int empId = 12345;

		wireMockRule.stubFor(get(urlPathMatching("/api/v1/employees/" + empId)).willReturn(
				aResponse().withStatus(404).withHeader("Content-Type", "application/json").withBodyFile("404.json")));

		empRestClient.byId(12345);

	}

	@Test
	public void getEmployeesContainsNameViaQueryParam() {
		List<Employee> employeesContainNameGurram = new ArrayList<>();

		employeesContainNameGurram.add(buildEmployee("Bala Krishna", "Gurram"));
		employeesContainNameGurram.add(buildEmployee("Gurram", "Srinu"));

		String nameSubStr = "Gurram";

		wireMockRule.stubFor(
				get(urlPathEqualTo("/api/v1/employees/by-name/")).withQueryParam("empName", equalTo(nameSubStr))
						.willReturn(aResponse().withStatus(200).withHeader("Content-Type", "application/json")
								.withBody(Json.write(employeesContainNameGurram))));

		List<Employee> resultFromService = empRestClient.containsName(nameSubStr);

		assertEquals(resultFromService.size(), 2);

	}

	@Test
	public void getEmployeesContainsNameViaResponseTemplate() {
		String nameSubStr = "Kumar";

		wireMockRule.stubFor(get(urlPathEqualTo("/api/v1/employees/by-name/"))
				.withQueryParam("empName", equalTo(nameSubStr)).willReturn(aResponse().withStatus(200)
						.withHeader("Content-Type", "application/json").withBodyFile("queryNameTemplate.json")));

		List<Employee> emps = empRestClient.containsName(nameSubStr);

		assertEquals(emps.size(), 2);

		for (Employee emp : emps) {
			if (emp.getId() == 1) {
				assertEquals("Kumar", emp.getFirstName());
				assertEquals("Ponnam", emp.getLastName());
			} else if (emp.getId() == 2) {
				assertEquals("Lakshman", emp.getFirstName());
				assertEquals("Kumar", emp.getLastName());
			}

		}

	}

}

Create __files directory in src/test/resources and define 'allEmployees.json', 'employeeByIdTemplate.json', 404.json, queryNameTemplate.json files.

 

allEmployees.json
[
	{
		"id": 1,
		"firstName": "Ram",
		"lastName": "Ponnam"
	},
	{
		"id": 2,
		"firstName": "Lakshman",
		"lastName": "Gurram"
	}
]

employeeByIdTemplate.json

{
	"id": "{{request.path.[3]}}",
	"firstName": "Ram",
	"lastName": "Ponnam"
}

404.json

{
	"timeStamp": "{{now}}",
	"uri": "{{request.path}}",
	"message": "Requested resource not found",
	"errorCode": 404
}

queryNameTemplate.json

[
	{
		"id": 1,
		"firstName": "{{request.query.empName}}",
		"lastName": "Ponnam"
	},
	{
		"id": 2,
		"firstName": "Lakshman",
		"lastName": "{{request.query.empName}}"
	}
]

pom.xml

<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>com.sample.app</groupId>
	<artifactId>employee-rest-client</artifactId>
	<version>1</version>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.6.RELEASE</version>
	</parent>


	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-webflux</artifactId>
		</dependency>

		<dependency>
			<groupId>com.github.tomakehurst</groupId>
			<artifactId>wiremock-jre8-standalone</artifactId>
			<version>2.26.3</version>
			<scope>test</scope>
		</dependency>

		<!-- https://mvnrepository.com/artifact/junit/junit -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<scope>test</scope>
		</dependency>


	</dependencies>
</project>

Total project structure looks like below.


Run EmployeeRestClientTest.java to run junit test cases.

 

You can download complete working application from this link.




Previous                                                    Next                                                    Home

No comments:

Post a Comment