TestParameterInjector
=====================

[Link to Javadoc.](https://google.github.io/TestParameterInjector/docs/latest/)

## Introduction

`TestParameterInjector` is a JUnit4 test runner that runs its test methods for
different combinations of field/parameter values.

Parameterized tests are a great way to avoid code duplication between tests and
promote high test coverage for data-driven tests.

There are a lot of alternative parameterized test frameworks, such as
[junit.runners.Parameterized](https://github.com/junit-team/junit4/wiki/parameterized-tests)
and [JUnitParams](https://github.com/Pragmatists/JUnitParams). We believe
`TestParameterInjector` is an improvement of those because it is more powerful
and simpler to use.

[This blogpost](https://opensource.googleblog.com/2021/03/introducing-testparameterinjector.html)
goes into a bit more detail about how `TestParameterInjector` compares to other
frameworks used at Google.

## Getting started

To start using `TestParameterInjector` right away, copy the following snippet:

```java
import com.google.testing.junit.testparameterinjector.TestParameterInjector;
import com.google.testing.junit.testparameterinjector.TestParameter;

@RunWith(TestParameterInjector.class)
public class MyTest {

  @TestParameter boolean isDryRun;

  @Test public void test1(@TestParameter boolean enableFlag) {
    // ...
  }

  @Test public void test2(@TestParameter MyEnum myEnum) {
    // ...
  }

  enum MyEnum { VALUE_A, VALUE_B, VALUE_C }
}
```

And add the following dependency to your `.pom` file:

```xml

  com.google.testparameterinjector
  test-parameter-injector
  1.4

```

or see [this maven.org
page](https://search.maven.org/artifact/com.google.testparameterinjector/test-parameter-injector)
for instructions for other build tools.


## Basics

### `@TestParameter` for testing all combinations

#### Parameterizing a single test method

The simplest way to use this library is to use `@TestParameter`. For example:

```java
@RunWith(TestParameterInjector.class)
public class MyTest {

  @Test
  public void test(@TestParameter boolean isOwner) {...}
}
```

In this example, two tests will be automatically generated by the test framework:

-   One with `isOwner` set to `true`
-   One with `isOwner` set to `false`

When running the tests, the result will show the following test names:

```
MyTest#test[isOwner=true]
MyTest#test[isOwner=false]
```

#### Parameterizing the whole class

`@TestParameter` can also annotate a field:

```java
@RunWith(TestParameterInjector.class)
public class MyTest {

  @TestParameter private boolean isOwner;

  @Test public void test1() {...}
  @Test public void test2() {...}
}
```

In this example, both `test1` and `test2` will be run twice (once for each
parameter value).

#### Supported types

The following examples show most of the supported types. See the `@TestParameter` javadoc for more details. 

```java
// Enums
@TestParameter AnimalEnum a; // Implies all possible values of AnimalEnum
@TestParameter({"CAT", "DOG"}) AnimalEnum a; // Implies AnimalEnum.CAT and AnimalEnum.DOG.

// Strings
@TestParameter({"cat", "dog"}) String animalName;

// Java primitives
@TestParameter boolean b; // Implies {true, false}
@TestParameter({"1", "2", "3"}) int i;
@TestParameter({"1", "1.5", "2"}) double d;

// Bytes
@TestParameter({"!!binary 'ZGF0YQ=='", "some_string"}) byte[] bytes;
```

For non-primitive types (e.g. String, enums, bytes), `"null"` is always parsed as the `null` reference.

#### Multiple parameters: All combinations are run

If there are multiple `@TestParameter`-annotated values applicable to one test
method, the test is run for all possible combinations of those values. Example:

```java
@RunWith(TestParameterInjector.class)
public class MyTest {

  @TestParameter private boolean a;

  @Test public void test1(@TestParameter boolean b, @TestParameter boolean c) {
    // Run for these combinations:
    //   (a=false, b=false, c=false)
    //   (a=false, b=false, c=true )
    //   (a=false, b=true,  c=false)
    //   (a=false, b=true,  c=true )
    //   (a=true,  b=false, c=false)
    //   (a=true,  b=false, c=true )
    //   (a=true,  b=true,  c=false)
    //   (a=true,  b=true,  c=true )
  }
}
```

If you want to explicitly define which combinations are run, see the next
sections.

### Use a test enum for enumerating more complex parameter combinations

Use this strategy if you want to:

-   Explicitly specify the combination of parameters
-   or your parameters are too large to be encoded in a `String` in a readable
    way

Example:

```java
@RunWith(TestParameterInjector.class)
class MyTest {

  enum FruitVolumeTestCase {
    APPLE(Fruit.newBuilder().setName("Apple").setShape(SPHERE).build(), /* expectedVolume= */ 3.1),
    BANANA(Fruit.newBuilder().setName("Banana").setShape(CURVED).build(), /* expectedVolume= */ 2.1),
    MELON(Fruit.newBuilder().setName("Melon").setShape(SPHERE).build(), /* expectedVolume= */ 6);

    final Fruit fruit;
    final double expectedVolume;

    FruitVolumeTestCase(Fruit fruit, double expectedVolume) { ... }
  }

  @Test
  public void calculateVolume_success(@TestParameter FruitVolumeTestCase fruitVolumeTestCase) {
    assertThat(calculateVolume(fruitVolumeTestCase.fruit))
        .isEqualTo(fruitVolumeTestCase.expectedVolume);
  }
}
```

The enum constant name has the added benefit of making for sensible test names:

```
MyTest#calculateVolume_success[APPLE]
MyTest#calculateVolume_success[BANANA]
MyTest#calculateVolume_success[MELON]
```

### `@TestParameters` for defining sets of parameters

You can also explicitly enumerate the sets of test parameters via a list of YAML
mappings:

```java
@Test
@TestParameters({
  "{age: 17, expectIsAdult: false}",
  "{age: 22, expectIsAdult: true}",
})
public void personIsAdult(int age, boolean expectIsAdult) { ... }
```

The string format supports the same types as `@TestParameter` (e.g. enums). See
the `@TestParameters` javadoc for more info.

`@TestParameters` works in the same way on the constructor, in which case all
tests will be run for the given parameter sets.

## Advanced usage

### Dynamic parameter generation for `@TestParameter`

Instead of providing a list of parsable strings, you can implement your own
`TestParameterValuesProvider` as follows:

```java
@Test
public void matchesAllOf_throwsOnNull(
    @TestParameter(valuesProvider = CharMatcherProvider.class) CharMatcher charMatcher) {
  assertThrows(NullPointerException.class, () -> charMatcher.matchesAllOf(null));
}

private static final class CharMatcherProvider implements TestParameterValuesProvider {
  @Override
  public List provideValues() {
    return ImmutableList.of(CharMatcher.any(), CharMatcher.ascii(), CharMatcher.whitespace());
  }
}
```

Note that `provideValues()` dynamically construct the returned list, e.g. by
reading a file. There are no restrictions on the object types returned, but note
that `toString()` will be used for the test names.

### Dynamic parameter generation for `@TestParameters`

Instead of providing a YAML mapping of parameters, you can implement your own
`TestParametersValuesProvider` as follows:

```java
@Test
@TestParameters(valuesProvider = IsAdultValueProvider.class)
public void personIsAdult(int age, boolean expectIsAdult) { ... }

static final class IsAdultValueProvider implements TestParametersValuesProvider {
  @Override public ImmutableList provideValues() {
    return ImmutableList.of(
      TestParametersValues.builder()
        .name("teenager")
        .addParameter("age", 17)
        .addParameter("expectIsAdult", false)
        .build(),
      TestParametersValues.builder()
        .name("young adult")
        .addParameter("age", 22)
        .addParameter("expectIsAdult", true)
        .build()
    );
  }
}
```