JUnit with JPA

JUnit test cases for the Repositories

Project Structure for adding Test files

				
					<?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.0.2</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.brains.jpa.hibernate</groupId>
	<artifactId>jpa-hibernate-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>jpa-hibernate-demo</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-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.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>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

				
			

application.properties

				
					
spring.datasource.url=jdbc:h2:mem:testdb;NON_KEYWORDS=USER;DB_CLOSE_ON_EXIT=FALSE
spring.h2.console.enabled=true
#spring.data.jpa.repositories.bootstrap-mode=default
spring.jpa.defer-datasource-initialization=true

# Turn Statistics ON
spring.jpa.properties.hibernate.generate_statistics=true
logging.level.org.hibernate.stat=debug
logging.level.org.hibernate=debug
# Show all queries
spring.jpa.show-sql=true

# Format the queries
spring.jpa.properties.hibernate.format_sql=true

# Enable seeing the parameters with query
logging.level.org.hibernate.type=trace
				
			

data.sql

				
					insert into course(id, name) values(10001, 'JPA in 5 steps');
insert into course(id, name) values(10002, 'JDBC in 10 steps');
insert into course(id, name) values(10003, 'JPQL in 50 steps');
				
			
				
					package com.brains.jpa.hibernate.jpahibernatedemo.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import lombok.AccessLevel;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@Data
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Course {
	
	@Id
	@GeneratedValue
	private Long id;
	
	private String name;
	
	public Course(String name) {
		this.name = name;
	}

}

				
			

EntityManager – An interface to the PersistentContext. PersistentContext keeps tracks of the entities which are changed during transactions.

@Transactional – For making any changes to the database, this annotation needs to be enabled.

  • em.persist(Object) – saves the data, after this all the transactions are automatically saved and stored in the database
  • em.flush() – sends the data to the database
  • em.refresh() – get the data from the database
  • em.clear() – Clears the memory cache of EntityManager
  • em.detach(Object) – Detaches the object from the EntityManager cache memory and changes to the entity are no longer tracked.
				
					package com.brains.jpa.hibernate.jpahibernatedemo.repository;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.brains.jpa.hibernate.jpahibernatedemo.entity.Course;

import jakarta.persistence.EntityManager;
import jakarta.transaction.Transactional;

@Repository
@Transactional
public class CourseRepository {

	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
	@Autowired
	EntityManager em;
	
	public Course findById(Long id) {
		return em.find(Course.class, id);
	}
	
	public void deleteById(Long id) {
		Course course = findById(id);
		em.remove(course);
	}
	
	public Course save(Course course) {
		if(course.getId() == null) {
			//insert
			em.persist(course);
		}else {
			//update
			em.merge(course);
		}
		return course;
	}
	
	public void playWithEntityManager() {
		logger.info("playWithEntityManager - start");
		Course course1 = new Course("AngularJs in 100 Steps");
		em.persist(course1);
		em.flush();

		course1.setName("AngularJs in 100 Steps -- updated");
		em.refresh(course1);
		Course course2 = new Course("Microservices in 50 Steps");
		em.persist(course2);
		em.flush();
		course2.setName("Microservices in 50 Steps -- updated");
		
	}
}

				
			
				
					package com.brains.jpa.hibernate.jpahibernatedemo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.brains.jpa.hibernate.jpahibernatedemo.repository.CourseRepository;

@SpringBootApplication
public class JpaHibernateDemoApplication implements CommandLineRunner {

	public static void main(String[] args) {
		SpringApplication.run(JpaHibernateDemoApplication.class, args);
	}

	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
	@Autowired
	private CourseRepository courseRepository;
	
	@Override
	public void run(String... args) throws Exception {
		// TODO Auto-generated method stub
		logger.info("FindById 10001: -> {}", courseRepository.findById(10001L));
		courseRepository.playWithEntityManager();
	}

}

				
			
				
					package com.brains.jpa.hibernate.jpahibernatedemo;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class JpaHibernateDemoApplicationTests {

	@Test
	void contextLoads() {
	}

}

				
			

