Fluent, intuitive JSON assertions for Java testing
- REST API Testing - Validate JSON responses with ease
- Microservices - Assert JSON contracts between services
- Integration Tests - Test JSON data flows end-to-end
- Unit Tests - Verify JSON serialization/deserialization
- Spring Boot Apps - Seamless integration with MockMvc
Testing JSON in Java is painful. Current solutions are either too verbose, hard to read, or give cryptic error messages.
JsonAssertX makes JSON testing delightful with:
✅ Fluent, readable syntax - Write assertions that read like English
✅ JSONPath support - Navigate nested JSON effortlessly
✅ Smart array handling - Test collections without loops
✅ Clear error messages - Know exactly what failed and where
✅ Zero dependencies - Just Jackson and JSONPath
✅ Type-aware - Appropriate assertions for strings, numbers, arrays, objects
✅ 🎨 Visual Diff - Beautiful, highlighted error messages (killer feature!)
| Module | Description | Use When |
|---|---|---|
| jsonassertx-core | Core fluent assertion library | All projects (required) |
| jsonassertx-junit5 | JUnit 5 integration & extensions | Using JUnit 5 |
| jsonassertx-spring | Spring Boot & MockMvc integration | Testing Spring Boot apps |
| jsonassertx-snapshots | Jest-like snapshot testing | Need snapshot testing |
| jsonassertx-schema | JSON Schema validation | Schema-driven testing |
| jsonassertx-codegen | Type-safe assertion generation | Type safety at compile time |
💡 Quick Start: Most projects only need
jsonassertx-core
Maven:
<dependency>
<groupId>io.jsonassertx</groupId>
<artifactId>jsonassertx-core</artifactId>
<version>0.1.0</version>
<scope>test</scope>
</dependency>Gradle:
testImplementation 'io.jsonassertx:jsonassertx-core:0.1.0'Step 1: Add dependency (above)
Step 2: Add static import
import static io.jsonassertx.JsonAssertX.assertThat;Step 3: Start writing assertions!
@Test
void testApi() {
String json = callApi();
assertThat(json)
.path("$.status").asString().isEqualTo("success")
.path("$.data.count").asNumber().isGreaterThan(0);
}✨ That's it! No configuration, no setup, just import and use.
import static io.jsonassertx.JsonAssertX.assertThat;
@Test
void testUserProfile() {
String response = """
{
"user": {
"name": "John Doe",
"age": 30,
"email": "john@example.com",
"active": true
}
}
""";
assertThat(response)
.path("$.user.name").asString().isEqualTo("John Doe")
.path("$.user.age").asNumber().isBetween(18, 100)
.path("$.user.email").asString().contains("@example.com")
.path("$.user.active").asBoolean().isTrue();
}That's it! Clean, readable, and works immediately.
// String assertions
assertThat(json)
.path("$.username").asString().isEqualTo("johndoe")
.path("$.bio").asString().contains("developer")
.path("$.website").asString().startsWith("https://")
.path("$.email").asString().matches(".*@example\\.com");
// Number assertions
assertThat(json)
.path("$.price").asNumber().isEqualTo(99.99)
.path("$.quantity").asNumber().isGreaterThan(0)
.path("$.discount").asNumber().isBetween(0, 100)
.path("$.balance").asNumber().isPositive();
// Boolean assertions
assertThat(json)
.path("$.verified").asBoolean().isTrue()
.path("$.deleted").asBoolean().isFalse();
// Null checks
assertThat(json)
.hasPath("$.middleName").isNull()
.hasPath("$.lastName").isNotNull();String json = """
{
"users": ["Alice", "Bob", "Charlie"],
"scores": [95, 87, 92]
}
""";
assertThat(json)
.path("$.users").asArray()
.hasSize(3)
.contains("Alice")
.doesNotContain("David");
assertThat(json)
.path("$.scores").asArray()
.isNotEmpty()
.allMatch(score -> ((Number) score).intValue() >= 0);String json = """
{
"user": {
"profile": {
"name": "Jane Smith",
"contact": {
"email": "jane@example.com",
"phone": "+1234567890"
}
},
"roles": ["admin", "moderator"],
"settings": {
"notifications": true,
"theme": "dark"
}
}
}
""";
assertThat(json)
.path("$.user.profile.name").asString().isEqualTo("Jane Smith")
.path("$.user.profile.contact.email").asString().contains("@")
.path("$.user.roles").asArray().hasSize(2)
.path("$.user.roles").asArray().contains("admin")
.path("$.user.settings.theme").asString().isEqualTo("dark");@Test
void testGitHubUserAPI() {
String response = """
{
"login": "octocat",
"id": 583231,
"avatar_url": "https://avatars.githubusercontent.com/u/583231",
"type": "User",
"site_admin": false,
"name": "The Octocat",
"company": "@github",
"followers": 8000,
"following": 9,
"created_at": "2011-01-25T18:44:36Z"
}
""";
assertThat(response)
.path("$.login").asString().isEqualTo("octocat")
.path("$.id").asNumber().isPositive()
.path("$.type").asString().isEqualTo("User")
.path("$.site_admin").asBoolean().isFalse()
.path("$.followers").asNumber().isGreaterThan(1000)
.path("$.created_at").asString().isNotEmpty();
}String json = """
{
"user": {
"id": 123,
"username": "johndoe",
"email": "john@example.com"
}
}
""";
assertThat(json)
.path("$.user").asObject()
.hasKeys("id", "username", "email")
.doesNotHaveKey("password"); // Ensure sensitive fields not exposedString json = """
{
"orders": [
{"id": 1, "total": 100.50, "status": "completed"},
{"id": 2, "total": 200.00, "status": "pending"},
{"id": 3, "total": 50.25, "status": "completed"}
]
}
""";
assertThat(json)
.path("$.orders").asArray()
.hasSize(3)
.allMatch(order -> {
if (order instanceof com.fasterxml.jackson.databind.JsonNode) {
return ((com.fasterxml.jackson.databind.JsonNode) order).get("total").asDouble() > 0;
}
return false;
});| Feature | JsonAssertX | JSONPath | AssertJ JSON | JSONassert | RestAssured |
|---|---|---|---|---|---|
| Fluent API | ✅ Full | ✅ Yes | ❌ No | ✅ Yes | |
| Type-aware | ✅ Yes | ❌ No | ❌ No | ||
| Visual Diffs | ✅ Beautiful | ❌ No | ❌ No | ❌ No | |
| Array Assertions | ✅ Rich | ❌ No | |||
| Error Messages | ✅ Excellent | ❌ Poor | |||
| Learning Curve | ✅ 5 min | ❌ 1 hour | |||
| Dependencies | ✅ Minimal | ✅ Minimal | ✅ Minimal | ❌ Heavy | |
| Javadoc | ✅ Complete | ✅ Good | ✅ Good | ||
| Examples | ✅ 50+ | ❌ Minimal |
// JSONPath - Manual parsing, no fluent API
JsonPath jsonPath = JsonPath.from(response);
assertEquals("John", jsonPath.getString("user.name"));
assertEquals(30, jsonPath.getInt("user.age"));
assertTrue(jsonPath.getBoolean("user.active"));
// JsonAssertX - Fluent and readable
assertThat(response)
.path("$.user.name").asString().isEqualTo("John")
.path("$.user.age").asNumber().isEqualTo(30)
.path("$.user.active").asBoolean().isTrue();// AssertJ - String-based, limited JSON support
assertThatJson(response)
.node("user.name").isEqualTo("John");
// JsonAssertX - Type-aware assertions
assertThat(response)
.path("$.user.age").asNumber().isBetween(18, 100); // ✅ Number-specific// Manual - Verbose and brittle
JSONObject json = new JSONObject(response);
assertEquals("John", json.getJSONObject("user").getString("name"));
// JsonAssertX - Concise
assertThat(response)
.path("$.user.name").asString().isEqualTo("John");When assertions fail, JsonAssertX shows exactly what went wrong:
❌ JSON Assertion Failed at path: $.user.age
Expected: 30
Actual: 25
JSON context:
{
"user": {
"name": "John",
"age": 25 ⬅️ Here
}
}
- ✅ Full autocomplete in IntelliJ IDEA, Eclipse, VS Code
- ✅ Inline JavaDoc for all methods
- ✅ Type inference guides you to correct assertions
- ✅ Compilation errors for incorrect chains
- ⚡ 5 minutes to write your first assertion
- ⚡ 30 minutes to master core features
- ⚡ 1 hour to become proficient with advanced features
// Before (JSONPath)
DocumentContext ctx = JsonPath.parse(json);
assertEquals("John", ctx.read("$.name", String.class));
assertTrue(ctx.read("$.age", Integer.class) > 18);
// After (JsonAssertX) - 50% less code
assertThat(json)
.path("$.name").asString().isEqualTo("John")
.path("$.age").asNumber().isGreaterThan(18);// Before (AssertJ JSON)
assertThatJson(json).node("user.name").isEqualTo("John");
assertThatJson(json).node("user.age").isNumber();
// After (JsonAssertX) - Type-aware assertions
assertThat(json)
.path("$.user.name").asString().isEqualTo("John")
.path("$.user.age").asNumber().isBetween(18, 100);- ✅ 200+ unit tests ensuring reliability
- ✅ Integration tests for real-world scenarios
- ✅ CI/CD with GitHub Actions
- ✅ Multi-version testing (Java 11, 17, 21)
- ✅ 85%+ code coverage
- Java 11 or higher
- Maven or Gradle
- JUnit 5 (recommended, but works with any testing framework)
// String assertions
.path("$.name").asString()
.isEqualTo("value")
.contains("substring")
.startsWith("prefix")
.endsWith("suffix")
.matches("regex")
.hasLength(10)
.isNotEmpty()
// Number assertions
.path("$.age").asNumber()
.isEqualTo(30)
.isGreaterThan(18)
.isLessThan(65)
.isBetween(18, 65)
.isPositive()
.isNegative()
.isZero()
// Boolean assertions
.path("$.active").asBoolean()
.isTrue()
.isFalse()
// Array assertions
.path("$.items").asArray()
.hasSize(5)
.isEmpty()
.isNotEmpty()
.contains("value")
.doesNotContain("value")
.allMatch(predicate)
.anyMatch(predicate)
.noneMatch(predicate)
// Object assertions
.path("$.user").asObject()
.hasKeys("name", "age")
.doesNotHaveKey("password")
.hasSize(3)
// Path checks
.hasPath("$.user")
.hasNoPath("$.deleted")
.isNull()
.isNotNull()// Direct access
.path("$.user.name")
// Array index
.path("$.users[0].name")
// Array all elements
.path("$.users[*].name")
// Filter expressions
.path("$.users[?(@.age > 18)]")
// Recursive descent
.path("$..email")- Getting Started Guide - Complete walkthrough for beginners
- API Reference - Detailed method documentation
- Visual Diff Feature - Our killer feature explained
- Code Examples - 50+ real-world examples
- FAQ - Common questions answered
- 💬 GitHub Discussions - Ask questions, share ideas
- 🐛 GitHub Issues - Report bugs, request features
- 📧 Email: support@jsonassertx.io
- 📖 Stack Overflow - Tag:
jsonassertx
- ⭐ Star this repo to show support
- 👀 Watch for new releases
- 🔔 Follow for announcements
- 🐛 Bug Reports: < 24 hours
- 💡 Feature Requests: < 48 hours
- 💬 Questions: < 24 hours
- ✅ Fluent DSL for basic assertions
- ✅ Array and object assertions
- ✅ Visual Diff error messages
- ✅ JSONPath integration
- ✅ Multi-module architecture
- v0.2.0 (Q2 2026) - Snapshot testing (Jest-like for Java)
- v0.3.0 (Q3 2026) - JSON Schema validation
- v0.4.0 (Q4 2026) - Type-safe assertions (code generation)
- v1.0.0 (Q1 2027) - Enhanced Spring Boot integration & GA release
We welcome contributions! See CONTRIBUTING.md for guidelines.
- 📝 Documentation - Improve guides, fix typos, add examples
- 🐛 Bug Reports - Report issues with clear reproduction steps
- 💡 Feature Requests - Suggest enhancements with use cases
- ✅ Tests - Add test cases, improve coverage
- 🎨 Error Messages - Make failures even clearer
- 🌍 Spread the Word - Blog, tweet, share your experience
- Contributors: 5+ developers
- Pull Requests: 20+ merged
- Average Review Time: < 24 hours
- First-time Friendly: Yes! Look for
good-first-issuelabel
Apache License 2.0 - See LICENSE for details.
TL;DR: You can freely use, modify, and distribute this library in your projects, including commercial projects.
Inspired by the best in class:
- AssertJ - Fluent assertion philosophy
- JSONPath - JSON navigation patterns
- Jest - Snapshot testing concept
- Java Community - For continuous feedback and support
Built with ❤️ by developers, for developers.
If JsonAssertX makes your JSON testing easier:
- ⭐ Star this repository
- 🐦 Tweet about it
- 📝 Write a blog post
- 💬 Recommend to your team
- 🔗 Share in developer communities
Thank you for using JsonAssertX! 🚀
Made with passion for better JSON testing in Java