Open In App

Spring WebFlux Testing

In Spring Boot, Spring WebFlux is the reactive programming framework that can provide support for the building of asynchronous, non-blocking, and event-driven applications when it comes to testing in the spring WebFlux.

Key Terminologies:

Some Important Testing related annotations:

Example Project:

Step 1: Create the spring project using spring initializer and it named as spring-webflux-testing-demo on creating the project adding the below dependencies into the project.



Dependencies:

Once create the spring project then the file structure looks like the below image.



Step 2: Create the new package and it named as model in that package create the new java class and it named as the User.

Go to src > main > java > com.gfg.springwebfluxtestingdemo > model > User and put the below code.




package com.gfg.springwebfluxtestingdemo.model;
  
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
  
// Annotation to indicate that this class is a model class
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    // Annotation to mark the field as the primary identifier
    @Id
    private String id; // User ID field
    private String name; // User name field
    private int age; // User age field
}

Step 3: Create the new package named repository in that package create the new Java interface named UserRepository.

Go to src > main > java > com.gfg.springwebfluxtestingdemo > repository > UserRepository and put the below code.




package com.gfg.springwebfluxtestingdemo.repository;
  
import com.gfg.springwebfluxtestingdemo.model.User;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
  
// repository annotation to indicate that this interface is a repository
@Repository
public interface UserRepository extends ReactiveCrudRepository<User, String> {
    // method to find a user by ID
    Mono<User> findById(String id);
  
    // Method to find all users
    Flux<User> findAll();
  
    // Method to save a user
    Mono<Void> save(User user);
}

Step 4: Create the new package and it named as service in that package create the new java class and it named as UserService .

Go to src > main > java > com.gfg.springwebfluxtestingdemo > service> UserService and put the below code.




package com.gfg.springwebfluxtestingdemo.service;
  
import com.gfg.springwebfluxtestingdemo.model.User;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
  
// Service annotation to indicate that this interface is a service
@Service
public interface UserService {
    // Method to get a user by ID
    Mono<User> getUserById(String id);
  
    // Method to get all users
    Flux<User> getAllUsers();
  
    // Method to save a user
    Mono<Void> saveUser(User user);
}

Step 5: Create the new package and it named as service in that package create the new java class and it named as UserServiceImpl .

Go to src > main > java > com.gfg.springwebfluxtestingdemo > service> UserServiceImpl and put the below code.




package com.gfg.springwebfluxtestingdemo.service;
  
import com.gfg.springwebfluxtestingdemo.model.User;
import com.gfg.springwebfluxtestingdemo.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
  
// Service implementation class for UserService interface
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
    // Final field for UserRepository
    private final UserRepository userRepository;
  
    // Method to get a user by ID
    @Override
    public Mono<User> getUserById(String id) {
        return userRepository.findById(id);
    }
  
    // Method to get all users
    @Override
    public Flux<User> getAllUsers() {
        return userRepository.findAll();
    }
  
    // Method to save a user
    @Override
    public Mono<Void> saveUser(User user) {
        return userRepository.save(user);
    }
}

Step 6: Create the new package and it named as controller in that package create the new java class and it named as UserController.

Go to src > main > java > com.gfg.springwebfluxtestingdemo > controller > UserController and put the below code.




package com.gfg.springwebfluxtestingdemo.controller;
  
import com.gfg.springwebfluxtestingdemo.model.User;
import com.gfg.springwebfluxtestingdemo.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
  
// REST controller for handling user-related endpoints
@RestController
@RequiredArgsConstructor
public class UserController {
    // Final field for UserService
    private final UserService userService;
  
    // Endpoint to get a user by ID
    @GetMapping("/users/{id}")
    public Mono<User> getUserById(@PathVariable String id) {
        return userService.getUserById(id);
    }
  
    // Endpoint to get all users
    @GetMapping("/users")
    public Flux<User> getAllUsers() {
        return userService.getAllUsers();
    }
  
    // Endpoint to save a user
    @PostMapping("/users")
    @ResponseStatus(HttpStatus.CREATED)
    public Mono<Void> saveUser(@RequestBody User user) {
        return userService.saveUser(user);
    }
}

Step 7: Open the main class file and add the @EnableReactiveMongoRepositories annotation into it.




package com.gfg.springwebfluxtestingdemo;
  
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories;
  
// Main class for starting the Spring Webflux application
@SpringBootApplication
@EnableReactiveMongoRepositories
public class SpringWebfluxTestingDemoApplication {
  
    // Main method to run the Spring Webflux application
    public static void main(String[] args) {
        SpringApplication.run(SpringWebfluxTestingDemoApplication.class, args);
    }
  
}

