SpringBoot WebFlux Test – @WebFluxTest

In the tutorial, JavaSampleApproach will show you how to work with SpringBoot WebFlux Tests using @WebFluxTest.

Related posts:
SpringBoot WebFlux Annotation-based RestAPIs
Spring WebClient with Spring Webflux RestAPIs | SpringBoot 2

I. Technologies

– Java: 1.8
– Maven: 3.3.9
– Spring Tool Suite: Version 3.9.0.RELEASE
– Spring Boot: 2.0.0.M4
– Spring Boot Starter Webflux

II. SpringBoot WebFlux Tests

@WebFluxTest helps to test Spring WebFlux controllers with auto-configuring the Spring WebFlux infrastructure, limit scanned beans like {@Controller, @ControllerAdvice, @JsonComponent, WebFluxConfigurer} and never scan @Component beans.

@WebFluxTest will auto-configures WebTestClient to quickly test WebFlux controllers without starting a full HTTP server.

@RunWith(SpringRunner.class)
@WebFluxTest
public class SpringWebFluxTestApplicationTests {
	
	@Autowired
    private WebTestClient webClient;
	
	...
    
	// GET Test-case
	@Test
    public void get() throws Exception {
    	
        webClient.get().uri("/api/customer/{id}", 2).accept(MediaType.APPLICATION_JSON)
        		.exchange()
		        .expectStatus().isOk()
		        .expectBody(Customer.class)
		        .isEqualTo(customerMap.get("Peter"));
    }
	
	// POST Test-case
	@Test
	public void post throws Exception {
		
		webClient.post().uri("/api/customer/post")
							.contentType(MediaType.APPLICATION_JSON)
							.body(BodyInserters.fromObject(customerMap.get("Mary")))
							.exchange()
							.expectStatus().isCreated()
							.expectBody(String.class)
							.isEqualTo("Post Successfully!");
	}
	
	// PUT Test-case
	@Test
	public void put() throws Exception {
		
		webClient.put().uri("/api/customer/put/{id}", 3)
							.contentType(MediaType.APPLICATION_JSON)
							.body(BodyInserters.fromObject(customerMap.get("Amy")))
							.exchange()
							.expectStatus().isCreated()
							.expectBody(Customer.class)
							.isEqualTo(customerMap.get("Amy"));
		
	}
	
	// DELETE Test-case
	@Test
	public void delete() throws Exception {
		
		webClient.delete().uri("/api/customer/delete/{id}", 1)
							.exchange()
					        .expectStatus().isAccepted()
					        .expectBody(String.class)
					        .isEqualTo("Delete Succesfully!");
	}
	
}

III. Practice

We create a SpringBoot project as below:

SpringBoot WebFlux test - project structure

Step to do:
– Create SpringBoot project
– Define data model
– Implement WebFlux APIs
– Implement Testcases
– Run and check results

1. Create SpringBoot project

– Using SpringToolSuite to create a SpringBoot project with spring-boot-starter-webflux dependency:


	
		org.springframework.boot
		spring-boot-starter-webflux
	

	
		org.springframework.boot
		spring-boot-starter-test
		test
	
	
		io.projectreactor
		reactor-test
		test
	



	
		
			org.springframework.boot
			spring-boot-maven-plugin
		
	



	
		spring-snapshots
		Spring Snapshots
		https://repo.spring.io/snapshot
		
			true
		
	
	
		spring-milestones
		Spring Milestones
		https://repo.spring.io/milestone
		
			false
		
	



	
		spring-snapshots
		Spring Snapshots
		https://repo.spring.io/snapshot
		
			true
		
	
	
		spring-milestones
		Spring Milestones
		https://repo.spring.io/milestone
		
			false
		
	

2. Define data model

– Define a Customer model:

package com.javasampleapproach.webflux.model;

public class Customer {
	private long custId;
	private String firstname;
	private String lastname;
	private int age;
	
	public Customer(){}
	
	public Customer(long custId, String firstname, String lastname, int age){
		this.custId = custId;
		this.firstname = firstname;
		this.lastname = lastname;
		this.age = age;
	}
 
	public long getCustId() {
		return custId;
	}
 
	public void setCustId(Long custId) {
		this.custId = custId;
	}
 
	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 int getAge() {
		return age;
	}
 
	public void setAge(int age) {
		this.age = age;
	}
	
	
	@Override
	public boolean equals(Object o) {
		if (this == o) return true;
		if (o == null || getClass() != o.getClass()) return false;

		Customer c = (Customer) o;

		if (custId != c.custId) return false;
		return firstname.equals(c.firstname);
	}

	@Override
	public int hashCode() {
		int result = Long.toString(custId).hashCode();
		result = 31 * result + firstname.hashCode();
		return result;
	}
	
	@Override
	public String toString() {
		String info = String.format("custId = %d, firstname = %s, lastname = %s, age = %d", custId, firstname, lastname, age);
		return info;
	}
}
3. Implement WebFlux APIs

Refer at SpringBoot WebFlux Annotation-based RestAPIs

– Implement a WebFlux RestControllerAPIs:

package com.javasampleapproach.webflux.controller;

import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

import javax.annotation.PostConstruct;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.javasampleapproach.webflux.model.Customer;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@RestController
@RequestMapping(value="/api/customer")
public class RestControllerAPIs {
	
	Map custStores = new HashMap();
	
    @PostConstruct
    public void initIt() throws Exception {
        custStores.put(Long.valueOf(1), new Customer(1, "Jack", "Smith", 20));
        custStores.put(Long.valueOf(2), new Customer(2, "Peter", "Johnson", 25));
    }
	
    @GetMapping
    public Flux getAll() {
    	return Flux.fromIterable(custStores.entrySet().stream()
    	        										.map(entry -> entry.getValue())
    	        										.collect(Collectors.toList()));
    }
    
	@GetMapping("/{id}")
    public Mono getCustomer(@PathVariable Long id) {
		return Mono.justOrEmpty(custStores.get(id));
    }
	
	
	@PostMapping("/post")
    public Mono> postCustomer(@RequestBody Customer customer){
		// do post
		custStores.put(customer.getCustId(), customer);
		
		// log on console
		System.out.println("########### POST:" + customer);
				
		return Mono.just(new ResponseEntity<>("Post Successfully!", HttpStatus.CREATED));
	}
	
	@PutMapping("/put/{id}")
	public Mono> putCustomer(@PathVariable Long id, @RequestBody Customer customer){
		// reset customer.Id
		customer.setCustId(id);
		
		custStores.put(id, customer);
		
		// log on console
		System.out.println("########### PUT:" + customer);
		
		return Mono.just(new ResponseEntity<>(customer, HttpStatus.CREATED));
	}
	
	@DeleteMapping("/delete/{id}")
    public Mono> deleteMethod(@PathVariable Long id) {
		// delete processing
    	custStores.remove(id);
    	return Mono.just(new ResponseEntity<>("Delete Succesfully!", HttpStatus.ACCEPTED));
    }
}

4. Implement Testcases
package com.javasampleapproach.webflux;

import java.util.HashMap;
import java.util.Map;

import org.junit.BeforeClass;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.web.reactive.function.BodyInserters;

import com.javasampleapproach.webflux.model.Customer;

@RunWith(SpringRunner.class)
@WebFluxTest
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class SpringBootWebFluxAnnotationBasedApplicationTests {
	
	@Autowired
    private WebTestClient webClient;
	
	private static Map customerMap = new HashMap<>();
	
	@BeforeClass
    public static void setup() throws Exception {
		customerMap.put("Jack", new Customer(1, "Jack", "Smith", 20));
		customerMap.put("Peter", new Customer(2, "Peter", "Johnson", 25));
		customerMap.put("Mary", new Customer(3, "Mary", "Taylor", 27));
		customerMap.put("Amy", new Customer(3, "Amy", "Taylor", 24));
	}
	
    @Test
    public void tc_1_getAllCustomer() throws Exception {
        
        webClient.get().uri("/api/customer").accept(MediaType.APPLICATION_JSON)
                .exchange()
                .expectStatus().isOk()
                .expectBodyList(Customer.class)
                .hasSize(2)
                .contains(customerMap.get("Jack"), customerMap.get("Peter"));
    }
    
	@Test
    public void tc_2_getCustomer() throws Exception {
    	
        webClient.get().uri("/api/customer/{id}", 2).accept(MediaType.APPLICATION_JSON)
        		.exchange()
		        .expectStatus().isOk()
		        .expectBody(Customer.class)
		        .isEqualTo(customerMap.get("Peter"));
    }
	
	@Test
	public void tc_3_postCustomer() throws Exception {
		
		webClient.post().uri("/api/customer/post")
							.contentType(MediaType.APPLICATION_JSON)
							.body(BodyInserters.fromObject(customerMap.get("Mary")))
							.exchange()
							.expectStatus().isCreated()
							.expectBody(String.class)
							.isEqualTo("Post Successfully!");
	}
	
	@Test
	public void tc_4_putCustomer() throws Exception {
		
		webClient.put().uri("/api/customer/put/{id}", 3)
							.contentType(MediaType.APPLICATION_JSON)
							.body(BodyInserters.fromObject(customerMap.get("Amy")))
							.exchange()
							.expectStatus().isCreated()
							.expectBody(Customer.class)
							.isEqualTo(customerMap.get("Amy"));
		
	}
	
	@Test
	public void tc_5_deleteCustomer() throws Exception {
		
		webClient.delete().uri("/api/customer/delete/{id}", 1)
							.exchange()
					        .expectStatus().isAccepted()
					        .expectBody(String.class)
					        .isEqualTo("Delete Succesfully!");
	}
	
	@Test
	public void tc_6_finalCheckByGetAllCustomer() throws Exception {
		
		webClient.get().uri("/api/customer").accept(MediaType.APPLICATION_JSON)
					        .exchange()
					        .expectStatus().isOk()
					        .expectBodyList(Customer.class)
					        .hasSize(2)
					        .contains(customerMap.get("Peter"), customerMap.get("Amy"));
	}
}

5. Run and check results

– Run unit-test as below image:

SpringBoot WebFlux test - run unitest

-> Results:

SpringBoot WebFlux test - results

IV. Sourcecode

SpringWebFluxTest



By grokonez | October 4, 2017.


Related Posts


1 thought on “SpringBoot WebFlux Test – @WebFluxTest”

  1. Hi,

    Thanks for the detailed tutorial.
    I am getting below error on test cases.

    java.lang.AssertionError: Status expected: but was:

    > POST /optimize
    > WebTestClient-Request-Id: [1]
    > Content-Type: [application/json]

    < 200 OK
    < Content-Type: [application/json;charset=UTF-8]

    Content not available yet

    at org.springframework.test.web.reactive.server.ExchangeResult.assertWithDiagnostics(ExchangeResult.java:197)
    at org.springframework.test.web.reactive.server.StatusAssertions.assertStatusAndReturn(StatusAssertions.java:201)
    at org.springframework.test.web.reactive.server.StatusAssertions.isCreated(StatusAssertions.java:71)
    at com.yantriks.yso.api.SourcingOptimizerAPITests.shouldSuccessfullyReturnSourcingOptimizerResult(SourcingOptimizerAPITests.java:139)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

Got Something To Say:

Your email address will not be published. Required fields are marked *

*