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