@SpringBootTest(classes = JpaHibernateDemoApplication.class)

This will load the SpringContext of the defined class on application startup.  Run this file as “JUnit Test”.

@DirtiesContext – Resets the database for other methods

				
					package com.brains.jpa.hibernate.jpahibernatedemo.repository;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;

import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;

import com.brains.jpa.hibernate.jpahibernatedemo.JpaHibernateDemoApplication;
import com.brains.jpa.hibernate.jpahibernatedemo.entity.Course;

@SpringBootTest(classes = JpaHibernateDemoApplication.class)
class CourseRepositoryTest {

	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
	@Autowired
	CourseRepository courseRepository;
	
	@Test
	void find_by_id() {
		Course course = courseRepository.findById(10001L);
		assertEquals("JPA in 5 steps", course.getName());
	}
	
	@Test
	@DirtiesContext
	void delete_by_id() {
		courseRepository.deleteById(10002L);
		assertNull(courseRepository.findById(10002L));
	}
	
	@Test
	@DirtiesContext
	void save() {
		// getById 10001
		Course course = courseRepository.findById(10001L);
		assertEquals("JPA in 5 steps", course.getName());
		
		// update course
		course.setName("JPA in 5 steps -- updated");
		courseRepository.save(course);
		// check the value
		assertEquals("JPA in 5 steps -- updated", courseRepository.findById(10001L).getName());
		
		// insert new course
		Course course1 = courseRepository.save(new Course("JPA_JDBC"));
		// check the value
		assertEquals("JPA_JDBC", course1.getName());
	}

}

				
			

JPQL – we use entities to make queries.

				
					package com.brains.jpa.hibernate.jpahibernatedemo;

import java.util.List;

import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import com.brains.jpa.hibernate.jpahibernatedemo.entity.Course;

import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import jakarta.persistence.TypedQuery;

@SpringBootTest(classes = JpaHibernateDemoApplication.class)
class JPQLTest {

	@Autowired
	EntityManager em;
	
	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
	@Test
	void jpql_basic() {
		Query query = em.createQuery("select c from Course c");
		List resultList = query.getResultList();
		logger.info("list: -> {}", resultList);
	}
	
	// List of fixed type
	@Test
	void jpql_typed() {
		TypedQuery<Course> query = em.createQuery("select c from Course c", Course.class);
		List resultList = query.getResultList();
		logger.info("Course: -> {}", resultList);
	}

    // Query with where clause
	@Test
	void jpql_where() {
		TypedQuery<Course> query = em.createQuery("select c from Course c where name like '%10%'", Course.class);
		List resultList = query.getResultList();
		logger.info("Where Course: -> {}", resultList);
	}

}

				
			

Related Tutorials

SpringBoot JPA with H2

JPA is Java Persistence API, is an interface and Hibernate is an implementation of JPA and is an ORM Framework. ORM stands for Object-Relational Mapping

 

 

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.0.2</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.brains.database</groupId>
	<artifactId>database-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>database-demo</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-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.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>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

				
			

application.properties

				
					#spring.datasource.url=jdbc:h2:mem:testdb;NON_KEYWORDS=USER
spring.datasource.url=jdbc:h2:mem:public;MODE=MYSQL;DATABASE_TO_UPPER=false;INIT=CREATE SCHEMA IF NOT EXISTS public
spring.h2.console.enabled=true
spring.data.jpa.repositories.bootstrap-mode=default
spring.jpa.defer-datasource-initialization=true

spring.jpa.show-sql=true
				
			

See the UI for the H2 database by typing this url

				
					http://localhost:8080/h2-console
				
			

Add data.sql in the resources folder and it would automatically called at startup. Load some data in the  table by adding some records in the same data.sql file.

data.sql

				
					insert into person (id, name, location, birth_date)
values(10001,'Ranga','Hyderabad', now() );
insert into person (id, name, location, birth_date)
values(10002,'John','Guntur', now() );
insert into person (id, name, location, birth_date)
values(10003,'Ravi','Ahmedabad', now() );
				
			

Create PersonJdbcDao which can interact with the database. Here all the magic happens using Autoconfiguration by SpringBoot. @JdbcTemplate is the class responsible such database interactions.

				
					package com.brains.database.databasedemo.bean;


import java.util.Date;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.NamedQuery;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@Data @AllArgsConstructor @NoArgsConstructor
@NamedQuery(name = "find_all_persons", query = "select p from Person p")
public class Person {

	@Id
	@GeneratedValue
	private int id;
	
	private String name;
	private String location;
	private Date birth_date;
	
	public Person(String name, String location, Date birth_date) {
		super();
		this.name = name;
		this.location = location;
		this.birth_date = birth_date;
	}
}
				
			
				
					package com.brains.database.databasedemo.repository;

import java.util.List;

import org.springframework.stereotype.Repository;

import com.brains.database.databasedemo.bean.Person;

import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.TypedQuery;
import jakarta.transaction.Transactional;

@Repository
@Transactional
public class PersonJpaRepository {

	@PersistenceContext
	EntityManager entityManager;
	
	public List<Person> findAll(){
		TypedQuery<Person> personNamedQuery = entityManager.createNamedQuery("find_all_persons", Person.class);
		return personNamedQuery.getResultList();
	}
	
	public Person findById(int id) {
		return entityManager.find(Person.class, id);
	}
	
	public Person update(Person person) {
		return entityManager.merge(person);
	}
	
	public Person insert(Person person) {
		return entityManager.merge(person);
	}
	
	public void delete(int id) {
		Person person = findById(id);
		entityManager.remove(person);
	}
}

				
			

Extend the main applicatino with CommandLineRunner so that run() method can be executed while application startup.

				
					package com.brains.database.databasedemo;

import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.brains.database.databasedemo.bean.Person;
import com.brains.database.databasedemo.repository.PersonJpaRepository;

@SpringBootApplication
public class SpringJpaDemoApplication implements CommandLineRunner {

	public static void main(String[] args) {
		SpringApplication.run(SpringJpaDemoApplication.class, args);
	}

	@Autowired
	PersonJpaRepository jpaRepository;

	private Logger logger = LoggerFactory.getLogger(this.getClass());

	@Override
	public void run(String... args) throws Exception {
		logger.info("Peson found: -> {}", jpaRepository.findById(10002));
		logger.info("Insert new person -> {}", jpaRepository.insert(new Person("Suresh", "Ahmedabad", new Date())));
		jpaRepository.delete(10001);
		
		logger.info("All persons: -> {}", jpaRepository.findAll());
	}
}
				
			

Running the Application

				
					2023-02-21T00:28:37.518+05:30  INFO 26412 --- [           main] SpringJpaDemoApplication$$SpringCGLIB$$0 : Peson found: -> Person(id=10002, name=John, location=Guntur, birth_date=2023-02-21 00:28:37.298462)
Hibernate: select next value for person_seq
Hibernate: insert into person (birth_date, location, name, id) values (?, ?, ?, ?)
2023-02-21T00:28:37.527+05:30  INFO 26412 --- [           main] SpringJpaDemoApplication$$SpringCGLIB$$0 : Insert new person -> Person(id=1, name=Suresh, location=Ahmedabad, birth_date=2023-02-21 00:28:37.518)
Hibernate: select p1_0.id,p1_0.birth_date,p1_0.location,p1_0.name from person p1_0 where p1_0.id=?
Hibernate: delete from person where id=?
Hibernate: select p1_0.id,p1_0.birth_date,p1_0.location,p1_0.name from person p1_0
2023-02-21T00:28:37.551+05:30  INFO 26412 --- [           main] SpringJpaDemoApplication$$SpringCGLIB$$0 : All persons: -> [Person(id=1, name=Suresh, location=Ahmedabad, birth_date=2023-02-21 00:28:37.518), Person(id=10002, name=John, location=Guntur, birth_date=2023-02-21 00:28:37.298462), Person(id=10003, name=Ravi, location=Ahmedabad, birth_date=2023-02-21 00:28:37.298631)]

				
			

Related Tutorials