https://github.com/lemick/hibernate-query-asserts
Assert SQL statement count generated by Hibernate in Spring tests
https://github.com/lemick/hibernate-query-asserts
hibernate jpa jpa-test spring spring-test spring-test-web sql testing-tools
Last synced: 3 months ago
JSON representation
Assert SQL statement count generated by Hibernate in Spring tests
- Host: GitHub
- URL: https://github.com/lemick/hibernate-query-asserts
- Owner: Lemick
- License: apache-2.0
- Created: 2022-04-14T19:19:35.000Z (almost 4 years ago)
- Default Branch: main
- Last Pushed: 2025-02-08T20:45:29.000Z (about 1 year ago)
- Last Synced: 2025-07-21T07:49:14.778Z (8 months ago)
- Topics: hibernate, jpa, jpa-test, spring, spring-test, spring-test-web, sql, testing-tools
- Language: Java
- Homepage:
- Size: 75.2 KB
- Stars: 15
- Watchers: 1
- Forks: 2
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Hibernate SQL Query Assertions for Spring
Hibernate is a powerful ORM, but you need to have control over the executed SQL queries to avoid **huge performance problems** (N+1 selects, batch insert not working...)
You can enable SQL query logging, this is a great help in dev, but not in production. This tool helps you to count the **executed SQL queries by Hibernate in your integration tests, it can assert L2C statistics too**.
It consists of just a Hibernate SQL inspector service and a Spring Test Listener that controls it (no proxy around the Datasource).
The assertion will work seamlessly whether you're testing Spring repositories or doing HTTP integration tests.
## Examples
A full-working demo of the examples below [is available here](https://github.com/Lemick/demo-hibernate-query-utils)
*Tested versions*: Hibernate 5 & 6
### Assert SQL statements declaratively
You just have to add the `@AssertHibernateSQLCount` annotation to your test and it will verify the SQL statements (SELECT, UPDATE, INSERT, DELETE) count at the end of the test :
```java
@Test
@Transactional
@AssertHibernateSQLCount(inserts = 6)
void create_two_blog_posts() {
BlogPost post_1 = new BlogPost("Blog post 1");
post_1.addComment(new PostComment("Good article"));
post_1.addComment(new PostComment("Very interesting"));
blogPostRepository.save(post_1);
BlogPost post_2 = new BlogPost("Blog post 2");
post_2.addComment(new PostComment("Nice"));
post_2.addComment(new PostComment("So cool, thanks"));
blogPostRepository.save(post_2);
}
```
If the actual count is different, an exception is thrown with the executed statements:
```
com.mickaelb.assertions.HibernateAssertCountException:
Expected 5 INSERT but got 6:
=> '/* insert com.lemick.demo.entity.BlogPost */ insert into blog_post (id, title) values (default, ?)'
=> '/* insert com.lemick.demo.entity.PostComment */ insert into post_comment (id, blog_post_id, content) values (default, ?, ?)'
=> '/* insert com.lemick.demo.entity.PostComment */ insert into post_comment (id, blog_post_id, content) values (default, ?, ?)'
=> '/* insert com.lemick.demo.entity.BlogPost */ insert into blog_post (id, title) values (default, ?)'
=> '/* insert com.lemick.demo.entity.PostComment */ insert into post_comment (id, blog_post_id, content) values (default, ?, ?)'
=> '/* insert com.lemick.demo.entity.PostComment */ insert into post_comment (id, blog_post_id, content) values (default, ?, ?)'
```
### Assert SQL statements programmatically
You can also assert statements from several transactions in your test using the programmatic API:
```java
@Test
void multiple_assertions_using_programmatic_api() {
QueryAssertions.assertInsertCount(2, () -> {
BlogPost post_1 = new BlogPost("Blog post 1");
post_1.addComment(new PostComment("Good article"));
blogPostRepository.save(post_1);
});
QueryAssertions.assertSelectCount(1, () -> blogPostRepository.findById(1L));
// Or even multiple asserts at once
QueryAssertions.assertStatementCount(Map.of(INSERT, 2, SELECT, 1), () -> {
BlogPost post_1 = new BlogPost("Blog post 1");
post_1.addComment(new PostComment("Good article"));
blogPostRepository.save(post_1);
blogPostRepository.findById(1L);
});
}
```
### Assert L2C statistics declaratively
It supports assertions on Hibernate level two cache statistics, useful for checking that your entities are cached correctly and that they will stay forever:
```java
@Test
@AssertHibernateL2CCount(misses = 1, puts = 1, hits = 1)
void create_one_post_and_read_it() {
doInTransaction(() -> {
BlogPost post_1 = new BlogPost("Blog post 1");
blogPostRepository.save(post_1);
});
doInTransaction(() -> {
blogPostRepository.findById(1L); // 1 MISS + 1 PUT
});
doInTransaction(() -> {
blogPostRepository.findById(1L); // 1 HIT
});
}
```
## How to integrate
1. Import the dependency
```xml
com.mickaelb
hibernate-query-asserts
2.2.0
```
2. Register the integration with Hibernate, you just need to add this key in your configuration (here for yml):
spring:
jpa:
properties:
hibernate.session_factory.statement_inspector: com.mickaelb.integration.hibernate.HibernateStatementInspector
3. Register the Spring TestListener that will launch the SQL inspection if the annotation is present:
* By adding the listener on each of your integration test:
```java
@SpringBootTest
@TestExecutionListeners(
listeners = HibernateAssertTestListener.class,
mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS
)
class MySpringIntegrationTest {
...
}
```
* **OR** by adding a **META-INF/spring.factories** file that contains the definition, that will register the listener for all your tests:
```
org.springframework.test.context.TestExecutionListener=com.mickaelb.integration.spring.HibernateAssertTestListener
```