Introduction

We will see the use of @WebMvcTest annotation in Spring MVC applications. The Spring MVC application may be Spring Boot application as well. The @WebMvcTest annotation can be used not only to test Spring Controllers but also Spring REST Controllers. We will build the applications using both maven and gradle tools.

@WebMvcTest annotation is used for unit testing of Spring MVC Applications in situation where the test objective is to just focus on Spring MVC Components. In the snapshot shown below, we want to launch only the ToTestController. All other controllers and mappings will not be launched when this unit test is executed.

@WebMvcTest(ToTestController.class)

Prerequisites

Eclipse 4.12, Java at least 1.8, Maven 3.6.1, Gradle 5.6, Spring Boot 2.2.3

Create Project

You can create either gradle or maven based project in Eclipse. The name of the project is spring-boot-web-controller-test.

If you are creating gradle based project then you can update project’s build.gradle file as shown below:

buildscript {
	ext {
		springBootVersion = '2.2.3.RELEASE'
	}
	
    repositories {
        mavenCentral()
    }
    
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

plugins {
    id 'java-library'
    id 'org.springframework.boot' version '2.2.3.RELEASE'
}

sourceCompatibility = 12
targetCompatibility = 12

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web:${springBootVersion}")
    
    testImplementation("org.springframework.boot:spring-boot-starter-test:${springBootVersion}") {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
}

If you are creating maven based project then use below pom.xml file:

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.roytuts</groupId>
	<artifactId>spring-boot-web-controller-test</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.3.RELEASE</version>
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

    <build>
        <plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.1</version>
				<configuration>
					<source>at least 8</source>
					<target>at least 8</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

Controller Class

We will create a controller class which will be tested using @WebMvcTest annotation.

The controller class is annotated with @Controller annotation.

package com.roytuts.spring.boot.web.controller.test;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class SpringController {

	@ResponseBody
	@GetMapping("/")
	public String greeting() {
		return "Hello World!";
	}

}

In the above controller class we have just one method with GET request and it returns the Hello World! in the response body.

REST Controller Class

We will also create a REST controller class which will be tested using @WebMvcTest annotation.

The REST controller class is annotated with @Controller annotation.

package com.roytuts.spring.boot.web.controller.test;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SpringRestController {

	@ResponseBody
	@GetMapping("/greet")
	public String greeting() {
		return "Hello World!";
	}

}

In the above REST controller class we have just one method with GET request and it returns the Hello World! in the response body.

Use of @WebMvcTest

Now we will create Junit class to test controller and REST controller by applying the @WebMvcTest annotation.

In the below classes we have used @WebMvcTest annotation along with the controller or REST controller class which we want to test.

We mocked the MVC using MockMvc class to test our controller’s or REST controller’s endpoint.

Junit for Controller Class

package com.roytuts.spring.boot.web.controller.test;

import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;

@WebMvcTest(SpringController.class)
public class SpringControllerTest {

	@Autowired
	private MockMvc mockMvc;

	@Test
	public void shouldReturnDefaultMessage() throws Exception {
		mockMvc.perform(MockMvcRequestBuilders.get("/")).andDo(MockMvcResultHandlers.print())
				.andExpect(MockMvcResultMatchers.status().isOk())
				.andExpect(MockMvcResultMatchers.content().string(Matchers.containsString("Hello World!")));
	}

}

Junit for REST Controller Class

package com.roytuts.spring.boot.web.controller.test;

import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;

@WebMvcTest(SpringRestController.class)
public class SpringRestControllerTest {

	@Autowired
	private MockMvc mockMvc;

	@Test
	public void shouldReturnDefaultMessage() throws Exception {
		mockMvc.perform(MockMvcRequestBuilders.get("/greet")).andDo(MockMvcResultHandlers.print())
				.andExpect(MockMvcResultMatchers.status().isOk())
				.andExpect(MockMvcResultMatchers.content().string(Matchers.containsString("Hello World!")));
	}

}

Testing the Controllers

Now you can simple run the Junit classes as Junit test from the Eclipse IDE to test controller classes. Your junit tests will be passed.

Thanks for reading.

Leave a Reply

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