Spring WebClient Mocking Code Repo (#7525)
* adding complete code implementation of Hexagonal Architectute example * refactored the code * added the webclient mocking * removed the unwanted repo * updated the test cases * removed commented code * fixed the code review comments * fixed the test cases * removed unwanted dependencies * removed the unwanted project * fixed the code review comments * added the mock to the variable name * added the mock to the variable name * addressed the code review comments * removed the unnecessary semi colon * fixed the compilation issues * Update spring-5-reactive-client/pom.xml Co-Authored-By: KevinGilmore <kpg102@gmail.com> * Update spring-5-reactive-client/pom.xml Co-Authored-By: KevinGilmore <kpg102@gmail.com> * added the missing dependency * fixed the compilation issue in the pom.xml file
This commit is contained in:
parent
2757d0a3ad
commit
0a67756dee
@ -54,6 +54,18 @@
|
|||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
<artifactId>commons-lang3</artifactId>
|
<artifactId>commons-lang3</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- okhttp -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.okhttp3</groupId>
|
||||||
|
<artifactId>okhttp</artifactId>
|
||||||
|
<version>4.0.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.okhttp3</groupId>
|
||||||
|
<artifactId>mockwebserver</artifactId>
|
||||||
|
<version>4.0.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- runtime and test scoped -->
|
<!-- runtime and test scoped -->
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -88,14 +100,25 @@
|
|||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
<!-- WebClient logging with Jetty -->
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-junit-jupiter</artifactId>
|
||||||
|
<version>2.23.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.projectreactor</groupId>
|
||||||
|
<artifactId>reactor-test</artifactId>
|
||||||
|
<version>3.2.10.RELEASE</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>jetty-reactive-httpclient</artifactId>
|
<artifactId>jetty-reactive-httpclient</artifactId>
|
||||||
<version>${jetty-reactive-httpclient.version}</version>
|
<version>${jetty-reactive-httpclient.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
@ -108,6 +131,29 @@
|
|||||||
<layout>JAR</layout>
|
<layout>JAR</layout>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>1.8</source>
|
||||||
|
<target>1.8</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>2.22.0</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>2.19.1</version>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.platform</groupId>
|
||||||
|
<artifactId>junit-platform-surefire-provider</artifactId>
|
||||||
|
<version>1.0.1</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.baeldung.reactive.enums;
|
||||||
|
|
||||||
|
public enum Role {
|
||||||
|
ENGINEER, SENIOR_ENGINEER, LEAD_ENGINEER
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
package com.baeldung.reactive.model;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baeldung.reactive.enums.Role;
|
||||||
|
|
||||||
|
public class Employee {
|
||||||
|
private Integer employeeId;
|
||||||
|
private String firstName;
|
||||||
|
private String lastName;
|
||||||
|
private Integer age;
|
||||||
|
private Role role;
|
||||||
|
|
||||||
|
public Employee() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Employee(Integer employeeId, String firstName, String lastName, Integer age, Role role) {
|
||||||
|
this.employeeId = employeeId;
|
||||||
|
this.firstName = firstName;
|
||||||
|
this.lastName = lastName;
|
||||||
|
this.age = age;
|
||||||
|
this.role = role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getEmployeeId() {
|
||||||
|
return employeeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmployeeId(Integer employeeId) {
|
||||||
|
this.employeeId = employeeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 Integer getAge() {
|
||||||
|
return age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAge(Integer age) {
|
||||||
|
this.age = age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Role getRole() {
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRole(Role role) {
|
||||||
|
this.role = role;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,55 @@
|
|||||||
|
package com.baeldung.reactive.service;
|
||||||
|
import com.baeldung.reactive.model.Employee;
|
||||||
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
public class EmployeeService {
|
||||||
|
|
||||||
|
private WebClient webClient;
|
||||||
|
public static String PATH_PARAM_BY_ID = "/employee/{id}";
|
||||||
|
public static String ADD_EMPLOYEE = "/employee";
|
||||||
|
|
||||||
|
public EmployeeService(WebClient webClient) {
|
||||||
|
this.webClient = webClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EmployeeService(String baseUrl) {
|
||||||
|
this.webClient = WebClient.create(baseUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Mono<Employee> getEmployeeById(Integer employeeId) {
|
||||||
|
return webClient
|
||||||
|
.get()
|
||||||
|
.uri(PATH_PARAM_BY_ID, employeeId)
|
||||||
|
.retrieve()
|
||||||
|
.bodyToMono(Employee.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Mono<Employee> addNewEmployee(Employee newEmployee) {
|
||||||
|
|
||||||
|
return webClient
|
||||||
|
.post()
|
||||||
|
.uri(ADD_EMPLOYEE)
|
||||||
|
.syncBody(newEmployee)
|
||||||
|
.retrieve().
|
||||||
|
bodyToMono(Employee.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Mono<Employee> updateEmployee(Integer employeeId, Employee updateEmployee) {
|
||||||
|
|
||||||
|
return webClient
|
||||||
|
.put()
|
||||||
|
.uri(PATH_PARAM_BY_ID,employeeId)
|
||||||
|
.syncBody(updateEmployee)
|
||||||
|
.retrieve()
|
||||||
|
.bodyToMono(Employee.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Mono<String> deleteEmployeeById(Integer employeeId) {
|
||||||
|
return webClient
|
||||||
|
.delete()
|
||||||
|
.uri(PATH_PARAM_BY_ID,employeeId)
|
||||||
|
.retrieve()
|
||||||
|
.bodyToMono(String.class);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,121 @@
|
|||||||
|
package com.baeldung.reactive.service;
|
||||||
|
|
||||||
|
import com.baeldung.reactive.model.Employee;
|
||||||
|
import com.baeldung.reactive.enums.Role;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import okhttp3.mockwebserver.MockResponse;
|
||||||
|
import okhttp3.mockwebserver.MockWebServer;
|
||||||
|
import okhttp3.mockwebserver.RecordedRequest;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.jupiter.api.*;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
import reactor.test.StepVerifier;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class EmployeeServiceIntegrationTest {
|
||||||
|
|
||||||
|
public static MockWebServer mockBackEnd;
|
||||||
|
private EmployeeService employeeService;
|
||||||
|
private ObjectMapper MAPPER = new ObjectMapper();
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
static void setUp() throws IOException {
|
||||||
|
mockBackEnd = new MockWebServer();
|
||||||
|
mockBackEnd.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
static void tearDown() throws IOException {
|
||||||
|
mockBackEnd.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void initialize() {
|
||||||
|
|
||||||
|
String baseUrl = String.format("http://localhost:%s", mockBackEnd.getPort());
|
||||||
|
employeeService = new EmployeeService(baseUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getEmployeeById() throws Exception {
|
||||||
|
|
||||||
|
Employee mockEmployee = new Employee(100, "Adam", "Sandler", 32, Role.LEAD_ENGINEER);
|
||||||
|
mockBackEnd.enqueue(new MockResponse().setBody(MAPPER.writeValueAsString(mockEmployee))
|
||||||
|
.addHeader("Content-Type", "application/json"));
|
||||||
|
|
||||||
|
Mono<Employee> employeeMono = employeeService.getEmployeeById(100);
|
||||||
|
|
||||||
|
StepVerifier.create(employeeMono)
|
||||||
|
.expectNextMatches(employee -> employee.getRole().equals(Role.LEAD_ENGINEER))
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
RecordedRequest recordedRequest = mockBackEnd.takeRequest();
|
||||||
|
assertEquals("GET", recordedRequest.getMethod());
|
||||||
|
assertEquals("/employee/100", recordedRequest.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void addNewEmployee() throws Exception {
|
||||||
|
|
||||||
|
Employee newEmployee = new Employee(null, "Adam", "Sandler", 32, Role.LEAD_ENGINEER);
|
||||||
|
Employee webClientResponse = new Employee(100, "Adam", "Sandler", 32, Role.LEAD_ENGINEER);
|
||||||
|
mockBackEnd.enqueue(new MockResponse().setBody(MAPPER.writeValueAsString(webClientResponse))
|
||||||
|
.addHeader("Content-Type", "application/json"));
|
||||||
|
|
||||||
|
Mono<Employee> employeeMono = employeeService.addNewEmployee(newEmployee);
|
||||||
|
|
||||||
|
StepVerifier.create(employeeMono)
|
||||||
|
.expectNextMatches(employee -> employee.getEmployeeId().equals(100))
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
RecordedRequest recordedRequest = mockBackEnd.takeRequest();
|
||||||
|
assertEquals("POST", recordedRequest.getMethod());
|
||||||
|
assertEquals("/employee", recordedRequest.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void updateEmployee() throws Exception {
|
||||||
|
|
||||||
|
Integer newAge = 33;
|
||||||
|
String newLastName = "Sandler New";
|
||||||
|
Employee updateEmployee = new Employee(100, "Adam", newLastName, newAge, Role.LEAD_ENGINEER);
|
||||||
|
mockBackEnd.enqueue(new MockResponse().setBody(MAPPER.writeValueAsString(updateEmployee))
|
||||||
|
.addHeader("Content-Type", "application/json"));
|
||||||
|
|
||||||
|
Mono<Employee> updatedEmploye = employeeService.updateEmployee(100, updateEmployee);
|
||||||
|
|
||||||
|
StepVerifier.create(updatedEmploye)
|
||||||
|
.expectNextMatches(employee -> employee.getLastName().equals(newLastName) && employee.getAge() == newAge)
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
RecordedRequest recordedRequest = mockBackEnd.takeRequest();
|
||||||
|
assertEquals("PUT", recordedRequest.getMethod());
|
||||||
|
assertEquals("/employee/100", recordedRequest.getPath());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void deleteEmployee() throws Exception {
|
||||||
|
|
||||||
|
String responseMessage = "Employee Deleted SuccessFully";
|
||||||
|
Integer employeeId = 100;
|
||||||
|
mockBackEnd.enqueue(new MockResponse().setBody(MAPPER.writeValueAsString(responseMessage))
|
||||||
|
.addHeader("Content-Type", "application/json"));
|
||||||
|
|
||||||
|
Mono<String> deletedEmployee = employeeService.deleteEmployeeById(employeeId);
|
||||||
|
|
||||||
|
StepVerifier.create(deletedEmployee)
|
||||||
|
.expectNext("\"Employee Deleted SuccessFully\"")
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
RecordedRequest recordedRequest = mockBackEnd.takeRequest();
|
||||||
|
assertEquals("DELETE", recordedRequest.getMethod());
|
||||||
|
assertEquals("/employee/100", recordedRequest.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,114 @@
|
|||||||
|
package com.baeldung.reactive.service;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baeldung.reactive.model.Employee;
|
||||||
|
import com.baeldung.reactive.enums.Role;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.exceptions.base.MockitoException;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
import reactor.test.StepVerifier;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class EmployeeServiceUnitTest {
|
||||||
|
|
||||||
|
EmployeeService employeeService;
|
||||||
|
@Mock
|
||||||
|
private WebClient webClientMock;
|
||||||
|
@Mock
|
||||||
|
private WebClient.RequestHeadersSpec requestHeadersMock;
|
||||||
|
@Mock
|
||||||
|
private WebClient.RequestHeadersUriSpec requestHeadersUriMock;
|
||||||
|
@Mock
|
||||||
|
private WebClient.RequestBodySpec requestBodyMock;
|
||||||
|
@Mock
|
||||||
|
private WebClient.RequestBodyUriSpec requestBodyUriMock;
|
||||||
|
@Mock
|
||||||
|
private WebClient.ResponseSpec responseMock;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
employeeService = new EmployeeService(webClientMock);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenEmployeeId_whenGetEmployeeById_thenReturnEmployee() {
|
||||||
|
|
||||||
|
Integer employeeId = 100;
|
||||||
|
Employee mockEmployee = new Employee(100, "Adam", "Sandler", 32, Role.LEAD_ENGINEER);
|
||||||
|
when(webClientMock.get()).thenReturn(requestHeadersUriMock);
|
||||||
|
when(requestHeadersUriMock.uri("/employee/{id}", employeeId)).thenReturn(requestHeadersMock);
|
||||||
|
when(requestHeadersMock.retrieve()).thenReturn(responseMock);
|
||||||
|
when(responseMock.bodyToMono(Employee.class)).thenReturn(Mono.just(mockEmployee));
|
||||||
|
|
||||||
|
Mono<Employee> employeeMono = employeeService.getEmployeeById(employeeId);
|
||||||
|
|
||||||
|
StepVerifier.create(employeeMono)
|
||||||
|
.expectNextMatches(employee -> employee.getRole().equals(Role.LEAD_ENGINEER))
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenEmployee_whenAddEmployee_thenAddNewEmployee() {
|
||||||
|
|
||||||
|
Employee newEmployee = new Employee(null, "Adam", "Sandler", 32, Role.LEAD_ENGINEER);
|
||||||
|
Employee webClientResponse = new Employee(100, "Adam", "Sandler", 32, Role.LEAD_ENGINEER);
|
||||||
|
when(webClientMock.post()).thenReturn(requestBodyUriMock);
|
||||||
|
when(requestBodyUriMock.uri(EmployeeService.ADD_EMPLOYEE)).thenReturn(requestBodyMock);
|
||||||
|
when(requestBodyMock.syncBody(newEmployee)).thenReturn(requestHeadersMock);
|
||||||
|
when(requestHeadersMock.retrieve()).thenReturn(responseMock);
|
||||||
|
when(responseMock.bodyToMono(Employee.class)).thenReturn(Mono.just(webClientResponse));
|
||||||
|
|
||||||
|
Mono<Employee> employeeMono = employeeService.addNewEmployee(newEmployee);
|
||||||
|
|
||||||
|
StepVerifier.create(employeeMono)
|
||||||
|
.expectNextMatches(employee -> employee.getEmployeeId().equals(100))
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenEmployee_whenupdateEmployee_thenUpdatedEmployee() {
|
||||||
|
|
||||||
|
Integer newAge = 33;
|
||||||
|
String newLastName = "Sandler New";
|
||||||
|
Employee updateEmployee = new Employee(100, "Adam", newLastName, newAge, Role.LEAD_ENGINEER);
|
||||||
|
when(webClientMock.put()).thenReturn(requestBodyUriMock);
|
||||||
|
when(requestBodyUriMock.uri(EmployeeService.PATH_PARAM_BY_ID, 100)).thenReturn(requestBodyMock);
|
||||||
|
when(requestBodyMock.syncBody(updateEmployee)).thenReturn(requestHeadersMock);
|
||||||
|
when(requestHeadersMock.retrieve()).thenReturn(responseMock);
|
||||||
|
when(responseMock.bodyToMono(Employee.class)).thenReturn(Mono.just(updateEmployee));
|
||||||
|
|
||||||
|
Mono<Employee> updatedEmployee = employeeService.updateEmployee(100, updateEmployee);
|
||||||
|
|
||||||
|
StepVerifier.create(updatedEmployee)
|
||||||
|
.expectNextMatches(employee -> employee.getLastName().equals(newLastName) && employee.getAge() == newAge)
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void givenEmployee_whenDeleteEmployeeById_thenDeleteSuccessful() {
|
||||||
|
|
||||||
|
String responseMessage = "Employee Deleted SuccessFully";
|
||||||
|
when(webClientMock.delete()).thenReturn(requestHeadersUriMock);
|
||||||
|
when(requestHeadersUriMock.uri(EmployeeService.PATH_PARAM_BY_ID, 100)).thenReturn(requestHeadersMock);
|
||||||
|
when(requestHeadersMock.retrieve()).thenReturn(responseMock);
|
||||||
|
when(responseMock.bodyToMono(String.class)).thenReturn(Mono.just(responseMessage));
|
||||||
|
|
||||||
|
Mono<String> deletedEmployee = employeeService.deleteEmployeeById(100);
|
||||||
|
|
||||||
|
StepVerifier.create(deletedEmployee)
|
||||||
|
.expectNext(responseMessage)
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user