Zerocode automated testing framework for a REST API project concept is getting seen via this tutorial by taking a sample spring boot maven project. Let us see the dependencies for Zerocode :
<dependency> <groupId>org.jsmart</groupId> <artifactId>zerocode-tdd</artifactId> <version>1.3.27</version> <scope>test</scope> </dependency>
Zerocode framework supports the following
- REST
- SOAP
- Security
- Load/Stress
- Database
- Apache Kafka
- GraphQL
In this tutorial let us see REST API testing.
Example Project
Project Structure:
pom.xml
<? xml version = "1.0" encoding = "UTF-8" ?>
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
< modelVersion >4.0.0</ modelVersion >
< groupId >com.gfg.zerocode</ groupId >
< artifactId >zerocode</ artifactId >
< packaging >jar</ packaging >
< version >1.0-SNAPSHOT</ version >
< dependencies >
< dependency >
< groupId >org.springframework.boot</ groupId >
< artifactId >spring-boot-starter-web</ artifactId >
< version >${spring.boot.version}</ version >
</ dependency >
< dependency >
< groupId >org.springframework.boot</ groupId >
< artifactId >spring-boot-starter-test</ artifactId >
< version >${spring.boot.version}</ version >
< scope >test</ scope >
</ dependency >
< dependency >
< groupId >org.jsmart</ groupId >
< artifactId >zerocode-tdd</ artifactId >
< version >${zerocode-tdd.version}</ version >
< scope >test</ scope >
</ dependency >
</ dependencies >
< build >
< plugins >
< plugin >
< groupId >org.springframework.boot</ groupId >
< artifactId >spring-boot-maven-plugin</ artifactId >
< configuration >
< profiles >
< profile >it</ profile >
</ profiles >
</ configuration >
< executions >
< execution >
< id >pre-integration-test</ id >
< goals >
< goal >start</ goal >
</ goals >
< configuration >
< skip >${skip.it}</ skip >
</ configuration >
</ execution >
< execution >
< id >post-integration-test</ id >
< goals >
< goal >stop</ goal >
</ goals >
< configuration >
< skip >${skip.it}</ skip >
</ configuration >
</ execution >
</ executions >
</ plugin >
< plugin >
< groupId >org.apache.maven.plugins</ groupId >
< artifactId >maven-failsafe-plugin</ artifactId >
< version >${maven-failsafe-plugin.version}</ version >
< configuration >
< skip >${skip.it}</ skip >
</ configuration >
< dependencies >
< dependency >
< groupId >org.apache.maven.surefire</ groupId >
< artifactId >surefire-junit47</ artifactId >
< version >${surefire-junit47.version}</ version >
</ dependency >
</ dependencies >
< executions >
< execution >
< goals >
< goal >integration-test</ goal >
< goal >verify</ goal >
</ goals >
</ execution >
</ executions >
</ plugin >
</ plugins >
</ build >
< properties >
< maven-failsafe-plugin.version >3.0.0-M5</ maven-failsafe-plugin.version >
< surefire-junit47.version >3.0.0-M5</ surefire-junit47.version >
< maven.compiler.source >8</ maven.compiler.source >
< maven.compiler.target >8</ maven.compiler.target >
< spring.boot.version >2.4.2</ spring.boot.version >
< skip.it >true</ skip.it >
< zerocode-tdd.version >1.3.27</ zerocode-tdd.version >
</ properties >
</ project >
|
To test REST API, let us create a sample spring boot application. Let us create the model class first
GeekUser.java
public class GeekUser {
private String id;
private String firstName;
private String lastName;
private String departmentName;
public String getDepartmentName() {
return departmentName;
}
public void setDepartmentName(String departmentName) {
this .departmentName = departmentName;
}
public float getSalary() {
return salary;
}
public void setSalary( float salary) {
this .salary = salary;
}
private float salary;
public String getId() {
return id;
}
public void setId(String id) {
this .id = id;
}
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;
}
} |
GeekUserZerocodeApplication.java
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
@SpringBootApplication @RestController @RequestMapping ( "/api/users" )
public class GeekUserZerocodeApplication {
private List<GeekUser> users = new ArrayList<>();
public static void main(String[] args) {
SpringApplication.run(GeekUserZerocodeApplication. class , args);
}
@PostMapping
public ResponseEntity create( @RequestBody GeekUser user) {
if (!StringUtils.hasText(user.getFirstName())) {
return new ResponseEntity( "firstName can't be empty!" , HttpStatus.BAD_REQUEST);
}
if (!StringUtils.hasText(user.getLastName())) {
return new ResponseEntity( "lastName can't be empty!" , HttpStatus.BAD_REQUEST);
}
if (!StringUtils.hasText(user.getDepartmentName())) {
return new ResponseEntity( "DeparmentName can't be empty!" , HttpStatus.BAD_REQUEST);
}
if (user.getSalary() < 0 ) {
return new ResponseEntity( "Salary is not valid!" , HttpStatus.BAD_REQUEST);
}
user.setId(UUID.randomUUID()
.toString());
users.add(user);
return new ResponseEntity(user, HttpStatus.CREATED);
}
} |
We have to write a scenario to test the same
{ "scenarioName": "geek test user creation endpoint", "steps": [ // Array of JSON objects, as much we want we can store { "name": "geek_test_successful_creation", "url": "/api/users", // Relative URL "method": "POST", "request": { "body": { // We have to specify whole bean class parameter and its values "firstName": "Rachel", "lastName": "Green", "departmentName":"IT", "salary":100000.0 } }, "verify": { // expected part containing status and body "status": 201, // status code for a given HTTP call "body": { // Resultant body from the call "id": "$NOT.NULL", "firstName": "Rachel", "lastName": "Green", "departmentName":"IT", "salary":100000.0 } } } }
The above one is a success call that creates a user. Similarly, we can do for validation part as well
{ "name": "test_firstname_validation", "url": "/api/users", "method": "POST", "request": { "body": { "firstName": "", "lastName": "Bing", "departmentName":"IT", "salary":100000.0 } }, "assertions": { "status": 400, "rawBody": "firstName can't be empty!" } }, { "name": "test_lastname_validation", "url": "/api/users", "method": "POST", "request": { "body": { "firstName": "Monica", "lastName": "", "departmentName":"Chef", "salary":100000.0 } }, "assertions": { "status": 400, "rawBody": "lastName can't be empty!" } }, { "name": "test_departmentname_validation", "url": "/api/users", "method": "POST", "request": { "body": { "firstName": "Phoebe", "lastName": "Buffe", "departmentName":"", "salary":50000.0 } }, "assertions": { "status": 400, "rawBody": "DeparmentName can't be empty!" } }
We can combine everything together and keep it under the test/resources folder. Basically, it is a JSON file and combines all the entries that are getting tested. Now coming to the test file part
- @RunWith(ZeroCodeUnitRunner.class) – ZeroCodeUnitRunner, as it is responsible for it
- @TargetEnv – Provide the property file that is required for running the scenario
GeekUserEndpointIT.java
import org.jsmart.zerocode.core.domain.Scenario;
import org.jsmart.zerocode.core.domain.TargetEnv;
import org.jsmart.zerocode.core.runner.ZeroCodeUnitRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
// Here in RunWith it has been specified // as ZeroCodeUnitRunner, as it is responsible @RunWith (ZeroCodeUnitRunner. class )
// @TargetEnv – this points to the property file // that will be used when our scenario runs @TargetEnv ( "rest_api.properties" )
public class GeekUserEndpointIT {
@Test
@Scenario ( "rest/geek_user_create_test.json" )
public void test_geekuser_creation_endpoint() {
}
} |
rest_api.properties
web.application.endpoint.host=http://localhost # In case of changes they need to be modified appropriately web.application.endpoint.port=8080 web.application.endpoint.context=
For the execution of tests, in pom.xml necessary dependencies are added
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <version>3.0.0-M5</version> <dependencies> <dependency> <groupId>org.apache.maven.surefire</groupId> <artifactId>surefire-junit47</artifactId> <version>3.0.0-M5</version> </dependency> </dependencies> <executions> <execution> <goals> <goal>integration-test</goal> <goal>verify</goal> </goals> </execution> </executions> </plugin>
We can run the project in the command line by using
mvn verify -Dskip.it=false
Under the target folder of the directory, we can see multiple files that help to understand different layers of testing
Similarly whatever testing scenarios given are validated against Zerocode