Step 8: Create the new package and it named as controller in that package create the new java class and it named as UserControllerTest.

Go to src > test > java > com.gfg.springwebfluxtestingdemo > controller > UserControllerTest and put the below code.




package com.gfg.springwebfluxtestingdemo.controller;
  
import com.gfg.springwebfluxtestingdemo.model.User;
import com.gfg.springwebfluxtestingdemo.service.UserService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.reactive.server.WebTestClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
  
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
  
// Unit tests for UserController class
class UserControllerTest {
    private WebTestClient webTestClient;
    private UserService userService;
  
    // Set up mock UserService and WebTestClient before each test
    @BeforeEach
    void setUp() {
        userService = mock(UserService.class);
        webTestClient = WebTestClient.bindToController(new UserController(userService)).build();
    }
  
    // Test for retrieving a user by ID
    @Test
    void getUserById() {
        User user = new User("1", "Sweta", 24);
        when(userService.getUserById("1")).thenReturn(Mono.just(user));
  
        webTestClient.get().uri("/users/1")
                .exchange()
                .expectStatus().isOk()
                .expectBody(User.class).isEqualTo(user);
    }
  
    // Test for retrieving all users
    @Test
    void getAllUsers() {
        User user1 = new User("1", "Sweta", 24);
        User user2 = new User("2", "Ami", 26);
        when(userService.getAllUsers()).thenReturn(Flux.just(user1, user2));
  
        webTestClient.get().uri("/users")
                .exchange()
                .expectStatus().isOk()
                .expectBodyList(User.class).contains(user1, user2);
    }
  
    // Test for saving a user
    @Test
    void saveUser() {
        User user = new User("1", "Sweta", 24);
        when(userService.saveUser(user)).thenReturn(Mono.empty());
  
        webTestClient.post().uri("/users")
                .contentType(MediaType.APPLICATION_JSON)
                .body(Mono.just(user), User.class)
                .exchange()
                .expectStatus().isCreated();
    }
}

Step 9: Create the new package and it named as service in that package create the new java class and it named as UserServiceTest.

Go to src > test > java > com.gfg.springwebfluxtestingdemo > service > UserServiceTest and put the below code.




package com.gfg.springwebfluxtestingdemo.service;
  
import com.gfg.springwebfluxtestingdemo.model.User;
import com.gfg.springwebfluxtestingdemo.repository.UserRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
  
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
  
// Unit tests for UserService class
class UserServiceTest {
    private UserService userService;
    private UserRepository userRepository;
  
    // Set up mock UserRepository and UserService before each test
    @BeforeEach
    void setUp() {
        userRepository = mock(UserRepository.class);
        userService = new UserServiceImpl(userRepository);
    }
  
    // Test for retrieving a user by ID
    @Test
    void getUserById() {
        User user = new User("1", "Sweta", 24);
        when(userRepository.findById("1")).thenReturn(Mono.just(user));
  
        Mono<User> result = userService.getUserById("1");
  
        StepVerifier.create(result)
                .expectNext(user)
                .verifyComplete();
    }
  
    // Test for retrieving all users
    @Test
    void getAllUsers() {
        User user1 = new User("1", "Sweta", 24);
        User user2 = new User("2", "Ami", 26);
        when(userRepository.findAll()).thenReturn(Flux.just(user1, user2));
  
        Flux<User> result = userService.getAllUsers();
  
        StepVerifier.create(result)
                .expectNext(user1)
                .expectNext(user2)
                .verifyComplete();
    }
  
    // Test for saving a user
    @Test
    void saveUser() {
        User user = new User("1", "Sweta", 24);
        when(userRepository.save(user)).thenReturn(Mono.empty());
  
        Mono<Void> result = userService.saveUser(user);
  
        StepVerifier.create(result)
                .verifyComplete();
    }
}

Step 10: Open the test main class and put the below code.




package com.gfg.springwebfluxtestingdemo;
  
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
  
// Integration test for SpringWebfluxTestingDemoApplication class
@SpringBootTest
class SpringWebfluxTestingDemoApplicationTests {
  
    // Test to verify the context loads successfully
    @Test
    void contextLoads() {
    }
  
}

Step 11: Once completed the writing the test cases for the UserController and UserService and run test the cases using the below command:

mvn test

Refer the below image for the better understanding.

Below we can see the all the tests runs and build successfully.

UserControllerTest Test Cases:

UserServiceTest Test Cases:

If we can follow the above steps, then we can successfully build the Spring WebFlux testing application with CRUD operations of the spring project.


Article Tags :