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
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

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

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

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

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • Spring Microservices RESTFul API Documentation With Swagger Part 1
  • Develop a Spring Boot REST API in AWS: PART 4 (CodePipeline / CI/CD)
  • RESTful Web Services: How To Create a Context Path for Spring Boot Application or Web Service
  • Aggregating REST APIs Calls Using Apache Camel

Trending

  • Why Database Migrations Take Months and How to Speed Them Up
  • How Can Developers Drive Innovation by Combining IoT and AI?
  • Comprehensive Guide to Property-Based Testing in Go: Principles and Implementation
  • How To Build Resilient Microservices Using Circuit Breakers and Retries: A Developer’s Guide To Surviving
  1. DZone
  2. Coding
  3. Frameworks
  4. Test-Driven Development With a Spring Boot REST API

Test-Driven Development With a Spring Boot REST API

While TDD starts with unit tests, it doesn't stop there. Let's look at how integration tests come into play with a Spring Boot-based REST API.

By 
Swathi Prasad user avatar
Swathi Prasad
·
Sep. 12, 18 · Tutorial
Likes (8)
Comment
Save
Tweet
Share
62.8K Views

Join the DZone community and get the full member experience.

Join For Free

I deal with integration tests for RESTful applications a lot, however, I had not particularly tried Test Driven Development (TDD) methodologies. Therefore, I decided to give it a try, and I say now tell that I quite like it. I shall assume you already have some basic ideas of TDD, therefore I shall forgo an introduction to TDD.

In this article, let us look at how we can adopt TDD methodology in implementing a Spring Boot RESTful application.

Creating a Spring Boot Application

To start an application with Spring Boot is really easy; we just need to include Spring Boot dependencies in the Maven pom.xml and we need a Java class file.

Create a simple Maven project in the IDE of your choice. I have created mine in Eclipse. The project structure is as follows:

The Maven POM contains the following:

<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.swathisprasad.tdd</groupId>
       <artifactId>tdd-springboot</artifactId>
       <version>1.0.0-SNAPSHOT</version>
       <!—Spring Boot starter parent goes here -->
<properties>
              <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
              <java.version>1.8</java.version>
       </properties>
</project>

Edit the pom.xml and add the following Spring Boot dependencies. Here, we are adding spring-boot-starter-parent as a parent for our project.

<parent>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-parent</artifactId>
              <version>2.0.4.RELEASE</version>
              <relativePath /> <!-- lookup parent from repository -->
  </parent>

Under the dependencies section, add the following dependency.

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

In combination with spring-boot-starter-parent, the spring-boot-starter-web dependency allows us to run the web application.

Here is the class which is responsible for running the application.

package com.swathisprasad.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
 * @author swathi
 *
 */
@SpringBootApplication
public class Application {
                  /**
                   * @param args
                   */
                  public static void main(String[] args) {
                                    SpringApplication.run(Application.class, args);
                  }
}

So far we have created a simple Spring Boot application. We can test our application by running Application.java as a Java application.

As we are focusing on TDD methodologies, let us first create a simple integration test. Edit the pom.xml file and add the following dependencies.

             <dependency>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-starter-actuator</artifactId>
              </dependency>
              <dependency>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-starter-test</artifactId>
                      <scope>test</scope>
              </dependency>
             <dependency>
                      <groupId>com.jayway.restassured</groupId>
                      <artifactId>rest-assured</artifactId>
                      <version>2.8.0</version>
                     <scope>test</scope>
              </dependency>
              <dependency>
                      <groupId>org.codehaus.groovy</groupId>
                      <artifactId>groovy-all</artifactId>
                      <version>2.4.5</version>
              </dependency>

Here, spring-boot-starter-actuator provides production ready feature such as monitoring our app, gathering metrics and so on. The spring-boot-starter-test allows to bootstrap Spring context before executing tests.

The Maven plugin rest-assured is a Java DSL for testing REST services. This plugin requires groovy-all to run the tests.

We will add maven-failsafe-plugin plugin to execute the integration tests.

<build>
	<plugins>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-failsafe-plugin</artifactId>
			<executions>
				<execution>
					<id>integration-test</id>
					<goals>
						<goal>integration-test</goal>
					</goals>
				</execution>
				<execution>
					<id>verify</id>
					<phase>verify</phase>
					<goals>
						<goal>verify</goal>
					</goals>
				</execution>
			</executions>
		</plugin>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
			<executions>
				<execution>
					<id>pre-integration-test</id>
					<goals>
						<goal>start</goal>
					</goals>
				</execution>
				<execution>
					<id>post-integration-test</id>
					<goals>
						<goal>stop</goal>
					</goals>
				</execution>
			</executions>
		</plugin>
	</plugins>
</build>

Here, we have also added spring-boot-maven-plugin with some execution tasks in order to execute the tests during the deployment process.

Let's create a test which makes a simple GET request and expects data in the response body.

package com.swathisprasad.springboot.controller;
import static com.jayway.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.swathisprasad.springboot.Application;
import com.jayway.restassured.RestAssured;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
/**
 * @author swathi
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration(classes = Application.class) 
@TestPropertySource(value={"classpath:application.properties"})
@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT)
public class SpringRestControllerTest {
    @Value("${server.port}") 
    int port;
       @Test
       public void getDataTest() {
              get("/api/tdd/responseData").then().assertThat().body("data", equalTo("responseData"));
       }
       @Before
       public void setBaseUri () {
               RestAssured.port = port;
               RestAssured.baseURI = "http://localhost"; // replace as appropriate
       }
}

Note that we have added some annotations here to run the tests in a web environment.

@RunWith(SpringJUnit4ClassRunner.class) supports loading of the Spring application context.

@ContextConfiguration defines class-level metadata that is used to determine how to load and configure an ApplicationContext for integration tests.

@TestPropertySource is used to configure the location of properties files.

SpringBootTest tells Spring Boot to go and look for a main configuration class (one with @SpringBootApplication, for instance) and use that to start a Spring application context.

As we have not defined a REST endpoint yet, we can run the above test using the mvn verify command to see the test fail.

Let's fix our test by introducing a REST controller.

package com.swathisprasad.springboot;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
 * @author swathi
 *
 */
@RestController
public class SpringRestController {
                  @RequestMapping(path = "/api/tdd/{data}", method= RequestMethod.GET)
                  public Response getData(@PathVariable("data") String data) {
                                    return new Response(data);
                  }
                  //inner class
                  class Response {
                                    private String data;
                                    public Response(String data) {
                                                      this.data = data;
                                    }
                                    public String getData() {
                                                      return data;
                                    }
                  }
}

In the class above, we have a REST endpoint which accepts "data" as an input and returns a new instance of "Response" in the response body.

Let's run the mvn verify command again. It should now run the tests successfully.

Wrapping Up

Developing our implementation with TDD enables us to define the requirements in the form of tests. This approach also helps to maintain our code to make it easier to read and maintain while still passing the tests.

The complete source code can be found on GitHub.

Spring Framework REST Web Protocols Spring Boot Test-driven development API Testing application

Published at DZone with permission of Swathi Prasad, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Spring Microservices RESTFul API Documentation With Swagger Part 1
  • Develop a Spring Boot REST API in AWS: PART 4 (CodePipeline / CI/CD)
  • RESTful Web Services: How To Create a Context Path for Spring Boot Application or Web Service
  • Aggregating REST APIs Calls Using Apache Camel

Partner Resources

×

Comments

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: