HTTP headers allow the client and the server to pass additional information with the request or the response, if you want to know more about the list we can use as Http headers, please go here. In this technical post we will see how to validate a server response including their headers using WebTestClient. If you want to know more about how to create Spring Webflux please go to my previous post getting started with Spring Webflux here. Then, let’s create a new Spring Boot project with Webflux as dependencies:
spring init --dependencies=webflux,lombok --language=java --build=gradle spring-webflux-webclient-workshop
Here is the complete build.gradle
file generated:
plugins {
id 'org.springframework.boot' version '2.2.2.RELEASE'
id 'io.spring.dependency-management' version '1.0.8.RELEASE'
id 'java'
}
group = 'com.jos.dem.spring.webflux.webclient'
version = '1.0.0-SNAPSHOT'
sourceCompatibility = '11'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-webflux'
compileOnly('org.projectlombok:lombok')
annotationProcessor 'org.projectlombok:lombok'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testImplementation 'io.projectreactor:reactor-test'
}
test {
useJUnitPlatform()
}
Let’s start by creating a controller to retrieve persons :)
package com.jos.dem.spring.webflux.webclient.controller;
import reactor.core.publisher.Mono;
import reactor.core.publisher.Flux;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.beans.factory.annotation.Autowired;
import com.jos.dem.spring.webflux.webclient.model.Person;
import com.jos.dem.spring.webflux.webclient.repository.PersonRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@RestController
@RequestMapping("/persons")
public class PersonController {
@Autowired
private PersonRepository personRepository;
private Logger log = LoggerFactory.getLogger(this.getClass());
@GetMapping("")
public Flux<Person> getAll(){
log.info("Getting persons");
return personRepository.findAll();
}
}
Next step is to create a person collection so that we can have some data in our PersonRepository
package com.jos.dem.spring.webflux.webclient;
import com.jos.dem.spring.webflux.webclient.model.Person;
import com.jos.dem.spring.webflux.webclient.repository.PersonRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import java.util.Arrays;
@SpringBootApplication
public class DemoApplication {
private Logger log = LoggerFactory.getLogger(this.getClass());
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Bean
CommandLineRunner start(PersonRepository personRepository){
return args -> {
Arrays.asList(
new Person("josdem", "joseluis.delacruz@gmail.com"),
new Person("tgrip", "tgrip@email.com"),
new Person("edzero", "edzero@email.com"),
new Person("siedrix", "siedrix@email.com"),
new Person("mkheck", "mkheck@losheckler.com"))
.forEach(person -> personRepository.save(person));
};
}
}
It is time to create our test case in order to verify our behaviour.
package com.jos.dem.spring.webflux.webclient;
import com.jos.dem.spring.webflux.webclient.model.Person;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.http.MediaType;
import org.springframework.test.web.reactive.server.WebTestClient;
import java.util.Date;
import static org.hamcrest.Matchers.equalTo;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class PersonControllerTest {
@Autowired
private WebTestClient webTestClient;
private Logger log = LoggerFactory.getLogger(this.getClass());
@Test
@DisplayName("Should get all of persons")
public void shouldGetAllPersons() throws Exception {
log.info("Running: Should get all persons at {}", new Date());
webTestClient.get().uri("/persons/")
.exchange()
.expectStatus().isOk()
.expectHeader().contentType(MediaType.APPLICATION_JSON_VALUE)
.expectBodyList(Person.class)
.value(persons -> persons.size(), equalTo(5))
.value(persons -> persons.contains(new Person("josdem","joseluis.delacruz@gmail.com")))
.value(persons -> persons.contains(new Person("tgrip", "tgrip@email.com")))
.value(persons -> persons.contains(new Person("edzero", "edzero@email.com")))
.value(persons -> persons.contains(new Person("siedrix", "siedrix@email.com")))
.value(persons -> persons.contains(new Person("mkheck", "mkheck@losheckler.com")));
}
}
That’s it, we are validating HttpHeaders using expectHeader().contentType(MediaType.APPLICATION_JSON_VALUE)
if you want to see the complete list of validations we can do using Spring header assertions, please go here.
To run the project:
gradle bootRun
To test the project:
gradle test
To browse the project go here, to download the project:
git clone git@github.com:josdem/spring-webflux-webclient-workshop.git