Tutorial 6.2: Integration Testing - McGill-ECSE429-Winter2022/tutorials GitHub Wiki
1. Spring Framework
- The Spring framework provides comprehensive support for developing Java applications.
- Provides the plumbing
- OOP best practices built-in
- DRY Principle
2. Why Spring Boot:
- Supports rapid development
- Removes boilerplate of application setup
- Many uses
- Cloud-native support, but also traditional
Reference to explore more on this topic.
The meaning of Integration testing is quite straightforward- Integrate/combine the unit tested module one by one and test the behaviour as a combined unit. The main function or goal of this testing is to test the interfaces between the units/modules.
1. Bottom Up:
2. Top Down:
Why Service Layer:
- Separation of concern
- Loose coupling
- Orchestration
- Caching
e.g: Steps for rest controller:
- URL Mapping
- Deserialize Input
- Validate Input
- Bussiness Logic
- Serialize Onput
- Translate Exceptions
Following is the order we do things in this guide:
- Bootstrap a project using Spring Initializr.
- Implement a Business Service for our API - StudentService.
- Implement the API - using StudentController. First, we implement the GET methods and then the POST methods.
- Write Integration Tests for our API.
Spring Initializr http://start.spring.io/ is great tool to bootstrap your Spring Boot projects.
image for spring analyzer
As shown in the image above, the following steps have to be done
- Launch Spring Initializr and choose the following:
- Choose com.ECSE429.springboot as Group
- Choose student services as Artifact
- Choose the following dependencies
- Web
- Actuator
- DevTools
- Click Generate Project.
- Import the project into Eclipse.
Please update your POM file with this sample POM file.
All applications need data. Instead of talking to a real database, we will use an ArrayList - kind of an in-memory data store.
A student can take multiple courses. A course has an id, name, description and a list of steps you need to complete to finish the course. A student has an id, name, description and a list of courses he/she is currently registered for. We have StudentService exposing methods to
- public List retrieveAllStudents() - Retrieve details for all students
- public Student retrieveStudent(String studentId) - Retrieve a specific student details
- public List retrieveCourses(String studentId) - Retrieve all courses a student is registered for
- public Course retrieveCourse(String studentId, String courseId) - Retrieve details of a specific course a student is registered for
- public Course addCourse(String studentId, Course course) - Add a course to an existing student
Refer to these files at the bottom of the article for exact implementation of the Service StudentService and the model classes Course and Student.
- src/main/java/com/ECSE429/springboot/model/Course.java
- src/main/java/com/ECSE429/springboot/model/Student.java
- src/main/java/com/ECSE429/springboot/service/StudentService.java
github for the source code.
The Rest Service StudentController exposes a couple of get services.
- @Autowired private StudentService studentService : We are using Spring Autowiring to wire the student service into the StudentController.
- @GetMapping("/students/{studentId}/courses"): Exposing a Get Service with studentId as a path variable
- @GetMapping("/students/{studentId}/courses/{courseId}"): Exposing a Get Service for retrieving specific course of a student.
- @PathVariable String studentId : Value of studentId from the uri will be mapped to this parameter.
github for the source code.
When we are writing an integration test for a rest service, we would want to launch the entire spring context.
- @SpringBootTest(classes = StudentServicesApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) : Launch the entire Spring Boot Application on a Random Port
- @LocalServerPort private int port;: Autowire the random port into the variable so that we can use it to create the url.
- createURLWithPort(String URL): Utility method to create the url given an uri. It appends the port.
- HttpEntity entity = new HttpEntity(null, headers);: We use entity so that we have the flexibility of adding in request headers in future.
- restTemplate.exchange(createURLWithPort("/students/Student1/courses/Course1"),HttpMethod.GET, entity, String.class): Fire a GET request to the specify uri and get the response as a String.
- JSONAssert.assertEquals(expected, response.getBody(), false): Assert that the response contains expected fields.
github for the source code.
Now run and test the service.