Skip to content

Commit

Permalink
Improve Cartesian test documentation (#665 / #666)
Browse files Browse the repository at this point in the history
`@CartesianTest.MethodFactory`-annotated methods can be non-static
under certain circumstances, but the demo snippets showed non-static
factory methods that didn't match these and were thus wrong. This
change fixes that, which required moving the factory methods from
non-static inner classes into the outer class. For conistency and to
make things easier in the future, the same was done for all other
snippets as well.

The snippets were prepended with imports, which was incoherent when
the snippets turned from classes to just methods. Hence the imports
were removed as well, which has the eadded benefit of not having to
maintain the imports and making the snippets shorter.

Closes: #665
PR: #666
  • Loading branch information
nipafx committed Sep 19, 2022
1 parent 01713d7 commit 2038be8
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 269 deletions.
119 changes: 12 additions & 107 deletions docs/cartesian-product.adoc
Expand Up @@ -27,23 +27,21 @@ NOTE: The CartesianTest extension has undergone significant changes in 1.6.0.
This included moving it into a new package.
link:/docs/cartesian-product-v1[The old variant] is deprecated and will be removed in the 2.0 release (tentatively scheduled for 2022).

== Basic Use
== Basic use

`@CartesianTest` is used _instead_ of `@Test` or other such annotations (e.g. `@RepeatedTest`).

You can supply test parameters to `@CartesianTest` in two ways:

- You can annotate your test method, providing all parameter values in a single annotation.
- The test parameters can be annotated with `@CartesianTest.Values`, `@CartesianTest.Enum`, or range source annotations (see <<Annotating your test parameters>>)
- You can annotate the test parameters directly with `@CartesianTest.Values`, `@CartesianTest.Enum`, or range source annotations (see <<Defining arguments on parameters>>)
- You can annotate test method itself with `@CartesianTest.MethodFactory` to point at a factory method that creates sets of arguments (see <<Defining arguments with factories>>)

Specifying more than one kind of parameter source (i.e.: annotating your test parameters and the test method itself) does not work and will throw an `ExtensionConfigurationException`.

Our earlier example with `{ 1, 2 }` and `{ 3, 4 }`, would look like this:

[source,java,indent=0]
----
import org.junitpioneer.jupiter.cartesian.CartesianTest.Values;
include::{demo}[tag=cartesian_simple_demo]
----

Expand All @@ -56,21 +54,14 @@ If your input is `{ 1, 1, 3 }` and `{ 2, 2 }` the extension will consider their
Otherwise, the test would run with the same parameters multiple times.
If you need to pass the same parameters multiple times, you might want to look into https://junit.org/junit5/docs/current/user-guide/#writing-tests-repeated-tests[repeated tests].

== Annotating your test parameters
== Defining arguments on parameters

You can annotate the parameters of your `@CartesianTest`, to provide values to that specific parameter.
Parameter annotations are "self-contained", they only provide values to the parameter they are on and do not interfere with each other.
You can mix and match parameter annotations as you need.

[source,java,indent=0]
----
import java.time.temporal.ChronoUnit;
import org.junitpioneer.jupiter.cartesian.*;
import org.junitpioneer.jupiter.params.*;
import org.junitpioneer.jupiter.cartesian.CartesianTest.Values;
import org.junitpioneer.jupiter.cartesian.CartesianTest.Enum;
include::{demo}[tag=cartesian_annotating_parameters]
----

Expand All @@ -81,9 +72,6 @@ The test will try every combination those values can have.

[source,java,indent=0]
----
import org.junitpioneer.jupiter.cartesian.*;
import org.junitpioneer.jupiter.cartesian.CartesianTest.Values;
include::{demo}[tag=cartesian_combining_values]
----

Expand Down Expand Up @@ -113,11 +101,6 @@ To demonstrate with a table:

[source,java,indent=0]
----
import java.time.temporal.ChronoUnit;
import org.junitpioneer.jupiter.cartesian.*;
import org.junitpioneer.jupiter.cartesian.CartesianTest.Enum;
include::{demo}[tag=cartesian_with_enum]
----

Expand All @@ -131,11 +114,6 @@ The `value` attribute is required in the following example because the method pa

[source,java,indent=0]
----
import java.time.temporal.*;
import org.junitpioneer.jupiter.cartesian.*;
import org.junitpioneer.jupiter.cartesian.CartesianTest.Enum;
include::{demo}[tag=cartesian_enum_with_type]
----

Expand All @@ -144,11 +122,6 @@ If omitted, all constants will be used.

[source,java,indent=0]
----
import java.time.temporal.*;
import org.junitpioneer.jupiter.cartesian.*;
import org.junitpioneer.jupiter.cartesian.CartesianTest.Enum;
include::{demo}[tag=cartesian_enum_with_type_and_names]
----

Expand All @@ -157,31 +130,18 @@ For example, you can exclude names from the enum constant pool or specify regula

[source,java,indent=0]
----
import java.time.temporal.*;
import org.junitpioneer.jupiter.cartesian.*;
import org.junitpioneer.jupiter.cartesian.CartesianTest.Enum;
include::{demo}[tag=cartesian_enum_with_mode]
----

[source,java,indent=0]
----
import java.time.temporal.*;
import org.junitpioneer.jupiter.cartesian.*;
import org.junitpioneer.jupiter.cartesian.CartesianTest.Enum;
include::{demo}[tag=cartesian_enum_with_regex]
----

The example below shows how to use `@CartesianTest.Enum` with two `Enum` types.

[source,java,indent=0]
----
import org.junitpioneer.jupiter.cartesian.*;
import org.junitpioneer.jupiter.cartesian.CartesianTest.Enum;
include::{demo}[tag=cartesian_enum_with_enums]
----

Expand All @@ -202,16 +162,13 @@ To demonstrate with a table:
| 6th test | THREE | GAMMA
|===

=== Range Source annotations
=== Range source annotations

You can annotate your test parameters with link:docs/range-sources[range source annotations].
For _this purpose only_, range sources can be used on parameters.

[source,java,indent=0]
----
import org.junitpioneer.jupiter.cartesian.*;
import org.junitpioneer.jupiter.params.*;
include::{demo}[tag=cartesian_enum_with_range_sources]
----

Expand All @@ -233,7 +190,7 @@ To demonstrate with a table:

For more information, please see the link:docs/range-sources[separate documentation about range sources].

== Annotating your test method
== Defining arguments with factories

You can annotate your test method to supply arguments to all parameters simultaneously.

Expand All @@ -245,9 +202,9 @@ Just like with JUnit's `@MethodSource`, you can specify the factory method with
This method must return `ArgumentSets`.

`ArgumentSets` is a helper class, specifically for creating sets for `@CartesianTest`.
To create the test data, instantiate with the static factory method `argumentsForFirstParameter`, then call the `addValuesForNextParameter` method once per additional parameter in the order in which the they appear in the test method.
To create the test data, instantiate with the static factory method `argumentsForFirstParameter`, then call the `addValuesForNextParameter` method once per additional parameter in the order in which they appear in the test method.
In each call, pass in all values for the corresponding parameter.
For convenience, all methods return with your `ArgumentSets` instance, so you can chain `add()` calls.
For convenience, all methods return with your `ArgumentSets` instance, so you can chain `add...` calls.
If you want to create an initially-empty `ArgumentSets`, call the static factory method `create()`.

Let's look at an example.
Expand Down Expand Up @@ -288,11 +245,11 @@ You can reuse the same argument provider method multiple times.
include::{demo}[tag=cartesian_argument_sets_reuse]
----

You can use an argument provider method in nested classes, as long as these are annotated with `@TestInstance(Lifecycle.PER_CLASS)`.
You can make the argument provider method non-static if the test class is annotated with `@TestInstance(Lifecycle.PER_CLASS)`.

[source,java,indent=0]
----
include::{demo}[tag=cartesian_argument_sets_with_nested_classes]
include::{demo}[tag=cartesian_argument_sets_with_non_static_factory]
----

==== Requirements for the factory method
Expand Down Expand Up @@ -341,10 +298,7 @@ Let's create an annotation for it.

[source,java,indent=0]
----
import java.lang.annotation.*;
import org.junitpioneer.jupiter.cartesian.CartesianArgumentsSource;
include::{demo}[tag=cartesian_argument_sets_int_argument_provider]
include::{demo}[tag=cartesian_argument_sets_ints_annotation]
----

The annotation targets parameters because we want to use it directly on a parameter.
Expand All @@ -355,15 +309,7 @@ Next, we need to implement `IntArgumentsProvider`, that takes these values and p

[source,java,indent=0]
----
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Stream;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junitpioneer.jupiter.cartesian.CartesianParameterArgumentsProvider;
include::{demo}[tag=cartesian_argument_sets_ints_annotation]
include::{demo}[tag=cartesian_argument_sets_int_argument_provider]
----

The class has to implement `CartesianParameterArgumentsProvider`.
Expand All @@ -376,14 +322,6 @@ You could do additional processing, for example:

[source,java,indent=0]
----
import java.lang.annotation.*;
import java.util.*;
import java.lang.reflect.Parameter;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junitpioneer.jupiter.cartesian.CartesianArgumentsSource;
import org.junitpioneer.jupiter.cartesian.CartesianParameterArgumentsProvider;
include::{people}[tag=cartesian_people_provider_with_CartesianParameterArgumentsProvider]
----

Expand All @@ -392,15 +330,6 @@ The previous example would look like the following:

[source,java,indent=0]
----
import java.lang.annotation.*;
import java.util.*;
import java.lang.reflect.Parameter;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.support.AnnotationConsumer;
import org.junitpioneer.jupiter.cartesian.CartesianArgumentsSource;
import org.junitpioneer.jupiter.cartesian.CartesianParameterArgumentsProvider;
include::{people}[tag=cartesian_people_provider_with_AnnotationConsumer]
----

Expand All @@ -416,9 +345,6 @@ Let's create an annotation for it.

[source,java,indent=0]
----
import java.lang.annotation.*;
import org.junitpioneer.jupiter.cartesian.CartesianArgumentsSource;
include::{bit}[tag=cartesian_bit_source_annotation]
----

Expand All @@ -430,14 +356,6 @@ Next, we need to implement `BitArgumentsProvider`.

[source,java,indent=0]
----
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Stream;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junitpioneer.jupiter.cartesian.CartesianMethodArgumentsProvider;
include::{bit}[tag=cartesian_bit_argument_provider]
----

Expand All @@ -454,16 +372,6 @@ For example:

[source,java,indent=0]
----
import java.lang.annotation.*;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Stream;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junitpioneer.jupiter.cartesian.CartesianArgumentsSource;
import org.junitpioneer.jupiter.cartesian.CartesianMethodArgumentsProvider;
include::{number}[tag=cartesian_number_argument_provider]
----

Expand All @@ -475,9 +383,6 @@ For example:

[source,java,indent=0]
----
import org.junitpioneer.jupiter.cartesian.*;
import org.junitpioneer.jupiter.cartesian.CartesianTest.Values;
include::{demo}[tag=cartesian_testWithCustomDisplayName]
----

Expand Down

0 comments on commit 2038be8

Please sign in to comment.