DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Be Punctual! Avoiding Kotlin’s lateinit In Spring Boot Testing
  • Spring Boot - Unit Test your project architecture with ArchUnit
  • Top 10 Advanced Java and Spring Boot Courses for Full-Stack Java Developers
  • Advanced Functional Testing in Spring Boot Using Docker in Tests

Trending

  • Advancing Robot Vision and Control
  • The Perfection Trap: Rethinking Parkinson's Law for Modern Engineering Teams
  • The Role of AI in Identity and Access Management for Organizations
  • Building a Real-Time Audio Transcription System With OpenAI’s Realtime API
  1. DZone
  2. Coding
  3. Frameworks
  4. Spring Boot WebClient and Unit Testing

Spring Boot WebClient and Unit Testing

Learn more about the Spring Boot WebClient and writing your own unit test cases.

By 
Deepak Mehra user avatar
Deepak Mehra
·
Jul. 11, 19 · Tutorial
Likes (4)
Comment
Save
Tweet
Share
74.5K Views

Join the DZone community and get the full member experience.

Join For Free

In this article, we will talk about the Spring Boot WebClient. If you are using Spring WebFlux, you can choose to use WebClient to call external rest services. It was introduced in Spring 5 as part of the web reactive framework that helps build reactive and non-blocking web applications.

WebClient is simply an interface that offers methods to make calls to rest services. This includes methods like GET, POST, PUT, PATCH, DELETE, and OPTIONS. You can leverage any of these methods to make calls to the external service asynchronously.

The main advantage of using the WebClient is that it is reactive, as it uses Webflux and is also non-blocking by nature and the response will always be returned in either Mono or Flux. So, make sure you are using Spring WebFlux already if you plan to use WebClient to make API calls.

How to Use Spring WebClient?

Note that I would be using a Maven build tool to show the demo. If you are using any other build tool, please find the dependency on the Internet, as they should be easily available.

Step 1. Add Spring WebFlux dependency to you POM.XML

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


Step 2. Create an interface with a method that will return the response from the REST call.

public interface ContentService {
    public Mono<Post> getPost(int id);
}


Step 3. Create a ServiceImpl class that will have the implementation of the Service interface created in Step 2.

@Service
public class ContentServiceImpl implements ContentService {

    private static final Logger LOGGER = Logger.getLogger(ContentServiceImpl.class.getName());

    private final WebClient webClient;

    public ContentServiceImpl(@Value("${content-service}") String baseURL) {
        this.webClient = WebClient.builder().baseUrl(baseURL)
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE)
                .filter(logRequest())
                .build();
    }

    @Override
    public Mono<Post> getPost(int id) {
        return webClient.get().uri("posts/{id}", id).retrieve().bodyToMono(Post.class);
    }

}


In step 3, we have created an instance of WebClient and initialized it by using the WebClient builder. It will then create a WebClient object and also allow you to customize your call with several methods that it offers. Please refer to all the methods while you use it.

You can choose HTTP methods, depending upon the nature of the HTTP call, and make a request to it. In the scenario above, we are leveraging the GET method and returning a response from the API call.

The method getPost is the method that will be making the request with the help of the WebClient instance and retrieve the response from an external API call. If you have to make a POST call, you can leverage the POST method. And in that case, you will have to pass a body to the method body; there are a lot of methods to play around with. Once you start to use it, you will have various methods to put in use for sure.

How to Handle Errors

To handle errors in WebClient, you can use extend retrieve method. The retrieve method in WebClient throws an  WebClientResponseException when there will be a 4xx and 5xx series exception received. You can further customize it using the  onStatus() method, like below.
.retrieve()
            .onStatus(HttpStatus::is4xxClientError, response ->
                Mono.error(new MyCustomException())
            )
            .onStatus(HttpStatus::is5xxServerError, response ->
                Mono.error(new MyCustomException())
            )
            .bodyToFlux(Post.class);


Unlike the .retrieve() method, the .exchange() method will not be throwing exceptions in case 4xx and 6xx series exception from the other end. So, it is always recommended to use the .retrieve()  method so that you can find the real cause of the exception and pass it further to the client after wrapping it in a Custom Exception. And if you can want to silence the exception and move further, you can use .exchange() method (which, however, I am not recommending).

Writing Unit Test Cases for WebClient

Writing unit test cases for WebClient is a little tricky, as it includes the use of a library called the MockWebServer.

Below is the Maven dependency for that library. Once you add the library dependency, you can start to write the test cases for WebClient.

How to Write Test Cases

Step 1. First, create an object of MockWebServer, like below:

private final MockWebServer mockWebServer = new MockWebServer();


Step 2. Once the object is created, you can stub the mock response, like below:

mockWebServer.enqueue(
                new MockResponse()
                        .setResponseCode(200)
                        .setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                        .setBody("{\"userId\": 1,\"id\": 1, \"title\": \"sunt aut facere repellat p


Now, you can simply assert the actual response with the expected response.

That's it, we are good to go! In this article, we learned both how to make HTTP calls using WebClient and how to write unit test cases designed for testing the functionality.

Please refer to GitHub for full code access, and let us know your thoughts down in the comments below.

Spring Framework unit test Spring Boot

Published at DZone with permission of Deepak Mehra, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Be Punctual! Avoiding Kotlin’s lateinit In Spring Boot Testing
  • Spring Boot - Unit Test your project architecture with ArchUnit
  • Top 10 Advanced Java and Spring Boot Courses for Full-Stack Java Developers
  • Advanced Functional Testing in Spring Boot Using Docker in Tests

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!