I have created a new Spring Boot application using Spring Data.
I got an issue when I try to test my JpaRepository:
[ERROR] Failures:
[ERROR] EmployeeRepositoryTest.testDeleteEmployee:46 NullPointer
[ERROR] EmployeeRepositoryTest.testGetEmployee:37 NullPointer
[ERROR] EmployeeRepositoryTest.testSaveEmployee ยป Test
Expected exception of type cla...
java.lang.NullPointerException in the line
repository.save(employee);
where a repository has been defined as:
#Autowired
private EmployeeRepository repository;
Follow my pom.xml and test class:
#ExtendWith({SpringExtension.class})
#DataJpaTest
class EmployeeRepositoryTest {
#Autowired
private EmployeeRepository repository;
#Test(expectedExceptions = ResourceNotFoundException.class)
void testSaveEmployee() throws ResourceNotFoundException {
Employee employee = new Employee("John", "Smith", "john.smith#email.com");
repository.save(employee);
employee = repository.findById(employee.getId()).orElseThrow(() -> new ResourceNotFoundException(""));
assertNotNull(employee);
assertEquals(employee.getFirstName(), "John", "The employee firstname should be John");
}
}
...
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.5.2</version>
<scope>test</scope>
</dependency>
</dependencies>
...
Could you please help to understand which is the issue?
Below the EmployeeRepository interface:
#Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long>{
}
Related
I am using Spring Data Mongodb and Embeded mongoDB to persist the data.
Pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
</dependency>
applicaiton.properties
spring.data.mongodb.port=2019
spring.data.mongodb.database=testdb
spring.data.mongodb.host=localhost
Main class:
#SpringBootApplication
#EnableAutoConfiguration
#EnableMongoRepositories(basePackages = { "com.koka.mongotest.repo"})
public class MongotestApplication {
public static void main(String[] args) {
SpringApplication.run(MongotestApplication.class, args);
}
}
Enity or Domain class :
#Document
public class Person
{
#Indexed
private String personId;
private String name;
//getter and setters
}
Repo:
#Repository
public interface PersonRepo extends MongoRepository { //No Custom emthod}
Service layer :
#Service
public class ServiceImpl {
#Autowired
PresonRepo repo;
public void saveJon(Person p )
{
repo.save(p);
}
}
but Int DB its getting saved as
{"_id":{"$oid":"60e18f9d7eb50d70b56b543f"},"_class":"com.koka.mongotest.entity.Person"}
But that person Object hold info which is not being saved. Please advise on this,
I have project with integrated JavaFX and Spring Boot as one. I have problem with an injecting repository to Controller of JavaFX.
I have annotation #Controller in JavaFX controller, but although it's every time reproduce the same error: No qualifying bean of type 'TaxRepository' available.
Has anyone idea how resolve this problem ? I want use TaxRepository in NewTaxWindowController, but when I has previous configuration with other spring integration I get every time null for TaxRepository.
Below is my configuration:
Maven pom file:
<?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>2.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.hubertstruminski.invoice.app</groupId>
<artifactId>com-hubertstruminski-invoice-app</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>invoiceApp</name>
<description>Management system for invoices</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>14</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-media</artifactId>
<version>14</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics</artifactId>
<version>14</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>14</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-base</artifactId>
<version>14</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-swing</artifactId>
<version>14</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-web</artifactId>
<version>14</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>2.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>2.3.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20160810</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.4.RELEASE</version>
</dependency>
<dependency>
<groupId>de.jensd</groupId>
<artifactId>fontawesomefx</artifactId>
<version>8.9</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.193</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>io.github.fvarrui</groupId>
<artifactId>javapackager</artifactId>
<version>0.9.7</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>package</goal>
</goals>
<configuration>
<!-- mandatory -->
<mainClass>com.hubertstruminski.invoice.app.InvoiceAppApplication</mainClass>
<!-- optional -->
<bundleJre>true</bundleJre>
<generateInstaller>true</generateInstaller>
<administratorRequired>false</administratorRequired>
<platform>windows</platform>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
application.properties
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:file:./db/invoiceAppDatabase;MV_STORE=FALSE;MVCC=FALSE
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=user
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
InvoiceAppApplication class - main Spring boot class which extends from Application Javafx class
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.data.jpa.repository.config.*;
#SpringBootApplication
#EntityScan(basePackages = {"com.hubertstruminski.invoice.app.model"})
public class InvoiceAppApplication extends Application {
private ConfigurableApplicationContext springContext;
private Parent rootNode;
public static void main(String[] args) {
System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
Application.launch(args);
}
#Override
public void init() throws Exception {
springContext = SpringApplication.run(InvoiceAppApplication.class);
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/static/mainWindow.fxml"));
fxmlLoader.setControllerFactory(springContext::getBean);
rootNode = fxmlLoader.load();
}
#Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(rootNode));
stage.show();
}
#Override
public void stop() throws Exception {
springContext.close();
}
}
TaxRepository class
import com.hubertstruminski.invoice.app.model.Tax;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository
public interface TaxRepository extends CrudRepository<Tax, Long> {
public List<Tax> findByName(String name);
public List<Tax> findById(long id);
}
Tax model class
import javax.persistence.*;
#Entity
#Table(name = "Taxs")
public class Tax {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String name;
private String description;
private String taxAmount;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getTaxAmount() {
return taxAmount;
}
public void setTaxAmount(String taxAmount) {
this.taxAmount = taxAmount;
}
}
NewTaxWindowController JavaFX class
#Controller
public class NewTaxWindowController extends BaseController implements Initializable
{
#Autowired
private TaxRepository taxRepository;
#FXML
private Label nameLabel;
public NewTaxWindowController() {
}
public NewTaxWindowController(ViewCreator viewCreator, String fxmlName) {
super(viewCreator, fxmlName);
}
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
}
}
Stacktrace:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type 'com.xxxx.xxxx.xxxxx.repository.TaxRepository'
available: expected at least 1 bean which qualifies as autowire candidate.
Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
I am trying to do unit testing for spring boot RESTFUL controller but I am receiving a null pointer exception. The application has a StudentController which depends on a StudentService.
Here is the controller code:
package com.demo.student.demo.controller;
import com.demo.student.demo.annotation.ApiDescription;
import com.demo.student.demo.entity.Student;
import com.demo.student.demo.entity.StudentDto;
import com.demo.student.demo.service.StudentService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.stream.Collectors;
#RestController
#RequestMapping(value = "/v1/students")
#Api(description = "This is a general description for StudentController RESTFUL Controller")
public class StudentController {
private StudentService studentService;
private ModelMapper modelMapper;
public StudentController(ModelMapper modelMapper, StudentService studentService){
this.studentService = studentService;
this.modelMapper = modelMapper;
}
private StudentDto convertToDto(Student student) {
StudentDto studentDto = modelMapper.map(student, StudentDto.class);
return studentDto;
}
private Student convertToEntity(StudentDto studentDto) {
Student student = modelMapper.map(studentDto, Student.class);
return student;
}
#GetMapping
#ApiOperation("Returns a list of all students in the system.")
#ApiDescription("FIND_ALL_STUDENTS.md")
public List<StudentDto> findAll(){
List<Student> students = studentService.findAl();
return students.stream()
.map(student -> convertToDto(student))
.collect(Collectors.toList());
}
#GetMapping("/{id}")
#ApiOperation("Returns a specific Student by his/her identifier. 404 if does not exist.")
#ApiDescription("FIND_STUDENT_BY_ID.md")
public StudentDto findById(#PathVariable("id") long id){
return convertToDto(studentService.findById(id));
}
#PostMapping
#ApiOperation("Creates/Updates a new Student.")
#ApiDescription("SAVE_OR_UPDATE_STUDENT.md")
public StudentDto saveOrUpdate(#RequestBody StudentDto studentDto) {
Student student = convertToEntity(studentDto);
student.setUsername(student.getEmail() + "----" + student.getId());
Student studentCreated = studentService.saveOrUpdate(student);
return convertToDto(studentCreated);
}
#DeleteMapping("/{id}")
#ApiOperation("Deletes a Student from the system. 404 if the Student's identifier is not found.")
#ApiDescription("DELETE_STUDENT_BY_ID.md")
public void deleteById(#PathVariable("id") long id){
studentService.deleteById(id);
}
}
And here is the service implementation code:
package com.demo.student.demo.service;
import com.demo.student.demo.entity.Student;
import com.demo.student.demo.exception.StudentNotFoundException;
import com.demo.student.demo.repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
#Service
public class StudentServiceImpl implements StudentService {
private StudentRepository studentRepository;
#Autowired
public StudentServiceImpl(StudentRepository studentRepository){
this.studentRepository = studentRepository;
}
#Override
public List<Student> findAl() {
return studentRepository.findAll();
}
#Override
public Student findById(long id) {
return studentRepository.findById(id).orElseThrow(() -> new StudentNotFoundException(id));
}
#Override
public Student saveOrUpdate(Student student) {
studentRepository.save(student);
return student;
}
#Override
public void deleteById(long id) {
if(this.findById(id) != null)
studentRepository.deleteById(id);
}
}
And this is the test class for the controller:
package com.demo.student.demo.controller;
import com.demo.student.demo.entity.Student;
import com.demo.student.demo.service.StudentService;
import com.demo.student.demo.service.StudentServiceImpl;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;
import java.util.Arrays;
import java.util.List;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
#WebMvcTest(StudentController.class)
class StudentControllerTest {
private final static String URI = "/v1/students";
#Autowired
private MockMvc mockMvc;
#MockBean
private StudentService studentService;
#Test
void findAll() throws Exception {
// given
Student student = new Student(1, "test", "test#test.test");
List<Student> students = Arrays.asList(student);
given(studentService.findAl()).willReturn(students);
// when + then
mockMvc.perform(get(URI))
.andExpect(status().isOk())
.andExpect(content().json("[{'id':1,'email':'test#test.test'}]"));
}
}
Here is also the pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
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>2.0.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.demo.student</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</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-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/org.modelmapper/modelmapper -->
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>0.7.5</version>
</dependency>
<dependency>
<groupId>org.springframework.plugin</groupId>
<artifactId>spring-plugin-core</artifactId>
<version>1.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-bean-validators</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>javax.xml</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.25.0-GA</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.22.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.skyscreamer</groupId>
<artifactId>jsonassert</artifactId>
<version>1.5.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
When I run the test I receive a NULL POINTER EXCEPTION pointing to a code line in the StudentController class where the student service retrieves all the student data: List<Student> students = studentService.findAl();
java.lang.NullPointerException: null
at com.demo.student.demo.controller.StudentController.findAll
Can anyone tell me what is the problem?
Finally I found an answer, to add #ExtendWith(SpringExtension.class) in order to work in JUnit5.
So, my controller test class would be:
package com.demo.student.demo.controller;
import com.demo.student.demo.entity.Student;
import com.demo.student.demo.service.StudentService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import java.util.Arrays;
import java.util.List;
import static org.mockito.BDDMockito.given;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
#ExtendWith(SpringExtension.class)
#WebMvcTest
class StudentControllerTest {
private final static String URI = "/v1/students";
#Autowired
private MockMvc mockMvc;
#MockBean
private StudentService studentService;
#Test
void findAll() throws Exception {
// given
Student student = new Student(1, "test", "test#test.test");
List<Student> students = Arrays.asList(student);
given(studentService.findAl()).willReturn(students);
// when + then
mockMvc.perform(get(URI))
.andExpect(status().isOk())
.andExpect(content().json("[{'id':1,'email':'test#test.test'}]"));
}
}
And also here is the pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
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>2.0.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.demo.student</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</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-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/org.modelmapper/modelmapper -->
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>0.7.5</version>
</dependency>
<dependency>
<groupId>org.springframework.plugin</groupId>
<artifactId>spring-plugin-core</artifactId>
<version>1.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-bean-validators</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>javax.xml</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.25.0-GA</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.22.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.skyscreamer</groupId>
<artifactId>jsonassert</artifactId>
<version>1.5.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
There are a couple of things with your test, first you are mixing JUnit4 and JUnit5, don't, second you are trying to work against the Spring Boot created mock, don't. Finally you are creating a new mock for the service and register behavior.
Remove the #RunWith annotation, that is for JUnit4 tests and not needed with JUnit5.
Remove your #BeforeEach method, as that interferes with the prepared MockMvc by Spring Boot (through the #WebMvcTest) and the mock created by #MockBean.
Remove StudentService studentService = mock(StudentService.class); from your test method. #MockBean already creates a mock. This creates a new mock, not tied to the controller.
The version of Spring Boot used (2.0.x) doesn't yet have an #WebMvcTest that includes the #ExtendWith annotation (as of Spring Boot 2.1.x). So add that as well to use the proper execution model.
pro-tip: Remove the no-args constructor and #Autowired from your StudentController, Spring is smart enough to pick the single constructor.
Annotate your test class this way.
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
Autowire this:
#Autowired
private WebApplicationContext wac;
This is just a class variable:
private MockMvc mockMvc;
Your setup method:
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
Before this line:
given(studentService.findAl()).willReturn(students);
Create:
StudentService studentService = org.mockito.Mockito.mock(StudentService.class);
It should run.
I have created a springboot project splitted into three maven modules, the domain layer, the core layer (contains persistence and business logic) and the web layer. I try to unit test my repository ProductRepository (located in the core layer)
#RunWith(SpringRunner.class) // provide bridge between SpringBoot test features and JUnit, for usage of springboot tsting features
#DataJpaTest
class ProductRepositoryTest {
#Autowired
private TestEntityManager em;
#Autowired
private ProductRepository repository;
#Test
void shouldReturnProduct() {
// given
Product p = Product.builder().id(1).designation("Test").reference("TEST").unitPrice(150).build();
this.em.persistAndFlush(p);
// when
Product found = repository.findByReference(p.getReference());
// then
assertThat(found.getReference()).isEqualTo(p.getReference());
}
}
But the repository is always instanciated to null. I run this test as JUnit Test in eclipse and i got a nullpointerexception.
Here is my pom.xml file
<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-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
You say you try to unit test the controller but you use #RunWith(SpringRunner.class), this is used for integration tests. This annotation starts the complete application. And you just want to test the repository. What you can do is create an abstract DAO which you can implement in your unit tests.
public abstract class AbstractRepository<RepositoryType> {
RepositoryType repository;
private DBI dbi;
protected abstract RepositoryType createRepository(final DBI dbi);
#Before
public final void setUpDataSource() throws Exception {
final JdbcDataSource jdbcDataSource = new JdbcDataSource();
// DB_CLOSE_DELAY=-1 ==> h2 will keep its content as long as the vm lives otherwise the content of the database
// is lost at the moment the last connection is closed.
jdbcDataSource
.setURL("jdbc:h2:mem:play;MODE=MySQL;DB_CLOSE_DELAY=-1L;INIT=RUNSCRIPT FROM 'classpath:path/to/file/init_test.sql';");
final Flyway flyway = new Flyway();
flyway.setDataSource(jdbcDataSource);
flyway.setLocations("/path/to/locations");
flyway.migrate();
dbi = new DBI(jdbcDataSource);
runDbScript("/data.sql");
repository = createRepository(dbi);
}
private void runDbScript(final String scriptPath) throws Exception {
try (InputStreamReader reader = new InputStreamReader(AbstractDaoTest.class.getResourceAsStream(scriptPath),
Charsets.UTF_8); Handle h = dbi.open()) {
RunScript.execute(h.getConnection(), reader);
}
}
}
Now you can overwrite the createRepository method in your test class.
public class ProductRepositoryTest() {
#Override
protected ProductRepository createRepository(Dbi dbi) { return new ProductRepository(dbi); }
#Test
public void testGetProductById() {
Product response = repository.getProductById(1);
assertThat(response).isEqualTo(someObject);
}
}
If you need a framework to mock objects you can use Mockito and if you need to mock static or void methods you can use PowerMock.
Hope this helps.
Add these annotations to your test classes.
#SpringBootTest
#TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DbUnitTestExecutionListener.class,
TransactionalTestExecutionListener.class })
public class YourTestClass {....
here's a working version of your example - hope this helps. I think you may have some conflicting configuration or dependencies in your own project. https://github.com/tndavidson/springbootjparepositorytest
I'm using Spring Data Jpa and facing an exception when I deployed the project
I have used findAll() method in service and serviceImpl class and I received an exception, this is my source:
Model:
#Entity
#Table(name="CITY")
public class City {
#Id
#Column(name="ID", nullable = false, unique = true)
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
#Column(name = "NAME")
private String name;
// get, set method
}
Repository class:
public interface CityJpaRepositoryCustom extends JpaRepository<City, Integer> {
}
Service class:
public interface CityService {
public List<City> findAll();
}
ServiceImpl class:
#Service
public class CityServiceImpl implements CityService {
#Resource
private CityJpaRepositoryCustom cityRepository;
#Override
#Transactional
public List<City> findAll() {
// TODO Auto-generated method stub
return cityRepository.findAll();
}
}
Controller class:
#Controller
public class CityController {
#Autowired
private CityService cityService;
#RequestMapping(value="/list", method=RequestMethod.GET)
public ModelAndView getListCity(HttpServletRequest request,
HttpServletResponse response,
ModelMap model) {
ModelAndView mav = new ModelAndView("manageCity");
List<City> cityList = cityService.findAll();
mav.addObject("cityList", cityList);
return mav;
}
Pom.xml:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.0.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<exclusions>
<exclusion>
<artifactId>hibernate-entitymanager</artifactId>
<groupId>org.hibernate</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- SOLR -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-solr</artifactId>
<version>${spring-data-solr.verion}</version>
</dependency>
<!-- JSON -->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.11</version>
</dependency>
<!-- WEB -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<!-- Hibernate 4 dependencies -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>${hibernate.version}</version>
</dependency>
</dependencies>
Log message:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cityJpaRepositoryCustom': Invocation of init method failed; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property delete found for type void!
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1553)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
I have found some same topic but it's not get good result for me, How to fix this exception? thank you so much!
Upgrade your version of Spring Boot to the latest (1.5.1.RELEASE).
You're using an ancient version which will in turn be pulling in an old version of Spring Data which may have not supported delete.
If you want to use delete operation but don't want to update Spring Data JPA, you have to write your own delete implementation. Example:
public interface CityJpaRepositoryCustom extends JpaRepository<City, Integer> {
#Modifying
#Query("delete from City where name = :name")
void deleteByName(#Param("name") String name);
}
Related docs:
Using #Query annotation
#Modifying annotation
#Param annotation