GitPedia

TestParameterInjector

A simple yet powerful parameterized test runner for Java.

From google·Updated June 4, 2026·View on GitHub·

[Link to Javadoc.](https://google.github.io/TestParameterInjector/docs/latest/) The project is written primarily in Java, distributed under the Apache License 2.0 license, first published in 2021. Key topics include: java, junit4, junit5, parameterized-tests, testing.

Latest release: v1.0TestParameterInjector 1.0 release
March 11, 2021View Changelog →

TestParameterInjector

Link to Javadoc.

Introduction

TestParameterInjector is a JUnit4 and JUnit5 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
and JUnitParams. We believe
TestParameterInjector is an improvement of those because it is more powerful
and simpler to use.

This blogpost
goes into a bit more detail about how TestParameterInjector compares to other
frameworks used at Google.

Getting started

<details> <summary><b>JUnit4 (Java)</b></summary>

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; import com.google.testing.junit.testparameterinjector.TestParameters; @RunWith(TestParameterInjector.class) public class MyTest { @TestParameter boolean isDryRun; enum FetchResponseCode { FOUND, NOT_FOUND, ERROR } @Test public void test1(@TestParameter FetchResponseCode responseCode) { // This test method is run 6 times for all combinations of isDryRun and responseCode } @Test public void test2( @TestParameter boolean withDeadline, @TestParameter({"20", "100"}) int limit) { // This test method is run 2*2*2=8 times } @Test @TestParameters("{age: 17, expectIsAdult: false}") @TestParameters("{age: 22, expectIsAdult: true}") public void test3(int age, boolean expectIsAdult) { // This test method is run 4 times: // - isDryRun=false, age=17, expectIsAdult=false // - isDryRun=false, age=22, expectIsAdult=true // - isDryRun=true, age=17, expectIsAdult=false // - isDryRun=true, age=22, expectIsAdult=true } }

And add the following dependency to your .pom file:

xml
<dependency> <groupId>com.google.testparameterinjector</groupId> <artifactId>test-parameter-injector</artifactId> <version>1.22</version> <scope>test</scope> </dependency>

or see this Maven
page

for instructions for other build tools.

Additionally, Java needs to be compiled with the -parameters compiler option.
This can be done for example:

  • In Maven with the maven-compiler-plugin: Add <parameters>true</parameters> to <configuration>
  • With Gradle: Add options.compilerArgs << "-parameters"
</details> <details> <summary><b>JUnit4 (Kotlin)</b></summary>

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

kotlin
import com.google.testing.junit.testparameterinjector.TestParameterInjector import com.google.testing.junit.testparameterinjector.TestParameter import com.google.testing.junit.testparameterinjector.KotlinTestParameters.testValues @RunWith(TestParameterInjector::class) class MyTest( @TestParameter val isDryRun: Boolean ) { enum class FetchResponseCode { FOUND, NOT_FOUND, ERROR } @Test fun test1(@TestParameter responseCode: FetchResponseCode) { // This test method is run 6 times for all combinations of isDryRun and responseCode } @Test fun test2( @TestParameter withDeadline: Boolean @TestParameter limit: Int = testValues(20, 100)) { // This test method is run 2*2*2=8 times } data class AgeCheckTestCase(val age: Int, val expectIsAdult: Boolean) @Test fun test3( @TestParameter testCase: AgeCheckTestCase = testValues( AgeCheckTestCase(17, false), AgeCheckTestCase(22, true), ) ) { // This test method is run 4 times: // - isDryRun=false, testCase=AgeCheckTestCase(17, false) // - isDryRun=false, testCase=AgeCheckTestCase(22, true) // - isDryRun=true, testCase=AgeCheckTestCase(17, false) // - isDryRun=true, testCase=AgeCheckTestCase(22, true) } }

And add the following dependency to your .pom file:

xml
<dependency> <groupId>com.google.testparameterinjector</groupId> <artifactId>test-parameter-injector</artifactId> <version>1.22</version> <scope>test</scope> </dependency>

or see this Maven
page

for instructions for other build tools.

</details> <details> <summary><b>JUnit5 (Jupiter)</b></summary>

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

java
import com.google.testing.junit.testparameterinjector.junit5.TestParameterInjectorTest; import com.google.testing.junit.testparameterinjector.junit5.TestParameter; import com.google.testing.junit.testparameterinjector.junit5.TestParameters; class MyTest { @TestParameter boolean isDryRun; enum FetchResponseCode { FOUND, NOT_FOUND, ERROR } @TestParameterInjectorTest public void test1(@TestParameter FetchResponseCode responseCode) { // This test method is run 6 times for all combinations of isDryRun and responseCode } @TestParameterInjectorTest public void test2( @TestParameter boolean withDeadline, @TestParameter({"20", "100"}) int limit) { // This test method is run 2*2*2=8 times } @TestParameterInjectorTest @TestParameters("{age: 17, expectIsAdult: false}") @TestParameters("{age: 22, expectIsAdult: true}") public void test3(int age, boolean expectIsAdult) { // This test method is run 4 times: // - isDryRun=false, age=17, expectIsAdult=false // - isDryRun=false, age=22, expectIsAdult=true // - isDryRun=true, age=17, expectIsAdult=false // - isDryRun=true, age=22, expectIsAdult=true } }

And add the following dependency to your .pom file:

xml
<dependency> <groupId>com.google.testparameterinjector</groupId> <artifactId>test-parameter-injector-junit5</artifactId> <version>1.22</version> <scope>test</scope> </dependency>

or see this Maven
page

for instructions for other build tools.

Additionally, Java needs to be compiled with the -parameters compiler option.
This can be done for example:

  • In Maven with the maven-compiler-plugin: Add <parameters>true</parameters> to <configuration>
  • With Gradle: Add options.compilerArgs << "-parameters"
</details>

Basics

Note about JUnit4 vs JUnit5:<br />
The code below assumes you're using JUnit4. For JUnit5 users, simply remove the
@RunWith annotation and replace @Test by @TestParameterInjectorTest.

@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).

The test runner will set these fields before calling any methods, so it is safe
to use such @TestParameter-annotated fields for setting up other test values
and behavior in @Before methods.

Supported types

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

<details> <summary><b>Java</b></summary>
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; // Durations (segments of number+unit as shown below) @TestParameter({"1d", "2h", "3min", "4s", "5ms", "6us", "7ns"}) java.time.Duration d; @TestParameter({"1h30min", "-2h10min20s", "1.5h", ".5s", "0"}) java.time.Duration d;

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

</details> <details> <summary><b>Kotlin</b></summary>
kotlin
// Enums @TestParameter a: AnimalEnum // Implies all possible values of AnimalEnum @TestParameter a: AnimalEnum = testValues(AnimalEnum.CAT, AnimalEnum.DOG) // Strings @TestParameter animalName: String = testValues("cat", "dog") // Primitives @TestParameter b: Boolean // Implies {true, false} @TestParameter i: Int = testValues(1, 2, 3) @TestParameter d: Double = testValues(1.0, 1.5, 2.0) // ... Any type is supported when using testValues()
</details>

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.

Defining correlated parameters

Custom type

<details> <summary><b>Java</b></summary>

Use a test enum 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) public 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) { this.fruit = fruit; this.expectedVolume = 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]
</details> <details> <summary><b>Kotlin</b></summary>

To explicitly specify the combination of parameters, we recommend using a data
class
as follows:

kotlin
@RunWith(TestParameterInjector::class) class MyTest { data class AgeCheckTestCase(val age: Int, val expectIsAdult: Boolean) @Test fun personIsAdult( @TestParameter testCase: AgeCheckTestCase = testValues( AgeCheckTestCase(17, false), AgeCheckTestCase(22, true), ) ) { /*...*/ } }

Tip: Consider setting a custom name if the data class is non-trivial:

kotlin
import com.google.testing.junit.testparameterinjector.KotlinTestParameters.namedTestValues @Test fun personIsAdult( @TestParameter testCase: AgeCheckTestCase = namedTestValues( "teenager" to AgeCheckTestCase(17, false), "young adult" to AgeCheckTestCase(22, true), ) ) { /*...*/ }
</details>

@TestParameters

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

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

which would generate the following tests:

MyTest#personIsAdult[{age: 17, expectIsAdult: false}]
MyTest#personIsAdult[{age: 22, expectIsAdult: true}]

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.

Tip: Consider setting a custom name if the YAML string is large:

java
@Test @TestParameters(customName = "teenager", value = "{age: 17, expectIsAdult: false}") @TestParameters(customName = "young adult", value = "{age: 22, expectIsAdult: true}") public void personIsAdult(int age, boolean expectIsAdult) { /*...*/ }

This will generate the following test names:

MyTest#personIsAdult[teenager]
MyTest#personIsAdult[young adult]

Note: The parameters string is parsed as YAML without knowing the target
types. Therefore, strings that could be interpreted as numbers or booleans
should be escaped.

For example:

java
@Test @TestParameters("{phoneNumber: +12155555555}") public void parsePhoneNumber_success(String phoneNumber) { /*...*/ }

will result phoneNumber = "12155555555", without the + prefix. You can fix
this by surrounding the string value with quotes:

java
@Test @TestParameters("{phoneNumber: '+12155555555'}") public void parsePhoneNumber_success(String phoneNumber) { /*...*/ }

Filtering unwanted parameters

Sometimes, you want to exclude a parameter or a combination of parameters. We
recommend doing this via JUnit assumptions which is also supported by
Truth:

java
import static com.google.common.truth.TruthJUnit.assume; @Test public void myTest(@TestParameter Fruit fruit) { assume().that(fruit).isNotEqualTo(Fruit.BANANA); // At this point, the test will only run for APPLE and CHERRY. // The BANANA case will silently be ignored. } enum Fruit { APPLE, BANANA, CHERRY }

Note that the above works regardless of what parameterization framework you
choose.

[Advanced] Dynamic parameter generation

Note about JUnit4 vs JUnit5:<br />
The code below assumes you're using JUnit4. For JUnit5 users, simply remove the
@RunWith annotation and replace @Test by @TestParameterInjectorTest.

@TestParameter

<details> <summary><b>Java</b></summary>

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

java
import com.google.testing.junit.testparameterinjector.TestParameterValuesProvider; @Test public void matchesAllOf_throwsOnNull( @TestParameter(valuesProvider = CharMatcherProvider.class) CharMatcher charMatcher) { assertThrows(NullPointerException.class, () -> charMatcher.matchesAllOf(null)); } private static final class CharMatcherProvider extends TestParameterValuesProvider { @Override protected ImmutableList<CharMatcher> provideValues(Context context) { return ImmutableList.of(CharMatcher.any(), CharMatcher.ascii(), CharMatcher.whitespace()); } }

Notes:

  • The provideValues() method can dynamically construct the returned list,
    e.g. by reading a file.

  • There are no restrictions on the object types returned.

  • The provideValues() method is called before @BeforeClass, so don't rely
    on any static state initialized in there.

  • The returned objects' toString() will be used for the test names. If you
    want to customize the value names, you can do that as follows:

    java
    private static final class FruitProvider extends TestParameterValuesProvider { @Override protected ImmutableList<?> provideValues(Context context) { return ImmutableList.of( value(new Apple()).withName("apple"), value(new Banana()).withName("banana")); } }
  • The given Context contains the test class and other annotations on the
    @TestParameter-annotated parameter/field. This allows more generic
    providers that take into account custom annotations with extra data, or the
    implementation of abstract methods on a base test class.

</details> <details> <summary><b>Kotlin</b></summary>

Instead of providing a varargs list of values, you can dynamically provide one
as follows:

kotlin
import com.google.testing.junit.testparameterinjector.KotlinTestParameters.testValuesIn @Test fun sendInvalidRequest_fails( @TestParameter invalidRequest: GetGshoeRequest = testValuesIn(readRequestsFromFile("invalid_get_gshoe_requests.textproto")) ) { /*...*/ } private fun readRequestsFromFile(filename: String): List<GetGshoeRequest> { /*...*/ }

Notes:

  • The test values are calculated before @Before[Class] or any @Rules, so
    don't rely on any state initialized in there.

  • The test values' toString() will be used for the test names. If you want
    to customize the value names, you can do that as follows:

    kotlin
    import com.google.testing.junit.testparameterinjector.KotlinTestParameters.namedTestValuesIn @Test fun sendInvalidRequest_fails( @TestParameter invalidRequest: GetGshoeRequest = namedTestValuesIn(readRequestsFromFile("invalid_get_gshoe_requests.textproto")) ) { /*...*/ } private fun readRequestsFromFile(filename: String): Map<String, GetGshoeRequest> { /*...*/ }
</details>

@TestParameters

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

java
import com.google.testing.junit.testparameterinjector.TestParametersValuesProvider; import com.google.testing.junit.testparameterinjector.TestParameters.TestParametersValues; @Test @TestParameters(valuesProvider = IsAdultValueProvider.class) public void personIsAdult(int age, boolean expectIsAdult) { ... } static final class IsAdultValueProvider extends TestParametersValuesProvider { @Override public ImmutableList<TestParametersValues> provideValues(Context context) { 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() ); } }

Limitations

Kotlin constructor values

Due to JUnit limitations (in both JUnit4 and JUnit5), it is impossible to
use KotlinTestParameters.testValues and friends in a constructor:

kotlin
// This does *not* work class MyTest( @TestParameter val age: Int = testValues(17, 22) ) { /* ... */ } // Fall back to Java version. This works: class MyTest( @TestParameter("17", "22") val age: Int ) { /* ... */ }

Combination with other runners

Robolectric (Android)

A Robolectric compatible version of TestParameterInjector is available as
RobolectricTestParameterInjector,
which supports all the features of the base RobolectricTestRunner in addition
to the parameterization features of TestParameterInjector.

java
import org.robolectric.RobolectricTestParameterInjector; @RunWith(RobolectricTestParameterInjector.class) public class MyRobolectricTest { @Test public void test(@TestParameter boolean value) { /*...*/ } }

Contributors

Showing top 11 contributors by commit count.

View all contributors on GitHub →

This article is auto-generated from google/TestParameterInjector via the GitHub API.Last fetched: 6/29/2026