Release Notes
| AssertJ Core would not exist without its contributors, you can find them all directly on GitHub. |
The latest release notes can be found in the GitHub releases.
Even older release notes can be found in the old site: joel-costigliola.github.io/assertj/assertj-core-news.html, this is important to be aware of breaking changes if you are migrating from an old version.
AssertJ Core 3.23.0
Release date: 2022-05-31
Contributors
Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio, BJ Hargrave, Jeremy Landis, Ashley Scopes, Roland Weisleder , Benedikt Bogason , Andreas Kutschera , Matthew , Chris HeZean , Leo0506 , Zhou Yicheng , Saria , Chunhao Liao , maxwell142857 , Jessica Hamilton , nith2001 , Arman Sharif , Yuta Saito , Minami Yoshihiko , Martin Witt , Wojciech Zankowski , Gatien Bovyn , Flora Zheng , Natalia Struharova , Sára Juhošová , Pawel , Diego Krupitza , Jiashu Zhang , YeeTone Wang , Yitong , Anugrah Singhal , Stefan Bratanov , and Almir James Lucena .
Binary compatibility
The release is binary compatible with the previous minor version.
New features
-
Add
hasYear,hasMonth,hasMonthValueandhasDayOfMonthLocalDateassertions (#2541). (Jessica Hamilton and nith2001) -
Add
hasHour,hasMinute,hasSecondandhasNanoLocalTimeassertions (#2541). (Saria, Chunhao Liao, Jessica Hamilton and maxwell142857) -
Add
hasYear,hasMonth,hasMonthValue,hasDayOfMonth,hasHour,hasMinute,hasSecondandhasNanoLocalDateTimeassertions (#2541). (Leo0506, Chris HeZean, Chunhao Liao, Zhou Yicheng, Yitong and Matthew) -
Add ignoring case variants of
startsWith,endsWith,doesNotStartWith, anddoesNotEndWithtoCharSequenceassertions. (Benedikt Bogason) -
Add
linesOfvariants to load aPathcontent. (#2618). (Stefan Bratanov) -
Add
hasFileSystemandhasSameFileSystemAsPathassertions. (Ashley Scopes) -
Add
binaryContentPathandFileassertions. (Ashley Scopes) -
Add more assertThat…Exception alternatives (#2454). (Minami Yoshihiko)
-
Add
isStatic/isNotStaticclass assertions (#2455). (Wojciech Zankowski) -
Add
containsIgnoringNewLinesString assertion. (Flora Zheng) -
Add
BigDecimalscale assertion. (Almir James Lucena) -
Add
assertThatExceptionOfType/thenExceptionOfTypeto Soft/BDDSoft assertions. -
Add
java.util.regex.Matcherassertions class withmatchesassertion. (Jiashu Zhang) -
Add
hasNumberOfRowsto two-dimensional array assertions. (Wojciech Zankowski) -
Sync assumptions and assertions methods. (Wojciech Zankowski)
-
Expose
ComparisonStrategy::areEqualinAbstractAssert. (Stefano Cordio)
Improvements
-
Improved
containsExactlyperformance from O(n2) to O(n) when the assertion succeeds (#2548). (nith2001, Sára Juhošová) -
Display first stack trace elements of failures in
AssertJMultipleFailuresErrorto ease code navigation. -
Add assertThat{Interface}/then{Interface} methods like
assertThatIterableto address potential ambiguous resolution. -
Replace
forloop with enhancedforloop (#2501). (Diego Krupitza) -
Remove unnecessary unboxing in
ComparatorFactory(#2502). (Diego Krupitza) -
Update
MapEntry::hashCodeto honorMap.Entry::hashCodecontract (#2503). (BJ Hargrave) -
Use
AbstractComparableAssertas parent class forURIassertions. (Pawel) -
Avoid ValueNode being considered as iterable while using recursive comparison. (Gatien Bovyn)
-
Improve Float/Double
isCloseToassertions and comparators to honor offset check exactly. (YeeTone Wang) -
Improve recursive comparison error when comparing unordered iterables by show expected elements not found in actual instead of unmatched actual elements.
-
Keep assertion state with
getCauseandgetRootCause. (Stefano Cordio) -
Improve compatibility of
assertThatComparable(#2532). (Stefano Cordio) -
Increase test coverage for internal and api package (#2543). (Natalia Struharova)
-
Increase
AbstractIntegerAsserttest coverage to 100% (#2515). (Sára Juhošová) -
Add more tests for ShortAssert, FloatAssert, BigDecimalAssert, DoubleAssert, IntegerAssert, ShortArrayAssert, IntArrayAssert, IteratorAssert, OptionalAssert, PathAssert and InputStreamAssert. (Sára Juhošová)
-
Throw
AssertionErrorwithextracting(String)if actual isnull. (Stefano Cordio) -
Keep assertion state with
contentassertions forFileandPath. (Stefano Cordio) -
Skip well-known JDK types in
AbstractCollectionAssert::isUnmodifiable(#2599). (Stefano Cordio) -
Remove Byte Buddy shading (#2477). (Stefano Cordio)
-
Avoid cloning
MultiValueMapAdapterinstances (#2549). (Stefano Cordio) -
Javadoc improvements. (Stefano Cordio)
-
Fix typos in Javadoc of ObjectEnumerableAssert (#2624). (Roland Weisleder)
-
Internal: Update maven wrapper to 3.1.1 (#2622). (Jeremy Landis)
-
Internal: Bump maven wrapper distributionUrl to 3.8.5 (#2551). (Jeremy Landis)
-
Internal: Align Javadoc stylesheet to be compatible with Java 17. (Stefano Cordio)
-
Internal: Add Gitpod configuration. (Stefano Cordio)
-
Internal: Open user specific fork on Gitpod. (Anugrah Singhal)
-
Internal: Verify binary compatibility with latest release also with PRs (#2613). (Stefano Cordio)
-
Internal: Change visibility of constructor in final util class to private (#2465). (Martin Witt)
-
Internal: Update license headers to 2022. (Stefano Cordio)
-
Internal: Add build with Java 19 EA. (Stefano Cordio)
-
Internal: Add binary compatibility result to job summary. (Stefano Cordio)
-
Internal: Use Java 18 GA in build (Stefano Cordio)
-
Internal: Use Java 17 in workflows (#2584) (Stefano Cordio)
-
Internal: Fix Maven Central badge. (Stefano Cordio)
-
Internal: Add navigation method tests to
extractingvariants. (Stefano Cordio) -
Internal: Apply binary incompatible label to PRs (#2478). (Stefano Cordio)
-
Internal: Refactor test verifying that
Assertions,BDDAssertions,WithAssertionsand soft assertions are in sync. -
Internal: Bump Bnd version to 6.2.0. (BJ Hargrave)
-
Internal: Bump spring-core from 5.3.14 to 5.3.20
-
Internal: Bump jboss-logging from 3.4.2.Final to 3.5.0.Final
-
Internal: Bump byte-buddy.version from 1.12.6 to 1.12.10
-
Internal: Bump github/codeql-action from 1 to 2
-
Internal: Bump pitest-maven from 1.7.5 to 1.8.0
-
Internal: Bump equalsverifier from 3.7.1 to 3.10
-
Internal: Bump parent POM to version 2.2.14 (Stefano Cordio)
-
Internal: Bump Mockito to version 4.5.1 (Stefano Cordio, Erhard Pointl)
-
Internal: Bump jacoco-maven-plugin.version from 0.8.7 to 0.8.8 (Erhard Pointl)
-
Internal: Bump hibernate-core from 6.0.0.Beta3 to 6.0.2.Final
-
Internal: Bump japicmp-maven-plugin from 0.15.4 to 0.15.7
-
Internal: Bump pitest-maven from 1.7.3 to 1.7.5
-
Internal: Bump actions/github-script from 5 to 6
-
Internal: Bump actions/checkout from 2 to 3 (Stefano Cordio)
-
Internal: Bump actions/upload-artifact from 2 to 3 (Stefano Cordio)
-
Internal: Bump actions/setup from 2 to 3
-
Internal: Bump guava from 31.0.1-jre to 31.1-jre
-
Internal: Bump jackson-databind from 2.13.1 to 2.13.3
-
Internal: Bump org.eclipse.osgi from 3.17.100 to 3.17.200
-
Internal: Bump cdg.pitest.version from 0.1.0 to 0.2.0
-
Internal: Bump pitest-github-maven-plugin from 0.1.0 to 0.1.3
-
Internal: Bump github/codeql-action from 1 to 2
-
Internal: Bump maven-invoker-plugin from 3.2.2 to 3.3.0
Fixed
-
Update docs describing passing Fail.fail() as a lambda (#2512). (Arman Sharif)
-
Fix recursive comparison that can throw
IllegalStateExceptionwhen comparing Maps -
Recursive comparison did not honor
comparingOnlyFieldswhen getting actual fields to compare (#2610). (Andreas Kutschera) -
Fix comparingOnlyFields that was greedily evaluating fields to compare.
-
Fix usingRecursiveComparison with usingOverriddenEquals ignores equals method of the root object (#2479). (Yuta Saito)
-
Fix error in Javadoc. (Yuta Saito)
-
As Java 17 forbids it, don’t use reflection to compare java types in the recursive comparison, use equals even if not overridden (#2450).
-
Recursive comparison: Compare Atomic types embedded value recursively (value is not accessed by reflection) (#2466).
-
Fix pom url to match the actual url to the doc (#2514). (BJ Hargrave)
-
Fix file names to prevent MacOS casing issues (#2534). (Sára Juhošová)
-
Disable
setup-javacache to fix some cache corruption. (Stefano Cordio) -
Fix
ShouldBeSameerror message that inverted actual and expected (#2565). (Stefano Cordio) -
Fix Sonar bug. (Stefano Cordio)
Deprecated
-
Deprecate
getCauseandgetRootCauseforThrowableassertions
Add more assertThat…Exception alternatives
Add more ThrowableTypeAssert entry point methods for commonly used exception:
-
assertThatException -
assertThatRuntimeException -
assertThatReflectiveOperationException -
assertThatIndexOutOfBoundsException
This allow to check that piece of code expressed as a ThrowingCallable throws the proper exception type and chain additional assertions.
Example:
// succeeds
assertThatRuntimeException().isThrownBy(() -> {
throw new RuntimeException("boom");
}).withMessage("boom");
// fails
assertThatRuntimeException().isThrownBy(() -> {
throw new IOException();
})
Add linesOf variants to load a Path content
Loads the text content of a file at a given path into a list of strings with the given charset or the default charset if none is specified.
Each string corresponding to a line, the line endings are either \n, \r or \r\n.
Example:
// Terry-Pratchett.txt content:
// I'll be more enthusiastic about encouraging thinking outside the box ...
// ...when there's evidence of any thinking going on inside it.
Path pratchettQuotePath = Paths.get("Terry-Pratchett.txt");
assertThat(linesOf(pratchettQuotePath)).contains("I'll be more enthusiastic about encouraging thinking outside the box ...",
"...when there's evidence of any thinking going on inside it");
Add isStatic/isNotStatic class assertions
Add assertions to verify whether a class is static or not.
Example:
class MyClass {
static class MyStaticClass {}
}
assertThat(MyClass.class).isNotStatic();
assertThat(MyStaticClass.class).isStatic();
Add containsIgnoringNewLines string assertion
Verifies that the {@code CharSequence} under test contains all the given values ignoring new line differences.
Example:
assertThat("Gandalf\nthe\ngrey").containsIgnoringNewLines("alf")
.containsIgnoringNewLines("alf", "grey")
.containsIgnoringNewLines("thegrey")
.containsIgnoringNewLines("thegr\ney")
.containsIgnoringNewLines("t\nh\ne\ng\nr\ney");
Add BigDecimal scale assertion
Returns an assert object that allows performing assertions on the scale of the BigDecimal under test.
Once this method is called, the object under test is no longer the BigDecimal but its scale.
To go back performing assertions on the BigDecimal, call returnToBigDecimal().
Example:
assertThat(new BigDecimal("3.14")).scale()
.isGreaterThan(1L)
.isLessThan(5L)
.returnToBigDecimal()
.isPositive();
Add java.util.regex.Matcher assertions class with matches assertion
Verifies that the java.util.regex.Matcher matches.
Example:
Pattern pattern = Pattern.compile("a*");
Matcher matcher = pattern.matcher("aaa");
assertThat(matcher).matches();
Add hasNumberOfRows to two-dimensional array assertions
Verifies that the actual two-dimensional array has the given number of rows.
Example:
assertThat(new int[][] {{1, 2, 3}, {4, 5, 6}}).hasNumberOfRows(2);
assertThat(new long[][] {{1}, {1, 2}, {1, 2, 3}}).hasNumberOfRows(3);
Add hasYear, hasMonth, hasMonthValue and hasDayOfMonth LocalDate assertions
Verifies that actual LocalDate is in the given year, month/monthValue or day of month.
Example:
assertThat(LocalDate.of(2000, 12, 31)).hasYear(2000)
.hasMonth(Month.DECEMBER)
.hasMonthValue(12)
.hasDayOfMonth(31);
Add hasHour, hasMinute, hasSecond and hasNano LocalTime assertions
Verifies that actual LocalTime is in the given hour, minute, second or nano.
Example:
assertThat(LocalTime.of(23, 17, 59, 05)).hasHour(23)
.hasMinute(17)
.hasSecond(59)
.hasNano(05);
Add hasYear, hasMonth, hasMonthValue, hasDayOfMonth, hasHour, hasMinute, hasSecond and hasNano LocalDateTime assertions
Verifies that actual LocalDateTime is in the given year, month/monthValue, day of month, hour, minute, second or nano.
Example:
assertThat(LocalDateTime.of(2000, 12, 31, 23, 17, 59, 05)).hasYear(2000)
.hasMonth(Month.DECEMBER)
.hasMonthValue(12)
.hasDayOfMonth(31)
.hasHour(23)
.hasMinute(17)
.hasSecond(59)
.hasNano(05);
Add hasFileSystem and hasSameFileSystemAs Path assertions
Verifies that a path has the given file system or the same file system as another path
Examples:
Path jarFile = Paths.get("assertj-core.jar");
FileSystem mainFileSystem = jarFile.getFileSystem();
try (FileSystem fs = FileSystems.newFileSystem(jarFile, (ClassLoader) null)) {
Path manifestFile = fs.getPath("META-INF", "MANIFEST.MF");
assertThat(manifestFile).hasFileSystem(fs)
.hasSameFileSystemAs(jarFile);
}
Add binaryContent Path/File assertions
Returns ByteArray assertions on the content of the Path/File read.
Examples:
Path xFilePath = Files.write(Paths.get("xfile.txt"), "The Truth Is Out There".getBytes());
File xFile = xFilePath.toFile();
byte[] expectedBinaryContent = "The Truth Is Out There".getBytes()
assertThat(xFilePath).binaryContent().isEqualTo(expectedBinaryContent);
assertThat(xFile).binaryContent().isEqualTo(expectedBinaryContent);
Add ignoring case variants of startsWith, endsWith, doesNotStartWith, and doesNotEndWith CharSequence assertions
Add startsWithIgnoringCase, endsWithIgnoringCase, doesNotStartWithIgnoringCase and doesNotEndWithIgnoringCase to CharSequence assertions.
Examples:
assertThat("Gandalf the grey").startsWithIgnoringCase("gandalf")
.startsWithIgnoringCase("Gandalf")
.doesNotStartWithIgnoringCase("Saroumane")
.endsWithIgnoringCase("Grey")
.endsWithIgnoringCase("grey")
.doesNotEndWithIgnoringCase("great");
AssertJ Core 3.22.0
Release date: 2022-01-03
Contributors
Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio, Yusuke Mukai , Martin Tarjányi , Trang Nguyen , jbock , Annette0127, Zihan Xu , Ashley Scopes , Benjamin Ze’ev Tels , Ahmad Sadeed , temp-droid , Ilya Koshaleu , Spacca , Erik Pragt , and Jeremy Landis.
Binary compatibility
The release is not binary compatible with the previous minor version.
Breaking changes
-
Breaking change:
extractingnow throws an assertion error if actual is null (Fixes #2401). -
Breaking change:
extracting/mapfor iterables now throws an assertion error if the actualIterableis null (Fixes #2411). -
Breaking change:
flatExtracting/flatMapfor iterables now throws an assertion error if the actualIterableis null (Fixes #2412).
New features
-
Add size assertions for
File(#2322). (Erik Pragt) -
Add
message()navigation method forThrowable(#2378). (Trang Nguyen) -
Add support for fine-grained representations (#2048). (Annette0127)
-
Add
singleElementtoObject[]assertions (#2320). -
Add
hasNoHosttoURIandURLassertions (#2436). (Ashley Scopes) -
Allow overriding error messages for specific fields and types in the recursive comparison. (Ilya Koshaleu)
-
Add
catchThrowableOfTypealternatives for commonly used exceptions (#2397). (Spacca) -
Add
doesNotReturntoObjectassertions (#2453). (Stefano Cordio)
Improvements
-
Treat class cast exception as comparison failure in the recursive comparison. (#2434)
-
Improve
Classrepresentation for anonymous and local types (#2445). (Stefano Cordio) -
Return
nullwhen extracting the value of an emptyOptional(#2372). (Stefano Cordio) -
Assumptions: avoid proxying methods that don’t need to be proxied.
-
Accept vararg for
AbstractAssert.satisfies. (Martin Tarjányi) -
Print offending token in error message from containsSubsequence. (jbock)
-
extractingnow throws an assertion error if actual is null (Fixes #2401). (Trang Nguyen) -
extracting/mapfor iterables now throws an assertion error if the actualIterableis null (Fixes #2411). (Trang Nguyen) -
flatExtracting/flatMapfor iterables now throws an assertion error if the actualIterableis null (Fixes #2412). (Zihan Xu) -
Allow checking of
nullkeys and values with maps that do not allow them (see #2379 and #2382). (Benjamin Ze’ev Tels, Stefano Cordio) -
Better
isEqualToerror messages when values are multi lined (#2366). (temp-droid) -
Javadoc improvements. (Stefano Cordio)
-
Internal: Avoid mocks for testing
Fileassertions (#2337). (Ahmad Sadeed) -
Internal: Align
assertContainsKeysandassertDoesNotContainKeystesting to the pattern introduced in #2167. (Stefano Cordio) -
Internal: Add JDK 9 collection factories (#2386). (Stefano Cordio)
-
Internal: Add release workflow (#1986). (Stefano Cordio)
-
Internal: Add additional test cases to
isUnmodifiable. (Stefano Cordio) -
Internal: Exclude Guava transitive dependency from EqualsVerifier. (Stefano Cordio)
-
Internal: Bump junit-jupiter.version from 5.8.0 to 5.8.2 (Erhard Pointl)
-
Internal: Bump mockito.version from 3.12.4 to 4.2.0 (Erhard Pointl, Stefano Cordio)
-
Internal: Bump jackson-databind from 2.12.5 to 2.13.1
-
Internal: Bump byte-buddy.version from 1.11.6 to 1.12.6
-
Internal: Bump guava from 30.1.1-jre to 31.0.1-jre
-
Internal: Bump assertj-parent-pom from 2.2.13 to 2.2.14
-
Internal: Bump pitest-maven from 1.7.0 to 1.7.3
-
Internal: Bump bnd.version from 5.3.0 to 6.1.0
-
Internal: Bump japicmp-maven-plugin from 0.15.3 to 0.15.4
-
Internal: Bump Maven version from 3.8.2 to 3.8.4 (Erhard Pointl)
-
Internal: Bump spring-core from 5.3.10 to 5.3.14
-
Internal: Bump equalsverifier from 3.7.1 to 3.8.1
-
Internal: Bump org.eclipse.osgi from 3.17.0 to 3.17.100
-
Internal: Switch to the official Maven Wrapper by Apache (#2452). (Jeremy Landis)
Fixed
-
Avoid reflection when extracting
Optionalvalue that fails with Java 17 (#2364). (Stefano Cordio) -
Fix assumptions for
extractingmethods usingasInstanceOf -
Fix Javadoc for
containsExactlyInAnyOrderElementsOf(#2405). (Yusuke Mukai) -
Fix
DefaultAssertionErrorCollectorthat dismisses expected/actual fields during injection of line numbers. -
Fall back to
Mapcopy when cloning causes anyRuntimeException(#2448). (Stefano Cordio)
Deprecated
Deprecate encodedAsBase64 / decodedAsBase64 in favor of asBase64Encoded / asBase64Decoded
Add size assertions for File
Returns an Assert object that allows performing assertions on the size of the File under test.
Once this method is called, the object under test is no longer the File but its size, to return performing assertions on the File, call returnToFile().
Example:
File file = File.createTempFile("tmp", "bin");
Files.write(file.toPath(), new byte[] {1, 1});
assertThat(file).size()
.isGreaterThan(1L)
.isLessThan(5L)
.returnToFile()
.hasBinaryContent(new byte[] {1, 1});
Add message() navigation method for Throwable
A shortcut for extracting(Throwable::getMessage, as(InstanceOfAssertFactories.STRING)) which allows to extract a throwable’s message and then execute assertions on it.
Note that once you have navigated to the throwable’s message you can’t navigate back to the throwable.
Example:
Throwable throwable = new Throwable("boom!");
assertThat(throwable).message().startsWith("boo")
.endsWith("!");
Add singleElement for Object[] assertions
Verifies that the array under test contains a single element and allows performing assertions on that element.
The assertions can be strongly typed if given an AssertFactory parameter.
Example:
String[] babySimpsons = { "Maggie" };
// object assertions
assertThat(babySimpsons).singleElement()
.isEqualTo("Maggie");
// strongly typed assertions with a predefined AssertFactory
import static org.assertj.core.api.Assertions.as; // syntactic sugar
import static org.assertj.core.api.InstanceOfAssertFactories.STRING;
assertThat(babySimpsons).singleElement(as(STRING))
.startsWith("Mag");
Add hasNoHost to URI and URL assertions
Verifies that the actual URI/URL has no host.
Example:
assertThat(new URI("file:///home/user/Documents/hello-world.txt")).hasNoHost();
assertThat(new URL("file:///home/user/Documents/hello-world.txt")).hasNoHost();
Add doesNotReturn to Object assertions
Verifies that the object under test does not return the given expected value from the given Function, a typical usage is to pass a method reference to assert object’s property.
Wrapping the given Function with Assertions.from(Function) makes the assertion more readable.
Example:
// from is not mandatory but it makes the assertions more readable
assertThat(frodo).doesNotReturn("Bilbo", from(TolkienCharacter::getName))
.doesNotReturn("Bilbo", TolkienCharacter::getName) // no from :(
.doesNotReturn(null, from(TolkienCharacter::getRace));
AssertJ Core 3.21.0
Release date: 2021-09-20
Contributors
Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio, Shivakumar Swamy, Iván Aguilar, Alberto Pascual, Gily H, Stefan Bischof, RGalways17, Andrey Kuzmin, Eugene Lesnov, Szymon Linowski, Julian Honnen, Almir James Lucena and Golan Levy.
Binary compatibility
The release is binary compatible with the previous minor version.
Breaking changes
-
Custom comparison now takes precedence over reference comparison in recursive comparison (Fixes #2335).
New features
-
Add
content()/content(Charset)toPathassertions to allow chaining string assertions on thePathcontent. (#2252) -
Add
content()/content(Charset)toFileassertions to allow chaining string assertions on theFilecontent. (#2243) -
Add
hasSize(long expectedSizeInBytes)toPathassertions (#2198). (Gily-H) -
Add
isMixedCase()toCharSequenceassertions (#2246). (Andrey Kuzmin) -
Add
containsAnyOf(CharSequence… values)toCharSequenceassertions (#2309). (Eugene Lesnov) -
Add
hasExtension(String extension)toPathassertions (#2255). (Szymon Linowski) -
Add
hasNoExtension()toPathassertions (#2318). (Szymon Linowski) -
Add
hasNoExtension()toFileassertions. -
Add
hasScaleOf(int expectedScale)toBigDecimalsassertions (#2321). (Almir James Lucena) -
Add
isUnmodifiable()toCollectionassertions (#2328). (Stefano Cordio)
Improvements
-
Add
CollectionAsserthierarchy (#2315). (Stefano Cordio) -
Change AssertJ
MapEntryand JavaMap.Entryrepresentation to bekey=value. -
Improve
containsEntryandcontainsAllEntriesOferror message when keys match but not values. -
Improve assertion error for
hasSameElementsAs(emptyList()). (RGalways17) -
Add stack trace information of
Throwablethat failshasCauseInstanceOforhasCauseExactlyInstanceOf(#2209). (RGalways17) -
Add
isReadableas an alias ofcanReadforFileassertions (#2249). (Alberto Pascual) -
Add
isWritableas an alias ofcanWriteforFileassertions (#2273). (Iván Aguilar) -
Add
hasFileNameas an alias ofhasNameforFileassertions (#2247). (Shivakumar Swamy) -
Add
satisfieswithThrowingConsumerto accept consumers that throw checked exceptions (#2297). -
Add
satisfiesAnyOfwithThrowingConsumerto accept consumers that throw checked exceptions. -
Add
allSatisfy,anySatisfy,satisfiesExactly,noneSatisfy,satisfiesExactlyInAnyOrderandfilteredOnAssertionswithThrowingConsumerto accept consumers that throw checked exceptions. -
Allow specifying supertype consumers for
satisfiesandsatisfiesAnyOfinAbstractAssert. -
Allow configuring the preferred assumption exception (#2267).
-
Generate proper
conditionDescriptionWithStatusinMappedCondition. (Stefan Bischof) -
Use
conditionDescriptionWithStatusonJoinCondition. (Stefan Bischof) -
Add type parameter to
ThrowableAssert(#2311). (Stefano Cordio) -
Sync
BDDAssumptionswithAssumptions(#2313). (Stefano Cordio) -
Javadoc improvements (#2274). (Golan Levy)
-
Javadoc improvements. (Stefano Cordio)
-
Fix Javadoc warnings. (Stefano Cordio)
-
Internal: Add binary compatibility check of
mainagainst latest release (#2271). (Stefano Cordio) -
Internal: Add binary compatibility check of branches against
main(#2285). (Stefano Cordio) -
Internal: Use custom display name generator instead of
@DisplayNameon each test and remove unnecessary@DisplayNameannotation. (Stefano Cordio) -
Internal:
PathandFileassertions refactoring. (Stefano Cordio) -
Internal: Add additional tests for
Pathassertions. (Stefano Cordio) -
Internal: Remove unnecessary clean goal in build. (Stefano Cordio)
-
Internal: Remove
MockPathsBaseTestin favor ofPathsBaseTestand@TempDir. (Stefano Cordio) -
Internal: Remove memoryfilesystem. (Stefano Cordio)
-
Internal: Reorder POM based on Maven code conventions. (Stefano Cordio)
-
Internal: Use Java 17 GA, remove EOL Java 16 in CI build. (Stefano Cordio)
-
Internal: Bump junit-jupiter.version from 5.7.2 to 5.8.0. (Stefano Cordio)
-
Internal: Bump mockito.version from 3.11.1 to 3.12.4. (Stefano Cordio)
-
Internal: Bump byte-buddy version from 1.11.2 to 1.11.16
-
Internal: Bump cdg.pitest.version from 0.0.10 to 0.1.0
-
Internal: Bump Bump pitest-junit5-plugin from 0.14 to 0.15
-
Internal: Bump pitest-maven from 1.6.7 to 1.7.0
-
Internal: Bump jackson-databind from 2.12.3 to 2.12.5
-
Internal: Bump equalsverifier from 3.6.1 to 3.7.1
-
Internal: Bump commons-io from 2.10.0 to 2.11.0.
-
Internal: Bump spring-core from 5.3.8 to 5.3.10
-
Internal: Bump org.eclipse.osgi from 3.16.300 to 3.17.0
-
Internal: Bump maven version from 3.8.1 to 3.8.2. (Stefano Cordio)
Fixed
-
Add default method lookup to
hasMethods(#2324). (Stefano Cordio) -
Load default configuration after default constants values to make sure the latter are initialized.
-
Don’t use
String.formatto describeComparisonDifferencein case the given string has a % that must not be interpreted (#2279). -
Fix handling of mappings to null in
MappedCondition. (Stefan Bischof) -
Fix Javadoc warnings.
Add content()/content(Charset) to Path/File assertions to allow chaining string assertions on the Path/File content
Returns String assertions on the content of the actual Path/File read with the given charset or the default charset if no charset was given.
Example with content():
File xFile = Files.write(Paths.get("xfile.txt"), "The Truth Is Out There".getBytes()).toFile();
// assertion succeeds (default charset is used to read xFile content)
assertThat(xFile).content().startsWith("The Truth Is ")
.endsWith("There");
// assertion fails
assertThat(xFile).content().contains("Elsewhere");
Example with content(Charset):
File utf8File = Files.write(Paths.get("utf8.txt"), "é à".getBytes()).toFile();
// assertion succeeds
assertThat(utf8File).content(StandardCharsets.UTF_8).startsWith("é")
.endsWith("à");
// assertion fails
assertThat(utf8File).content(StandardCharsets.UTF_8).contains("e");
Add hasSize(long expectedSizeInBytes) to Path assertions
Asserts that the tested Path has the given size in bytes.
Note that the actual Path must exist and be a regular file.
Examples:
Path foxPath = Files.write(Paths.get("/fox.txt"), "The Quick Brown Fox.".getBytes());
// assertion succeeds
assertThat(foxPath).hasSize(20);
// assertion fails
assertThat(foxPath).hasSize(3);
Add isMixedCase() to CharSequence assertions
Verifies that the actual CharSequence is a mixed case CharSequence, i.e., neither uppercase nor lowercase.
If actual is empty or contains only case-independent characters, the assertion will pass.
Examples:
// assertions succeed
assertThat("Capitalized").isMixedCase();
assertThat("camelCase").isMixedCase();
assertThat("rAndOMcAse1234").isMixedCase();
assertThat("1@3$567").isMixedCase();
assertThat("").isMixedCase();
// assertions fail
assertThat("I AM GROOT!").isMixedCase();
assertThat("please be quiet").isMixedCase();
Add containsAnyOf(CharSequence… values) to CharSequence assertions
Verifies that the actual CharSequence contains any of the given values.
Examples:
// assertion succeeds
assertThat("Gandalf the grey").containsAnyOf("grey", "black");
// assertion fails
assertThat("Gandalf the grey").containsAnyOf("white", "black");
Add hasExtension(String extension) to Path assertions
Verifies that the actual Path has the given extension.
Examples:
Path path = Paths.get("file.java");
// assertion succeeds
assertThat(path).hasExtension("java");
// assertion fails
assertThat(path).hasExtension("png");
Add hasNoExtension() to Path and File assertions
Verifies that the actual Path or File has no extension.
Examples with Path:
// assertion succeeds
assertThat(Paths.get("file")).hasNoExtension();
assertThat(Paths.get("file.")).hasNoExtension();
// assertion fails
assertThat(Paths.get("file.txt")).hasNoExtension();
Add hasScaleOf(int expectedScale) to BigDecimals assertions
Verifies the BigDecimal under test has the given scale.
Examples:
// assertions succeed
assertThat(new BigDecimal("8.00")).hasScaleOf(2);
assertThat(new BigDecimal("8.00").setScale(4)).hasScaleOf(4);
// assertion fail
assertThat(new BigDecimal("8.00")).hasScaleOf(3);
assertThat(new BigDecimal("8.00").setScale(4)).hasScaleOf(2);
Add isUnmodifiable() to Collection assertions
Verifies that the actual collection is unmodifiable, i.e., throws an UnsupportedOperationException with any attempt to modify the collection.
Example:
// assertions succeed
assertThat(Collections.unmodifiableCollection(new ArrayList<>())).isUnmodifiable();
assertThat(Collections.unmodifiableList(new ArrayList<>())).isUnmodifiable();
assertThat(Collections.unmodifiableSet(new HashSet<>())).isUnmodifiable();
// assertions fail
assertThat(new ArrayList<>()).isUnmodifiable();
assertThat(new HashSet<>()).isUnmodifiable();
AssertJ Core 3.20.2
Release date: 2021-06-20
Bugfix release that revert a breaking change in 3.20.0 due to the heavy impact on binary compatibility and to continue allowing third-party libraries returning their own assertion classes with overridden assertThat methods.
Thanks to David Schlosnagle and Stefano Cordio for the fixes in this release.
Binary compatibility
The release is not binary compatible with the previous minor version.
Fixed
-
Restore deep equality comparison for map
containsOnlyassertions. (David Schlosnagle) -
Revert "[Breaking change] Align return types across assertions / assumptions / soft assertions and do not use Abstract Asserts" introduced in 3.20.0.
AssertJ Core 3.20.1
Release date: 2021-06-16
Bugfix release.
Binary compatibility
The release is not binary compatible with the previous minor version.
Fixed
-
Fix
StandardComparisonStrategy.areEqualarray comparison when given a non null array and a null one.
AssertJ Core 3.20.0
Release date: 2021-06-15
Contributors
Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio, Harsha Vipparti, Julien Roy, Aakarshit Uppal, Abhijeet Shukla, Jack Gough, Filip Hrisafov, RGalways17, Stefan Birkner, Stefan Bischof, Matthieu Baechler, sustc11810424, Henry Coles, Annette0127, Johannes Becker, Slawomir Jaranowski, and Patrick Allain.
Special thanks to Filip Hrisafov to have got rid of the heap pollution compiler warning when using soft assertions or assumptions with methods having a generic vararg parameters.
Binary compatibility
The release is not binary compatible with the previous minor version.
Breaking changes
-
PropertyOrFieldSupportfails when trying to get map value for an unknown key instead of returning null, this impacts:-
assertThat(map).hasFieldOrPropertyWithValue(name, value)andassertThat(map).hasFieldOrProperty(name)now fail ifnameis not a known key. -
assertThat(map).extracting("unknown")now fails instead of returningnull. -
assertThat(map).flatExtracting("unknown1", "unknown2")now fails instead of returning a list of withnullvalues for unknown keys.
-
-
assertThat(map).containsAllEntriesOf(otherMap)now succeeds whenotherMapis empty instead of failing. -
RecursiveComparisonConfigurationnow uses the same default values when built from builder and constructor. -
usingRecursiveFieldByFieldElementComparatorin iterable/array/atomic reference array now uses the new recursive comparison instead of the old implementation. -
RecursiveFieldByFieldComparatorwas removed as it has been replaced by the recursive comparison inusingRecursiveFieldByFieldElementComparator. -
Public methods that could cause heap pollution have been made
finalto improve the user experience with soft assertions and soft assumptions. In case a subclass was overriding any of these methods, a similar result can be achieved by overriding the correspondingForProxymethod. For example,AbstractMapAssert#containsnow delegates the implementation toAbstractMapAssert#containsForProxy, which isprotectedand therefore can be overridden. -
Align return types across assertions / assumptions / soft assertions and return concrete types. The breaking change is for people that have implemented
WithAssertionsorWithAssumptionas they now have different return types, the regular user should not see any difference.
New features
-
Add
containsIgnoringWhitespacestoStringassertions. (Johannes Becker) -
Add
IterableAssert.elements(int…)to assert on specific elements in anIterable. (Matthieu Baechler) -
Add
hasExactlyElementsOfTypesassertion for iterables, arrays and AtomicReferenceArrays. (RGalways17) -
Add
asString(charset)toAbstractInputStreamAssertto supportStringassertions. (Stefan Birkner) -
Add
assertWithassertion construct. -
Add
isNotFinitefloat and double assertions. -
Add
isNotInfinitefloat and double assertions. -
Add
comparingOnlyFieldsto the recursive comparison to restrict the comparison to the specified fields. -
Add
usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration configuration)toAtomicReferenceArrayandObject[]assertions (it is already supported for iterable assertions). -
Add
usingRecursiveFieldByFieldElementComparatorOnFields(String…)for iterable/array/atomic reference array assertions to restrict the recursive comparison to the specified fields. -
Add
usingRecursiveFieldByFieldElementComparatorIgnoringFields(String…)to iterable/array/atomic reference array assertions. -
Add
MappedConditionto verify aConditionon the result of a map operation. (Stefan Bischof) -
Add
VerboseConditionto get a detailed description when the condition fails. (Stefan Bischof)
Improvements
-
In error messages, use 'toString' method of subclasses of
AtomicReferencewhen overridden. (sustc11810424) -
SoftAssertionsExtensionnow reports line number in reported assertion errors. -
Align return types across assertions / assumptions / soft assertions and do not use Abstract Asserts. (Filip Hrisafov)
-
Use varargs for
satisfiesAnyOfto remove the multiple overloaded versions. (Filip Hrisafov) -
Remove compiler heap pollution warnings that were raised for soft assertions or assumptions. (Filip Hrisafov)
-
Improve performance in
StandardComparisonStrategy#areEqual. (Filip Hrisafov) -
Return concrete type where proxyable types were used in Assumptions, BDDAssumptions and WithAssumptions.
-
RecursiveComparisonConfigurationnow uses the same default values when built from builder and constructor. -
Improve error message when map is not empty and expected entries is. (Abhijeet Shukla)
-
ThrowableTypeAlternativenow inherits fromAbstractObjectAssertasAbstractThrowableAssertdid. -
Make
assertThat(map).containsAllEntriesOf(otherMap)assertion to succeed whenotherMapis empty. (Aakarshit Uppal) -
Add non assertions methods in
BDDAssertionsthat existed inAssertionsbut were missing inBDDAssertions. -
Display proper collection type in
containsandcontainsAllerror messages . (Patrick Allain) -
Rework
StandardComparisonStrategy#areEqualto avoid shortcuts. (Stefano Cordio) -
Disambiguate error messages by adding "actual" before printing actual value. (Harsha Vipparti)
-
Recursive comparison: properly track field location for maps and honor ignored fields.
-
allOfcondition error message shows state (successful/failed) of each combined conditions. -
Javadoc improvements. (Stefano Cordio)
-
Clarify
newListAssertInstanceJavadoc. -
Fix flaky test by making sure default date formats are used before tests.
-
Remove unnecessary space
ShouldNotBeandShouldNotHaveerror messages. (Annette0127) -
Internal: Rename test to match its purpose. (Matthieu Baechler)
-
Internal: Fix some warnings in AssertJ codebase. (Filip Hrisafov)
-
Internal: Remove Proxyable assert classes since we don’t need to subclass assert classes to fix heap pollution with
@SafeVarargs. -
Internal: Hide implementation detail of
assertContainsOnlyKeys. (Stefano Cordio) -
Internal: Remove unnecessary Javadoc from internal class, import
Map.Entry. (Stefano Cordio) -
Internal: Favor
requireNonNullwithSupplier. (Stefano Cordio) -
Internal: Update CodeQL workflow. (Stefano Cordio)
-
Internal: Mention the JDK 11 requirement in the contribution guidelines. (Stefano Cordio)
-
Internal: Remove EOL JDK versions from CI multi versions build. (Stefano Cordio)
-
Internal: Bump maven version from 3.6.3 to 3.8.1 (Stefano Cordio)
-
Internal: Bump jacoco-maven-plugin.version from 0.8.6 to 0.8.7
-
Internal: Bump guava from 30.1-jre to 30.1.1-jre
-
Internal: Bump org.eclipse.osgi from 3.16.100 to 3.16.200
-
Internal: Bump jackson-databind from 2.12.1 to 2.12.3
-
Internal: Bump commons-lang3 from 3.11 to 3.12.0
-
Internal: Bump commons-io from 2.8.0 to 2.9.0.
-
Internal: Bump mockito.version from 3.7.7 to 3.10.0 (Erhard Pointl)
-
Internal: Bump bnd.version from 5.2.0 to 5.3.0
-
Internal: Bump sonar-maven-plugin to version 3.8.0.2131 (Stefano Cordio)
-
Internal: Bump equalsverifier from 3.5.2 to 3.6.1
-
Internal: Bump spring-core from 5.3.6 to 5.3.7
-
Internal: Bump byte-buddy version from 1.10.19 to 1.11.1
-
Internal: Bump maven-invoker-plugin from 3.2.1 to 3.2.2
-
Internal: Bump junit-jupiter.version from 5.6.3 to 5.7.2 (Erhard Pointl)
-
Internal: Bump junit.version from 4.13.1 to 4.13.2 (Erhard Pointl)
-
Internal: Fix IntelliJ flaky test due to JUnit upgrade to version 5.7. (Stefano Cordio)
-
Internal: Build AssertJ Core with java 16 in CI cross version build. (Erhard Pointl)
-
Internal: Bump actions/setup-java to version 2 (Stefano Cordio)
-
Internal: Verify PRs with pitest (Henry Coles)
-
Internal: Add .DS_Store to .gitignore (Slawomir Jaranowski)
-
Internal: Enforce Java 11 or newer to build the project (Slawomir Jaranowski)
-
Internal: Define Java 9 compile execution instead of maven profile (Slawomir Jaranowski)
Fixed
-
Honor map key comparison semantics in
containsOnlyassertions. (Stefano Cordio and Filip Hrisafov) -
Fix
containsSubsequenceString assertion failing when given multiple empty values. (Jack Gough) -
Fix
NullPointerExceptionin primitive double assertions where a nullDoubleis compared to a primtive one. (Jack Gough) -
Fix
NullPointerExceptioninStandardRepresentation. (Jack Gough) -
Make
IterableDiffto always compare actual elements to expected elements and not the other way around in case the comparison is not symmetrical. -
Add
enumtypes to the types that can’t cause cycles in a recursive comparison. -
Fix hasOnlyFields which should not consider static fields.
-
Fix
StackOverflowErrorwhenusingRecursiveComparisonofPathon Windows by using path natural comparator. (Julien Roy) -
Extract value only if the map key exists in
PropertyOrFieldSupport. (Stefano Cordio) -
Replace references to
mapOfby GuavaImmutableMap.ofin Javadoc. -
Fix Javadoc warnings.
Deprecated
The main deprecations are related to shallow field by field comparison classes and methods:
usingFieldByFieldElementComparator
Use usingRecursiveFieldByFieldElementComparator() or usingRecursiveComparison() instead to perform a true recursive comparison.
usingElementComparatorOnFields
usingElementComparatorIgnoringFields
usingComparatorForElementFieldsWithNames
This method is used with usingFieldByFieldElementComparator() which is deprecated in favor of usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration) or usingRecursiveComparison().
When using usingRecursiveComparison() the equivalent is:
and when using usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration config), sets the config with:
usingComparatorForElementFieldsWithType
This method is used with usingFieldByFieldElementComparator() which is deprecated in favor of usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration) or usingRecursiveComparison().
When using usingRecursiveComparison() the equivalent is:
and when] using usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration config), sets the config with:
Add containsIgnoringWhitespaces to String assertions
Verifies that the actual CharSequence contains all the given values, ignoring whitespace differences.
Example:
assertThat("Gandalf the grey").containsIgnoringWhitespaces("alf")
.containsIgnoringWhitespaces("alf", "grey")
.containsIgnoringWhitespaces("thegrey")
.containsIgnoringWhitespaces("thegr ey")
.containsIgnoringWhitespaces("t h e g r\t\r\n ey");
Add IterableAssert.elements(int…) to assert on specific elements in an Iterable
Allow to perform assertions on the elements corresponding to the given indices (the iterable Iterable under test is changed to an iterable with the selected elements).
Example:
Iterable<TolkienCharacter> hobbits = Arrays.asList(frodo, sam, pippin);
// assertion succeeds
assertThat(hobbits).elements(1, 2)
.hasSize(2)
.containsExactly(sam, pippin);
// assertion fails
assertThat(hobbits).element(1, 2)
.containsExactly(frodo, pippin);
Add hasExactlyElementsOfTypes assertion for iterables, arrays and AtomicReferenceArrays
Verifies that the actual elements are of the given types in the given order, there should be as many expected types as there are actual elements.
This assertion is available for iterables, arrays and AtomicReferenceArrays.
Example:
Iterable<Object> list = Arrays.asList(1, "a", "b", 1.00);
assertThat(list).hasExactlyElementsOfTypes(Integer.class, String.class, String.class, Double.class);
Add asString(charset) to AbstractInputStreamAssert to support String assertions
Converts the content of the actual InputStream to a String by decoding its bytes using the given charset and returns assertions for the computed String allowing String specific assertions from this call.
Example:
InputStream abcInputStream = new ByteArrayInputStream("abc".getBytes());
assertThat(abcInputStream).asString(UTF_8)
.startsWith("a");
allOf condition error message shows state (successful/failed) of each combined conditions
allOf condition error message reports which conditions failed [✗] and which succeeded [✓] to ease understanding the failure cause.
Let’s use an allOf condition checking 3 conditions: young, very tall and Jedi and try it on Yoda, it fails with the following error:
Expecting actual:
"Yoda"
to be:
[✗] all of:[
[✓] a Jedi,
[✗] very tall,
[✗] young
]
Add assertWith assertion construct
Uses the given instance as the instance under test for all the assertions expressed as the passed Consumer.
This is useful to avoid repeating getting the instance to test, a bit like a with block which turns the target into the equivalent of this (as in Groovy for example).
Example:
assertWith(team.getPlayers().get(0).getStats(),
stats -> {
assertThat(stats.pointPerGame).isGreaterThan(25.7);
assertThat(stats.assistsPerGame).isGreaterThan(7.2);
assertThat(stats.reboundsPerGame).isBetween(9, 12);
});
assertWith is variation of AbstractAssert.satisfies(Consumer) hopefully easier to find for some users.
Add isNotFinite float and double assertions
Verifies that the double/float value is not a finite floating-point value.
Note that 'not finite' is not equivalent to infinite as NaN is neither finite or infinite.
Examples:
assertThat(Double.POSITIVE_INFINITY).isNotFinite();
assertThat(Double.NEGATIVE_INFINITY).isNotFinite();
assertThat(Double.NaN).isNotFinite();
assertThat(Float.POSITIVE_INFINITY).isNotFinite();
assertThat(Float.NEGATIVE_INFINITY).isNotFinite();
assertThat(Float.NaN).isNotFinite();
Add isNotInfinite float and double assertions
Verifies that the double/float value represents neither positive infinity nor negative infinity.
Examples with doubles:
// assertions succeed
assertThat(1.0).isNotInfinite();
assertThat(Double.NaN).isNotInfinite();
// assertions fail
assertThat(Double.POSITIVE_INFINITY).isNotInfinite();
assertThat(Double.NEGATIVE_INFINITY).isNotInfinite();
Add comparingOnlyFields float and double assertions
Makes the recursive comparison to only compare given actual fields and their subfields (no other fields will be compared).
Specifying a field will make all its subfields to be compared, for example specifying person will lead to compare person.name, person.address and all other Person fields.
On the other hand if you specify person.name, person won’t be compared but person.name will be.
The fields are specified by name, not by value, for example you can specify person.name but not "Jack" as "Jack" is not a field value.
comparingOnlyFields can be combined with ignoring fields methods to restrict further the fields actually compared, the resulting compared fields = {specified compared fields} - {specified ignored fields}.
For example if compared fields = {"foo", "bar", "baz"} and ignored fields = {"bar"} then only {"foo", "baz"} fields will be compared.
Example:
public class Person {
String name;
double height;
Home home = new Home();
}
public class Home {
Address address = new Address();
}
public static class Address {
int number;
String street;
}
Person sherlock = new Person("Sherlock", 1.80);
sherlock.home.address.street = "Baker Street";
sherlock.home.address.number = 221;
Person moriarty = new Person("Moriarty", 1.80);
moriarty.home.address.street = "Butcher Street";
moriarty.home.address.number = 221;
// assertion succeeds as name and home.address.street fields are not compared.
assertThat(sherlock).usingRecursiveComparison()
.comparingOnlyFields("height", "home.address.number")
.isEqualTo(moriarty);
// assertion fails as home.address.street fields differ.
assertThat(sherlock).usingRecursiveComparison()
.comparingOnlyFields("height", "home")
.isEqualTo(moriarty);
Add usingRecursiveFieldByFieldElementComparatorOnFields(String…) to iterable/array/atomic reference array assertions to restrict the recursive comparison to the specified fields
The assertions chained after this method will use a recursive field by field comparison on the given fields (including inherited fields) instead of relying on the element equals method. This is handy when the element equals method is not overridden or implemented as you expect.
Nested fields are supported and are expressed like: name.first
The comparison is recursive: elements are compared field by field, if a field type has fields they are also compared field by field (and so on).
Example:
Player derrickRose = new Player(new Name("Derrick", "Rose"), "Chicago Bulls");
derrickRose.nickname = new Name("Crazy", "Dunks");
Player jalenRose = new Player(new Name("Jalen", "Rose"), "Chicago Bulls");
jalenRose.nickname = new Name("Crazy", "Defense");
// assertion succeeds as all compared fields match
assertThat(list(derrickRose)).usingRecursiveFieldByFieldElementComparatorOnFields("name.last", "team", "nickname.first")
.contains(jalenRose);
// assertion fails, name.first values differ
assertThat(list(derrickRose)).usingRecursiveFieldByFieldElementComparatorOnFields("name")
.contains(jalenRose);
This method is actually a shortcut of usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration) with a configuration comparing only the given fields, the previous example can be written as:
RecursiveComparisonConfiguration configuration = RecursiveComparisonConfiguration.builder()
.withComparedFields("name.last", "team", "nickname.first")
.build();
assertThat(list(derrickRose)).usingRecursiveFieldByFieldElementComparator(configuration)
.contains(jalenRose);
Add usingRecursiveFieldByFieldElementComparatorIgnoringFields(String…) to iterable/array/atomic reference array assertions to ignore some fields in the recursive comparison
The assertions chained after this method will use a recursive field by field comparison on all fields (including inherited fields) except the given ones instead of relying on the element equals method. This is handy when the element equals method is not overridden or implemented as you expect.
Nested fields are supported and are expressed like: name.first
The comparison is recursive: elements are compared field by field, if a field type has fields they are also compared field by field (and so on).
Example:
Player derrickRose = new Player(new Name("Derrick", "Rose"), "Chicago Bulls");
derrickRose.nickname = new Name("Crazy", "Dunks");
Player jalenRose = new Player(new Name("Jalen", "Rose"), "Chicago Bulls");
jalenRose.nickname = new Name("Crazy", "Defense");
// assertion succeeds as all compared fields match
assertThat(list(derrickRose)).usingRecursiveFieldByFieldElementComparatorIgnoringFields("name.last", "nickname.first")
.contains(jalenRose);
// assertion fails, names are ignored but nicknames are not and nickname.last values differ
assertThat(list(derrickRose)).usingRecursiveFieldByFieldElementComparatorIgnoringFields("name")
.contains(jalenRose);
This method is actually a shortcut of usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration) with a configuration comparing only the given fields, the previous example can be written as:
RecursiveComparisonConfiguration configuration = RecursiveComparisonConfiguration.builder()
.withIgnoredFields("name.first", "nickname.last")
.build();
assertThat(list(derrickRose)).usingRecursiveFieldByFieldElementComparator(configuration)
.contains(jalenRose);
Add MappedCondition to verify a Condition on the result of a map operation
A MappedCondition is defined with a map operation and a Condition that accepts the type returned by the map operation.
When applied the MappedCondition first map the value under test and then verify the resulting mapped value against its nested Condition.
Let’s see how it works on an example:
// nested Condition
Condition<String> hasLineSeparator = new Condition<>(s -> s.contains(System.lineSeparator()), "has lineSeparator");
// mapped Condition
Condition<Optional<String>> optionalWithLineSeparator = MappedCondition.mappedCondition(Optional::get, hasLineSeparator, "optional value has lineSeparator");
// assertion succeeds
assertThat(Optional.of("a" + System.lineSeparator())).is(optionalWithLineSeparator)
// assertion fails
assertThat(Optional.of("a")).is(optionalWithLineSeparator)
Add VerboseCondition to get a detailed description when the condition fails
A VerboseCondition shows the value under test when it fails thanks to the specified objectUnderTestDescriptor function.
When defining the objectUnderTestDescriptor function, you should take in consideration whether the condition is going to be used with is(Condition) or has(Condition) since the start of the error message is different between the two.
Let’s see how it works with an example that works well with is(Condition):
Condition<String> shorterThan4 = VerboseCondition.verboseCondition(actual -> actual.length() < 4,
// predicate description
"shorter than 4",
// value under test description transformation function
s -> String.format(" but length was %s", s.length()));
If we execute:
assertThat("foooo").is(shorterThan4);
we get the following assertion error:
Expecting actual:
"foooo"
to be shorter than 4 but length was 5
Note that the beginning of the error message looks nice with is(Condition) but not so much has(Condition):
Expecting actual:
"foooo"
to have shorter than 4 but length was 5
AssertJ Core 3.19.0
Release date: 2021-01-24
Contributors
Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio, Pascal Schumacher, Arsen Ibragimov, Kim S. Ly, Victor Wang, Omar Morales, Reto Weiss, Michael Florian Grafl, Sergei Tachenov, Mayra Lucero Garcia Ramírez, Eveneko, Julieta Navarro, Michael Keppler, Alex Dukhno, Himadri Mandal and Jin Kwon.
Binary compatibility
The release is not binary compatible with the previous minor version.
Breaking changes
-
Replacement of
FieldLocationbyStringbreaking changes:-
Remove deprecated
RecursiveComparisonConfiguration.registerComparatorForField(Comparator<?> comparator, FieldLocation fieldLocation)in favor ofregisterComparatorForFields(Comparator<?> comparator, String… fieldLocations) -
getIgnoredCollectionOrderInFields(),getIgnoredFields()andgetIgnoredOverriddenEqualsForFields()now return a collection ofStringinstead ofFieldLocation -
comparatorByFields()now returnsStream<Entry<String, Comparator<?>>>instead ofStream<Entry<FieldLocation, Comparator<?>>>
-
-
Ignore static and synthetic fields when introspecting fields as they are not relevant in for instance assertions. This change impacts:
-
hasFieldOrProperty -
hasFieldOrPropertyWithValue -
extracting field by name
-
-
Probably not an impactful breaking change: abstract classes' constructors are now
protectedinstead ofpublic. -
Return generic return type for
AbstractSoftAssertions.failfor convenience and to be consistent withAssertions.fail. This is a binary incompatible but still source compatible change.
New features
-
Add
isEqualToNormalizingUnicodeCharSequence assertion. (Julieta Navarro) -
Add
satisfiesExactlyiterable/array assertion. (Michael Florian Grafl) -
Add
satisfiesExactlyInAnyOrderiterable/array assertion. -
Add Instant variants to Date assertions. (Arsen Ibragimov)
-
Add float/double finite or infinite assertions. (Jin Kwon)
-
Add
doesNotHaveSameHashCodeAsassertion. (Kim S. Ly) -
Add
doesNotHaveToStringassertion. (Kim S. Ly) -
Add overloaded
containsassertions with boxed arrays to primitive array assertions. (Stefano Cordio, Mayra Lucero Garcia Ramírez, Omar Morales) -
Add
hasOnlyFieldsassertion. (Victor Wang) -
Allow to pass a lazy description only evaluated if the assertion fails.
-
Add
isEmptyFile/isNotEmptyFiletoPathassertions. (Omar Morales)
Improvements
-
Change
isEqualToerror message to follow pattern:
expected: "abc"
but was : "bcd"
-
Remove
<>from error messages when displaying values as it was deemed noisy. (Erhard Pointl, Omar Morales, Himadri Mandal) -
Better indentation consistency in error messages.
-
Include the first 3 stacktrace elements in throwable representation (configurable). (Eveneko)
-
Change abstract class constructor to protected.
-
Use normalized
actualandexpectedin String assertion errors that compare normalized values. (Etienne Miret) -
Refactor common representation code into
UnambiguousRepresentation. (Etienne Miret) -
Use
org.junit.ComparisonFailurewhen available. (Etienne Miret) -
Improve describe error readability of
ElementsShouldSatisfy. (Drummond Dawson) -
Recursive comparison: show the index of the array/list element compared in the reported differences.
-
Recursive comparison documentation: make it clear that
ignoringFieldsandignoringFieldsMatchingRegexesoperate on field names. -
Ignore getters with void return type during property introspection. (Reto Weiss)
-
Recalculate description for nested Conditions like
NotandJoinas someConditiondescription when theConditionis evaluated. (Stefan Bischof) -
Javadoc Date assertions improvements.
-
Explain reference to
newLinkedHashMapin Javadoc. -
Internal: Only instantiate assertion error from AssertionErrorCreator. (Alex Dukhno)
-
Internal: Use parent pom 2.2.10 that bumps the licence year to 2021. (Erhard Pointl)
-
Internal: Use java11 in codeql workflow. (Erhard Pointl)
-
Internal: Fix a bunch of sonar violations. (Erhard Pointl)
-
Internal: Reduce test fragility. (Erhard Pointl)
-
Internal: Enforce surefire encoding. (Stefano Cordio)
-
Internal: Bump junit version from 4.13 to 4.13.1 (Erhard Pointl)
-
Internal: Bump highlight version to 10.4.0
-
Internal: Bump mockito version from 3.6.0 to 3.6.28 (Erhard Pointl)
-
Internal: Bump jackson-databind from 2.11.3 to 2.12.1
-
Internal: Bump guava from 30.0-jre to 30.1-jre
-
Internal: Bump org.eclipse.osgi from 3.16.0 to 3.16.100
-
Internal: Bump byte-buddy version from 1.10.18 to 1.10.19
-
Internal: Bump mockito version from 3.6.28 to 3.7.7
-
Internal: Bump equalsverifier from 3.5 to 3.5.2
Fixed
-
Fix long overflow in AbstractTemporalAssert. (Sergei Tachenov)
-
Make
CollectionextendingAtomicIntegerto be represented as a collection instead of anAtomicInteger. -
Fix Javadoc typo. (Michael Keppler)
Deprecated
-
Deprecate
isXmlEqualToContentOfin favor of XML Unit.
Add isEqualToNormalizingUnicode CharSequence assertion
Verifies that the actual CharSequence is equal to the given one after they have been normalized according to the Normalizer.Form.NFC form, which is a canonical decomposition followed by canonical composition.
Examples:
// assertions succeed:
// Ä = \u00C4 - Ä = \u0041\u0308
assertThat("Ä").isEqualToNormalizingUnicode("Ä");
assertThat("\u00C4").isEqualToNormalizingUnicode("\u0041\u0308");
// assertions fail:
assertThat("ñ").isEqualToNormalizingUnicode("n");
assertThat("Ä").isEqualToNormalizingUnicode("b");
Add satisfiesExactly iterable/array assertion
Verifies that each element satisfies the requirements corresponding to its index, so the first element must satisfy the first requirements, the second element the second requirements etc…
Each requirement is expressed as a Consumer, and there must be as many requirements as there are iterable elements.
Examples:
Iterable<TolkienCharater> characters = list(frodo, aragorn, legolas);
// assertions succeed
assertThat(characters).satisfiesExactly(character -> assertThat(character.getRace()).isEqualTo("Hobbit"),
character -> assertThat(character.isMortal()).isTrue(),
character -> assertThat(character.getName()).isEqualTo("Legolas"));
// you can specify more that one assertion per requirements
assertThat(characters).satisfiesExactly(character -> {
assertThat(character.getRace()).isEqualTo("Hobbit");
assertThat(character.getName()).isEqualTo("Frodo");
},
character -> {
assertThat(character.isMortal()).isTrue();
assertThat(character.getName()).isEqualTo("Aragorn");
},
character -> {
assertThat(character.getRace()).isEqualTo("Elf");
assertThat(character.getName()).isEqualTo("Legolas");
});
// assertion fails as aragorn does not meet the second requirements
assertThat(characters).satisfiesExactly(character -> assertThat(character.getRace()).isEqualTo("Hobbit"),
character -> assertThat(character.isMortal()).isFalse(),
character -> assertThat(character.getName()).isEqualTo("Legolas"));
Add satisfiesExactlyInAnyOrder iterable/array assertion
Verifies that at least one combination of iterable elements exists that satisfies the consumers in order (there must be as many consumers as iterable elements and once a consumer is matched it cannot be reused to match other elements).
This is a variation of satisfiesExactly where order does not matter.
Examples:
List<String> starWarsCharacterNames = list("Luke", "Leia", "Yoda");
// these assertions succeed:
assertThat(starWarsCharacterNames).satisfiesExactlyInAnyOrder(name -> assertThat(name).contains("Y"), // matches "Yoda"
name -> assertThat(name).contains("L"), // matches "Luke" and "Leia"
name -> {
assertThat(name).hasSize(4);
assertThat(name).doesNotContain("a"); // matches "Luke" but not "Leia"
})
// satisfiesExactly would have succeeded for this assertion
.satisfiesExactlyInAnyOrder(name -> assertThat(name).contains("Lu"),
name -> assertThat(name).contains("Le"),
name -> assertThat(name).contains("Yo"))
// satisfiesExactly would have failed for this assertion
.satisfiesExactlyInAnyOrder(name -> assertThat(name).contains("Yo"),
name -> assertThat(name).contains("Lu"),
name -> assertThat(name).contains("Le"))
// satisfiesExactly would have failed for this assertion
.satisfiesExactlyInAnyOrder(name -> assertThat(name).contains("Le"),
name -> assertThat(name).contains("Yo"),
name -> assertThat(name).contains("Lu"));
// this assertion fails as 3 consumer/requirements are expected
assertThat(starWarsCharacterNames).satisfiesExactlyInAnyOrder(name -> assertThat(name).contains("Y"),
name -> assertThat(name).contains("L"));
// this assertion fails as no element contains "Han" (first consumer/requirements can't be met)
assertThat(starWarsCharacterNames).satisfiesExactlyInAnyOrder(name -> assertThat(name).contains("Han"),
name -> assertThat(name).contains("L"),
name -> assertThat(name).contains("Y"));
// this assertion fails as "Yoda" element can't satisfy any consumers/requirements (even though all consumers/requirements are met)
assertThat(starWarsCharacterNames).satisfiesExactlyInAnyOrder(name -> assertThat(name).contains("L"),
name -> assertThat(name).contains("L"),
name -> assertThat(name).contains("L"));
// this assertion fails as no combination of elements can satisfy the consumers in order
// the problem is if the last consumer is matched by Leia then no other consumer can match Luke (and vice versa)
assertThat(starWarsCharacterNames).satisfiesExactlyInAnyOrder(name -> assertThat(name).contains("Y"),
name -> assertThat(name).contains("o"),
name -> assertThat(name).contains("L"));
Add Instant variants to Date assertions
Date assertions now understand Instant parameters.
Examples:
final Date dateTimeWithMs = parseDatetimeWithMs("2001-02-03T04:05:06.700");
assertThat(dateTimeWithMs).isEqualTo(dateTimeWithMs.toInstant())
.isBefore(Instant.parse("2002-01-01T00:00:00.00Z"))
.isAfter(Instant.parse("2000-01-01T00:00:00.00Z"))
.isBetween(Instant.parse("2000-01-01T00:00:00.00Z"),
Instant.parse("2002-01-01T00:00:00.00Z"))
.isCloseTo(dateTimeWithMs.toInstant().minusMillis(10), 20)
.isEqualToIgnoringHours(dateTimeWithMs.toInstant().plus(1, ChronoUnit.HOURS))
.isEqualToIgnoringMinutes(dateTimeWithMs.toInstant().plus(1, ChronoUnit.MINUTES))
.isEqualToIgnoringSeconds(dateTimeWithMs.toInstant().plus(1, ChronoUnit.SECONDS))
.isEqualToIgnoringMillis(dateTimeWithMs.toInstant().plus(1, ChronoUnit.MILLIS))
.isIn(dateTimeWithMs.toInstant(), dateTimeWithMs.toInstant().plusMillis(10))
.isInSameDayAs(dateTimeWithMs.toInstant().plus(1, ChronoUnit.MINUTES))
.isInSameMonthAs(Instant.parse("2001-02-01T00:00:00.00Z"))
.isInSameYearAs(Instant.parse("2001-01-01T00:00:00.00Z"))
.isNotIn(dateTimeWithMs.toInstant().minusMillis(10), dateTimeWithMs.toInstant().plusMillis(10));
Add float/double finite or infinite assertions
Examples:
assertThat(1.0f).isFinite();
assertThat(Float.NEGATIVE_INFINITY).isInfinite();
assertThat(1.0).isFinite();
assertThat(Double.POSITIVE_INFINITY).isInfinite();
Add doesNotHaveSameHashCodeAs assertion
Verifies that the actual object does not have the same hashCode as the given object.
Examples:
// assertions succeed
assertThat(42L).doesNotHaveSameHashCodeAs(2501L);
assertThat("The Force").doesNotHaveSameHashCodeAs("Awakens");
// assertions fail
assertThat(42L).doesNotHaveSameHashCodeAs(42L);
assertThat("The Force").doesNotHaveSameHashCodeAs("The Force");
assertThat(new Jedi("Yoda", "Blue")).doesNotHaveSameHashCodeAs(new Jedi("Yoda", "Blue"));
Add doesNotHaveToString assertion
Verifies that the actual object does not have the same toString as the given object.
Examples:
CartoonCharacter homer = new CartoonCharacter("Homer");
// Instead of writing ...
assertThat(homer.toString()).isNotEqualTo("Marge");
// ... you can simply write:
assertThat(homer).doesNotHaveToString("Marge");
Add overloaded contains assertions with boxed arrays for primitive array assertions
Primitive array assertions (like long[] assertions) support variants with boxed arrays (e.g. Long[]) for contains assertions.
Examples:
assertThat(new boolean[] { true, false, true }).containsExactly(new Boolean[] {true, false, true });
assertThat(new short[] { 1, 2, 3 }).containsExactly(new Short[] { 1, 2, 3 });
assertThat(new int[] { 1, 2, 3 }).containsExactly(new Integer[] { 1, 2, 3 });
assertThat(new long[] { 1L, 2L, 3L }).contains(new Long[] { 1L, 2L });
assertThat(new float[] { 1.0f, 2.0f, 3.0f }).containsExactly(new Float[] { 1.0f, 2.0f, 3.0f });
assertThat(new double[] { 1.0, 2.0, 3.0 }).containsExactly(new Double[] { 1.0, 1.98, 3.01 }, withPrecision(0.05));
assertThat(new char[] { 'a', 'b', 'c' }).contains(new Character[] { 'a', 'b' });
Add hasOnlyFields assertion
Verifies that the actual object has only the specified fields and nothing else.
The assertion only checks declared fields (inherited fields are not checked) that are not static or synthetic.
Examples:
public class TolkienCharacter {
private String name;
public int age;
public String getName() {
return this.name;
}
}
TolkienCharacter frodo = new TolkienCharacter("Frodo", 33);
// assertion succeeds:
assertThat(frodo).hasOnlyFields("name", "age");
// assertions fail:
assertThat(frodo).hasOnlyFields("name");
assertThat(frodo).hasOnlyFields("not_exists");
Allow to pass a lazy description only evaluated when the assertion fails
Lazily specifies the description of the assertion that is going to be called, the given description is not evaluated if the assertion succeeds. This is useful if descriptions are expansive to build.
Examples:
// we all know Mr Frodo is 33 years old
frodo.setAge(33);
// the lazy test description is not evaluated as the assertion succeeds
assertThat(frodo.getAge()).as(() -> "check Frodo's age").isEqualTo(33);
// the lazy test description is evaluated as the assertion fails
assertThat(frodo.getAge()).as(() -> "check Frodo's age").isEqualTo(50);
The error message of the failing assertion is:
[check Frodo's age]
expected: 33
but was : 50
Add isEmptyFile and isNotEmptyFile to Path assertions
Verify that the actual Path is respectively an empty or non empty regular file.
Note that the actual Path must exist and be a regular file.
Examples given the files below:
/root/sub-dir-1/file-1.ext (no content)
/root/sub-dir-1/file-2.ext (content)
Here are some assertions examples:
Path withoutContent = Paths.get("/root/sub-dir-1/file-1.ext");
Path withContent = Paths.get("/root/sub-dir-1/file-2.ext");
// The following assertions succeed:
assertThat(withoutContent).isEmptyFile();
assertThat(withContent).isNotEmptyFile();
// The following assertions fail:
assertThat(withoutContent).isNotEmptyFile();
assertThat(withContent).isEmptyFile();
AssertJ Core 3.18.1
Release date: 2020-11-11
Contributors
Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio and Kim S. Ly.
Binary compatibility
The release is not binary compatible with the previous minor version.
New features
-
Add
mapandflatMapto iterable assertions as aliases ofextractingandflatExtracting.
Improvements
-
Make
isElementOfCustomAssertprotected to ease integration with 3rd party libraries like XML Unit. -
Add Javadoc for methods that needs to be implemented in
AbstractIterableAssertsubclasses. -
Internal: Adjust
hasPackagetests style. (Stefano Cordio) -
Internal: Bump junit-jupiter version from 5.6.2 to 5.6.3. (Erhard Pointl)
-
Internal: Bump mockito from 3.5.15 to 3.6.0. (Erhard Pointl)
-
Internal: Bump byte-buddy version from 1.10.17 to 1.10.18.
Fixed
-
Fix
ShouldNotHaveSameClasserror message. ( Kim S. Ly) -
Fix
hasNotFailedJavadoc deprecation example.
AssertJ Core 3.18.0
Release date: 2020-10-25
Contributors
Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio, Pascal Schumacher, Fr Jeremy Krieg, BJ Hargrave, Matteo Mirk and Valeriy Vyrva.
Shout out to Fr Jeremy Krieg for adding soft assertions field injection capability in JUnit 5 SoftAssertionsExtension!
Binary compatibility
The release is not binary compatible with the previous minor version.
Breaking changes
-
Breaking change: disable bare name getter by default, to get the previous behaviour back, call
Assertions.setExtractBareNamePropertyMethods(true); -
Exclude
net.bytebuddy.experimentalproperty from shading scope: ensures that the property controls ByteBuddy experimental features also inside AssertJ, usually needed when using JDK early access builds. Before this change, ByteBuddy experimental features in AssertJ could only be controlled byorg.assertj.core.internal.bytebuddy.experimental.
New features
-
Add field injection capability to
SoftAssertionsExtension. (Fr Jeremy Krieg) -
Add
hasPackagetoClassassertions. (Matteo Mirk) -
Add
hasValueSatisfyingtoAtomicReferenceassertions. (Valeriy Vyrva) -
Add
hasValueMatchingtoAtomicReferenceassertions. (Valeriy Vyrva) -
Add
isCloseTotoDurationassertions. -
Add
failsWithintoFutureandCompletableFutureassertions.
Improvements
-
Add
AssertionErrorfactory methods toAbstractAssert. (Fr Jeremy Krieg) -
Improve describe error readability of
ElementsShouldSatisfy. (Drummond Dawson) -
Use two spaces indentation in "should be close to" error messages.
-
Internal: Add CodeQL analysis. (Stefano Cordio)
-
Internal: Clean up some pom dependencies now that Bnd 5.2.0 is being used (BJ Hargrave)
-
Internal: Add assumptions it tests. (Stefano Cordio)
-
Internal: Reduce visibility of FieldUtils as no method is publicly accessible. (Stefano Cordio)
-
Internal: Remove unnecessary semicolons. (Erhard Pointl)
-
Internal: Enforce surefire encoding. (Stefano Cordio)
-
Internal: Bump jackson-databind from 2.11.2 to 2.11.3.
-
Internal: Bump org.eclipse.osgi from 3.15.300 to 3.16.0.
-
Internal: Bump equalsverifier from 3.4.2 to 3.5.
-
Internal: Bump byte-buddy from 1.10.14 to 1.10.17.
-
Internal: Bump assertj-parent-pom from 2.2.7 to 2.2.8.
-
Internal: Bump mockito from 3.5.10 to 3.5.15.
-
Internal: Bump guava from 29.0-jre to 30.0-jre.
-
Internal: Bump jacoco-maven-plugin from 0.8.5 to 0.8.6. (Stefano Cordio)
-
Internal: Bump bnd from 5.1.2 to 5.2.0.
Fixed
-
Honor toString if overridden in Iterable that are not collections.
Deprecated
-
Deprecate
isXmlEqualToin favor of XML Unit. -
Deprecate
SoftlyExtensionin favor ofSoftAssertionsExtensionthat now supports field injection. -
Deprecate
hasFailed()CompletableFutureassertion:
// deprecated
assertThat(future).hasFailed();
// instead calls
assertThat(future).isCompletedExceptionally()
.isNotCancelled();
-
Deprecate
hasFailedWithThrowableThat()CompletableFutureassertion in favorfailsWithin:
// deprecated
CompletableFuture future = new CompletableFuture();
future.completeExceptionally(new RuntimeException("boom!"));
assertThat(future).hasFailedWithThrowableThat().isInstanceOf(RuntimeException.class);
.hasMessage("boom!");
// instead calls
assertThat(future).failsWithin(1, TimeUnit.SECONDS)
.withThrowableOfType(RuntimeException.class)
.withMessage("boom!");
Please note that the semantics of a failure in failsWithin differs from hasFailedWithThrowableThat, failsWithin tries to get the future after the given duration and return the exception that led to its failure while hasFailedWithThrowableThat checks the future is completed exceptionnaly and was not cancelled.
-
Deprecate
hasNotFailed()CompletableFutureassertion:
CompletableFuture future = new CompletableFuture();
future.cancel(true);
// deprecated
assertThat(future).hasNotFailed();
// instead calls
assertThat(future).matches (f -> f.isNotCompletedExceptionally() || f.isCancelled());
Add hasPackage to Class assertions
Verifies that the actual Class under test has the given package name.
Example:
package one.two;
class MyClass {}
assertThat(MyClass.class).hasPackage("one.two")
.hasPackage(Package.getPackage("one.two"));
Add isCloseTo to java.time.Duration assertions
Verifies that the actual Duration is close to the given one within the given allowed difference (assertion succeeds if difference = allowed difference).
This is equivalent of: abs(actual - expected) ≤ allowed difference.
For readability, Assertions.withMarginOf(Duration) can be used to express the allowed difference.
Examples:
Duration twoMinutes = Duration.ofMinutes(2);
assertThat(twoMinutes).isCloseTo(Duration.ofMinutes(3), Duration.ofMinutes(5));
assertThat(twoMinutes).isCloseTo(Duration.ofMinutes(-3), Duration.ofMinutes(10));
assertThat(twoMinutes).isCloseTo(Duration.ofMinutes(3), Duration.ofMinutes(1));
// assertions using withMarginOf syntactic sugar
assertThat(twoMinutes).isCloseTo(Duration.ofMinutes(3), withMarginOf(Duration.ofMinutes(5)));
assertThat(twoMinutes).isCloseTo(Duration.ofMinutes(3), withMarginOf(Duration.ofMinutes(1)));
Add failsWithin to Future and CompletableFuture assertionss
Checks that the Future/CompletableFuture does not complete within the given time and returns the exception that caused the failure for further (exception) assertions, the exception can be any of InterruptedException, ExecutionException, TimeoutException or CancellationException as per Future.get(long, TimeUnit) behaviour.
WARNING
failsWithin does not fully integrate with soft assertions, if the future completes the test will fail immediately (the error is not collected as a soft assertion error), if the assertion succeeds the chained assertions are executed and any errors will be collected as a soft assertion errors.
The rationale is that if we collect failsWithin error as a soft assertion error, the chained assertions would be executed but that does not make sense since there is no exception to check as the future has completed.
Examples:
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<String> future = executorService.submit(() -> {
Thread.sleep(100);
return "ook!";
});
// assertion succeeds as the future is not completed after 50ms
assertThat(future).failsWithin(Duration.ofMillis(10))
.withThrowableOfType(TimeoutException.class);
// alternative assertion syntax, the time out is expressed with a TimeUnit value
assertThat(future).failsWithin(10, TimeUnit.MILLISECONDS);
// fails as the future is completed within 200ms
assertThat(future).failsWithin(Duration.ofMillis(200));
Improve isTrue/isFalse assertions error messages
Before:
Expecting:
<false>
to be equal to:
<true>
but was not.
After:
Expecting value to be true but was false
Add hasValueSatisfying to AtomicReference assertions
Verifies that the atomic under test has a value satisfying the given predicate.
Examples:
assertThat(new AtomicReference("foo")).hasValueMatching(result -> result != null);
// you can pass a description for the predicate that will be used in the error message
assertThat(new AtomicReference("foo")).hasValueMatching(result -> result != null, "expected not null");
Add hasValueSatisfying to AtomicReference assertions
Verifies that the atomic under test has a value satisfying the given requirements.
Example:
assertThat(new AtomicReference("foo")).hasValueSatisfying(result -> assertThat(result).isNotBlank());
AssertJ Core 3.17.2
Release date: 2020-09-06
Contributors
Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio and BJ Hargrave.
Binary compatibility
The release is not binary compatible with the previous minor version.
Breaking changes
-
Change precedence of assumption classes when raising the assumption exception:
-
Old order:
org.opentest4j.TestAbortedException,org.testng.SkipExceptionandorg.junit.AssumptionViolatedException -
New order:
org.testng.SkipException,org.junit.AssumptionViolatedExceptionandorg.opentest4j.TestAbortedException
-
Improvements
-
Handle soft proxies for custom assert classes in OSGi bundles. (BJ Hargrave)
-
Internal: Add OSGi integration tests. (BJ Hargrave)
-
Internal: Fix maven-shade-plugin warning about overlapping MANIFEST.MF. (Stefano Cordio)
-
Internal: Exclude net.bytebuddy.experimental from shading scope. (Stefano Cordio)
-
Internal: Bump mockito version from 3.5.5 to 3.5.10. (Erhard Pointl, Stefano Cordio)
Fixed
-
Fix: assumptions were broken in JUnit4 when opentest4j is in the classpath. (Stefano Cordio)
AssertJ Core 3.17.1
Release date: 2020-08-30
Contributors
Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio, Pascal Schumacher, rpolton, Andrey Nudko and Davide Angelocola.
Binary compatibility
The release is not binary compatible with the previous minor version.
Breaking changes
-
Change precedence of assumption classes when raising the assumption exception:
-
Old order:
org.junit.AssumptionViolatedException,org.opentest4j.TestAbortedExceptionandorg.testng.SkipException -
New order:
org.opentest4j.TestAbortedException,org.testng.SkipExceptionandorg.junit.AssumptionViolatedException
-
Improvements
-
Speed up recursive comparison by caching results of
Methodlookup performed by reflection and using conditions instead of catching exceptions. (Andrey Nudko) -
Make
containsandcontainsOnlyassertions to work for iterables that can be traversed only once. (rpolton) -
Minor code cleanup. (Davide Angelocola)
-
Internal: Add Java 16 EA build. (Stefano Cordio)
Fixed
-
Fix
Object2DArrayAssert#isDeepEqualTo(). (Stefano Cordio)
AssertJ Core 3.17.0
Release date: 2020-08-23
Contributors
Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio, Pascal Schumacher, Junhao Liang, Bibibiu, Andrey "Bass" Shcheglov, SuntCrick, Yubin Hu, rpolton, Ting Sun, Peng Weiyuan, Brummolix, Maciej Wajcht, Hayden Meloche, Cal027, sullis, mgrafl, Rupert Madden-Abbott, Shiva, Ahmad M, Phillip Webb and BJ Hargrave.
Joel Costigliola: Apologies to Hayden Meloche, when integrating his work the final squashed commit was pushed with me as the author instead of him, sorry Hayden!
Binary compatibility
The release is not binary compatible with the previous minor version.
Breaking changes
-
Make the recursive comparison to ignore all overridden equals by default as most users were confused by it, call
usingOverriddenEqualsto revert to the previous behaviour. -
Improve
AssertionFailedErrorby replacing actual and expected by their representation as some defaulttoStringare not great (arrays for example). -
Make
Offset,MapEntry,Percentage,FieldLocationandIndexfinal. -
Add 2D array assertions, which provide new and potentially different methods for existing array assertions having two-dimensional arguments.
New features
-
Add
java.time.Periodassertions. (Hayden Meloche) -
Add
assertThatNoException().isThrownBy(code)assertion (and alsothenNoException()). (Phillip Webb) -
Add isNotEqualTo() to
RecursiveComparisonAssert. (Junhao Liang) -
Add JUnit 5
SoftlyExtensionto set upSoftAssertionsfield and automatically callassertAll()after each test. (Bibibiu) -
Add lazy error message overriding to only build the message when the assertion fails. (Yubin Hu)
-
Add
usingRecursiveFieldByFieldElementComparator(RecursiveComparisonConfiguration)to get the recursive api full power to all iterable assertions. -
Add
isEmptytoInputStreamassertion. (Peng Weiyuan) -
Add
isNotEmptytoInputStreamassertion. (Peng Weiyuan) -
Add
doesNotContainIgnoringCasetoCharSequenceassertions. (Brummolix) -
Add primitive and
Object2D array assertions. (Maciej Wajcht) -
Add
isEven/isOddassertions forbyte,short,intandlong. (Cal027) -
Soft assertions: add a way to react to collected assertion error.
-
Add
singleElement()andsingleElement(InstanceOfAssertFactory)to iterable assertions (it replaceshasOnlyOneElementSatisfying). (mgrafl) -
Add
filteredOn(Function, expectedValue)toIterable,Object[]andAtomicReferenceArrayassertions. (mgrafl) -
Add
succeedsWithintoFutureandCompletableFutureassertions. (Rupert Madden-Abbott)
Improvements
-
Allow specifying
equals BiPredicateinstead ofComparatorin recursive comparison. -
Display the beginning and the end of huge iterables/array/map instead of just the beginning. (SuntCrick)
-
Handle infinite or singly-traversable iterables for sequences assertions. (rpolton) - see #1938 for details.
-
Explicitly set Javadoc locale to English. (Erhard Pointl)
-
Make
PercentageandFieldLocationfinal, updateequals()andhashCode(). (Ahmad M) -
Make
Offset,MapEntryandIndexfinal, updateequals()andhashCode(). (Stefano Cordio) -
Javadoc improvements. (Stefano Cordio, Erhard Pointl)
-
Better handle soft proxies for custom assert classes in OSGi bundles. (BJ Hargrave)
-
Best effort to avoid cycles when representing iterables or object arrays.
-
Internal: Refactor urls test classes. (SuntCrick)
-
Internal: Add tests for
hasNoPathURL/URI assertions. (Ting Sun) -
Internal: Bump
equalsverifierfrom 3.2 to 3.4.2. -
Internal: Bump
commons-iofrom 2.6 to 2.7. -
Internal: Bump
commons-lang3from 3.10 to 3.11. -
Internal: Bump
bnd versionfrom 5.0.1 to 5.1.2 and re-enable java 15 build. (Pascal Schumacher) -
Internal: Bump
maven-shade-pluginfrom 3.2.3 to 3.2.4. -
Internal: Bump
byte-buddy versionfrom 1.10.10 to 1.10.14. -
Internal: Bump
mockito versionfrom 3.3.3 to 3.5.5 (Erhard Pointl) -
Internal: Add
dependabot. (sullis) -
Internal: Bump
actions/cachefrom v1 to v2. -
Internal: Fix "Remove this 'public' modifier" sonar violations. (Erhard Pointl, Shiva)
-
Internal: Make
Longs_assertIsOne_Test#should_succeed_since_actual_is_onetesting assertIsOne. (Erhard Pointl) -
Internal: Make
IterableAssert_anyMatch_TesttestinganyMatchandIterableAssert_anySatisfy_TesttestinganySatisfy. (Erhard Pointl) -
Internal: Add missing
ObjectArrayAssert_anySatisfy_Testtest. (Erhard Pointl) -
Internal: Fix mockito warnings. (Erhard Pointl)
-
Internal: Disable shallow clone during Sonar analysis. (Stefano Cordio)
-
Internal: Clean up code. (Stefano Cordio, Erhard Pointl)
Fixed
-
AbstractByteArrayAssert#asStringnow build a new String with the default or a given charset instead returning the byte array toString. -
Allow soft assertion failures to be recorded from multiple threads. (Andrey "Bass" Shcheglov)
-
Fix
containsExactlyassertion that failed for iterable that can only be read once. (rpolton) -
Fix references to
mainbranch aftermasterwas renamed tomainto support Black Lives Matter. (Steven Crockett) -
Fix Recursive comparison that did not compare enums as they don’t have fields, now it compares enums with
equals.
Deprecated
-
hasOnlyOneElementSatisfying(Consumer<? super ELEMENT> elementAssertions)has been deprecated in favor ofsingleElement() -
Deprecate all non recursive field by field comparison assertions in favor of the recursive comparison ones:
-
isEqualToComparingFieldByField -
isEqualToIgnoringNullFields -
isEqualToComparingOnlyGivenFields
-
-
Deprecate
AssertionErrorMessagesAggregratorin favor ofAssertionErrorMessagesAggregator. (Ahmad M)
Add java.time.Period assertions
Provides the following assertions for the Period:
-
hasDays(int expectedDays): Verifies that the actual Period has the given days. -
hasMonths(int expectedMonths): Verifies that the actual Period has the given months. -
hasYears(int expectedYears): Verifies that the actual Period has the given years. -
isNegative(): Verifies that the actual Period is negative (i.e. is less thanPeriod.ZERO). -
isPositive(): Verifies that the actual Period is positive (i.e. is greater thanPeriod.ZERO).
Examples:
assertThat(Period.ofYears(5)).hasYears(5);
assertThat(Period.ofMonths(5)).hasMonths(5);
assertThat(Period.ofDays(5)).hasDays(5)
.isPositive();
assertThat(Period.ofMonths(-5)).isNegative();
Display the beginning and the end of huge iterables/array/map
Before this version only the first maxElementsForPrinting elements would be displayed, now the maxElementsForPrinting displayed elements are split between first and last elements.
The number of elements to display can be set with Assertions.setMaxElementsForPrinting(n);
Example:
// 6 elements array
String[] greatBooks = {"A Game of Thrones", "The Lord of the Rings", "Assassin's Apprentice",
"Guards! Guards!", "The Lies of Locke Lamora", "Aux Ombres d’Abyme"};
// limit the number of elements to display/print to 4
Assertions.setMaxElementsForPrinting(4);
// formatted as:
["A Game of Thrones", "The Lord of the Rings", ... "The Lies of Locke Lamora", "Aux Ombres d’Abyme"]
Add isEmpty to InputStream assertion
Verifies whether the content of the actual InputStream is empty.
Examples:
// assertion will pass
assertThat(new ByteArrayInputStream(new byte[] {})).isEmpty());
// assertions will fail
assertThat(new ByteArrayInputStream(new byte[] {0xa})).isEmpty();
Add isNotEmpty to InputStream assertion
Verifies that the content of the actual InputStream is not empty.
Examples:
// assertion will pass
assertThat(new ByteArrayInputStream(new byte[] {0xa})).isNotEmpty());
// assertions will fail
assertThat(new ByteArrayInputStream(new byte[] {})).isNotEmpty();
Add doesNotContainIgnoringCase to CharSequence assertions
Verifies that the actual CharSequence does not contain any of the given values, ignoring case considerations.
Example:
// assertions will pass
assertThat("Frodo").doesNotContainIgnoringCase("pippin")
.doesNotContainIgnoringCase("Merry", "sam");
// assertions will fail
assertThat("Frodo").doesNotContainIgnoringCase("Fro", "Gimli", "Legolas");
assertThat("Frodo").doesNotContainIgnoringCase("fro");
primitive and Object 2D array assertions
The following assertions are available 2D arrays, here they are for int[][]:
-
isEqualTo(Object expected): Verifies that the actual int[][] is equal to the given one. -
isDeepEqualTo(int[][] expected): Verifies that the actual 2D array is deeply equal to the given one. -
isEmpty(): Verifies that the actual array is empty, i.e the array has no elements, said otherwise it can have any number of rows but all rows must be empty. -
isNullOrEmpty(): Verifies that the actual array is null or empty, empty means the same asisEmpty(). -
isNotEmpty(): Verifies that the actual array is not empty, i.e. the array has at least one element. -
contains(int[] value, Index index): Verifies that the actual array contains the given int[] at the given index. -
doesNotContain(int[] value, Index index): Verifies that the actual array does not contain the given value at the given index. -
hasDimensions(int expectedFirstDimension, int expectedSecondDimension): Verifies that the actual 2D array has the given dimensions. -
hasSameDimensionsAs(Object array): Verifies that the actual int[][] has the same dimensions as the given array.
The same assertions are available for long[][], short[][], byte[][], float[][], double[][], boolean[][] and Object[][] (obviously replacing int by the array type).
Object[][] assertions are generic, they take a parameter type, ex: isDeepEqualTo(ELEMENT[][] expected).
The migration path from one-dimensional array assertions is the following:
| Before 3.17.0 | After 3.17.0 |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The remaining one-dimensional array assertions do not have a direct replacement. Please raise a feature request if there is any use case for them.
Add isEven/isOdd assertions for byte, short, int and long
Verifies whether the given byte, short, int and or long is even/odd.
Examples:
assertThat(12).isEven();
assertThat(-46).isEven();
assertThat(3).isOdd();
assertThat(-17).isOdd();
Add singleElement to iterable assertions
singleElement() and singleElement(InstanceOfAssertFactory assertFactory) verify that the Iterable under test contains a single element and allow to perform assertions on that element (this is a shorthand for hasSize(1).first()).
You can only chain Object assertions after singleElement(), to get strongly typed assertions, use singleElement(InstanceOfAssertFactory) and pass the proper InstanceOfAssertFactory.
Examples:
import static org.assertj.core.api.InstanceOfAssertFactories.STRING;
import static org.assertj.core.api.Assertions.as; // syntactic sugar
List<String> babySimpsons = list("Maggie");
// assertion succeeds, only Object assertions are available after singleElement()
assertThat(babySimpsons).singleElement()
.isEqualTo("Maggie");
// String assertion succeeds, String assertions as we have passed InstanceOfAssertFactories.STRING
assertThat(babySimpsons).singleElement(as(STRING))
.startsWith("Mag");
Add succeedsWithin to Future and CompletableFuture assertions
succeedsWithin waits if necessary for at most the given time for this future to complete and then returns its result for further assertions.
If the future’s result is not available for any reason an assertion error is thrown.
To get assertions for the future result’s type use the method taking an additionnal InstanceOfAssertFactory parameter instead.
Examples:
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<String> future = executorService.submit(() -> {
Thread.sleep(100);
return "ook!";
});
// assertion succeeds
assertThat(future).succeedsWithin(200, TimeUnit.MILLISECONDS)
.isEqualTo("ook!");
// same assertion with a Duration to express the time out
Duration timeout = Duration.ofMillis(200);
assertThat(future).succeedsWithin(timeout)
.isEqualTo("ook!");
// fails as the future is not done after the given timeout
assertThat(future).succeedsWithin(50, TimeUnit.MILLISECONDS);
Examples with stronly typed assertions and CompletableFuture:
import static org.assertj.core.api.InstanceOfAssertFactories.STRING;
import static org.assertj.core.api.Assertions.as; // syntactic sugar
CompletableFuture<String> future = CompletableFuture.completedFuture("ook!");
Duration timeout = Duration.ofMillis(200);
// strongly typed assertion:
assertThat(future).succeedsWithin(timeout, as(STRING))
.contains("ok");
// same assertion with the timeout expressed differently:
assertThat(future).succeedsWithin(200, TimeUnit.MILLISECONDS, as(STRING))
.contains("ok");
Add filteredOn(Function, expectedValue) to Iterable, Object[] and AtomicReferenceArray assertions
Filters the iterable under test keeping only elements for which the result of the function is equal to expectedValue.
It allows to filter elements more safely than by using filteredOn(String, Object) as it doesn’t utilize introspection.
As an example, let’s check all employees 800 years old (yes, special employees): Examples:
Employee yoda = new Employee(1L, new Name("Yoda"), 800);
Employee obiwan = new Employee(2L, new Name("Obiwan"), 800);
Employee luke = new Employee(3L, new Name("Luke", "Skywalker"), 26);
Employee noname = new Employee(4L, null, 50);
List<Employee> employees = newArrayList(yoda, luke, obiwan, noname);
assertThat(employees).filteredOn(Employee::getAge, 800)
.containsOnly(yoda, obiwan);
assertThat(employees).filteredOn(e -> e.getName(), null)
.containsOnly(noname);
AssertJ Core 3.16.1
Release date: 2020-05-09
Contributors
Thanks to Erhard Pointl and Eddú Meléndez Gonzales for their contributions.
Fixed
-
Fix NPE in recursive comparison when checking local or anonymous classes. (#1868)
-
Fix
assertThat(Duration actual)Javadoc. (Eddú Meléndez Gonzales)
AssertJ Core 3.16.0
Release date: 2020-05-05
Contributors
Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio, Pascal Schumacher, Wim Deblauwe, Fabien Duminy, Piotrek Żygieło, Indrek Priks, Jakzi666, Daniel Avila, Harisha Talanki, Grzegorz Piwowarek, Andreas Mager, Sunt-ing, ebundy, Stefan Birkner, WuYff, Cal027, Yubin Hu and Fr Jeremy Krieg.
Breaking changes
-
AbstractSoftAssertionsis nowabstract -
The following base soft assertions classes were changed to interfaces (with default methods) and renamed:
-
AbstractBDDSoftAssertionswas renamed toBDDSoftAssertionsProvider -
AbstractStandardSoftAssertionswas renamed toStandardSoftAssertionsProvider -
Java6AbstractBDDSoftAssertionswas renamed toJava6BDDSoftAssertionsProvider -
Java6AbstractStandardSoftAssertionswas renamed toJava6StandardSoftAssertionsProvider
-
-
Move ThrowingCallable from
AbstractSoftAssertionstoSoftAssertionsProvider.
New features
-
Allow combining soft assertions entry points. (Fr Jeremy Krieg)
-
Support injecting custom soft assertions in JUnit 5
SoftAssertionExtension. (Fr Jeremy Krieg) -
Add assertions on the cause and root cause exception message. (Wim Deblauwe)
-
Recursive comparison learned to ignore null fields from the expected object.
-
Recursive comparison learned to ignore all actual empty optional fields.
-
Add assertion to compare string ignoring punctuation and normalizing whitespaces. (Harisha Talanki)
-
Add
isBase64toStringassertions. (Stefano Cordio) -
Add
decodedAsBase64toStringassertions. (Stefano Cordio) -
Add
encodedAsBase64tobyte[]assertions. (Stefano Cordio) -
Add
java.util.concurrent.atomic.LongAdderassertions. (Grzegorz Piwowarek) -
Add
asHexStringtobyte[]assertions. (Andreas Mager) -
Add
isEqualToWithSortedQueryParameterstoURLassertions. (Sunt-ing) -
Add
isDirectoryRecursivelyContainingtoFile/Pathassertions. (ebundy) -
Add
hasBinaryContenttoInputStreamassertions. (Stefan Birkner) -
Add
containsOnlyOnceElementsOftoIterable/Object array/AtomicReferenceArrayassertions. (Cal027)
Improvements
-
ByteArrayAssert.containsExactly(byte…)error message now mentions not found and unexpected elements. (Indrek Priks) -
In "should be package private" class assertion, the error message now explicitly mentions package-private instead of a blank value.
-
Use primitive comparison in
FloatandDoubleisNotEqualTowhen compared to primitive float/double values. -
Support up to four arguments for
satisfiesAnyOf(). (Jakzi666) -
Clarify the error message when comparing float/double NaN with ==.
-
Use a more descriptive element’s name in ShouldContain/ShouldContainOnly error message. (WuYff)
-
Add short array assertions taking
int…. (Daniel Avila) -
Use AssertJ site theme for Javadoc.
-
Improve converting JUnit/JUnit5 assertions to AssertJ. (Yubin Hu)
-
Move core
extractingfeatures fromAbstractObjectAsserttoAbstractAssert, making them available for custom assertions. (Stefano Cordio) -
Improve line number accuracy in soft assertion error messages. (Stefano Cordio)
-
Internal: introduce EqualsVerifier for internal tests. (Stefano Cordio)
-
Internal: optimize Charset finding in tests. (Fabien Duminy)
-
Internal: clean up unused imports (Erhard Pointl, Piotrek Żygieło, Stefano Cordio, Pascal Schumacher)
-
Internal: use static imports. (Piotrek Żygieło)
-
Internal: remove unnecessary type parameters from extractors. (Stefano Cordio)
-
Internal: access assertion info directly in
AtomicLongAssert/AtomicIntegerAssert. (Grzegorz Piwowarek) -
Re-enable Sonar reports. (Stefano Cordio)
-
Update ByteBuddy to version 1.10.10.
-
Update JUnit Jupiter to version 5.6.2 (still optional).
Fixed
-
Fix infinite recursion in recursive comparison when dealing with Path. (#1855)
-
Fix recursive comparison way of tracking already visited objects. (#1854)
-
Fix typos (Wim Deblauwe, Stefano Cordio)
Deprecated
-
Deprecate
areEqual()andareEqualArrays()inorg.assertj.core.util.Objects. -
Deprecate
temporaryFolder()inorg.assertj.core.util.Files. (Sunt-ing)
Add java.util.concurrent.atomic.LongAdder assertions
The following java.util.concurrent.atomic.LongAdder assertions are available:
-
hasValue(long expected), which verifies that the actual LongAdder sum has the given value. -
doesNotHaveValue(long unexpected), which verifies that the actual LongAdder sum has not the given value. -
All the assertions provided by
NumberAssert, using the LongAdder sum as actual value. -
All the assertions provided by
ComparableAssert, using the LongAdder sum as actual value.
Comparison ignoring punctuation and normalizing whitespaces
Verifies that the actual CharSequence is equal to the given one, after the punctuation of both strings have been normalized.
To be exact, the following rules are applied:
-
All punctuation of actual and expected strings are ignored and whitespaces are normalized
-
Punctuation is any of the following characters:
!"#$%&'()*+,-./:;=<>?@[\]^_{|}~\`
Examples:
// assertions succeed:
assertThat("Game'of'Thrones").isEqualToNormalizingPunctuationAndWhitespace("GameofThrones")
assertThat("Game of Throne's").isEqualToNormalizingPunctuationAndWhitespace("Game of Thrones")
assertThat(":Game of Thrones:").isEqualToNormalizingPunctuationAndWhitespace("Game of Thrones")
assertThat(":Game-of-Thrones:").isEqualToNormalizingPunctuationAndWhitespace("Game of Thrones")
assertThat("Game of Thrones?").isEqualToNormalizingPunctuationAndWhitespace("Game of Thrones")
assertThat("Game of Thrones!!!").isEqualToNormalizingPunctuationAndWhitespace("Game of Thrones")
assertThat("Game of {{(!)}} Thrones!!!").isEqualToNormalizingPunctuationAndWhitespace("Game of Thrones")
assertThat("{(Game)-(of)-(Thrones)!!!}").isEqualToNormalizingPunctuationAndWhitespace("GameofThrones");
// assertions fail:
assertThat("Game-of-Thrones").isEqualToNormalizingPunctuationAndWhitespace("Game of Thrones");
assertThat("{Game:of:Thrones}").isEqualToNormalizingPunctuationAndWhitespace("Game of Thrones");
assertThat("{(Game)-(of)-(Thrones)!!!}").isEqualToNormalizingPunctuationAndWhitespace("Game of Thrones");
isBase64
Verifies that the given String is a valid Base64 encoded string. (this is not available for CharSequence).
Examples:
// assertions succeeds
assertThat("QXNzZXJ0Sg==").isBase64();
// assertion succeeds even without padding as it is optional by specification
assertThat("QXNzZXJ0Sg").isBase64();
// assertion fails as it has invalid Base64 characters
assertThat("inv@lid").isBase64();
decodedAsBase64
Decodes the actual String value as a Base64 encoded string, the decoded bytes becoming the new array under test.
Examples:
// assertions succeeds
assertThat("QXNzZXJ0Sg==").decodedAsBase64()
.containsExactly("AssertJ".getBytes());
// assertion succeeds even without padding as it is optional by specification
assertThat("QXNzZXJ0Sg").decodedAsBase64()
.containsExactly("AssertJ".getBytes());
// assertion fails as it has invalid Base64 characters
assertThat("inv@lid").decodedAsBase64();
Add asHexString to byte[] assertions
Converts the actual byte array under test to an hexadecimal String and returns assertions for the computed String allowing String specific assertions from this call.
The hexadecimal String representation is in upper case.
Example :
byte[] bytes = new byte[] { -1, 0, 1 };
// assertion will pass
assertThat(bytes).asHexString()
.startsWith("FF")
.isEqualTo("FF0001");
Add isEqualToWithSortedQueryParameters] to URL assertions
Verifies that the actual URL is equivalent to the given one after their parameters are sorted.
Example :
URL url = new URL("http://example.com?a=b&c=d");
// these assertions succeed ...
assertThat(url).isEqualToWithSortedQueryParameters(new URL("http://example.com?c=d&a=b"))
.isEqualToWithSortedQueryParameters(new URL("http://example.com?a=b&c=d"));
// ... but this one fails as parameters do not match.
assertThat(url).isEqualToWithSortedQueryParameters(new URL("http://example.com?a=b&c=e"));
//... and this one fails as domains are different.
assertThat(url).isEqualToWithSortedQueryParameters(new URL("http://example2.com?amp;a=b&c=d"));
Add isDirectoryRecursivelyContaining to File/Path assertions
Verify that the actual File/Path directory or any of its subdirectories (recursively) contains at least one file matching the given criteria expressed as:
-
a
Stringinterpreted as a path matcher (as perFileSystem.getPathMatcher(String)) -
a
Stringinterpreted as a path matcher (as perFileSystem.getPathMatcher(String))
These assertions are similart to isDirectoryContaining but recursively go into subdirectories.
Note that the actual File/Path must exist and be a directory.
Examples with files given the following directory structure:
root
|—— foo
| |—— foobar
| |—— foo-file-1.ext
|—— foo-file-2.ext
Examples with syntax patterns:
File root = new File("root");
// The following assertions succeed:
assertThat(root).isDirectoryRecursivelyContaining("glob:**foo")
.isDirectoryRecursivelyContaining("glob:**ooba*")
.isDirectoryRecursivelyContaining("glob:**file-1.ext")
.isDirectoryRecursivelyContaining("regex:.*file-2.*")
.isDirectoryRecursivelyContaining("glob:**.{ext,dummy}");
// The following assertions fail:
assertThat(root).isDirectoryRecursivelyContaining("glob:**fooba");
assertThat(root).isDirectoryRecursivelyContaining("glob:**.bin");
assertThat(root).isDirectoryRecursivelyContaining("glob:**.{java,class}");
Examples with predicates:
File root = new File("root");
// The following assertions succeed:
assertThat(root).isDirectoryRecursivelyContaining(file -> file.getName().startsWith("foo-file-1"))
.isDirectoryRecursivelyContaining(file -> file.getName().endsWith("file-2.ext"))
.isDirectoryRecursivelyContaining(file -> file.getName().equals("foo"))
.isDirectoryRecursivelyContaining(file -> file.getParentFile().getName().equals("foo"))
// The following assertions fail:
assertThat(root).isDirectoryRecursivelyContaining(file -> file.getName().equals("foo-file-1"))
assertThat(root).isDirectoryRecursivelyContaining(file -> file.getName().equals("foo/foobar"));
Add hasBinaryContent to InputStream assertions
Verifies that the binary content of the actual InputStream is exactly equal to the given one.
Example: the following failing assertion …
InputStream inputStream = new ByteArrayInputStream(new byte[] {1, 2});
// assertion will pass
assertThat(inputStream).hasBinaryContent(new byte[] {1, 2});
// assertions will fail
assertThat(inputStream).hasBinaryContent(new byte[] { });
assertThat(inputStream).hasBinaryContent(new byte[] {0, 0});
Add containsOnlyOnceElementsOf to Iterable/Object array/AtomicReferenceArray assertions
Verifies that the actual group contains the elements of the given iterable only once (same semantic as containsOnlyOnce(Object…)).
Examples:
// assertions will pass
assertThat(list("winter", "is", "coming")).containsOnlyOnceElementsOf(list("winter"))
.containsOnlyOnceElementsOf(list("coming", "winter"));
// assertions will fail
assertThat(list("winter", "is", "coming")).containsOnlyOnceElementsOf(list("Lannister"));
assertThat(list("Arya", "Stark", "daughter", "of", "Ned", "Stark")).containsOnlyOnceElementsOf(list("Stark"));
assertThat(list("Arya", "Stark", "daughter", "of", "Ned", "Stark")).containsOnlyOnceElementsOf(list("Stark", "Lannister", "Arya"));
Disambiguate colliding date/time representation
Different date/time types can be represented the same way (LocalDateTime and Date for example) which makes it difficult to understand error messages as they don’t show any difference between actual and expected values. AssertJ now adds the date/time type name for types whose representation may collide.
Example: the following failing assertion …
Date now = new Date();
Object localDateTime = LocalDateTime.ofInstant(now.toInstant(), ZoneId.systemDefault());
assertThat(List.of(localDateTime)).containsExactly(now);
... fails with this error:
Expecting:
<[2020-03-19T22:32:42.875 (java.time.LocalDateTime)]>
to contain exactly (and in same order):
<[2020-03-19T22:32:42.875 (java.util.Date)]>
but some elements were not found:
<[2020-03-19T22:32:42.875 (java.util.Date)]>
and others were not expected:
<[2020-03-19T22:32:42.875 (java.time.LocalDateTime)]>
Before that the error would have been confusing:
Expecting:
<[2020-03-19T22:32:42.875]>
to contain exactly (and in same order):
<[2020-03-19T22:32:42.875]>
but some elements were not found:
<[2020-03-19T22:32:42.875]>
and others were not expected:
<[2020-03-19T22:32:42.875]>
AssertJ Core 3.15.0
Release date: 2020-01-28
The recursive comparison API has been promoted and is not a beta API anymore.
Contributors
Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio, Pascal Schumacher, BJ Hargrave, Raymond Augé, Thomas Weißschuh, Maciej Wajcht, Hayden Meloche, Filip Hrisafov, Jayati Goyal, Gyumin Kim, Clemens Grabmann, Roman Leventov, Fr Jeremy Krieg, Benoit Dupont, Nikolaos Georgiou, Christian Stein, Jeremy Landis, Graham Dennis, Fabien Duminy, Tommy Situ and Vincent Ricard.
Shout out to Vincent Ricard for the various tests refactoring, that was quite a lot of work!
Breaking changes
-
Compares
OffsetDateTime,ZonedDateTimeandLocalDateTimeusing theirtimeLineOrder()comparator as default.-
For
OffsetDateTimethetimeLineOrdercomparator only compares the underlying instant and ignores different timezones / offsets / chronologies. -
For
ZonedDateTimethetimeLineOrdercomparator ignores the chronology, this is equivalent to comparing the epoch-second and nano-of-second. -
For
LocalDateTimethetimeLineOrdercomparator ignores the chronology, this is equivalent to comparing the epoch-day and nano-of-day and allows dates in different calendar systems to be compared based on the position of the date-time on the local time-line.
-
-
A single
Pathparameter forcontainsOnlyKeysinMapassertions is treated as a single key rather than anIterableof keys. -
Fix floating point comparison behavior in
DoubleAssertandFloatAssert, which now follows primitive comparison (==,≤,≥) when the expected value is primitive but uses the correspondingequalssemantic when the expected value is a wrapper. -
Fix a double decoding issue in
UriAssert, which now uses the raw query to evaluate URI parameters avoiding the mishandling of escaped&and=. (Graham Dennis) -
Remove duplication for
Descriptableimplementations using default methods. This is a binary incompatible change. (Fr Jeremy Krieg)
New features
-
Add
java.time.Durationassertions. (Filip Hrisafov) -
Add
isPackagePrivatetoClassassertions. (Hayden Meloche) -
Add
hasSameBinaryContentAstoFile/Pathassertions. (Nikolaos Georgiou) -
Add
succeedsWithintoCompletableFutureassertions. -
Add
hasSuperclasstoClassassertions. (Stefano Cordio) -
Add
hasNoSuperclasstoClassassertions. (Stefano Cordio) -
Make the recursive comparison API directly available to
Iterable,Map,Optionaland array assertions. -
Allow to ignore fields by type in the recursive comparison. (Tommy Situ)
Improvements
-
Show explicitly if a class is
package-privateinClassModifierShouldBeerror message. -
Various module descriptor improvements: (Christian Stein and Stefano Cordio)
-
Remove JSR-305 due to issues with java 9 modules. (Stefano Cordio)
-
Remove .core.internal from exported packages. (Stefano Cordio)
-
-
Update ByteBuddy to version 1.10.6.
-
Update JUnit to version 4.13 (still optional).
-
Update JUnit Jupiter to version 5.6.0 (still optional).
-
Make OSGi import of jdk.* packages optional. (BJ Hargrave)
-
Use bnd 5.0.0 to a) use -noclassforname instruction b) generate most up to date OSGi metadata c) add verification that additional package imports never sneak in. (Raymond Augé)
-
Get rid of unnecessary extra arguments in
String.format. (Erhard Pointl) -
Unify
actualandexpectedformatting inhasToString()error which is nowAssertionFailedErrorto allow visual comparison. (Thomas Weißschuh) -
Add missing BDD assertions for exception handling (
thenExceptionOfType,thenNullPointerException,thenIllegalArgumentException,thenIOExceptionandthenIllegalStateException). (Maciej Wajcht) -
Rewrite
LocalDateAssert,LocalDateTimeAssert,LocalTimeAssertandOffsetDateTimeAsserttests to be more compliant with the contribution guidelines. (Clemens Grabmann) -
Remove IntelliJ IDEA configuration file for Language Injection as the rules are part of the built-in configuration since IntelliJ IDEA 2019.3. (Stefano Cordio)
-
Improve performance of
containsOnly()on very large collections. (Roman Leventov) -
Configure GitHub Actions for Windows and MacOS. (Filip Hrisafov)
-
Use parameterized tests for
assertHasParameter()in URI assertions. (Stefano Cordio) -
Show the stack trace of the Throwable under test when
hasMessageContainingandhasMessageContainingAllfails. (Benoit Dupont) -
Bump maven wrapper to 0.5.6. (Jeremy Landis)
-
Improve the representation of failed
CompletableFutureshowing the exception that caused the failure. -
Use
Objects.requireNonNullinstead of manually creating NullPointerExceptions. (Pascal Schumacher) -
Remove unused methods. (Fabien Duminy)
-
Replace
try/catchexception assertion withcatchThrowablepattern. (Vincent Ricard) -
Remove
failBecauseExpectedAssertionErrorWasNotThrown. (Vincent Ricard) -
Replace the
TestFailureshelper class by thecatchThrowablepattern. (Vincent Ricard) -
Update license year to 2020.
Fixed
-
Fix grammatical errors in README.md (Jayati Goyal)
-
Fix
allOf(Iterable)andanyOf(Iterable)that no longer tracked descriptions when built with anIterable<Condition>. -
Fix typos in Javadoc and comments. (Erhard Pointl)
-
Add
abstractmodifier forJava6AbstractStandardSoftAssertions. (Stefano Cordio) -
Fix typo in Javadoc. (Gyumin Kim)
-
Fix how
Enumare compared in recursive comparison which now compares them by value. -
Fix tests failing only on Windows. (Fr Jeremy Krieg)
-
Refactoring: remove useless null check. (Pascal Schumacher)
-
Fix use
equalsto compare enum names in recursive comparison. -
Fix how
containsOnlyKeysinMapAssertconsiders a singlePathparameter, which is now treated as a single key rather than anIterableof keys. (Stefano Cordio) -
Fix the recursive comparison that used to register fields of objects with overridden
equalswhen it should not have to. -
Fix property and field extraction with
Mapinput, which now tries at first to extract a property or a field by name and only in case of failure uses the input name as aMapkey. (Stefano Cordio)
Deprecated
-
Deprecate
hasSameContentAsin favor ofhasSameTextualContentAsand the newhasSameBinaryContentAs. -
Deprecate
Preconditions#checkNotNull(Object)in favor ofObjects.requireNonNull(Object). -
Deprecate
Preconditions#checkNotNull(Object, String)in favor ofObjects.requireNonNull(Object, String).
Add java.time.Duration assertions
The following java.time.Duration assertions are available:
-
hasDays(long otherDays): Verifies that the actual Duration has the given days. -
hasHours(long otherHours): Verifies that the actual Duration has the given hours. -
hasMillis(long otherMillis): Verifies that the actual Duration has the given millis. -
hasMinutes(long otherMinutes): Verifies that the actual Duration has the given minutes. -
hasNanos(long otherNanos): Verifies that the actual Duration has the given nanos. -
hasSeconds(long otherSeconds): Verifies that the actual Duration has the given seconds. -
isNegative(): Verifies that the actual Duration is negative (i.e. <Duration.ZERO) -
isPositive(): Verifies that the actual Duration is positive (i.e. >Duration.ZERO) -
isZero(): Verifies that the actual Duration isDuration.ZERO.
Examples:
assertThat(Duration.ofDays(5)).hasDays(5);
assertThat(Duration.ofHours(15)).hasHours(15);
assertThat(Duration.ofMinutes(65)).hasMinutes(65);
assertThat(Duration.ofSeconds(250)).hasSeconds(250);
assertThat(Duration.ofMillis(250)).hasMillis(250);
assertThat(Duration.ofNanos(145)).hasNanos(145);
assertThat(Duration.ofHours(5)).isPositive();
assertThat(Duration.ofMinutes(-15)).isNegative();
assertThat(Duration.ZERO).isZero();
Add isPackagePrivate to Class assertions
Verifies that the actual Class is package-private (i.e. has no modifier).
Example:
class MyClass {}
// this assertion succeeds:
assertThat(MyClass.class).isPackagePrivate();
// this assertion fails:
assertThat(String.class).isPackagePrivate();
Add hasSameBinaryContentAs to File/Path assertions
Verifies that the content of the actual file/path is equal to the content of the given one, the comparison is done at the binary level.
Example with Path (works the same with File):
// The first two paths have the same content, the third does not
Path aPath = Files.write(Paths.get("a-file.bin"), new byte[] { 42 });
Path bPath = Files.write(Paths.get("b-file.bin"), new byte[] { 42 });
Path cPath = Files.write(Paths.get("c-file.bin"), new byte[] { 24 });
// The following assertion succeeds:
assertThat(aPath).hasSameBinaryContentAs(bPath);
// The following assertion fails:
assertThat(aPath).hasSameBinaryContent(cPath);
Add succeedsWithin to CompletableFuture assertions
Waits if necessary for at most the given time for this future to complete, and then returns its result for futher assertions. If the future’s result is not available for any reason an assertion error is thrown.
The time to wait for can be expressed with a Duration or a TimeUnit.
To get assertions for the future result’s type use succeedsWithin that takes an additional InstanceOfAssertFactory parameter.
Examples:
CompletableFuture<String> future = CompletableFuture.completedFuture("ook!");
// assertion expressed with TimeUnit
assertThat(future).succeedsWithin(100, TimeUnit.MILLISECONDS)
.isEqualTo("ook!");
// same assertion with Duration
assertThat(future).succeedsWithin(Duration.ofMillis(100))
.isEqualTo("ook!");
// STRING is a static import of InstanceOfAssertFactories.STRING
// we can then chain String assertions
assertThat(future).succeedsWithin(100, TimeUnit.MILLISECONDS, STRING)
.startsWith("oo");
Add hasSuperclass to Class assertions
Verifies that the actual Class has the given superclass.
Example:
// this assertion succeeds:
assertThat(Integer.class).hasSuperclass(Number.class);
// this assertion succeeds as superclass for array classes is Object:
assertThat(Integer[].class).hasSuperclass(Object.class);
// this assertion fails:
assertThat(String.class).hasSuperclass(Number.class);
// this assertion fails as only direct superclass matches:
assertThat(String.class).hasSuperclass(Object.class);
// this assertion fails as interfaces are not superclasses:
assertThat(String.class).hasSuperclass(Comparable.class);
Add hasNoSuperclass to Class assertions
Verifies that the actual Class has no superclass.
Example:
// this assertion succeeds as interfaces have no superclass:
assertThat(Cloneable.class).hasNoSuperclass();
// this assertion succeeds as primitive types have no superclass:
assertThat(Integer.TYPE).hasNoSuperclass();
// this assertion succeeds as void type has no superclass:
assertThat(Void.TYPE).hasNoSuperclass();
// this assertion fails as Integer has Number as superclass:
assertThat(Integer.class).hasNoSuperclass();
Make recursive comparison API directly available to Iterable, Map, Optional and array assertions
Expose the recursive comparison for Iterable, Map, Optional and array assertions without having to cast them to Object as previously (because the API was only available for Object assertions).
At the moment, the only assertion available after in the recursive comparison is isEqualTo, there are plans to provide type specific recursive assertions in future (ex: iterable contains).
The recursive comparison API lets you finely control how to compare instances, please consult the documentation for a detailed guide.
For the following examples we use Person and Doctor, two classes with the same structure:
public class Person {
String name;
boolean hasPhd;
}
public class Doctor {
String name;
boolean hasPhd;
}
Doctor drSheldon = new Doctor("Sheldon Cooper", true);
Doctor drLeonard = new Doctor("Leonard Hofstadter", true);
Doctor drRaj = new Doctor("Raj Koothrappali", true);
Person sheldon = new Person("Sheldon Cooper", true);
Person leonard = new Person("Leonard Hofstadter", true);
Person raj = new Person("Raj Koothrappali", true);
Iterable example:
List<Doctor> doctors = list(drSheldon, drLeonard, drRaj);
List<Person> people = list(sheldon, leonard, raj);
// assertion succeeds as both lists contains equivalent items in order.
assertThat(doctors).usingRecursiveComparison()
.isEqualTo(people);
Array example:
Doctor[] doctors = { drSheldon, drLeonard, drRaj };
Person[] people = { sheldon, leonard, raj };
// assertion succeeds as both lists contains equivalent items in order.
assertThat(doctors).usingRecursiveComparison()
.isEqualTo(people);
Map example:
Map<String, Doctor> doctors = mapOf(entry(drSheldon.name, drSheldon),
entry(drLeonard.name, drLeonard),
entry(drRaj.name, drRaj));
Map<String, Person> people = mapOf(entry(sheldon.name, sheldon),
entry(leonard.name, leonard),
entry(raj.name, raj));
// assertion succeeds as both maps contains equivalent items.
assertThat(doctors).usingRecursiveComparison()
.isEqualTo(people);
Optional example:
Optional<Doctor> doctor = Optional.of(drSheldon);
Optional<Person> person = Optional.of(sheldon);
// assertion succeeds as both maps contains equivalent items.
assertThat(doctor).usingRecursiveComparison()
.isEqualTo(person);
AssertJ Core 3.14.0
Release date: 2019-10-27
Contributors
Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio, Jonas Berlin, Thami Inaflas, Geoffrey Arthaud, Carter Kozak, Kevin Toublanc, Krishna Chaithanya Ganta, sowmiyamuthuraman, Edgar Asatryan, Oleksii Khomchenko, Gonzalo Müller Bravo, Stephen O’Rourke, Sven Johansson, William Bakker, Rob Spieldenner, Raymond Pressly, Michael Keppler and Clemens Grabmann.
Breaking changes
-
Stop throwing an
IllegalArgumentExceptionwhenisInandisNotInare given an empty group of values.
New features
-
Add BDD assumptions. (Gonzalo Müller Bravo)
-
Add
Spliteratorassertions. (William Bakker) -
Add
isAtSameInstantAstoOffsetDateTimeassertions. (Raymond Pressly) -
Add
assertAlsoSoftAssertionsmethod to allow combining different soft assertions instances. (Kevin Toublanc) -
Add
isEmptyandisNotEmptyfile assertions. (Stephen O’Rourke) -
Add
hasSize(long expectedSizeInBytes)toFileassertions. (Krishna Chaithanya Ganta) -
Avoid BDDMockito/BDDAssertions
then(object)clash withand.then(object)method. (Gonzalo Müller Bravo) -
Add
hasRootCauseMessagetoThrowableassertions. (Oleksii Khomchenko) -
Add syntax sugar
as(InstanceOfAssertFactory)toAssertionsandWithAssertionsfor improved readability. (Stefano Cordio) -
Add
extracting(String, InstanceOfAssertFactory)toObjectassertions. (Stefano Cordio) -
Add
extracting(Function, InstanceOfAssertFactory)toObjectassertions. (Stefano Cordio) -
Add
extractingByKey(KEY)andextractingByKeys(KEY…)toMapassertions. (Stefano Cordio) -
Add
extractingByKey(KEY, InstanceOfAssertFactory)toMapassertions. (Stefano Cordio) -
Add
get(InstanceOfAssertFactory)toOptionalassertions. (Stefano Cordio) -
Add
first(InstanceOfAssertFactory)toIterableassertions. (Stefano Cordio) -
Add
last(InstanceOfAssertFactory)toIterableassertions. (Stefano Cordio) -
Add
element(int, InstanceOfAssertFactory)toIterableassertions. (Stefano Cordio) -
Add IntelliJ IDEA configuration file for Language Injection to add syntax highlighting on AssertJ methods with regexp parameters. (Jonas Berlin)
-
Add
String.formatsupport for expected message inhasMessageStartingWith,hasMessageContaining,hasMessageEndingWithandhasStackTraceContainingassertions. (Krishna Chaithanya Ganta)
Improvements
-
AssertJ’s Javadoc are now searchable.
-
Use beautiful AssertJ’s site code style for Javadoc :)
-
ObjectAssert.extracting(String…)learned to extract nested map key field/property. (Sven Johansson) -
Prettify
allOfandanyOfcombined conditions description. (Edgar Asatryan) -
Clearly differentiate top level objects in the new recursive comparison.
-
Show actual’s stack trace in
hasRootCauseandhasRootCauseMessageto give users more information. (Oleksii Khomchenko) -
Show actual’s stack trace in
hasMessageMatchingandhasMessageFindingMatchto give users more information. (Stephen O’Rourke) -
Update message text in
ShouldHaveSameSizeAsto show both actual and expected collections. (Thami Inaflas) -
Add
matchingsyntactic sugar method to use Hamcrest Matcher as Condition. (Jonas Berlin) -
Update ByteBuddy to version 1.10.2.
-
Update Hamcrest to version 2.2.
-
Fix Javadoc typos and incorrect references. (Erhard Pointl, Stefano Cordio)
-
Stop throwing an
IllegalArgumentExceptionwhenisInandisNotInare given an empty group of values. -
Expose
AbstractAssert.objectsto be used by subclasses. -
Bump opentest4j from 1.1.1 to 1.2.0. (still optional)
-
Improve
HamcrestConditiongeneric type inference. (Carter Kozak) -
Remove
shouldHaveThrown(Assertion.class)used internally. (sowmiyamuthuraman) -
Replace
catchThrowable+isInstanceOf(AssertionError.class)byexpectAssertionError(internal use). (Clemens Grabmann) -
Rewrite
CompletableFutureAsserttests withassertThatAssertionErrorIsThrownBy. (internal use). (Clemens Grabmann)
Fixed
-
Fix
BDDSoftAssertions.then(URL actual)that just did not work 🤦. (Rob Spieldenner) -
Fix possible
MissingFormatArgumentExceptioninShouldHaveMessageandShouldContain. (Erhard Pointl) -
Fix Javadoc search.
-
Fix Javadoc links. (Stefano Cordio)
-
Fix
hasSizeBetween()that did not work with strings. (Geoffrey Arthaud) -
Fix failing soft assertions when combined with
asInstanceOf. -
Fix missing soft assertions proxying for
getofOptionalAssert. (Stefano Cordio) -
Make
convert-junit-assertions-to-assertj.shconversion script work on Windows. (Michael Keppler)
Deprecated
-
Deprecate the confusing
containsOnlyElementsOfin favor ofisSubsetOforhasSameElementsAs. -
Deprecate
Mapassertionsextracting(Object)andextracting(Object…)in favor ofextractingByKey(KEY)andextractingByKeys(KEY…), respectively. (Stefano Cordio)
Add BDD assumptions
Add Behavior Driven Development style entry point for assumption methods for different types, which allow to skip test execution when assumptions are not met.
The difference with the Assumptions class is that entry point methods are named given instead of assumeThat.
Example:
String hobbit = "HOBBIT";
List<String> fellowshipOfTheRing = list("Aragorn", "Gandalf", "Frodo", "Legolas");
@Test
public void given_the_assumption_is_not_met_the_test_is_skipped() {
given(hobbit).isEqualTo("ORC");
// ... following code is not executed, the test is skipped
then(fellowshipOfTheRing).contains("Sauron");
}
@Test
public void given_the_assumption_is_met_the_test_is_executed() {
given(hobbit).isEqualTo("HOBBIT");
// ... following code is executed and fails!
then(fellowshipOfTheRing).doesNotContain("Sauron");
}
Add Spliterator assertions
Add hasCharacteristics and hasOnlyCharacteristics assertions for the Spliterator type.
Example:
Spliterator<Integer> spliterator = Stream.of(1, 2, 3).spliterator();
assertThat(spliterator).hasCharacteristics(Spliterator.SIZED,
Spliterator.ORDERED)
.hasOnlyCharacteristics(Spliterator.SIZED,
Spliterator.SUBSIZED,
Spliterator.IMMUTABLE,
Spliterator.ORDERED);
Add isAtSameInstantAs to OffsetDateTime assertions
Verifies that actual and given OffsetDateTime are at the same Instant.
Example:
OffsetDateTime offsetDateTime1 = OffsetDateTime.of(2000, 12, 12, 3, 0, 0, 0, ZoneOffset.ofHours(3));
OffsetDateTime offsetDateTime2 = OffsetDateTime.of(2000, 12, 12, 0, 0, 0, 0, ZoneOffset.ofHours(0));
// assertion succeeds
assertThat(offsetDateTime1).isAtSameInstantAs(offsetDateTime2);
offsetDateTime2 = OffsetDateTime.of(2000, 12, 12, 2, 0, 0, 0, ZoneOffset.ofHours(0));
// assertion fails
assertThat(offsetDateTime1).isAtSameInstantAs(offsetDateTime2);
Add assertAlso SoftAssertions method to allow combining different soft assertions instances
assertAlso lets you combine other soft assertions instances together.
Example:
Mansion mansion = new Mansion();
SoftAssertions check_kitchen() {
SoftAssertions softly = new SoftAssertions();
softly.assertThat(mansion.kitchen()).as("Kitchen").isEqualTo("clean");
return softly;
}
SoftAssertions check_library() {
SoftAssertions softly = new SoftAssertions();
softly.assertThat(mansion.library()).as("Library").isEqualTo("clean");
return softly;
}
@Test
void host_dinner_party_where_nobody_dies() {
SoftAssertions softly = new SoftAssertions();
mansion.hostPotentiallyMurderousDinnerParty();
softly.assertThat(mansion.guests()).as("Living Guests").isEqualTo(7);
softly.assertThat(mansion.revolverAmmo()).as("Revolver Ammo").isEqualTo(6);
softly.assertThat(mansion.candlestick()).as("Candlestick").isEqualTo("pristine");
softly.assertThat(mansion.colonel()).as("Colonel").isEqualTo("well kempt");
softly.assertThat(mansion.professor()).as("Professor").isEqualTo("well kempt");
SoftAssertions kitchen = check_kitchen();
softly.assertAlso(kitchen);
SoftAssertions library = check_library();
softly.assertAlso(library);
softly.assertAll();
}
Add isEmpty and isNotEmpty file assertions
Verify that the actual File is empty (i.e. the file size = 0) or not empty (i.e. the file size > 0) .
Example:
File file = File.createTempFile("tmp", "txt");
// assertion will pass
assertThat(file).isEmpty();
Files.write(file.toPath(), new byte[]{1, 1});
// assertion will pass
assertThat(file).isNotEmpty();
Add hasSize(long expectedSizeInBytes) to File assertions
Verifies that the size of the File under test is exactly equal to the given size in bytes.
Example:
File file = File.createTempFile("tmp", "bin");
Files.write(file.toPath(), new byte[] {1, 1});
// assertion will pass
assertThat(file).hasSize(2);
// assertion will fail
assertThat(file).hasSize(1);
Avoid BDDMockito/BDDAssertions then(object) clash with and.then(object)
To avoid clash with libraries like Mockito that exposes a static then(object) method, you can statically use the and field.
import static org.mockito.BDDMockito.then;
// can't use import static org.assertj.core.api.BDDAssertions.then because of BDDMockito.then;
import static org.assertj.core.api.BDDAssertions.and;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
// suppress and.then warning: The static method BDDAssertions.then() should be accessed in a static way
@SuppressWarnings("static-access")
@Test
public void bdd_assertions_with_bdd_mockito() {
// GIVEN
Person person = mock(Person.class)
// WHEN
person.ride(bike);
person.ride(bike);
// THEN
// mockito then()
then(person).should(times(2)).ride(bike);
// use AssertJ and.then(person) as then(person) would clash with mockito then(person)
and.then(person.hasBike()).isTrue();
}
Add hasRootCauseMessage to Throwable assertions
Verifies that the message of the root cause of the actual Throwable is equal to the given one, a simple String or String.format is supported to specify the expected root cause message.
Example:
Throwable throwable = new Throwable(new IllegalStateException(new NullPointerException("expected message")));
// assertions will pass
assertThat(throwable).hasRootCauseMessage("expected message")
.hasRootCauseMessage("expected %s", "message");
// assertions will fail
assertThat(throwable).hasRootCauseMessage("another message");
assertThat(throwable).hasRootCauseMessage("%s", "message");
// no root cause message
assertThat(new Throwable()).hasRootCauseMessage("%s %s", "expected", "message");
Add syntax sugar as(InstanceOfAssertFactory) to Assertions and WithAssertions for improved readability
A syntax sugar to write fluent assertion with methods having an InstanceOfAssertFactory parameter. Added as a static method in Assertions, it is also available as a default method in the WithAssertions interface.
Example:
Jedi yoda = new Jedi("Yoda", "Green");
assertThat(yoda).extracting(Jedi::getName, as(InstanceOfAssertFactories.STRING))
.startsWith("Yo");
as(InstanceOfAssertFactory) can be used together with the following assertion methods:
Add extracting with String and InstanceOfAssertFactory parameters to Object assertions
Extracts the value of given field/property from the object under test, the extracted value becoming the new object under test.
The InstanceOfAssertFactory parameter is used to get the assertions narrowed to the factory type.
Examples:
// Create frodo, setting its name, age and Race (Race having a name property)
TolkienCharacter frodo = new TolkienCharacter("Frodo", 33, HOBBIT);
// let's extract and verify Frodo's name:
assertThat(frodo).extracting("name", as(InstanceOfAssertFactories.STRING))
.startsWith("Fro");
// The following assertion will fail as Frodo's name is not an Integer:
assertThat(frodo).extracting("name", as(InstanceOfAssertFactories.INTEGER))
.isZero();
Add extracting with Function and InstanceOfAssertFactory parameters to Object assertions
Uses the given Function to extract a value from the object under test, the extracted value becoming the new object under test.
The InstanceOfAssertFactory parameter is used to get the assertions narrowed to the factory type.
Examples:
// Create frodo, setting its name, age and Race (Race having a name property)
TolkienCharacter frodo = new TolkienCharacter("Frodo", 33, HOBBIT);
// let's extract and verify Frodo's name:
assertThat(frodo).extracting(TolkienCharacter::getName, as(InstanceOfAssertFactories.STRING))
.startsWith("Fro");
// The following assertion will fail as Frodo's name is not an Integer:
assertThat(frodo).extracting(TolkienCharacter::getName, as(InstanceOfAssertFactories.INTEGER))
.isZero();
Add extractingByKey with KEY and InstanceOfAssertFactory parameters to Map assertions
Extracts the value of given key from the map under test, the extracted value becoming the new object under test.
The InstanceOfAssertFactory parameter is used to get the assertions narrowed to the factory type.
Examples:
Map<String, Object> map = new HashMap<>();
map.put("name", "kawhi");
// The following assertion will succeed:
assertThat(map).extractingByKey("name", as(InstanceOfAssertFactories.STRING))
.startsWith("kaw");
// The following assertion will fail as the value is not an Integer:
assertThat(map).extractingByKey("name", as(InstanceOfAssertFactories.INTEGER))
.isZero();
Add get with InstanceOfAssertFactory parameters to Optional assertions
Verifies that the optional is not null and not empty and returns an new assertion instance to chain assertions on the optional value.
The InstanceOfAssertFactory parameter is used to get the assertions narrowed to the factory type.
Examples:
Optional<String> optional = Optional.of("Frodo");
// The following assertion will succeed:
assertThat(optional).get(as(InstanceOfAssertFactories.STRING))
.startsWith("Fro");
// The following assertion will fail as the value is not an Integer:
assertThat(optional).get(as(InstanceOfAssertFactories.INTEGER))
.isZero();
Add first with InstanceOfAssertFactory parameters to Iterable assertions
Navigates and allows to perform assertions on the first element of the Iterable under test.
The InstanceOfAssertFactory parameter is used to get the assertions narrowed to the factory type.
Examples:
Iterable<String> hobbits = newArrayList("Frodo", "Sam", "Pippin");
// assertion succeeds
assertThat(hobbits).first(as(InstanceOfAssertFactories.STRING))
.startsWith("Fro")
.endsWith("do");
// assertion fails
assertThat(hobbits).first(as(InstanceOfAssertFactories.STRING))
.startsWith("Pip");
// assertion fails because of wrong factory type
assertThat(hobbits).first(as(InstanceOfAssertFactories.INTEGER))
.isZero();
Add last with InstanceOfAssertFactory parameters to Iterable assertions
Navigates and allows to perform assertions on the last element of the Iterable under test.
The InstanceOfAssertFactory parameter is used to get the assertions narrowed to the factory type.
Examples:
Iterable<String> hobbits = newArrayList("Frodo", "Sam", "Pippin");
// assertion succeeds
assertThat(hobbits).last(as(InstanceOfAssertFactories.STRING))
.startsWith("Pip")
.endsWith("pin");
// assertion fails
assertThat(hobbits).last(as(InstanceOfAssertFactories.STRING))
.startsWith("Fro");
// assertion fails because of wrong factory type
assertThat(hobbits).last(as(InstanceOfAssertFactories.INTEGER))
.isZero();
Add element with InstanceOfAssertFactory parameters to Iterable assertions
Navigates and allows to perform assertions on the chosen element of the Iterable under test.
The InstanceOfAssertFactory parameter is used to get the assertions narrowed to the factory type.
Examples:
Iterable<String> hobbits = newArrayList("Frodo", "Sam", "Pippin");
// assertion succeeds
assertThat(hobbits).element(1, as(InstanceOfAssertFactories.STRING))
.startsWith("Sa")
.endsWith("am");
// assertion fails
assertThat(hobbits).element(1, as(InstanceOfAssertFactories.STRING))
.startsWith("Fro");
// assertion fails because of wrong factory type
assertThat(hobbits).element(1, as(InstanceOfAssertFactories.INTEGER))
.isZero();
Add String.format support for expected message in hasMessageStartingWith, hasMessageContaining, hasMessageEndingWith and hasStackTraceContaining assertions
Instead of taking a simple String the assertions mentioned above now accept a String.format like parameters, i.e. (String description, Object… parameters) making it easier to build more involved expected strings.
Examples:
Throwable throwableWithMessage = new IllegalArgumentException("wrong amount 123");
assertThat(throwableWithMessage).hasMessageStartingWith("%s a", "wrong")
.hasMessageContaining("wrong %s", "amount")
.hasMessageEndingWith("%s 123", "amount")
.hasStackTraceContaining("%s amount", "wrong");
ObjectAssert.extracting(String…) learned to extract nested map key field/property
extracting is now able to extract a deeply nested map key, before this improvement extracting a value by key was only supported for a Map object under test (but not for fields of type Map).
Let’s clarify things with a concrete example:
Jedi luke = new Jedi(new Name("Luke", "Skywalker"), 26);
// setAttribute puts a new entry in 'attributes' Map field
luke.setAttribute("side", "light");
Jedi leia = new Jedi(new Name("Leia", "Skywalker"), 26);
// setRelation puts a new entry in 'relations' Map field
luke.setRelation("sister", leia);
leia.setRelation("brother", luke);
assertThat(luke).extracting("name.last",
"attributes.side",
"relations.sister",
"relations.sister.relations.brother")
.containsExactly("Skywalker",
"light",
leia,
luke);
Prettify allOf and anyOf combined conditions description
To make it more readable, reformat the error message when multiple combined conditions with allOf and anyOf fail.
Examples: the following assertion will fail …
private static Condition<String> contains(String s) {
return new Condition<>(value -> value.contains(s), "contains " + s);
}
// failing assertion:
assertThat("Gandalf").has(anyOf(contains("i"),
allOf(contains("o"),
anyOf(contains("a"),
contains("b"),
contains("c")))));
With the following error message
Expecting:
<"Gandalf">
to have:
<any of:[
contains i,
all of:[
contains o,
any of:[
contains a,
contains b,
contains c
]
]
]>
Add matching syntactic sugar method to use Hamcrest Matcher as Condition
Syntactic sugar to construct a Condition using the Hamcrest Matcher given as a parameter.
Example:
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.HamcrestCondition.matching;
import static org.hamcrest.core.StringContains.containsString;
@Test
public void matching_example() {
assertThat("abc").is(matching(containsString("a")));
}
AssertJ Core 3.13.2
Release date: 2019-08-04
This release ships a few improvements:
-
Fixes an annoyance in
InstanceOfAssertFactories, whereURLandURIconstants have been renamed toURL_TYPEandURI_TYPErespectively to avoid a clash withjava.net.URLandjava.net.URI. See github.com/assertj/assertj-core/issues/1567 for details. -
Updates ByteBuddy to version 1.10.0.
-
Fixes some Javadoc typos.
-
Enforces banned dependencies with
maven-enforcer-plugin.
AssertJ Core 3.13.1
Release date: 2019-07-29
This release addresses the 3.13.0 issue by which AssertJ required OpenTest4J to be on the classpath otherwise a java.lang.NoClassDefFoundError: org/opentest4j/MultipleFailuresError would be raised. Thanks Pascal Schumacher for the quick fix!
java.lang.NoClassDefFoundError: org/opentest4j/MultipleFailuresError
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)
at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:174)
at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:802)
at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:700)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:623)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at org.assertj.core.internal.Failures.<init>(Failures.java:46)
at org.assertj.core.internal.Failures.<clinit>(Failures.java:44)
at org.assertj.core.internal.Objects.<init>(Objects.java:87)
at org.assertj.core.internal.Objects.<init>(Objects.java:101)
at org.assertj.core.internal.Objects.<clinit>(Objects.java:82)
at org.assertj.core.api.AbstractAssert.<init>(AbstractAssert.java:65)
at org.assertj.core.api.AbstractCharSequenceAssert.<init>(AbstractCharSequenceAssert.java:53)
at org.assertj.core.api.AbstractStringAssert.<init>(AbstractStringAssert.java:28)
at org.assertj.core.api.StringAssert.<init>(StringAssert.java:25)
at org.assertj.core.api.AssertionsForClassTypes.assertThat(AssertionsForClassTypes.java:484)
at org.assertj.core.api.Assertions.assertThat(Assertions.java:2585)
AssertJ Core 3.13.0
Release date: 2019-07-28
The highlight of this release is the addition of asInstanceOf which allows to chain specific type assertions from a value that was initially declared with a different type (usually Object). Thanks Stefano Cordio for this contribution!
Example:
Object value = "abc";
// This line DOES NOT COMPILE since startsWith is a String assertion and value is an Object
assertThat(value).startsWith("ab");
// This line COMPILES because we tell AssertJ to consider value as a String
assertThat(value).asInstanceOf(InstanceOfAssertFactories.STRING).startsWith("ab");
This feature is more detailed in the notes below.
Contributors
Thanks to all the contributors of this release:
Pascal Schumacher, Erhard Pointl, Stefano Cordio, Thomas Traude, Andrei Solntsev, Matej Drobnič, Željko Mirović, Mike Gilchrist, Phillip Webb, Michal Fotyga,Valeriy Vyrva, Eddú Meléndez Gonzales, GaspardPO, Bengt Brodersen, Jiri Pejchal, Christian Stein, Nikolaos Georgiou and Sam Brannen.
Special thanks to Nils Winkler for his work on the assertions conversion scripts and Stefano Cordio for the asInstanceOf contribution.
Breaking changes
-
As the
extracting(String)method forObjectandMapextracts only one value, it now returnsObjectassertions instead of list assertions (on a singleton list). This means that any list assertions used won’t compile anymore, they need to be replaced byObjectassertions.
// GIVEN
Map<String, Object> basketballPlayer = new HashMap<>();
basketballPlayer.put("name", "kawhi");
basketballPlayer.put("age", 25);
// Does not compile anymore!
assertThat(basketballPlayer).extracting("name")
.containsExactly("kawhi"); // DOES NOT COMPILE
// Use Object assertions like isEqualTo
assertThat(basketballPlayer).extracting("name")
.isEqualTo("kawhi");
// multiple values work as before, no problem there!
assertThat(basketballPlayer).extracting("name", "age")
.containsExactly("kawhi", 25);
-
In the new recursive comparison, we now use the expected field as a reference to determine how to compare it to corresponding the actual field. Sorted vs non sorted collections comparison semantics have been replaced by ordered vs unordered collections semantics (ordered types are
List,SortedSetandLinkedHashSet). As a consequence of the two previous points, when comparing collection/map fields, if the actual field is ordered and the expected is unordered, the comparison is allowed but not the other way around (unless order is ignored explicitely in the comparison configuration).
New features
-
Add
asInstanceOfto chain specific type assertions. (Stefano Cordio) -
Add
extracting(String)toObjectandMapassertions. (Stefano Cordio) -
Add a way to configure AssertJ for all tests.
-
Add
hasCauseReferencethrowable assertion. (Mike Gilchrist) -
Add directory content assertions for
FileandPath. (Valeriy Vyrva) -
Add
hasMessageContainingAllandhasMessageNotContainingAnyto throwable assertions. (Phillip Webb) -
Allow using any custom assertions in soft assertions. (Bengt Brodersen)
-
Add
containsExactlyInAnyOrderEntriesOfto map assertions. (Stefano Cordio) -
Add
isCloseToUtcNowtoLocalDateTimeandOffsetDateTimeassertions. (Nikolaos Georgiou)
Improvements
-
Junit 4/5 and TestNG assertions convertion scripts improvements. (Nils Winkler)
-
Add support for combined millisecond and timezone parsing. (Matej Drobnič)
-
Add support for
Optionalin the new recursive comparison. -
Allow ignoring collection order in specific fields in the new recursive comparison. (Željko Mirović)
-
Make
catchThrowableOfTypeeasier to discover in the Javadoc. -
Rename methods
isBeforeOrEqualsToandisAfterOrEqualsTotoisBeforeOrEqualToandisAfterOrEqualTo. (Eddú Meléndez Gonzales) -
Improve error messages in the new recursive comparison when group size differs or when trying to compare actual unordered vs expected ordered.
-
Introduce explicit module descriptor. (Christian Stein)
-
Allow returned values of
WithAssertions#failmethods to be ignored by FindBugs/SpotBugs. (Jiri Pejchal) -
Improve the error message when multiple (soft) assertions error are raised.
-
Propagate value type with
extracting(Function). (Stefano Cordio)
Fixed
-
Fix Soft assertions JUnit 5 extension that did not support parallel test nor
@TestInstance(PER_CLASS)lifecycle semantics. (Sam Brannen) -
Fix JavaDoc regarding
AnyOfandAllOf. (Thomas Traude) -
Make sure that
isEqualTo("abc")is not resolved toisEqualTo(String, Object… args). (Andrei Solntsev) -
Fix Javadoc typos. (GaspardPO, Michal Fotyga)
-
Fix typo in error message factories
ShouldBeBeforeOrEqualToandShouldBeAfterOrEqualTo. (Stefano Cordio)
Deprecated
-
Deprecate Java 6/Android assertions entry points as they don’t truly provide 100% Java 6/Android compatibility.
-
Deprecate methods
isBeforeOrEqualToandisAfterOrEqualToin favor ofisBeforeOrEqualsToandisAfterOrEqualsTo(Eddú Meléndez Gonzales). -
Deprecate
JUnitJupiterSoftAssertionsandJUnitJupiterBDDSoftAssertionsin favor ofSoftAssertionsExtension
Add asInstanceOf to chain specific type assertions
asInstanceOf allows to chain specific type assertions from a value initially declared as a less specific type (often Object).
Let’s start with the problem asInstanceOf is solving: in the following example we would like to call String assertions but this is not possible since value is declared as an Object thus only Object assertions are accessible.
// Given a String declared as an Object
Object value = "Once upon a time in the west";
// We would like to call String assertions but this is not possible since value is declared as an Object
assertThat(value).startsWith("ab"); // this does not compile !
Thanks to asInstanceOf we can now tell AssertJ to consider value as a String in order to call String assertions.
To do so we need to pass an InstanceOfAssertFactory that can build a StringAssert, fortunately you don’t have to write it, it is already available in InstanceOfAssertFactories!
import static org.assertj.core.api.InstanceOfAssertFactories.STRING;
// Given a String declared as an Object
Object value = "Once upon a time in the west";
// With asInstanceOf, we switch to specific String assertion by specifying the InstanceOfAssertFactory for String
assertThat(value).asInstanceOf(STRING).startsWith("Once");
AssertJ verifies that the actual value is compatible with the assertions InstanceOfAssertFactory is going to give access to.
InstanceOfAssertFactories provides static factories for all types AssertJ provides assertions for, additional factories can be created with custom InstanceOfAssertFactory instances.
Here’s another example showing the parameterized type support:
// Actually a List<TolkienCharacter>
Object hobbits = list(frodo, pippin, merry, sam);
// As we specify the TolkienCharacter class, the following chained assertion expect to be given TolkienCharacters.
// This means that method like extracting or filteredOn are given a TolkienCharacter
assertThat(hobbits).asInstanceOf(InstanceOfAssertFactories.list(TolkienCharacter.class))
.contains(frodo, sam)
.extracting(TolkienCharacter::getName)
.contains("Frodo", "Sam");
// Use LIST if the elements type is not important but note that the chained assertions
// will be given Object not TolkienCharacter
assertThat(hobbits).asInstanceOf(InstanceOfAssertFactories.LIST)
//.extracting(TolkienCharacter::getName) does not work as extracting is given an Object
.contains(frodo);
Add extracting with single parameter to Object and Map assertions
Extracts the value of given field/property from the object under test, the extracted value becoming the new object under test.
Examples:
// Create frodo, setting its name, age and Race (Race having a name property)
TolkienCharacter frodo = new TolkienCharacter("Frodo", 33, HOBBIT);
// let's extract and verify Frodo's name:
assertThat(frodo).extracting("name")
.isEqualTo("Frodo");
// The extracted value being a String, we would like to use String assertions but we can't due to Java generics limitations.
// The following assertion does NOT compile:
assertThat(frodo).extracting("name")
.startsWith("Fro");
// To get String assertions use asInstanceOf:
assertThat(frodo).extracting("name")
.asInstanceOf(InstanceOfAssertFactories.STRING)
.startsWith("Fro");
If the object under test is a Map, the parameter is used as a key to the map.
Example:
Map<String, Object> basketballPlayer = new HashMap<>();
basketballPlayer.put("name", "kawhi");
basketballPlayer.put("age", 25);
// single value
assertThat(basketballPlayer).extracting("name")
.isEqualTo("kawhi");
AssertJ global configuration
AssertJ 3.13.0 introduces a Configuration class allowing to change AssertJ behavior and a way to register automatically.
Read Configuring AssertJ chapter to learn about it.
Add hasCauseReference to throwable assertions
Verifies that the actual Throwable has a cause that refers to the given one, i.e. using == comparison.
Example:
Throwable invalidArgException = new IllegalArgumentException("invalid arg");
Throwable throwable = new Throwable(invalidArgException);
// This assertion succeeds:
assertThat(throwable).hasCauseReference(invalidArgException);
// These assertions fail:
assertThat(throwable).hasCauseReference(new IllegalArgumentException("invalid arg"));
assertThat(throwable).hasCauseReference(new NullPointerException());
assertThat(throwable).hasCauseReference(null); // prefer hasNoCause()
New directory content assertions
The new assertions have been added for both File and Path, they add support for
-
checking what a directory contains with
isDirectoryContaining -
checking what a directory does not contain with
isDirectoryNotContaining -
checking if directory is empty with
isEmptyDirectoryor not withisNotEmptyDirectory
Both isDirectoryContaining and isDirectoryNotContaining accept either Predicate or String parameters, the String one being interpreted as a path matcher.
As File and Path assertions are similar, the examples will only show File assertions.
The examples use the following directory structure:
/root/
/root/sub-dir-1/
/root/sub-dir-1/file-1.ext
/root/sub-dir-1/file-2.ext
/root/sub-dir-2/
/root/sub-file-1.ext
/root/sub-file-2.ext
isDirectoryContaining assertions examples:
File root = new File("root");
// Successfull assertions with predicate parameter:
assertThat(root).isDirectoryContaining(file -> file.getName().startsWith("sub-dir"))
.isDirectoryContaining(file -> file.getName().startsWith("sub-file"))
.isDirectoryContaining(file -> file.getName().endsWith(".ext"))
.isDirectoryContaining(File::isDirectory);
// Successfull assertions with String path matcher parameter:
assertThat(root).isDirectoryContaining("glob:**sub-dir*")
.isDirectoryContaining("glob:**sub-file*")
.isDirectoryContaining("glob:**.ext")
.isDirectoryContaining("regex:.*ext")
.isDirectoryContaining("glob:**.{ext,bin");
// The following assertions fail:
assertThat(root).isDirectoryContaining(file -> file.getName().startsWith("dir"));
assertThat(root).isDirectoryContaining(file -> file.getName().endsWith(".bin"));
assertThat(root).isDirectoryContaining("glob:**dir");
assertThat(root).isDirectoryContaining("glob:**.bin");
isDirectoryNotContaining assertion examples:
File root = new File("root");
// Successfull assertions with predicate parameter:
assertThat(root).isDirectoryNotContaining(file -> file.getName().startsWith("dir"))
.isDirectoryNotContaining(file -> file.getName().endsWith(".bin"));
// Successfull assertions with String path matcher parameter:
assertThat(root).isDirectoryNotContaining("glob:**dir")
.isDirectoryNotContaining("glob:**.bin")
.isDirectoryNotContaining("regex:.*bin")
.isDirectoryNotContaining("glob:**.{java,class}");
// The following assertions fail:
assertThat(root).isDirectoryContaining(file -> file.getName().startsWith("dir"));
assertThat(root).isDirectoryContaining(file -> file.getName().endsWith(".bin"));
assertThat(root).isDirectoryNotContaining("glob:**sub-dir*");
assertThat(root).isDirectoryNotContaining("regex:.*ext");
assertThat(root).isDirectoryNotContaining("glob:**.{ext,bin");
isEmptyDirectory assertion examples:
File root = new File("root");
// The following assertion succeeds:
assertThat(new File(root, "sub-dir-2")).isEmptyDirectory();
// The following assertions fail:
assertThat(root).isEmptyDirectory();
assertThat(new File(root, "sub-dir-1")).isEmptyDirectory();
isNotEmptyDirectory assertion examples:
File root = new File("root");
// The following assertions succeed:
assertThat(root).isNotEmptyDirectory();
assertThat(new File(root, "sub-dir-1")).isNotEmptyDirectory();
// The following assertion fails:
assertThat(new File(root, "sub-dir-2")).isNotEmptyDirectory();
Add hasMessageContainingAll and hasMessageNotContainingAny to throwable assertions
These assertions are the equivalent of hasMessageContaining and hasMessageNotContaining but accepting multiple String parameters instead of only one.
Example:
Throwable throwableWithMessage = new IllegalArgumentException("wrong amount 123");
Throwable throwableWithoutMessage = new IllegalArgumentException();
// assertion will pass:
assertThat(throwableWithMessage).hasMessageContainingAll("amount", "123")
.hasMessageNotContainingAny("foo", "234");
assertThat(throwableWithoutMessage).hasMessageNotContainingAny("234");
// assertions will fail:
assertThat(throwableWithMessage).hasMessageContainingAll("234");
assertThat(throwableWithoutMessage).hasMessageContainingAll("123");
assertThat(throwableWithMessage).hasMessageNotContainingAny("foo", "amount");
The same assertions have been added to ThrowableAssertAlternative with these names withMessageContainingAll and withMessageNotContainingAny:
Throwable illegalArgumentException = new IllegalArgumentException("wrong amount 123");
// assertions will pass
assertThatExceptionOfType(Throwable.class)
.isThrownBy(() -> {throw illegalArgumentException;})
.withMessageContainingAll("amount", "123")
.withMessageNotContainingAny("foo", "234");
Allow using any custom assertions in soft assertions
The new check method catches and collect assertion errors coming from standard and custom assertions.
Example:
SoftAssertions softly = new SoftAssertions();
// custom assertions
softly.check(() -> LotrAssertions.assertThat(frodo).hasName("Frodon"));
softly.check(() -> LotrAssertions.assertThat(frodo).hasName("Frodo"));
// standard assertions
softly.assertThat("foo").startsWith("bar");
// could be written with check like (but it's as elegant as the standard use):
// softly.check(() -> Assertions.assertThat("foo").startsWith("bar"));
// 2 errors: "foo" does not start with "bar" and frodo's name is not "Frodon"
assertThat(softly.errorsCollected()).hasSize(2);
Add containsExactlyInAnyOrderEntriesOf to map assertions
Verifies that the actual map contains only the given entries and nothing else, in any order.
This is the same assertion as containsOnly(Map.Entry… entries), it simply handles the conversion of Map.entrySet() to array.
Example :
Map<Ring, TolkienCharacter> ringBearers = newLinkedHashMap(entry(oneRing, frodo),
entry(nenya, galadriel),
entry(narya, gandalf));
// assertion will pass
assertThat(ringBearers).containsExactlyInAnyOrderEntriesOf(newLinkedHashMap(entry(oneRing, frodo),
entry(nenya, galadriel),
entry(narya, gandalf)));
// assertion will pass although actual and expected order differ
assertThat(ringBearers).containsExactlyInAnyOrderEntriesOf(newLinkedHashMap(entry(nenya, galadriel),
entry(narya, gandalf),
entry(oneRing, frodo)));
// assertion will fail as actual does not contain all entries of expected
assertThat(ringBearers).containsExactlyInAnyOrderEntriesOf(newLinkedHashMap(entry(oneRing, frodo),
entry(nenya, galadriel),
entry(oneRing, frodo)));
// assertion will fail as actual and expected have different sizes
assertThat(ringBearers).containsExactlyInAnyOrderEntriesOf(newLinkedHashMap(entry(oneRing, frodo),
entry(nenya, galadriel),
entry(narya, gandalf),
entry(narya, gandalf)));
Add isCloseToUtcNow to LocalDateTime and OffsetDateTime assertions
Verifies that the actual LocalDateTime/OffsetDateTime is close to the current date and time on the UTC timezone, according to the given offset.
You can build the offset parameter using Assertions.within(long, TemporalUnit) or Assertions.byLessThan(long, TemporalUnit).
If the difference is equal to the offset, the assertion succeeds.
Example with LocalDateTime:
LocalDateTime actual = LocalDateTime.now(Clock.systemUTC());
// assertion will pass if executed less than one second after actual was built
assertThat(actual).isCloseToUtcNow(byLessThan(1, ChronoUnit.SECONDS));
// assertion will fail
assertThat(actual.plusSeconds(2)).isCloseToUtcNow(within(1, ChronoUnit.SECONDS));
The same example works with OffsetDateTime by simply defining actual as:
OffsetDateTime actual = OffsetDateTime.now(Clock.systemUTC());
Add support for combined millisecond and timezone parsing
Add yyyy-MM-dd HH:mm:ss.SSSX to the default date formats AssertJ supports in Date assertions that take a String parameter representating a Date.
Here’s an example of string following this format: "2003-04-26T00:00:00.123+00:00".
Example:
// GIVEN
SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
// WHEN
Date date = isoFormat.parse("2003-04-26T00:00:00.123");
// THEN
assertThat(date).isEqualTo("2003-04-26T00:00:00.123+00:00");
Add support for Optional in the new recursive comparison
The recursive comparison added in 3.12.0 now compares Optional values recursively instead of comparing Optional with equals. This is consistent with comparing list elements by elements as an Optional can be seen as a list with at most one element.
Example:
// Song constructor parameters: song, author and coAuthor (optional)
Song song = new Song("I Can't Get No Satisfaction", new Author("Mick Jagger"), new Author("Keith Richards"));
Song expectedSong = new Song("I Can't Get No Satisfaction", new Author("Mick Jagger"), new Author("Keith Richards"));
// THEN
assertThat(song).usingRecursiveComparison()
.isEqualTo(expectedSong);
where Song and Author don’t override equals:
class Song {
Author author;
Optional<Author> coAuthor;
String song;
Song(String song, Author author, Author coAuthor) {
this.song = song;
this.author = author;
this.coAuthor = Optional.ofNullable(coAuthor);
}
// no equals!
}
class Author {
String name;
Author(String name) {
this.name = name;
}
String getName() {
return name;
}
// no equals!
}
If we fail the test ...
Song song = new Song("I Can't Get No Satisfaction", new Author("Mick Jagger"), new Author("Jimi Hendrix"));
Song expectedSong = new Song("I Can't Get No Satisfaction", new Author("Mick Jagger"), new Author("Keith Richards"));
// FAIL
assertThat(song).usingRecursiveComparison()
.isEqualTo(expectedSong);
... here’s the error reported:
Expecting:
<Song [author=Mick Jagger, coAuthor=Optional[Jimi Hendrix], song=I Can't Get No Satisfaction]>
to be equal to:
<Song [author=Mick Jagger, coAuthor=Optional[Keith Richards], song=I Can't Get No Satisfaction]>
when recursively comparing field by field, but found the following difference:
field/property 'coAuthor.value.name' differ:
- actual value : "Jimi Hendrix"
- expected value : "Keith Richards"
The recursive comparison was performed with this configuration:
- overridden equals methods were used 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]
- 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).
Allow ignoring collection order in the new recursive comparison
The recursive comparison added in 3.12.0 can now ignore collection order in all fields in the object under test, this is handy when comparing list to set fields where only the content is relevant but not the order.
Example:
public class Person {
String name;
List<Person> friends = new ArrayList<>();
}
Person sherlock1 = new Person("Sherlock Holmes");
sherlock1.friends.add(new Person("Dr. John Watson"));
sherlock1.friends.add(new Person("Molly Hooper"));
Person sherlock2 = new Person("Sherlock Holmes");
sherlock2.friends.add(new Person("Molly Hooper"));
sherlock2.friends.add(new Person("Dr. John Watson"));
// assertion succeeds as all fields collection order is ignored in the comparison
assertThat(sherlock1).usingRecursiveComparison()
.ignoringCollectionOrder()
.isEqualTo(sherlock2);
// assertion fails as fields collection order is not ignored in the comparison
assertThat(sherlock1).usingRecursiveComparison()
.isEqualTo(sherlock2);
Propagate value type with extracting(Function)
extracting(Function) learned to propagate the type parameter of the resulting ObjectAssert allowing then to chain other type aware methods (e.g. additional extracting).
Example:
// Old implementation
assertThat(yoda).extracting(Jedi::getName) // ObjectAssert<Object>
.extracting(String::length) // Not compiling
.isEqualTo(4);
// New implementation
assertThat(yoda).extracting(Jedi::getName) // ObjectAssert<String>
.extracting(String::length) // Compiling!
.isEqualTo(4);
AssertJ Core 3.12.2
The main issue fixed was to ignore static methods when finding property accessors (contributed by Andy Wilkinson) which could break some tests since bare name method introspection was introduced in 3.12.0.
anySatisfy for Maps was improved and does not continue evaluating elements once a match is found (contributed by Erhard Pointl).
AssertJ Core 3.12.1
Fix a regression that included a bad module-info.class (thanks Jaro Kuruc) and other minor improvements.
AssertJ Core 3.12.0
Release date: 2019-02-14
The main feature of this release is a beta version of the new Recursive comparison API!
It covers what isEqualToComparingFieldByFieldRecursively used but easier to use and with more capabilities.
It is a Beta version because we want to have feedback from the community to make it even better before freezing the API. There are more capabilities to come in the next releases, stay tuned!
Contributors
Big thanks to all the contributors of this release:
Pascal Schumacher, Erhard Pointl, Vladimir Chernikov, Sandra Parsick, Martin Tarjanyi, Stephan Windmüller, Yaroslav Mitsynskiy, Thomas Traude, Georg Berky, Tomek Kaczanowski, Lukáš Křečan, Yoann Rodière, Filip Hrisafov, Steven Schlansker, Jeremy Landis, Jack Gough, Sebastian Kempken, Stefan Mandel, Alexandre de Champeaux, Arvid Heise, Jeff Walker, Dmitrii Priporov and Joshua Kitchen.
Breaking changes
-
Introduce first class
Iteratorassertions (Stephan Windmüller).
This removes the previously supported “Iterable” assertions (like containsOnly), call IteratorAssert#toIterable to access them again, ex:
|
Iterator<String> bestBasketBallPlayers = getBestBasketBallPlayers();
assertThat(bestBasketBallPlayers).toIterable().contains("Jordan", "Magic", "Lebron");
-
Add configurable support for bare-named property introspection. (Steven Schlansker)
AssertJ uses introspection in various places, one example is extracting properties as in extracting("name"). AssertJ is able to get values with getters like getName(), with this improvement it now can get property values with bare name method like name().
| Bare-named property introspection is enabled by default and thus changes AssertJ behavior which can break some existing tests relying on introspection, this is especially true as AssertJ wrongly tries static methods (github.com/assertj/assertj-core/issues/1458 had been created to address that). |
It is possible to avoid this problem by calling Assertions.setExtractBareNamePropertyMethods(false); before every impacted tests.
This is a bit tedious but an improvement is planned in the next release to provide a place to perform global configuration with the same mechanism allowing to register a custom representation.
New features
-
New Recursive comparison API! (Beta version)
-
Add
satisfiesAnyOfbase assertion. -
Add
isAbstracttoClassassertions. (Erhard Pointl) -
Add
hasValueCloseTo(percentage)toOptionalDoubleassertion. (Joshua Kitchen) -
Add
hasOnlyOneElementSatisfying(Consumer)toAtomicReferenceArrayassertions. (Vladimir Chernikov) -
Add
hasAllNullFieldsOrPropertiesandhasAllNullFieldsOrPropertiesExcept. (Vladimir Chernikov) -
Add
hasSizeGreaterThan,hasSizeLessThanOrEqualTo,hasSizeGreaterThanOrEqualToandhasSizeGreaterThantoCharSequenceandStringassertions. (Sandra Parsick) -
Add
hasSizeGreaterThan,hasSizeLessThanOrEqualTo,hasSizeGreaterThanOrEqualTo,hasSizeGreaterThanandhasSizeBetweento object and primitives array,IterableandMap. (Martin Tarjanyi) -
Add
hasSizeBetweentoCharSequenceandStringassertions. (Martin Tarjanyi) -
Add
noneSatisfy(BiConsumer)toMapassertions. (Erhard Pointl) -
Add
containsExactlyEntriesOfassertion to check that aMapcontains exactly all entries of anotherMap. (Filip Hrisafov) -
Add
containsOnlyKeys(Iterable keys)toMapassertion. (Sebastian Kempken) -
Add
anySatifies(BiConsumer)toMapassertion. (Stefan Mandel) -
Add
hasMessageNotContainingtoThrowableassertions. (Georg Berky and Sandra Parsick) -
Add
shouldHaveRootCausetoThrowableassertions to check the content of a root cause. (Jack Gough) -
Add
isEqualTo(String string, Objects… param)toStringassertion. (Dmitrii Priporov) -
Add
assertThatObject/thenObjectto force Object assertion. (Arvid Heise) -
Add JUnit5 to AssertJ assertions migration script for osx. (Tomek Kaczanowski)
Improvements
-
Add stack trace of original exception to
catchThrowableOfType. (Sam Smyth) -
anySatisfyandnoneSatisfynow reports all failing elements. (Erhard Pointl) -
ElementsShouldSatisfynow uses the configuredRepresentationto format objects. -
ZipSatisfyErrornow uses the configuredRepresentationto format objects. (Jeff Walker) -
AssertJ
DoubleandFloatcomparators now supportInfinity. (Alexandre de Champeaux) -
Throw
AssertionFailedErrorinstead ofAssertionErrorin someStringassertions to allow IDEs to showactualvsexpectedvisual differences. (Yaroslav Mitsynskiy) -
OptionalhasValue/containsassertions throwsAssertionFailedErrorto allow IDEs to showactualvsexpectedvisual differences. -
Annotate
AssertionsandAssumptionsclasses with@CheckReturnValueand annotate methods to exclude from checking with@CanIgnoreReturnValue. (Pascal Schumacher) -
The error message of
allSatisfy(BiConsumer)Mapassertion now reports all failing entries instead of the first one. (Stefan Mandel) -
Add missing
@Sinceannotations. (Erhard Pointl) -
Get rid of
Argumentsusage when possible in unit tests. (Erhard Pointl) -
Unit tests code cleanup and better use of JUnit 5. (Erhard Pointl, Pascal Schumacher and Jack Gough)
-
Update to JUnit 5.4.0. (Erhard Pointl)
-
Update to opentest4j to 1.1.1. (Erhard Pointl)
-
Update to Byte Buddy 1.9.10. (Pascal Schumacher)
-
Update Maven version to and the Maven wrapper. (Thomas Traude, Jeremy Landis)
-
Do not proxy
useComparatormethod in soft assertions. (Lukáš Křečan) -
Fix an NPE in
ObjectArrays#assertHasOnlyElementsOfType. (Yoann Rodière) -
Deprecate
Extractorin favor ofjava.util.function.Function. (Filip Hrisafov)
Fixed
-
Use
@CanIgnoreReturnValueonAssertionsfail*methods to revert the effect of the default@CheckReturnValueannotation. (Erhard Pointl) -
Fix
ElementsShouldSatisfythat failed to handle objects whose string representation contained%. -
Fix
ElementsShouldZipSatisfythat failed to handle objects whose string representation contained%. (Arvid Heise)