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>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</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 -->
|
||||
<dependency>
|
||||
|
@ -88,14 +100,25 @@
|
|||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- WebClient logging with Jetty -->
|
||||
<dependency>
|
||||
<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>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-reactive-httpclient</artifactId>
|
||||
<version>${jetty-reactive-httpclient.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -108,6 +131,29 @@
|
|||
<layout>JAR</layout>
|
||||
</configuration>
|
||||
</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>
|
||||
</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…
Reference in New Issue