Name Date Size #Lines LOC

..--

.github/H25-Apr-2025-11557

junit4/H25-Apr-2025-8,2735,685

junit5/H25-Apr-2025-5,5863,575

src/H25-Apr-2025-6,5154,501

.gitignoreH A D25-Apr-20258 21

Android.bpH A D25-Apr-20251.8 KiB6460

CHANGELOG.mdH A D25-Apr-20256.3 KiB186134

CONTRIBUTING.mdH A D25-Apr-20251.1 KiB3021

LICENSEH A D25-Apr-202511.1 KiB203169

METADATAH A D25-Apr-2025412 1816

MODULE_LICENSE_APACHE2HD25-Apr-20250

OWNERSH A D25-Apr-202538 32

README.mdH A D25-Apr-202511.9 KiB410305

pom.xmlH A D25-Apr-20257.1 KiB242204

README.md

1TestParameterInjector
2=====================
3
4[Link to Javadoc.](https://google.github.io/TestParameterInjector/docs/latest/)
5
6## Introduction
7
8`TestParameterInjector` is a JUnit4 and JUnit5 test runner that runs its test methods for
9different combinations of field/parameter values.
10
11Parameterized tests are a great way to avoid code duplication between tests and
12promote high test coverage for data-driven tests.
13
14There are a lot of alternative parameterized test frameworks, such as
15[junit.runners.Parameterized](https://github.com/junit-team/junit4/wiki/parameterized-tests)
16and [JUnitParams](https://github.com/Pragmatists/JUnitParams). We believe
17`TestParameterInjector` is an improvement of those because it is more powerful
18and simpler to use.
19
20[This blogpost](https://opensource.googleblog.com/2021/03/introducing-testparameterinjector.html)
21goes into a bit more detail about how `TestParameterInjector` compares to other
22frameworks used at Google.
23
24## Getting started
25
26### JUnit4
27
28To start using `TestParameterInjector` right away, copy the following snippet:
29
30```java
31import com.google.testing.junit.testparameterinjector.TestParameterInjector;
32import com.google.testing.junit.testparameterinjector.TestParameter;
33
34@RunWith(TestParameterInjector.class)
35public class MyTest {
36
37  @TestParameter boolean isDryRun;
38
39  @Test public void test1(@TestParameter boolean enableFlag) {
40    // ...
41  }
42
43  @Test public void test2(@TestParameter MyEnum myEnum) {
44    // ...
45  }
46
47  enum MyEnum { VALUE_A, VALUE_B, VALUE_C }
48}
49```
50
51And add the following dependency to your `.pom` file:
52
53```xml
54<dependency>
55  <groupId>com.google.testparameterinjector</groupId>
56  <artifactId>test-parameter-injector</artifactId>
57  <version>1.18</version>
58  <scope>test</scope>
59</dependency>
60```
61
62or see [this maven.org
63page](https://search.maven.org/artifact/com.google.testparameterinjector/test-parameter-injector)
64for instructions for other build tools.
65
66### JUnit5 (Jupiter)
67<details>
68<summary>Click to expand</summary>
69
70To start using `TestParameterInjector` right away, copy the following snippet:
71
72```java
73import com.google.testing.junit.testparameterinjector.junit5.TestParameterInjectorTest;
74import com.google.testing.junit.testparameterinjector.junit5.TestParameter;
75
76class MyTest {
77
78  @TestParameter boolean isDryRun;
79
80  @TestParameterInjectorTest
81  void test1(@TestParameter boolean enableFlag) {
82    // ...
83  }
84
85  @TestParameterInjectorTest
86  void test2(@TestParameter MyEnum myEnum) {
87    // ...
88  }
89
90  enum MyEnum { VALUE_A, VALUE_B, VALUE_C }
91}
92```
93
94And add the following dependency to your `.pom` file:
95
96```xml
97<dependency>
98  <groupId>com.google.testparameterinjector</groupId>
99  <artifactId>test-parameter-injector-junit5</artifactId>
100  <version>1.18</version>
101  <scope>test</scope>
102</dependency>
103```
104
105or see [this maven.org
106page](https://search.maven.org/artifact/com.google.testparameterinjector/test-parameter-injector-junit5)
107for instructions for other build tools.
108
109</details>
110
111## Basics
112
113**Note about JUnit4 vs JUnit5:**<br />
114The code below assumes you're using JUnit4. For JUnit5 users, simply remove the
115`@RunWith` annotation and replace `@Test` by `@TestParameterInjectorTest`.
116
117### `@TestParameter` for testing all combinations
118
119#### Parameterizing a single test method
120
121The simplest way to use this library is to use `@TestParameter`. For example:
122
123```java
124@RunWith(TestParameterInjector.class)
125public class MyTest {
126
127  @Test
128  public void test(@TestParameter boolean isOwner) {...}
129}
130```
131
132In this example, two tests will be automatically generated by the test framework:
133
134-   One with `isOwner` set to `true`
135-   One with `isOwner` set to `false`
136
137When running the tests, the result will show the following test names:
138
139```
140MyTest#test[isOwner=true]
141MyTest#test[isOwner=false]
142```
143
144#### Parameterizing the whole class
145
146`@TestParameter` can also annotate a field:
147
148```java
149@RunWith(TestParameterInjector.class)
150public class MyTest {
151
152  @TestParameter private boolean isOwner;
153
154  @Test public void test1() {...}
155  @Test public void test2() {...}
156}
157```
158
159In this example, both `test1` and `test2` will be run twice (once for each
160parameter value).
161
162The test runner will set these fields before calling any methods, so it is safe
163to use such `@TestParameter`-annotated fields for setting up other test values
164and behavior in `@Before` methods.
165
166#### Supported types
167
168The following examples show most of the supported types. See the `@TestParameter` javadoc for more details.
169
170```java
171// Enums
172@TestParameter AnimalEnum a; // Implies all possible values of AnimalEnum
173@TestParameter({"CAT", "DOG"}) AnimalEnum a; // Implies AnimalEnum.CAT and AnimalEnum.DOG.
174
175// Strings
176@TestParameter({"cat", "dog"}) String animalName;
177
178// Java primitives
179@TestParameter boolean b; // Implies {true, false}
180@TestParameter({"1", "2", "3"}) int i;
181@TestParameter({"1", "1.5", "2"}) double d;
182
183// Bytes
184@TestParameter({"!!binary 'ZGF0YQ=='", "some_string"}) byte[] bytes;
185
186// Durations (segments of number+unit as shown below)
187@TestParameter({"1d", "2h", "3min", "4s", "5ms", "6us", "7ns"}) java.time.Duration d;
188@TestParameter({"1h30min", "-2h10min20s", "1.5h", ".5s", "0"}) java.time.Duration d;
189```
190
191For non-primitive types (e.g. String, enums, bytes), `"null"` is always parsed as the `null` reference.
192
193#### Multiple parameters: All combinations are run
194
195If there are multiple `@TestParameter`-annotated values applicable to one test
196method, the test is run for all possible combinations of those values. Example:
197
198```java
199@RunWith(TestParameterInjector.class)
200public class MyTest {
201
202  @TestParameter private boolean a;
203
204  @Test public void test1(@TestParameter boolean b, @TestParameter boolean c) {
205    // Run for these combinations:
206    //   (a=false, b=false, c=false)
207    //   (a=false, b=false, c=true )
208    //   (a=false, b=true,  c=false)
209    //   (a=false, b=true,  c=true )
210    //   (a=true,  b=false, c=false)
211    //   (a=true,  b=false, c=true )
212    //   (a=true,  b=true,  c=false)
213    //   (a=true,  b=true,  c=true )
214  }
215}
216```
217
218If you want to explicitly define which combinations are run, see the next
219sections.
220
221### Use a test enum for enumerating more complex parameter combinations
222
223Use this strategy if you want to:
224
225-   Explicitly specify the combination of parameters
226-   or your parameters are too large to be encoded in a `String` in a readable
227    way
228
229Example:
230
231```java
232@RunWith(TestParameterInjector.class)
233class MyTest {
234
235  enum FruitVolumeTestCase {
236    APPLE(Fruit.newBuilder().setName("Apple").setShape(SPHERE).build(), /* expectedVolume= */ 3.1),
237    BANANA(Fruit.newBuilder().setName("Banana").setShape(CURVED).build(), /* expectedVolume= */ 2.1),
238    MELON(Fruit.newBuilder().setName("Melon").setShape(SPHERE).build(), /* expectedVolume= */ 6);
239
240    final Fruit fruit;
241    final double expectedVolume;
242
243    FruitVolumeTestCase(Fruit fruit, double expectedVolume) { ... }
244  }
245
246  @Test
247  public void calculateVolume_success(@TestParameter FruitVolumeTestCase fruitVolumeTestCase) {
248    assertThat(calculateVolume(fruitVolumeTestCase.fruit))
249        .isEqualTo(fruitVolumeTestCase.expectedVolume);
250  }
251}
252```
253
254The enum constant name has the added benefit of making for sensible test names:
255
256```
257MyTest#calculateVolume_success[APPLE]
258MyTest#calculateVolume_success[BANANA]
259MyTest#calculateVolume_success[MELON]
260```
261
262### `@TestParameters` for defining sets of parameters
263
264You can also explicitly enumerate the sets of test parameters via a list of YAML
265mappings:
266
267```java
268@Test
269@TestParameters("{age: 17, expectIsAdult: false}")
270@TestParameters("{age: 22, expectIsAdult: true}")
271public void personIsAdult(int age, boolean expectIsAdult) { ... }
272```
273
274which would generate the following tests:
275
276```
277MyTest#personIsAdult[{age: 17, expectIsAdult: false}]
278MyTest#personIsAdult[{age: 22, expectIsAdult: true}]
279```
280
281The string format supports the same types as `@TestParameter` (e.g. enums). See
282the `@TestParameters` javadoc for more info.
283
284`@TestParameters` works in the same way on the constructor, in which case all
285tests will be run for the given parameter sets.
286
287> Tip: Consider setting a custom name if the YAML string is large:
288>
289> ```java
290> @Test
291> @TestParameters(customName = "teenager", value = "{age: 17, expectIsAdult: false}")
292> @TestParameters(customName = "young adult", value = "{age: 22, expectIsAdult: true}")
293> public void personIsAdult(int age, boolean expectIsAdult) { ... }
294> ```
295>
296> This will generate the following test names:
297>
298> ```
299> MyTest#personIsAdult[teenager]
300> MyTest#personIsAdult[young adult]
301> ```
302
303### Filtering unwanted parameters
304
305Sometimes, you want to exclude a parameter or a combination of parameters. We
306recommend doing this via JUnit assumptions which is also supported by
307[Truth](https://truth.dev/):
308
309```java
310import static com.google.common.truth.TruthJUnit.assume;
311
312@Test
313public void myTest(@TestParameter Fruit fruit) {
314  assume().that(fruit).isNotEqualTo(Fruit.BANANA);
315
316  // At this point, the test will only run for APPLE and CHERRY.
317  // The BANANA case will silently be ignored.
318}
319
320enum Fruit { APPLE, BANANA, CHERRY }
321```
322
323Note that the above works regardless of what parameterization framework you
324choose.
325
326## Advanced usage
327
328**Note about JUnit4 vs JUnit5:**<br />
329The code below assumes you're using JUnit4. For JUnit5 users, simply remove the
330`@RunWith` annotation and replace `@Test` by `@TestParameterInjectorTest`.
331
332### Dynamic parameter generation for `@TestParameter`
333
334Instead of providing a list of parsable strings, you can implement your own
335`TestParameterValuesProvider` as follows:
336
337```java
338import com.google.testing.junit.testparameterinjector.TestParameterValuesProvider;
339
340@Test
341public void matchesAllOf_throwsOnNull(
342    @TestParameter(valuesProvider = CharMatcherProvider.class) CharMatcher charMatcher) {
343  assertThrows(NullPointerException.class, () -> charMatcher.matchesAllOf(null));
344}
345
346private static final class CharMatcherProvider extends TestParameterValuesProvider {
347  @Override
348  public List<CharMatcher> provideValues(Context context) {
349    return ImmutableList.of(CharMatcher.any(), CharMatcher.ascii(), CharMatcher.whitespace());
350  }
351}
352```
353
354Notes:
355
356-   The `provideValues()` method can dynamically construct the returned list,
357    e.g. by reading a file.
358-   There are no restrictions on the object types returned.
359-   The `provideValues()` method is called before `@BeforeClass`, so don't rely
360    on any static state initialized in there.
361-   The returned objects' `toString()` will be used for the test names. If you
362    want to customize the value names, you can do that as follows:
363
364    ```
365    private static final class FruitProvider extends TestParameterValuesProvider {
366      @Override
367      public List<?> provideValues(Context context) {
368        return ImmutableList.of(
369            value(new Apple()).withName("apple"),
370            value(new Banana()).withName("banana"));
371      }
372    }
373    ```
374
375-   The given `Context` contains the test class and other annotations on the
376    `@TestParameter`-annotated parameter/field. This allows more generic
377    providers that take into account custom annotations with extra data, or the
378    implementation of abstract methods on a base test class.
379
380### Dynamic parameter generation for `@TestParameters`
381
382Instead of providing a YAML mapping of parameters, you can implement your own
383`TestParametersValuesProvider` as follows:
384
385```java
386import com.google.testing.junit.testparameterinjector.TestParametersValuesProvider;
387import com.google.testing.junit.testparameterinjector.TestParameters.TestParametersValues;
388
389@Test
390@TestParameters(valuesProvider = IsAdultValueProvider.class)
391public void personIsAdult(int age, boolean expectIsAdult) { ... }
392
393static final class IsAdultValueProvider extends TestParametersValuesProvider {
394  @Override public ImmutableList<TestParametersValues> provideValues(Context context) {
395    return ImmutableList.of(
396      TestParametersValues.builder()
397        .name("teenager")
398        .addParameter("age", 17)
399        .addParameter("expectIsAdult", false)
400        .build(),
401      TestParametersValues.builder()
402        .name("young adult")
403        .addParameter("age", 22)
404        .addParameter("expectIsAdult", true)
405        .build()
406    );
407  }
408}
409```
410