assertj: AssertJ 3.27.7 lab (soft assertions, recursive comparison, custom and generated assertions)
Co-Authored-By: Claude Sonnet 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01CifR2BE7PBvRy5hT8TS9oz
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
startsWith failure:
|
||||
Expecting actual:
|
||||
"Hello, AssertJ"
|
||||
to start with:
|
||||
"Goodbye"
|
||||
isEqualTo failure:
|
||||
expected: 43
|
||||
but was: 42
|
||||
as(...) failure:
|
||||
[answer to everything]
|
||||
expected: 43
|
||||
but was: 42
|
||||
@@ -0,0 +1,2 @@
|
||||
assertThat(1); -> threw: nothing
|
||||
assertThat("any value"); -> threw: nothing
|
||||
@@ -0,0 +1,7 @@
|
||||
BigDecimal 2.00 isEqualTo 2.0:
|
||||
expected: 2.0
|
||||
but was: 2.00
|
||||
double 0.1+0.2 isEqualTo 0.3:
|
||||
expected: 0.3
|
||||
but was: 0.30000000000000004
|
||||
0.1 + 0.2 = 0.30000000000000004
|
||||
@@ -0,0 +1,4 @@
|
||||
Optional.empty() isPresent:
|
||||
Expecting Optional to contain a value but it was empty.
|
||||
null String startsWith:
|
||||
Expecting actual not to be null
|
||||
@@ -0,0 +1,17 @@
|
||||
containsExactly, wrong order:
|
||||
Expecting actual:
|
||||
["BOOK-1", "PEN-7", "BAG-3"]
|
||||
to contain exactly (and in same order):
|
||||
["PEN-7", "BOOK-1", "BAG-3"]
|
||||
but there were differences at these indexes:
|
||||
- element at index 0: expected "PEN-7" but was "BOOK-1"
|
||||
- element at index 1: expected "BOOK-1" but was "PEN-7"
|
||||
containsExactlyInAnyOrder, one missing and one unexpected:
|
||||
Expecting actual:
|
||||
["BOOK-1", "PEN-7", "BAG-3"]
|
||||
to contain exactly in any order:
|
||||
["BOOK-1", "PEN-7", "HAT-9"]
|
||||
elements not found:
|
||||
["HAT-9"]
|
||||
and elements not expected:
|
||||
["BAG-3"]
|
||||
@@ -0,0 +1,9 @@
|
||||
extracting(sku, quantity) with one wrong quantity:
|
||||
Expecting actual:
|
||||
[("BOOK-1", 2), ("PEN-7", 10), ("BAG-3", 1)]
|
||||
to contain exactly (and in same order):
|
||||
[("BOOK-1", 2), ("PEN-7", 11), ("BAG-3", 1)]
|
||||
but some elements were not found:
|
||||
[("PEN-7", 11)]
|
||||
and others were not expected:
|
||||
[("PEN-7", 10)]
|
||||
@@ -0,0 +1,13 @@
|
||||
allSatisfy, one element violates the rule: (stack frames omitted)
|
||||
Expecting all elements of:
|
||||
[OrderLine[sku=BOOK-1, quantity=2, unitPrice=12.50],
|
||||
OrderLine[sku=PEN-7, quantity=10, unitPrice=1.20],
|
||||
OrderLine[sku=BAG-3, quantity=1, unitPrice=40.00]]
|
||||
to satisfy given requirements, but these elements did not:
|
||||
|
||||
OrderLine[sku=PEN-7, quantity=10, unitPrice=1.20]
|
||||
error: java.lang.AssertionError: [quantity of PEN-7]
|
||||
Expecting actual:
|
||||
10
|
||||
to be less than:
|
||||
5
|
||||
@@ -0,0 +1,7 @@
|
||||
containsEntry with wrong value:
|
||||
Expecting map:
|
||||
{"BOOK-1"=4, "PEN-7"=0}
|
||||
to contain entries:
|
||||
["PEN-7"=5]
|
||||
but the following map entries had different values:
|
||||
["PEN-7"=0 (expected: 5)]
|
||||
@@ -0,0 +1,18 @@
|
||||
expected exception, nothing thrown: (stack frames omitted)
|
||||
Expecting code to raise a throwable.
|
||||
wrong message: (stack frames omitted)
|
||||
Expecting message to be:
|
||||
"payment failed"
|
||||
but was:
|
||||
"payment failed for order o-45"
|
||||
|
||||
Throwable that failed the check:
|
||||
|
||||
lab.assertj.custom.CheckoutException: payment failed for order o-45
|
||||
Caused by: java.lang.IllegalStateException: gateway unavailable
|
||||
Caused by: java.io.IOException: connection reset by gateway
|
||||
wrong type: (stack frames omitted)
|
||||
Expecting actual throwable to be an instance of:
|
||||
java.lang.IllegalStateException
|
||||
but was:
|
||||
lab.assertj.custom.CheckoutException: payment failed for order o-45
|
||||
@@ -0,0 +1,3 @@
|
||||
three wrong expectations, hard assertions:
|
||||
expected: "o-1"
|
||||
but was: "o-9"
|
||||
@@ -0,0 +1,15 @@
|
||||
exception type: org.assertj.core.error.AssertJMultipleFailuresError
|
||||
message:
|
||||
Multiple Failures (3 failures)
|
||||
-- failure 1 --
|
||||
expected: "o-1"
|
||||
but was: "o-9"
|
||||
at SoftAssertionsTest.lambda$assertSoftlyReportsAll$1(SoftAssertionsTest.java:48)
|
||||
-- failure 2 --
|
||||
expected: PAID
|
||||
but was: NEW
|
||||
at SoftAssertionsTest.lambda$assertSoftlyReportsAll$1(SoftAssertionsTest.java:49)
|
||||
-- failure 3 --
|
||||
expected: 75
|
||||
but was: 99.00
|
||||
at SoftAssertionsTest.lambda$assertSoftlyReportsAll$1(SoftAssertionsTest.java:50)
|
||||
@@ -0,0 +1,2 @@
|
||||
errors collected but not thrown: 2
|
||||
assertAll() throws: org.assertj.core.error.AssertJMultipleFailuresError
|
||||
@@ -0,0 +1 @@
|
||||
thrown: java.lang.NullPointerException
|
||||
@@ -0,0 +1,3 @@
|
||||
two Customers with identical fields, isEqualTo:
|
||||
expected: "Customer{id=7, name=Asha Patil, [email protected], address=Address[street=12 MG Road, city=Pune, postcode=411001], tags=[vip, newsletter], creditLimit=5000.00} (Customer@73c3cd09)"
|
||||
but was: "Customer{id=7, name=Asha Patil, [email protected], address=Address[street=12 MG Road, city=Pune, postcode=411001], tags=[vip, newsletter], creditLimit=5000.00} (Customer@74f827ad)"
|
||||
@@ -0,0 +1,20 @@
|
||||
DTO vs entity with withStrictTypeChecking():
|
||||
Expecting actual:
|
||||
CustomerDto[id=7, name=Asha Patil, [email protected], address=Address[street=12 MG Road, city=Pune, postcode=411001], tags=[vip, newsletter], createdAt=2026-10-01T10:00:00Z, creditLimit=5000.00]
|
||||
to be equal to:
|
||||
Customer{id=7, name=Asha Patil, [email protected], address=Address[street=12 MG Road, city=Pune, postcode=411001], tags=[vip, newsletter], creditLimit=5000.00}
|
||||
when recursively comparing field by field, but found the following difference:
|
||||
|
||||
Top level actual and expected objects differ:
|
||||
- actual value : CustomerDto[id=7, name=Asha Patil, [email protected], address=Address[street=12 MG Road, city=Pune, postcode=411001], tags=[vip, newsletter], createdAt=2026-10-01T10:00:00Z, creditLimit=5000.00]
|
||||
- expected value: Customer{id=7, name=Asha Patil, [email protected], address=Address[street=12 MG Road, city=Pune, postcode=411001], tags=[vip, newsletter], creditLimit=5000.00}
|
||||
actual and expected are considered different since the comparison enforces strict type check and expected type lab.assertj.domain.Customer is not a subtype of actual type lab.assertj.domain.CustomerDto
|
||||
|
||||
The recursive comparison was performed with this configuration:
|
||||
- no equals methods were used in the comparison EXCEPT for java JDK types since introspecting JDK types is forbidden in java 17+ (use withEqualsForType to register a specific way to compare a JDK type if you need it)
|
||||
- these types were compared with the following comparators:
|
||||
- java.lang.Double -> DoubleComparator[precision=1.0E-15]
|
||||
- java.lang.Float -> FloatComparator[precision=1.0E-6]
|
||||
- java.nio.file.Path -> lexicographic comparator (Path natural order)
|
||||
- actual and expected objects and their fields were considered different when of incompatible types (i.e. expected type does not extend actual's type) even if all their fields match, for example a Person instance will never match a PersonDto (call strictTypeChecking(false) to change that behavior).
|
||||
- the introspection strategy used was: DefaultRecursiveComparisonIntrospectionStrategy
|
||||
@@ -0,0 +1,35 @@
|
||||
recursive comparison, four fields differ:
|
||||
Expecting actual:
|
||||
Customer{id=7, name=Asha Patil, [email protected], address=Address[street=12 MG Road, city=Mumbai, postcode=411001], tags=[vip], creditLimit=5000.0}
|
||||
to be equal to:
|
||||
Customer{id=7, name=Asha Patil, [email protected], address=Address[street=12 MG Road, city=Pune, postcode=411001], tags=[vip, newsletter], creditLimit=5000.00}
|
||||
when recursively comparing field by field, but found the following 4 differences:
|
||||
|
||||
field/property 'address.city' differ:
|
||||
- actual value : "Mumbai"
|
||||
- expected value: "Pune"
|
||||
Compared objects have java types and were thus compared with equals method
|
||||
|
||||
field/property 'creditLimit' differ:
|
||||
- actual value : 5000.0
|
||||
- expected value: 5000.00
|
||||
Compared objects have java types and were thus compared with equals method
|
||||
|
||||
field/property 'email' differ:
|
||||
- actual value : "[email protected]"
|
||||
- expected value: "[email protected]"
|
||||
Compared objects have java types and were thus compared with equals method
|
||||
|
||||
field/property 'tags' differ:
|
||||
- actual value : ["vip"]
|
||||
- expected value: ["vip", "newsletter"]
|
||||
actual and expected values are collections of different size, actual size=1 when expected size=2
|
||||
|
||||
The recursive comparison was performed with this configuration:
|
||||
- no equals methods were used in the comparison EXCEPT for java JDK types since introspecting JDK types is forbidden in java 17+ (use withEqualsForType to register a specific way to compare a JDK type if you need it)
|
||||
- these types were compared with the following comparators:
|
||||
- java.lang.Double -> DoubleComparator[precision=1.0E-15]
|
||||
- java.lang.Float -> FloatComparator[precision=1.0E-6]
|
||||
- java.nio.file.Path -> lexicographic comparator (Path natural order)
|
||||
- actual and expected objects and their fields were compared field by field recursively even if they were not of the same type, this allows for example to compare a Person to a PersonDto (call strictTypeChecking(true) to change that behavior).
|
||||
- the introspection strategy used was: DefaultRecursiveComparisonIntrospectionStrategy
|
||||
@@ -0,0 +1,89 @@
|
||||
no knobs:
|
||||
Expecting actual:
|
||||
Customer{id=99, name=Asha Patil, [email protected], address=Address[street=12 MG Road, city=Pune, postcode=411001], tags=[newsletter, vip], creditLimit=5000.0}
|
||||
to be equal to:
|
||||
Customer{id=7, name=Asha Patil, [email protected], address=Address[street=12 MG Road, city=Pune, postcode=411001], tags=[vip, newsletter], creditLimit=5000.00}
|
||||
when recursively comparing field by field, but found the following 5 differences:
|
||||
|
||||
field/property 'createdAt' differ:
|
||||
- actual value : 2026-10-26T01:00:00Z
|
||||
- expected value: 2026-10-01T10:00:00Z
|
||||
Compared objects have java types and were thus compared with equals method
|
||||
|
||||
field/property 'creditLimit' differ:
|
||||
- actual value : 5000.0
|
||||
- expected value: 5000.00
|
||||
Compared objects have java types and were thus compared with equals method
|
||||
|
||||
field/property 'id' differ:
|
||||
- actual value : 99L
|
||||
- expected value: 7L
|
||||
Compared objects have java types and were thus compared with equals method
|
||||
|
||||
field/property 'tags[0]' differ:
|
||||
- actual value : "newsletter"
|
||||
- expected value: "vip"
|
||||
Compared objects have java types and were thus compared with equals method
|
||||
|
||||
field/property 'tags[1]' differ:
|
||||
- actual value : "vip"
|
||||
- expected value: "newsletter"
|
||||
Compared objects have java types and were thus compared with equals method
|
||||
|
||||
The recursive comparison was performed with this configuration:
|
||||
- no equals methods were used in the comparison EXCEPT for java JDK types since introspecting JDK types is forbidden in java 17+ (use withEqualsForType to register a specific way to compare a JDK type if you need it)
|
||||
- these types were compared with the following comparators:
|
||||
- java.lang.Double -> DoubleComparator[precision=1.0E-15]
|
||||
- java.lang.Float -> FloatComparator[precision=1.0E-6]
|
||||
- java.nio.file.Path -> lexicographic comparator (Path natural order)
|
||||
- actual and expected objects and their fields were compared field by field recursively even if they were not of the same type, this allows for example to compare a Person to a PersonDto (call strictTypeChecking(true) to change that behavior).
|
||||
- the introspection strategy used was: DefaultRecursiveComparisonIntrospectionStrategy
|
||||
everything but ignoringCollectionOrder():
|
||||
Expecting actual:
|
||||
Customer{id=99, name=Asha Patil, [email protected], address=Address[street=12 MG Road, city=Pune, postcode=411001], tags=[newsletter, vip], creditLimit=5000.0}
|
||||
to be equal to:
|
||||
Customer{id=7, name=Asha Patil, [email protected], address=Address[street=12 MG Road, city=Pune, postcode=411001], tags=[vip, newsletter], creditLimit=5000.00}
|
||||
when recursively comparing field by field, but found the following 2 differences:
|
||||
|
||||
field/property 'tags[0]' differ:
|
||||
- actual value : "newsletter"
|
||||
- expected value: "vip"
|
||||
Compared objects have java types and were thus compared with equals method
|
||||
|
||||
field/property 'tags[1]' differ:
|
||||
- actual value : "vip"
|
||||
- expected value: "newsletter"
|
||||
Compared objects have java types and were thus compared with equals method
|
||||
|
||||
The recursive comparison was performed with this configuration:
|
||||
- the following fields were ignored in the comparison: id, createdAt
|
||||
- no equals methods were used in the comparison EXCEPT for java JDK types since introspecting JDK types is forbidden in java 17+ (use withEqualsForType to register a specific way to compare a JDK type if you need it)
|
||||
- these types were compared with the following comparators:
|
||||
- java.lang.Double -> DoubleComparator[precision=1.0E-15]
|
||||
- java.lang.Float -> FloatComparator[precision=1.0E-6]
|
||||
- java.math.BigDecimal -> BigDecimal compared with compareTo (scale ignored)
|
||||
- java.nio.file.Path -> lexicographic comparator (Path natural order)
|
||||
- actual and expected objects and their fields were compared field by field recursively even if they were not of the same type, this allows for example to compare a Person to a PersonDto (call strictTypeChecking(true) to change that behavior).
|
||||
- the introspection strategy used was: DefaultRecursiveComparisonIntrospectionStrategy
|
||||
everything but the BigDecimal comparator:
|
||||
Expecting actual:
|
||||
Customer{id=99, name=Asha Patil, [email protected], address=Address[street=12 MG Road, city=Pune, postcode=411001], tags=[newsletter, vip], creditLimit=5000.0}
|
||||
to be equal to:
|
||||
Customer{id=7, name=Asha Patil, [email protected], address=Address[street=12 MG Road, city=Pune, postcode=411001], tags=[vip, newsletter], creditLimit=5000.00}
|
||||
when recursively comparing field by field, but found the following difference:
|
||||
|
||||
field/property 'creditLimit' differ:
|
||||
- actual value : 5000.0
|
||||
- expected value: 5000.00
|
||||
Compared objects have java types and were thus compared with equals method
|
||||
|
||||
The recursive comparison was performed with this configuration:
|
||||
- the following fields were ignored in the comparison: id, createdAt
|
||||
- no equals methods were used in the comparison EXCEPT for java JDK types since introspecting JDK types is forbidden in java 17+ (use withEqualsForType to register a specific way to compare a JDK type if you need it)
|
||||
- collection order was ignored in all fields in the comparison
|
||||
- these types were compared with the following comparators:
|
||||
- java.lang.Double -> DoubleComparator[precision=1.0E-15]
|
||||
- java.lang.Float -> FloatComparator[precision=1.0E-6]
|
||||
- java.nio.file.Path -> lexicographic comparator (Path natural order)
|
||||
- actual and expected objects and their fields were compared field by field recursively even if they were not of the same type, this allows for example to compare a Person to a PersonDto (call strictTypeChecking(true) to change that behavior).
|
||||
- the introspection strategy used was: DefaultRecursiveComparisonIntrospectionStrategy
|
||||
@@ -0,0 +1,10 @@
|
||||
hasNumber, wrong:
|
||||
Expected invoice number to be <INV-2026-002> but was <INV-2026-001>
|
||||
isArithmeticallyConsistent, wrong:
|
||||
Expected gross <118.00> (net 100.00 + tax 18.00) but declared gross was <120>
|
||||
as("billing currency").isIn("USD"):
|
||||
[billing currency]
|
||||
expected: "USD"
|
||||
but was: "INR"
|
||||
null actual:
|
||||
Expecting actual not to be null
|
||||
@@ -0,0 +1,8 @@
|
||||
allOf(upperCase, shortWord) on "Abcdef":
|
||||
Expecting actual:
|
||||
"Abcdef"
|
||||
to be:
|
||||
[✗] all of:[
|
||||
[✗] upper case,
|
||||
[✗] at most 4 characters
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
hasStatus(SHIPPED):
|
||||
Expecting status of:
|
||||
<Order{id=o-1, status=PAID, total=75.00}>
|
||||
to be:
|
||||
<SHIPPED>
|
||||
but was:
|
||||
<PAID>
|
||||
isNotPaid():
|
||||
Expecting that actual Order is not paid but is.
|
||||
hasTotal(new BigDecimal("75")) against 75.00:
|
||||
Expecting total of:
|
||||
<Order{id=o-1, status=PAID, total=75.00}>
|
||||
to be:
|
||||
<75>
|
||||
but was:
|
||||
<75.00>
|
||||
null actual:
|
||||
Expecting actual not to be null
|
||||
@@ -0,0 +1,10 @@
|
||||
generated SoftAssertions, one failing hasStatus:
|
||||
Multiple Failures (1 failure)
|
||||
-- failure 1 --
|
||||
Expecting status of:
|
||||
<Order{id=o-1, status=PAID, total=75.00}>
|
||||
to be:
|
||||
<SHIPPED>
|
||||
but was:
|
||||
<PAID>
|
||||
at GeneratedAssertionsTest.generatedSoftAssertionsEntryPoint(GeneratedAssertionsTest.java:48)
|
||||
@@ -0,0 +1,16 @@
|
||||
# files generated into target/generated-test-sources/assertj-assertions/
|
||||
lab/assertj/domain/AbstractAddressAssert.java
|
||||
lab/assertj/domain/AbstractCustomerAssert.java
|
||||
lab/assertj/domain/AbstractCustomerDtoAssert.java
|
||||
lab/assertj/domain/AbstractOrderAssert.java
|
||||
lab/assertj/domain/AbstractOrderLineAssert.java
|
||||
lab/assertj/domain/AbstractOrderStatusAssert.java
|
||||
lab/assertj/domain/AddressAssert.java
|
||||
lab/assertj/domain/CustomerAssert.java
|
||||
lab/assertj/domain/CustomerDtoAssert.java
|
||||
lab/assertj/domain/OrderAssert.java
|
||||
lab/assertj/domain/OrderLineAssert.java
|
||||
lab/assertj/domain/OrderStatusAssert.java
|
||||
lab/assertj/generated/Assertions.java
|
||||
lab/assertj/generated/BddAssertions.java
|
||||
lab/assertj/generated/SoftAssertions.java
|
||||
@@ -0,0 +1,15 @@
|
||||
# AbstractOrderAssert.java: annotation line, class declaration and the isPaid() method, verbatim
|
||||
@javax.annotation.Generated(value="assertj-assertions-generator")
|
||||
public abstract class AbstractOrderAssert<S extends AbstractOrderAssert<S, A>, A extends Order> extends AbstractObjectAssert<S, A> {
|
||||
public S isPaid() {
|
||||
// check that actual Order we want to make assertions on is not null.
|
||||
isNotNull();
|
||||
|
||||
// check that property call/field access is true
|
||||
if (!actual.isPaid()) {
|
||||
failWithMessage("\nExpecting that actual Order is paid but is not.");
|
||||
}
|
||||
|
||||
// return the current assertion for method chaining
|
||||
return myself;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
target/generated-test-sources/assertj-assertions/lab/assertj/domain/AbstractAddressAssert.java:[8,18] package javax.annotation does not exist
|
||||
target/generated-test-sources/assertj-assertions/lab/assertj/domain/AbstractCustomerAssert.java:[10,18] package javax.annotation does not exist
|
||||
target/generated-test-sources/assertj-assertions/lab/assertj/domain/AbstractCustomerDtoAssert.java:[8,18] package javax.annotation does not exist
|
||||
target/generated-test-sources/assertj-assertions/lab/assertj/domain/AbstractOrderAssert.java:[10,18] package javax.annotation does not exist
|
||||
target/generated-test-sources/assertj-assertions/lab/assertj/domain/AbstractOrderLineAssert.java:[8,18] package javax.annotation does not exist
|
||||
target/generated-test-sources/assertj-assertions/lab/assertj/domain/AbstractOrderStatusAssert.java:[8,18] package javax.annotation does not exist
|
||||
target/generated-test-sources/assertj-assertions/lab/assertj/domain/AddressAssert.java:[9,18] package javax.annotation does not exist
|
||||
target/generated-test-sources/assertj-assertions/lab/assertj/domain/CustomerAssert.java:[9,18] package javax.annotation does not exist
|
||||
target/generated-test-sources/assertj-assertions/lab/assertj/domain/CustomerDtoAssert.java:[9,18] package javax.annotation does not exist
|
||||
target/generated-test-sources/assertj-assertions/lab/assertj/domain/OrderAssert.java:[9,18] package javax.annotation does not exist
|
||||
target/generated-test-sources/assertj-assertions/lab/assertj/domain/OrderLineAssert.java:[9,18] package javax.annotation does not exist
|
||||
target/generated-test-sources/assertj-assertions/lab/assertj/domain/OrderStatusAssert.java:[9,18] package javax.annotation does not exist
|
||||
target/generated-test-sources/assertj-assertions/lab/assertj/generated/Assertions.java:[7,18] package javax.annotation does not exist
|
||||
target/generated-test-sources/assertj-assertions/lab/assertj/generated/BddAssertions.java:[6,18] package javax.annotation does not exist
|
||||
target/generated-test-sources/assertj-assertions/lab/assertj/generated/SoftAssertions.java:[6,18] package javax.annotation does not exist
|
||||
@@ -0,0 +1,4 @@
|
||||
assertj-core 4.0.0-M1 (milestone), same sources:
|
||||
Tests run: 27, Failures: 0, Errors: 0, Skipped: 0
|
||||
transcripts whose text differs from the 3.27.7 run (excluding the generator captures):
|
||||
(end of list; identity hashes like Customer@73c3cd09 are ignored in the comparison)
|
||||
Reference in New Issue
Block a user