Add parameterized module: JUnit 5 @ParameterizedTest argument sources, display names, and two real anti-pattern failures
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
Captured from a real `junit-platform-console-standalone --details=tree` run against
|
||||
ValueSourceTest, compiled and executed for real.
|
||||
|
||||
╷
|
||||
├─ JUnit Platform Suite ✔
|
||||
├─ JUnit Jupiter ✔
|
||||
│ └─ ValueSourceTest ✔
|
||||
│ └─ shouldIdentifyPalindromes(String) ✔
|
||||
│ ├─ "racecar" should be a palindrome ✔
|
||||
│ ├─ "radar" should be a palindrome ✔
|
||||
│ └─ "level" should be a palindrome ✔
|
||||
└─ JUnit Vintage ✔
|
||||
|
||||
Test run finished after 171 ms
|
||||
[ 3 tests successful ]
|
||||
[ 0 tests failed ]
|
||||
|
||||
name = "{0} should be a palindrome" is the whole trick: {0} is a positional reference to the
|
||||
single @ValueSource argument, and the console runner always quotes a String argument's own text
|
||||
when it substitutes it in -- which is why the output reads "racecar" should be a palindrome
|
||||
rather than requiring quotes inside the template itself. An earlier draft of this template used
|
||||
name = "''{0}'' should be a palindrome", which doubles up with the console's own quoting and
|
||||
renders as the much uglier '"racecar"' should be a palindrome -- fixed here before publishing by
|
||||
simply dropping the extra quote marks from the template.
|
||||
@@ -0,0 +1,23 @@
|
||||
Captured from a real `junit-platform-console-standalone --details=tree` run against
|
||||
NullAndEmptySourceTest, compiled and executed for real.
|
||||
|
||||
╷
|
||||
├─ JUnit Platform Suite ✔
|
||||
├─ JUnit Jupiter ✔
|
||||
│ └─ NullAndEmptySourceTest ✔
|
||||
│ └─ shouldRejectBlankUsernames(String) ✔
|
||||
│ ├─ blank username [null] should be rejected ✔
|
||||
│ ├─ blank username [""] should be rejected ✔
|
||||
│ ├─ blank username [" "] should be rejected ✔
|
||||
│ ├─ blank username ["\t"] should be rejected ✔
|
||||
│ └─ blank username ["\n"] should be rejected ✔
|
||||
└─ JUnit Vintage ✔
|
||||
|
||||
Test run finished after 185 ms
|
||||
[ 5 tests successful ]
|
||||
[ 0 tests failed ]
|
||||
|
||||
Five invocations, not three: @NullAndEmptySource contributes the null and "" cases, and the
|
||||
@ValueSource(strings = {" ", "\t", "\n"}) alongside it contributes the other three. All five are
|
||||
blank per String.isBlank() -- which is the actual point of the test, and the reason it needs real
|
||||
tab and newline characters rather than the letters "t" and "n", which are not blank at all.
|
||||
@@ -0,0 +1,20 @@
|
||||
Captured from a real `junit-platform-console-standalone --details=tree` run against
|
||||
CsvSourceTest#shouldAddNumbers, compiled and executed for real.
|
||||
|
||||
╷
|
||||
├─ JUnit Platform Suite ✔
|
||||
├─ JUnit Jupiter ✔
|
||||
│ └─ CsvSourceTest ✔
|
||||
│ └─ shouldAddNumbers(int, int, int) ✔
|
||||
│ ├─ "10" + "5" = "15" ✔
|
||||
│ ├─ "0" + "0" = "0" ✔
|
||||
│ ├─ "-3" + "7" = "4" ✔
|
||||
│ └─ "100" + "-50" = "50" ✔
|
||||
└─ JUnit Vintage ✔
|
||||
|
||||
Test run finished after 228 ms
|
||||
[ 4 tests successful ]
|
||||
[ 0 tests failed ]
|
||||
|
||||
The plainest @CsvSource shape: one inline comma-separated row per invocation, three columns
|
||||
mapped positionally onto the method's three int parameters, no header row involved at all.
|
||||
@@ -0,0 +1,27 @@
|
||||
Captured from a real `junit-platform-console-standalone --details=tree` run against
|
||||
CsvSourceTest#testPublishingPermissions, compiled and executed for real.
|
||||
|
||||
╷
|
||||
├─ JUnit Platform Suite ✔
|
||||
├─ JUnit Jupiter ✔
|
||||
│ └─ CsvSourceTest ✔
|
||||
│ └─ testPublishingPermissions(int, String, boolean) ✔
|
||||
│ ├─ user USER_ID = "1001" with role ROLE = "EDITOR" ✔
|
||||
│ ├─ user USER_ID = "1002" with role ROLE = "ADMIN" ✔
|
||||
│ └─ user USER_ID = "1003" with role ROLE = "USER" ✔
|
||||
└─ JUnit Vintage ✔
|
||||
|
||||
Test run finished after 228 ms
|
||||
[ 3 tests successful ]
|
||||
[ 0 tests failed ]
|
||||
|
||||
This is the genuinely new, easy-to-miss finding in this rewrite. The custom template is
|
||||
name = "user {0} with role {1}" -- plain positional placeholders, the same {0}/{1} syntax used
|
||||
everywhere else in this module. But because @CsvSource(useHeadersInDisplayName = true) is also
|
||||
set, each individual {0} and {1} does not resolve to the bare value ("1001", "EDITOR") the way
|
||||
it would without that flag -- it resolves to "HEADER = value" ("USER_ID = \"1001\"",
|
||||
"ROLE = \"EDITOR\""). useHeadersInDisplayName changes what every positional placeholder expands
|
||||
to, not just the auto-generated default name used when no custom name is given at all. Compare
|
||||
this against docs/output/05-csv-source-headers-default-display-name.txt (no custom name, same
|
||||
data, same flag) and docs/output/06-header-name-placeholder-throws.txt (an attempt to put the
|
||||
header name directly inside the template, which is a different thing entirely and throws).
|
||||
@@ -0,0 +1,24 @@
|
||||
Captured from a real `junit-platform-console-standalone --details=tree` run against
|
||||
CsvSourceTest#testPublishingPermissionsDefaultDisplayName, compiled and executed for real. Same
|
||||
@CsvSource(useHeadersInDisplayName = true) data as testPublishingPermissions, but with no custom
|
||||
`name` attribute at all, to isolate what the flag does on its own.
|
||||
|
||||
╷
|
||||
├─ JUnit Platform Suite ✔
|
||||
├─ JUnit Jupiter ✔
|
||||
│ └─ CsvSourceTest ✔
|
||||
│ └─ testPublishingPermissionsDefaultDisplayName(int, String, boolean) ✔
|
||||
│ └─ [1] USER_ID = "1001", ROLE = "EDITOR", CAN_PUBLISH = "true" ✔
|
||||
└─ JUnit Vintage ✔
|
||||
|
||||
Test run finished after 228 ms
|
||||
[ 1 tests successful ]
|
||||
[ 0 tests failed ]
|
||||
|
||||
With no custom name, useHeadersInDisplayName = true changes JUnit's own auto-generated default
|
||||
from the bare [1] "1001", "EDITOR", "true" you would otherwise get to the header-qualified
|
||||
[1] USER_ID = "1001", ROLE = "EDITOR", CAN_PUBLISH = "true" shown here. That is the documented,
|
||||
intended effect of the flag. The surprise in
|
||||
docs/output/04-csv-source-custom-name-with-headers.txt is that the exact same flag also changes
|
||||
what a *custom* name's positional placeholders resolve to, which is easy to miss if you only
|
||||
ever tested the flag against the default name.
|
||||
@@ -0,0 +1,33 @@
|
||||
Captured from a real `mvn test -Dtest=HeaderNamePlaceholderMistakeTest` run with the
|
||||
@Disabled annotation temporarily removed -- i.e. exactly
|
||||
name = "user {USER_ID} with role {ROLE}" on a real @CsvSource(useHeadersInDisplayName = true)
|
||||
test, run for real.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Test set: com.ankurm.tutorials.junit.parameterized.HeaderNamePlaceholderMistakeTest
|
||||
-------------------------------------------------------------------------------
|
||||
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.050 s <<< FAILURE! -- in com.ankurm.tutorials.junit.parameterized.HeaderNamePlaceholderMistakeTest
|
||||
com.ankurm.tutorials.junit.parameterized.HeaderNamePlaceholderMistakeTest.nameTemplateCannotReferenceHeadersByName(int, String, boolean) -- Time elapsed: 0.034 s <<< ERROR!
|
||||
org.junit.platform.commons.JUnitException: The display name pattern defined for the parameterized test is invalid. See nested exception for further details.
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
|
||||
Caused by: java.lang.IllegalArgumentException: can't parse argument number: USER_ID
|
||||
at java.base/java.text.MessageFormat.setFormatFromPattern(MessageFormat.java:1644)
|
||||
at java.base/java.text.MessageFormat.applyPatternImpl(MessageFormat.java:660)
|
||||
at java.base/java.text.MessageFormat.<init>(MessageFormat.java:516)
|
||||
... 2 more
|
||||
Caused by: java.lang.NumberFormatException: For input string: "USER_ID"
|
||||
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
|
||||
at java.base/java.lang.Integer.parseInt(Integer.java:565)
|
||||
at java.base/java.lang.Integer.parseInt(Integer.java:662)
|
||||
at java.base/java.text.MessageFormat.setFormatFromPattern(MessageFormat.java:1642)
|
||||
... 4 more
|
||||
|
||||
The stack trace gives away the mechanism: @ParameterizedTest's `name` attribute is not its own
|
||||
template language -- it compiles down to a real java.text.MessageFormat pattern, and
|
||||
MessageFormat only understands numeric argument indices ({0}, {1}, ...). "USER_ID" is not a
|
||||
number, so MessageFormat's own pattern parser throws NumberFormatException trying to read it
|
||||
as one, before the test ever runs a single invocation. useHeadersInDisplayName = true changes
|
||||
what JUnit generates automatically when no custom name is given (see
|
||||
docs/output/05-csv-source-headers-default-display-name.txt) -- it does not add a new kind of
|
||||
placeholder you can reference yourself.
|
||||
@@ -0,0 +1,23 @@
|
||||
Captured from a real `junit-platform-console-standalone --details=tree` run against
|
||||
CsvFileSourceTest, compiled and executed for real against the committed
|
||||
src/test/resources/test-data/postcode-regions.csv fixture.
|
||||
|
||||
╷
|
||||
├─ JUnit Platform Suite ✔
|
||||
├─ JUnit Jupiter ✔
|
||||
│ └─ CsvFileSourceTest ✔
|
||||
│ └─ shouldMapPostcodeToRegion(String, String) ✔
|
||||
│ ├─ postcode "SW1A" should map to region "London" ✔
|
||||
│ ├─ postcode "M1" should map to region "Manchester" ✔
|
||||
│ ├─ postcode "EH1" should map to region "Edinburgh" ✔
|
||||
│ ├─ postcode "CF10" should map to region "Cardiff" ✔
|
||||
│ └─ postcode "BT1" should map to region "Belfast" ✔
|
||||
└─ JUnit Vintage ✔
|
||||
|
||||
Test run finished after 208 ms
|
||||
[ 5 tests successful ]
|
||||
[ 0 tests failed ]
|
||||
|
||||
@CsvFileSource reads real rows from a real file on the classpath instead of inline strings --
|
||||
the five rows above are read from the CSV fixture's header row (postcode,region) plus five data
|
||||
rows, which exactly match the five entries Geocoder.java hardcodes internally.
|
||||
@@ -0,0 +1,25 @@
|
||||
Captured from a real `junit-platform-console-standalone --details=tree` run against
|
||||
EnumSourceTest, compiled and executed for real.
|
||||
|
||||
╷
|
||||
├─ JUnit Platform Suite ✔
|
||||
├─ JUnit Jupiter ✔
|
||||
│ └─ EnumSourceTest ✔
|
||||
│ ├─ nonPrivilegedRolesMustNotWrite(Role) ✔
|
||||
│ │ ├─ EDITOR must NOT have write access ✔
|
||||
│ │ ├─ USER must NOT have write access ✔
|
||||
│ │ └─ GUEST must NOT have write access ✔
|
||||
│ └─ privilegedRolesShouldHaveWriteAccess(Role) ✔
|
||||
│ ├─ ADMIN should have write access ✔
|
||||
│ └─ SUPERUSER should have write access ✔
|
||||
└─ JUnit Vintage ✔
|
||||
|
||||
Test run finished after 212 ms
|
||||
[ 5 tests successful ]
|
||||
[ 0 tests failed ]
|
||||
|
||||
Two @EnumSource tests over the same Role enum, using the two opposite selection modes:
|
||||
privilegedRolesShouldHaveWriteAccess uses mode = INCLUDE with names = {"ADMIN", "SUPERUSER"},
|
||||
and nonPrivilegedRolesMustNotWrite uses mode = EXCLUDE with the same two names -- so between
|
||||
them every one of the five Role constants is exercised exactly once, and AuthService.canWrite's
|
||||
real logic is what each assertion checks against.
|
||||
@@ -0,0 +1,19 @@
|
||||
Captured from a real `mvn test` run with badSharedConfigAccumulatesTouches NOT yet marked
|
||||
@Disabled -- i.e. exactly the code shape in the post's "BAD" example, run for real.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Test set: com.ankurm.tutorials.junit.parameterized.SharedMutableArgumentAntiPatternTest
|
||||
-------------------------------------------------------------------------------
|
||||
Tests run: 4, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.017 s <<< FAILURE! -- in com.ankurm.tutorials.junit.parameterized.SharedMutableArgumentAntiPatternTest
|
||||
com.ankurm.tutorials.junit.parameterized.SharedMutableArgumentAntiPatternTest.badSharedConfigAccumulatesTouches(Config)[2] -- Time elapsed: 0.005 s <<< FAILURE!
|
||||
org.opentest4j.AssertionFailedError: expected: <1> but was: <2>
|
||||
at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:569)
|
||||
at com.ankurm.tutorials.junit.parameterized.SharedMutableArgumentAntiPatternTest.badSharedConfigAccumulatesTouches(SharedMutableArgumentAntiPatternTest.java:23)
|
||||
|
||||
The first invocation passes (expected 1, got 1 -- the shared Config has been touched once).
|
||||
The second invocation fails with exactly the same assertion, same line number, same test
|
||||
method -- but now expects 1 and gets 2, because it is the SAME Config instance the first
|
||||
invocation already touched. Nothing about invocation 2's own code is wrong; the bug is that
|
||||
sharedProvider() built one Config and handed it to both Arguments.of(...) calls. This is
|
||||
exactly the failure mode the "fresh instance per invocation" fix in goodFreshConfigIsAlwaysTouchedOnce
|
||||
avoids -- that test passes all the way through for the identical reason this one fails.
|
||||
@@ -0,0 +1,26 @@
|
||||
Captured from a real `junit-platform-console-standalone --details=tree` run against
|
||||
SharedMutableArgumentAntiPatternTest, compiled and executed for real (badSharedConfigAccumulatesTouches
|
||||
stays @Disabled here so the module's build remains green; see
|
||||
docs/output/09-shared-mutable-argument-failure.txt for what it produces when that annotation is
|
||||
removed).
|
||||
|
||||
╷
|
||||
├─ JUnit Platform Suite ✔
|
||||
├─ JUnit Jupiter ✔
|
||||
│ └─ SharedMutableArgumentAntiPatternTest ✔
|
||||
│ ├─ badSharedConfigAccumulatesTouches(Config) ↷ Kept disabled so the module's build stays green -- see docs/output/09-shared-mutable-argument-failure.txt for the real failure this produces on its second invocation when the @Disabled annotation is removed.
|
||||
│ └─ goodFreshConfigIsAlwaysTouchedOnce(Config) ✔
|
||||
│ ├─ [1] Config[callCount=0] ✔
|
||||
│ └─ [2] Config[callCount=0] ✔
|
||||
└─ JUnit Vintage ✔
|
||||
|
||||
Test run finished after 161 ms
|
||||
[ 2 tests successful ]
|
||||
[ 0 tests failed ]
|
||||
|
||||
freshProvider() builds a new Config() inside the Stream for each Arguments.of(...) call, so each
|
||||
invocation gets its own isolated instance -- the whole fix is that simple. Both display names
|
||||
read Config[callCount=0], which is correct and not a bug: JUnit resolves each invocation's
|
||||
display name from the argument's toString() at argument-resolution time, before the test method
|
||||
body (and its config.touch() call) has run, so callCount is still 0 at the moment the name is
|
||||
built even though the assertion afterwards confirms it becomes 1.
|
||||
@@ -0,0 +1,25 @@
|
||||
Captured from a real `junit-platform-console-standalone --details=tree` run against
|
||||
MethodSourceTest, compiled and executed for real.
|
||||
|
||||
╷
|
||||
├─ JUnit Platform Suite ✔
|
||||
├─ JUnit Jupiter ✔
|
||||
│ └─ MethodSourceTest ✔
|
||||
│ └─ testUserActiveStatus(User, boolean) ✔
|
||||
│ ├─ user alice active=true ✔
|
||||
│ ├─ user bob active=true ✔
|
||||
│ └─ user carol active=false ✔
|
||||
└─ JUnit Vintage ✔
|
||||
|
||||
Test run finished after 196 ms
|
||||
[ 3 tests successful ]
|
||||
[ 0 tests failed ]
|
||||
|
||||
activeUserProvider() hands out three real User objects built with real LocalDate renewal dates.
|
||||
alice's renewalDueDate is one day in the past but still inside the 3-day grace period
|
||||
isActive() allows, and she's enabled -- active. bob's is 30 days in the future and he's
|
||||
enabled -- active. carol's date is identical to alice's (one day in the past, still within the
|
||||
grace period), but she's enabled = false -- and isActive() requires both conditions, so she's
|
||||
inactive purely because of the enabled flag, not the date. All three outcomes match
|
||||
User.isActive()'s real logic -- see the module README for why this differs from the original
|
||||
post's version of the same example.
|
||||
@@ -0,0 +1,25 @@
|
||||
Captured from a real `junit-platform-console-standalone --details=tree` run against
|
||||
FieldSourceTest, compiled and executed for real.
|
||||
|
||||
╷
|
||||
├─ JUnit Platform Suite ✔
|
||||
├─ JUnit Jupiter ✔
|
||||
│ └─ FieldSourceTest ✔
|
||||
│ └─ shouldRecognizeIsoCurrencyCode(String) ✔
|
||||
│ ├─ ISO code "USD" should be recognized ✔
|
||||
│ ├─ ISO code "EUR" should be recognized ✔
|
||||
│ ├─ ISO code "GBP" should be recognized ✔
|
||||
│ ├─ ISO code "JPY" should be recognized ✔
|
||||
│ ├─ ISO code "INR" should be recognized ✔
|
||||
│ ├─ ISO code "AUD" should be recognized ✔
|
||||
│ └─ ISO code "CHF" should be recognized ✔
|
||||
└─ JUnit Vintage ✔
|
||||
|
||||
Test run finished after 217 ms
|
||||
[ 7 tests successful ]
|
||||
[ 0 tests failed ]
|
||||
|
||||
@FieldSource reads its arguments straight from a static field rather than a method or inline
|
||||
literals -- here FieldSourceTest's own static VALID_ISO_CODES field, which is kept in lock-step
|
||||
with the real Set CurrencyService.isValidCode checks against, so the seven invocations above are
|
||||
exactly the seven codes the real service recognizes.
|
||||
@@ -0,0 +1,23 @@
|
||||
Captured from a real `junit-platform-console-standalone --details=tree` run against
|
||||
ArgumentsSourceTest, compiled and executed for real.
|
||||
|
||||
╷
|
||||
├─ JUnit Platform Suite ✔
|
||||
├─ JUnit Jupiter ✔
|
||||
│ └─ ArgumentsSourceTest ✔
|
||||
│ └─ testWithExternalScenarios(String, int, boolean) ✔
|
||||
│ ├─ scenario: "happy_path" ✔
|
||||
│ ├─ scenario: "zero_value" ✔
|
||||
│ └─ scenario: "max_boundary" ✔
|
||||
└─ JUnit Vintage ✔
|
||||
|
||||
Test run finished after 212 ms
|
||||
[ 3 tests successful ]
|
||||
[ 0 tests failed ]
|
||||
|
||||
@ArgumentsSource(ScenarioArgumentsProvider.class) delegates argument production to a real,
|
||||
separately-compiled class implementing ArgumentsProvider -- the escape hatch to reach for once a
|
||||
data source needs more structure than @MethodSource's single static method comfortably holds
|
||||
(loading fixtures, branching on environment, composing other providers). ScenarioArgumentsProvider
|
||||
overrides the current provideArguments(ParameterDeclarations, ExtensionContext) overload rather
|
||||
than the older single-argument form, which still compiles but is now deprecated.
|
||||
@@ -0,0 +1,25 @@
|
||||
Captured from a real `junit-platform-console-standalone --details=tree` run against
|
||||
ConvertWithTest, compiled and executed for real.
|
||||
|
||||
╷
|
||||
├─ JUnit Platform Suite ✔
|
||||
├─ JUnit Jupiter ✔
|
||||
│ └─ ConvertWithTest ✔
|
||||
│ └─ testDatesAreIn2023(LocalDate) ✔
|
||||
│ ├─ date "2023-01-01" should be in 2023 ✔
|
||||
│ ├─ date "2023-06-15" should be in 2023 ✔
|
||||
│ └─ date "2023-12-31" should be in 2023 ✔
|
||||
└─ JUnit Vintage ✔
|
||||
|
||||
Test run finished after 146 ms
|
||||
[ 3 tests successful ]
|
||||
[ 0 tests failed ]
|
||||
|
||||
The @ValueSource arguments are plain ISO-format date strings; @ConvertWith(DashDateConverter.class)
|
||||
is what turns each one into a real java.time.LocalDate before the test method ever sees it, via
|
||||
DashDateConverter's own SimpleArgumentConverter.convert() override. JUnit actually has an
|
||||
implicit String-to-LocalDate conversion for this exact ISO shape, so this particular example
|
||||
would work without @ConvertWith too -- it's shown here because the same mechanism is what you
|
||||
reach for once the source strings need a format or extra validation JUnit's implicit converters
|
||||
don't cover, and DashDateConverter.java is the smallest possible shape to build that converter
|
||||
in when the need arises.
|
||||
@@ -0,0 +1,31 @@
|
||||
Captured from a real `junit-platform-console-standalone --details=tree` run against
|
||||
MixedAssertionsAntiPatternTest, compiled and executed for real.
|
||||
|
||||
╷
|
||||
├─ JUnit Platform Suite ✔
|
||||
├─ JUnit Jupiter ✔
|
||||
│ └─ MixedAssertionsAntiPatternTest ✔
|
||||
│ ├─ adminShouldDelete(Role) ✔
|
||||
│ │ └─ [1] ADMIN ✔
|
||||
│ ├─ testPermissions(String, boolean, boolean) ✔
|
||||
│ │ ├─ [1] "ADMIN", "true", "true" ✔
|
||||
│ │ └─ [2] "GUEST", "false", "true" ✔
|
||||
│ └─ allRolesShouldRead(Role) ✔
|
||||
│ ├─ [1] ADMIN ✔
|
||||
│ ├─ [2] SUPERUSER ✔
|
||||
│ ├─ [3] EDITOR ✔
|
||||
│ ├─ [4] USER ✔
|
||||
│ └─ [5] GUEST ✔
|
||||
└─ JUnit Vintage ✔
|
||||
|
||||
Test run finished after 246 ms
|
||||
[ 8 tests successful ]
|
||||
[ 0 tests failed ]
|
||||
|
||||
testPermissions is the BAD example: one parameterized test asserting two unrelated behaviors
|
||||
(canDelete and canRead) per row, so a failure in either one just says "testPermissions failed"
|
||||
without telling you which behavior broke. It passes here -- this is a design-smell illustration,
|
||||
not a test that's expected to fail -- but a reader who only sees it pass has no way to tell
|
||||
canDelete and canRead apart from the test name alone. adminShouldDelete and allRolesShouldRead
|
||||
are the fix: the same two behaviors, split into two single-assertion parameterized tests, each
|
||||
with a display name that says exactly what broke if it ever does.
|
||||
@@ -0,0 +1,21 @@
|
||||
Captured from a real `junit-platform-console-standalone --details=tree` run against
|
||||
DisplayNameTest, compiled and executed for real.
|
||||
|
||||
╷
|
||||
├─ JUnit Platform Suite ✔
|
||||
├─ JUnit Jupiter ✔
|
||||
│ └─ DisplayNameTest ✔
|
||||
│ └─ shouldMultiply(int, int, int) ✔
|
||||
│ ├─ [1] "3" × "4" = "12" ✔
|
||||
│ ├─ [2] "0" × "5" = "0" ✔
|
||||
│ └─ [3] "-2" × "3" = "-6" ✔
|
||||
└─ JUnit Vintage ✔
|
||||
|
||||
Test run finished after 173 ms
|
||||
[ 3 tests successful ]
|
||||
[ 0 tests failed ]
|
||||
|
||||
name = "[{index}] {0} × {1} = {2}" combines the built-in {index} keyword (the invocation's
|
||||
1-based position) with the three positional argument placeholders and a literal Unicode
|
||||
multiplication sign, to produce a display name that reads like the actual arithmetic the test
|
||||
is checking rather than a generic "[1] 3, 4, 12".
|
||||
@@ -0,0 +1,46 @@
|
||||
Captured from a real `mvn clean test` run against the whole module, as committed.
|
||||
|
||||
[INFO] -------------------------------------------------------
|
||||
[INFO] T E S T S
|
||||
[INFO] -------------------------------------------------------
|
||||
[INFO] Running com.ankurm.tutorials.junit.parameterized.ConvertWithTest
|
||||
[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.129 s -- in com.ankurm.tutorials.junit.parameterized.ConvertWithTest
|
||||
[INFO] Running com.ankurm.tutorials.junit.parameterized.HeaderNamePlaceholderMistakeTest
|
||||
[WARNING] Tests run: 1, Failures: 0, Errors: 0, Skipped: 1, Time elapsed: 0.003 s -- in com.ankurm.tutorials.junit.parameterized.HeaderNamePlaceholderMistakeTest
|
||||
[INFO] Running com.ankurm.tutorials.junit.parameterized.MethodSourceTest
|
||||
[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.073 s -- in com.ankurm.tutorials.junit.parameterized.MethodSourceTest
|
||||
[INFO] Running com.ankurm.tutorials.junit.parameterized.NullAndEmptySourceTest
|
||||
[INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.022 s -- in com.ankurm.tutorials.junit.parameterized.NullAndEmptySourceTest
|
||||
[INFO] Running com.ankurm.tutorials.junit.parameterized.EnumSourceTest
|
||||
[INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.022 s -- in com.ankurm.tutorials.junit.parameterized.EnumSourceTest
|
||||
[INFO] Running com.ankurm.tutorials.junit.parameterized.MixedAssertionsAntiPatternTest
|
||||
[INFO] Tests run: 8, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.089 s -- in com.ankurm.tutorials.junit.parameterized.MixedAssertionsAntiPatternTest
|
||||
[INFO] Running com.ankurm.tutorials.junit.parameterized.CsvSourceTest
|
||||
[INFO] Tests run: 8, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.046 s -- in com.ankurm.tutorials.junit.parameterized.CsvSourceTest
|
||||
[INFO] Running com.ankurm.tutorials.junit.parameterized.CsvFileSourceTest
|
||||
[INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.024 s -- in com.ankurm.tutorials.junit.parameterized.CsvFileSourceTest
|
||||
[INFO] Running com.ankurm.tutorials.junit.parameterized.FieldSourceTest
|
||||
[INFO] Tests run: 7, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.025 s -- in com.ankurm.tutorials.junit.parameterized.FieldSourceTest
|
||||
[INFO] Running com.ankurm.tutorials.junit.parameterized.ArgumentsSourceTest
|
||||
[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.006 s -- in com.ankurm.tutorials.junit.parameterized.ArgumentsSourceTest
|
||||
[INFO] Running com.ankurm.tutorials.junit.parameterized.DisplayNameTest
|
||||
[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.012 s -- in com.ankurm.tutorials.junit.parameterized.DisplayNameTest
|
||||
[INFO] Running com.ankurm.tutorials.junit.parameterized.SharedMutableArgumentAntiPatternTest
|
||||
[WARNING] Tests run: 3, Failures: 0, Errors: 0, Skipped: 1, Time elapsed: 0.009 s -- in com.ankurm.tutorials.junit.parameterized.SharedMutableArgumentAntiPatternTest
|
||||
[INFO] Running com.ankurm.tutorials.junit.parameterized.ValueSourceTest
|
||||
[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.007 s -- in com.ankurm.tutorials.junit.parameterized.ValueSourceTest
|
||||
[INFO]
|
||||
[INFO] Results:
|
||||
[INFO]
|
||||
[WARNING] Tests run: 57, Failures: 0, Errors: 0, Skipped: 2
|
||||
[INFO]
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] BUILD SUCCESS
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
|
||||
57 tests, 0 failures, 2 skipped. The two skips are HeaderNamePlaceholderMistakeTest and
|
||||
SharedMutableArgumentAntiPatternTest#badSharedConfigAccumulatesTouches -- both deliberately
|
||||
@Disabled so the committed build stays green, each with its own captured real failure
|
||||
(docs/output/06-header-name-placeholder-throws.txt and
|
||||
docs/output/09-shared-mutable-argument-failure.txt) from the one time each was temporarily
|
||||
re-enabled and run for real.
|
||||
Reference in New Issue
Block a user