Skip to content

Commit

Permalink
Improve documentation of custom implementations for parameterized tests
Browse files Browse the repository at this point in the history
This commit documents that custom implementations of APIs must be
either top-level or static nested classes.

This commit also ensures code listings for example implementations are
separated if appropriate.
  • Loading branch information
sbrannen committed Sep 10, 2018
1 parent 2529ceb commit f05bb52
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 13 deletions.
39 changes: 35 additions & 4 deletions documentation/src/docs/asciidoc/user-guide/writing-tests.adoc
Expand Up @@ -983,13 +983,20 @@ primitive type.
[[writing-tests-parameterized-tests-sources-ArgumentsSource]]
===== @ArgumentsSource

`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`.
`@ArgumentsSource` can be used to specify a custom, reusable `ArgumentsProvider`. Note
that an implementation of `ArgumentsProvider` must be declared as either a top-level
class or as a `static` nested class.

[source,java,indent=0]
----
include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsSource_example]
----

[source,java,indent=0]
----
include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsProvider_example]
----


[[writing-tests-parameterized-tests-argument-conversion]]
==== Argument Conversion
Expand Down Expand Up @@ -1072,7 +1079,8 @@ method_ or a _factory constructor_ as defined below.
accepts a single `String` argument and returns an instance of the target type. The name
of the method can be arbitrary and need not follow any particular convention.
- __factory constructor__: a non-private constructor in the target type that accepts a
single `String` argument.
single `String` argument. Note that the target type must be declared as either a
top-level class or as a `static` nested class.

NOTE: If multiple _factory methods_ are discovered, they will be ignored. If a _factory
method_ and a _factory constructor_ are discovered, the factory method will be used
Expand All @@ -1087,18 +1095,29 @@ as the title of the book.
include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example]
----

[source,java,indent=0]
----
include::{testDir}/example/ParameterizedTestDemo.java[tags=implicit_fallback_conversion_example_Book]
----

[[writing-tests-parameterized-tests-argument-conversion-explicit]]
===== Explicit Conversion

Instead of relying on implicit argument conversion you may explicitly specify an
`ArgumentConverter` to use for a certain parameter using the `@ConvertWith` annotation
like in the following example.
like in the following example. Note that an implementation of `ArgumentConverter` must be
declared as either a top-level class or as a `static` nested class.

[source,java,indent=0]
----
include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example]
----

[source,java,indent=0]
----
include::{testDir}/example/ParameterizedTestDemo.java[tags=explicit_conversion_example_ToStringArgumentConverter]
----

Explicit argument converters are meant to be implemented by test and extension authors.
Thus, `junit-jupiter-params` only provides a single explicit argument converter that may
also serve as a reference implementation: `JavaTimeArgumentConverter`. It is used via the
Expand Down Expand Up @@ -1139,13 +1158,20 @@ _aggregators_.
To use a custom aggregator simply implement the `{ArgumentsAggregator}` interface and
register it via the `@AggregateWith` annotation on a compatible parameter in the
`@ParameterizedTest` method. The result of the aggregation will then be provided as an
argument for the corresponding parameter when the parameterized test is invoked.
argument for the corresponding parameter when the parameterized test is invoked. Note
that an implementation of `ArgumentsAggregator` must be declared as either a top-level
class or as a `static` nested class.

[source,java,indent=0]
----
include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example]
----

[source,java,indent=0]
----
include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_example_PersonAggregator]
----

If you find yourself repeatedly declaring `@AggregateWith(MyTypeAggregator.class)` for
multiple parameterized test methods across your codebase, you may wish to create a custom
_composed annotation_ such as `@CsvToMyType` that is meta-annotated with
Expand All @@ -1157,6 +1183,11 @@ action with a custom `@CsvToPerson` annotation.
include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example]
----

[source,java,indent=0]
----
include::{testDir}/example/ParameterizedTestDemo.java[tags=ArgumentsAggregator_with_custom_annotation_example_CsvToPerson]
----


[[writing-tests-parameterized-tests-display-names]]
==== Customizing Display Names
Expand Down
20 changes: 11 additions & 9 deletions documentation/src/test/java/example/ParameterizedTestDemo.java
Expand Up @@ -201,15 +201,15 @@ void testWithArgumentsSource(String argument) {

// end::ArgumentsSource_example[]
static
// tag::ArgumentsSource_example[]
// tag::ArgumentsProvider_example[]
public class MyArgumentsProvider implements ArgumentsProvider {

@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
return Stream.of("foo", "bar").map(Arguments::of);
}
}
// end::ArgumentsSource_example[]
// end::ArgumentsProvider_example[]

// tag::ParameterResolver_example[]
@BeforeEach
Expand Down Expand Up @@ -246,7 +246,7 @@ void testWithImplicitFallbackArgumentConversion(Book book) {

// end::implicit_fallback_conversion_example[]
static
// tag::implicit_fallback_conversion_example[]
// tag::implicit_fallback_conversion_example_Book[]
public class Book {

private final String title;
Expand All @@ -263,7 +263,7 @@ public String getTitle() {
return this.title;
}
}
// end::implicit_fallback_conversion_example[]
// end::implicit_fallback_conversion_example_Book[]

// @formatter:off
// tag::explicit_conversion_example[]
Expand All @@ -277,7 +277,7 @@ void testWithExplicitArgumentConversion(

// end::explicit_conversion_example[]
static
// tag::explicit_conversion_example[]
// tag::explicit_conversion_example_ToStringArgumentConverter[]
public class ToStringArgumentConverter extends SimpleArgumentConverter {

@Override
Expand All @@ -286,7 +286,7 @@ protected Object convert(Object source, Class<?> targetType) {
return String.valueOf(source);
}
}
// end::explicit_conversion_example[]
// end::explicit_conversion_example_ToStringArgumentConverter[]

// tag::explicit_java_time_converter[]
@ParameterizedTest
Expand Down Expand Up @@ -337,7 +337,7 @@ void testWithArgumentsAggregator(@AggregateWith(PersonAggregator.class) Person p

// end::ArgumentsAggregator_example[]
static
// tag::ArgumentsAggregator_example[]
// tag::ArgumentsAggregator_example_PersonAggregator[]
public class PersonAggregator implements ArgumentsAggregator {
@Override
public Person aggregateArguments(ArgumentsAccessor arguments, ParameterContext context) {
Expand All @@ -347,7 +347,7 @@ public Person aggregateArguments(ArgumentsAccessor arguments, ParameterContext c
arguments.get(3, LocalDate.class));
}
}
// end::ArgumentsAggregator_example[]
// end::ArgumentsAggregator_example_PersonAggregator[]
// @formatter:on

// @formatter:off
Expand All @@ -360,13 +360,15 @@ public Person aggregateArguments(ArgumentsAccessor arguments, ParameterContext c
void testWithCustomAggregatorAnnotation(@CsvToPerson Person person) {
// perform assertions against person
}
// end::ArgumentsAggregator_with_custom_annotation_example[]

// tag::ArgumentsAggregator_with_custom_annotation_example_CsvToPerson[]
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@AggregateWith(PersonAggregator.class)
public @interface CsvToPerson {
}
// end::ArgumentsAggregator_with_custom_annotation_example[]
// end::ArgumentsAggregator_with_custom_annotation_example_CsvToPerson[]
// @formatter:on

// tag::custom_display_names[]
Expand Down

0 comments on commit f05bb52

Please sign in to comment.