``I am trying to learn spring boot and trying to send a list of course object from my api endpoint. But in the test case for retrieving a list of course object I am getting following error:
org.springframework.web.client.RestClientException: Error while extracting response for type [java.util.List[com.socgen.jpa.hibernate.learnjpa.entity.Course]] and content type [application/json]
My test case in which I am getting this error In postman I am receiving the list of courses object. I am populating the database with following data.sql file
insert into course(id, name) values(99, 'DBMS');
schema.sql DROP TABLE IF EXISTS course;
create table course (
id bigint not null,
name varchar(255) UNIQUE,
primary key (id)
);
@Test
void shouldReturnAListOfAllCourses() {
// List<Course> result = courseRepository.findAllCoursesInTable();
// assertThat(result.size()).isEqualTo(2);
ResponseEntity<List<Course>> getResponse = restTemplate.exchange(
"/all",
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<Course>>() {
});
assertThat(getResponse.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(getResponse.getBody()).isNotNull();
assertThat(getResponse.getBody().size()).isEqualTo(2); // Adjust the expected size as needed
}
All other test cases pass only the one in which I mentioned is failing.
testCase file
package com.jpa.hibernate.learnjpa;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import com.socgen.jpa.hibernate.learnjpa.entity.Course;
import com.socgen.jpa.hibernate.learnjpa.repository.CourseRepository;
import static org.assertj.core.api.Assertions.assertThat;
import java.net.URI;
import java.util.List;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class LearnjpaApplicationTests {
@Autowired
TestRestTemplate restTemplate;
@Autowired
private CourseRepository courseRepository;
@Test
void ShouldReturnACourseOfGivenId() {
ResponseEntity<String> response = restTemplate.getForEntity("/course/99", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
DocumentContext documentContext = JsonPath.parse(response.getBody());
Number id = documentContext.read("$.id");
assertThat(id).isNotNull();
assertThat(id).isEqualTo(99);
}
@Test
void ShouldReturn404ForNonRegisteredIds() {
ResponseEntity<String> response = restTemplate.getForEntity("/course/1000", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
}
@Test
@DirtiesContext
void shouldReturnNoContentWhenDelete() {
ResponseEntity<Void> response = restTemplate.exchange("/course/99", HttpMethod.DELETE, null, Void.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT);
}
@Test
@DirtiesContext
void shouldReturnCreated() {
// creating the new course
Course course = new Course("CSE");
ResponseEntity<Void> response = restTemplate.postForEntity("/course/add", course, Void.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
// course was created
URI locationOfNewCourse = response.getHeaders().getLocation();
ResponseEntity<String> getResponse = restTemplate.getForEntity(locationOfNewCourse, String.class);
assertThat(getResponse.getStatusCode()).isEqualTo(HttpStatus.OK);
// making sure can't create duplicate course
ResponseEntity<Void> response2 = restTemplate.postForEntity("/course/add", course, Void.class);
assertThat(response2.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
}
@Test
@DirtiesContext
void shouldUpdateAndReturnNewCourse() {
Course updatedCourse = new Course("NETWORKS");
updatedCourse.setId(99L);
HttpEntity<Course> requestObject = new HttpEntity<>(updatedCourse);
ResponseEntity<Course> updateResponse = restTemplate.exchange("/course/update/99", HttpMethod.PUT,
requestObject, Course.class);
assertThat(updateResponse.getStatusCode()).isEqualTo(HttpStatus.CREATED);
assertThat(updateResponse.getBody()).isNotNull();
assertThat(updateResponse.getBody().getName()).isNotEqualTo("DBMS");
assertThat(updateResponse.getBody().getName()).isEqualTo("NETWORKS");
}
@Test
void shouldReturnAListOfAllCourses() {
// List<Course> result = courseRepository.findAllCoursesInTable();
// assertThat(result.size()).isEqualTo(2);
ResponseEntity<List<Course>> getResponse = restTemplate.exchange(
"/all",
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<Course>>() {
});
assertThat(getResponse.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(getResponse.getBody()).isNotNull();
assertThat(getResponse.getBody().size()).isEqualTo(2); // Adjust the expected size as needed
}
}
Course entity
package com.jpa.hibernate.learnjpa.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@Entity
@Table(name = "course")
public class Course {
@Id
@GeneratedValue
private Long id;
@Column(unique = true)
private String name;
public Course(String name){
this.name = name;
}
public Course(){
}
// getters and setters
public Long getId() {
return id;
}
public String getName() {
return name;
}
public void setId(Long id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return name + " " + id;
}
}
Course Repository
package com.jpa.hibernate.learnjpa.repository;
import org.springframework.stereotype.Repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import com.socgen.jpa.hibernate.learnjpa.entity.Course;
import java.util.List;
import java.util.Optional;
@Repository
public interface CourseRepository extends JpaRepository<Course, Long> {
Optional<Course> findById(Long id);
void deleteById(Long id); //does nothing if ID not found
Optional<Course> findByName(String name);
@Query(value = "select * from course", nativeQuery = true)
List<Course> findAllCoursesInTable();
}
CourseController
package com.jpa.hibernate.learnjpa.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriComponentsBuilder;
import com.socgen.jpa.hibernate.learnjpa.Services.CourseService;
import com.socgen.jpa.hibernate.learnjpa.entity.Course;
import java.net.URI;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.PutMapping;
@RestController
@RequestMapping("/course")
public class CourseController {
@Autowired
private CourseService courseService;
@GetMapping("/{id}")
public ResponseEntity<Course> getCourseById(@PathVariable Long id) {
Course course = courseService.findById(id);
if(course == null){
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(course);
}
// getting all the courses
@GetMapping("/all")
public ResponseEntity<List<Course>> getAllCourses() {
return ResponseEntity.ok().body(courseService.getAllCourses());
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteCourseById(@PathVariable Long id){
if(courseService.deleteById(id)) return ResponseEntity.noContent().build();
return ResponseEntity.notFound().build();
}
@PostMapping("/add")
public ResponseEntity<Void> addCourse(@RequestBody Course course, UriComponentsBuilder ucb) {
Course newCourse = courseService.addNewCourse(course);
if(newCourse != null){
URI locationOfNewCourse = ucb.path("course/{id}").buildAndExpand(newCourse.getId()).toUri();
return ResponseEntity.created(locationOfNewCourse).build();
}
return ResponseEntity.badRequest().build();
}
@PutMapping("update/{id}")
public ResponseEntity<Course> putMethodName(@PathVariable String id, @RequestBody Course course, UriComponentsBuilder ucb) {
Course updatedCourse = courseService.updateCourse(course);
return ResponseEntity.created(null).body(updatedCourse);
}
}
Course Service
package com.jpa.hibernate.learnjpa.Services;
import java.util.List;
import com.jpa.hibernate.learnjpa.entity.Course;
public interface CourseService {
Course findById(Long id);
Boolean deleteById(Long id); //returns true if any object was deleted else returns false
Course addNewCourse(Course course);
Course updateCourse(Course course);
List<Course> getAllCourses();
}
CourseServiceImpl
package com.jpa.hibernate.learnjpa.Services;
import java.util.List;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.socgen.jpa.hibernate.learnjpa.entity.Course;
import com.socgen.jpa.hibernate.learnjpa.repository.CourseRepository;
@Service
public class CourseServiceImp implements CourseService {
Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
CourseRepository courseRepository;
@Override
public Course findById(Long id) {
Optional<Course> course = courseRepository.findById(id);
logger.info(course.toString());
if(course.isPresent()) return course.get();
return null;
}
@Override
public Boolean deleteById(Long id) {
Optional<Course> course = courseRepository.findById(id);
if(!course.isPresent()) return false;
courseRepository.deleteById(id);
return true;
}
@Override
public Course addNewCourse(Course course) {
Optional<Course> courseExists = courseRepository.findByName(course.getName());
if(courseExists.isPresent()) return null;
Course newCourse = courseRepository.save(course);
return newCourse;
}
@Override
public Course updateCourse(Course course) {
Course updatedCourse = courseRepository.save(course);
return updatedCourse;
}
@Override
public List<Course> getAllCourses() {
return courseRepository.findAllCoursesInTable();
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.1</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.socgen.jpa.hibernate</groupId>
<artifactId>learnjpa</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>learnjpa</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.3</version>
</plugin>
</plugins>
</build>
</project>
I have no idea what I am doing wrong because the endpoint works when I try to test it in postman. Its probably some issue with the testcase.`
You forgot the /course
prefix at
ResponseEntity<List<Course>> getResponse = restTemplate.exchange("/course/all", /* rest of params */);
Oh, and when testing controllers take a look at MockMvc.