Expand TestNG to AssertJ assertion coverage#1028
Conversation
Add dedicated recipes for assertSame/assertNotSame, assertThrows/expectThrows, assertEqualsNoOrder, and assertEqualsDeep/assertNotEqualsDeep, and fix assertEquals/assertNotEquals to use element-wise assertions (containsExactly, containsExactlyElementsOf, toIterable) for arrays, collections, sets and iterators instead of a reference-level isEqualTo. Each recipe is registered in testng.yml and covered by a mirror test with a @DocumentExample.
Cover the remaining org.testng.Assert static assertions: assertListContainsObject /assertListNotContainsObject map to assertThat(list).contains()/.doesNotContain(), and the predicate-based assertListContains/assertListNotContains map to .anyMatch()/.noneMatch().
…cipes Call super.visitMethodInvocation() before matching so assertions nested inside non-matching invocations (e.g. within a lambda argument) are still visited and migrated. Brings the TestNG recipes and JUnitFailToAssertJFail in line with the recursing pattern already used elsewhere.
timtebeek
left a comment
There was a problem hiding this comment.
Thanks a lot for your efforts here, especially considering where you're coming from! I've pushed one small change to handle nested cases too, but other than that the work looks solid here. Thanks for applying your in depth knowledge of mappings to complete the migration.
I hope all is well there; let me know if you'd like an expedited release to get this out. Otherwise our next scheduled release will be in two weeks.
|
To be honest, Claude did most of the work here, and I expect it to be good enough. We'll see how it holds up once the community starts testing it. Please ping me when the release is available, and I'll add the corresponding documentation on the TestNG side. |
Hah no worries; I'd recognized the signatures already indeed, and knew what to look for in the review. Still helpful!
Sure! I've put out release right now that's already up at Maven Central: Send a link when you have any messaging up that you'd like me to have a look over. |
|
Thanks for the continued reports and contributions! I've expanded coverage quite a bit today following your reports: Let me know if you plan any further validation (potentially using our snapshot versions), before I cut another release to get these fixes out. |
|
Validated against the full TestNG suite using The four reported issues now transform exactly as expected:
Running it over our already-migrated suite produced only correct simplifications, no regressions — and the new rules even caught cases our manual pass had missed, e.g. array length: assertThat(arr.length).isEqualTo(2); // -> assertThat(arr).hasSize(2);
assertThat(arr.length).isZero(); // -> assertThat(arr).isEmpty();
assertThat(passedTests.length).isEqualTo(passed.size()); // -> assertThat(passedTests).hasSameSizeAs(passed);Good to go for a release from our side. One item is out of scope for this repo and tracked upstream: Thanks again for the quick turnaround on all of these! |
|
Perfect, thanks for confirming, and thanks again for the helpful reports! I've just triggered the release, that should be out on Maven central in 30 minutes: |
What's changed
Widen
org.openrewrite.java.testing.testng.TestNgToAssertjfrom "scalarassertEquals/assertNotEquals+ Refaster basics" to full coverage of everystaticmethod onorg.testng.Assert(verified against TestNG 7.12.0).New recipes
TestNgAssertSameToAssertThatassertSame(a, b)→assertThat(a).isSameAs(b)TestNgAssertNotSameToAssertThatassertNotSame(a, b)→assertThat(a).isNotSameAs(b)TestNgAssertThrowsToAssertThatassertThrows(Type.class, run)/expectThrows(...)→assertThatExceptionOfType(Type.class).isThrownBy(run)(.actual()when the result is used);assertThrows(run)→assertThatThrownBy(run)TestNgAssertEqualsNoOrderToAssertThatassertEqualsNoOrder(...)→containsExactlyInAnyOrder/containsExactlyInAnyOrderElementsOf(arrays, collections, iterators)TestNgAssertEqualsDeepToAssertThatassertEqualsDeep/assertNotEqualsDeep(Map/Set) →usingRecursiveComparison().isEqualTo()/.isNotEqualTo()TestNgAssertListToAssertThatassertListContainsObject/assertListNotContainsObject→.contains()/.doesNotContain(); predicate-basedassertListContains/assertListNotContains→.anyMatch()/.noneMatch()Fix to existing
assertEquals/assertNotEqualsTestNgAssertEqualsToAssertThatmatched allassertEquals(..)overloads and always emittedisEqualTo(...)— wrong for the structural overloads (forIterator/Iterableit compared object identity rather than TestNG's element-wise semantics). It now dispatches on the actual argument's type:containsExactlySet→containsExactlyInAnyOrderElementsOfIterable(List/Collection) →containsExactlyElementsOfIterator→assertThat(actual).toIterable().containsExactlyElementsOf(() -> expected)Map/ scalars →isEqualTo(unchanged, already correct)Both
assertEqualsandassertNotEqualsalso gained an integral-actual + floating-delta guard (mirroringJUnitAssertEqualsToAssertThat) so anint/longactual with a floating delta falls back toisEqualTo/isNotEqualToinstead of an uncompilableisCloseTo.Coverage
After this PR, every
staticmethod onorg.testng.Assertis handled:assertEquals,assertNotEquals,assertEqualsDeep,assertNotEqualsDeep,assertEqualsNoOrder,assertSame,assertNotSame,assertThrows,expectThrows,assertListContains(Object),assertListNotContains(Object).assertTrue,assertFalse,assertNull,assertNotNull,fail.Notes
testng.ymland have a mirror*Testwith a single@DocumentExample.recipes.csvwas regenerated via./gradlew recipeCsvGenerate(not hand-edited)..as(...), consistent with the existing TestNG recipes. The known.as(...)vs.withFailMessage(...)divergence with the Picnic Refaster path is documented as future work in a comment intestng.ymlrather than resolved here.Test plan
./gradlew build— green (license check,recipes.csvcompleteness, full test suite).assertEquals(List, List)now producescontainsExactlyElementsOfrather thanisEqualTo, and that theIteratoroverloads ofassertEquals/assertEqualsNoOrderproduce compilabletoIterable()-based assertions.