• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1TestParameterInjector
2=====================
3
4[Link to Javadoc.](https://google.github.io/TestParameterInjector/docs/latest/)
5
6## Introduction
7
8`TestParameterInjector` is a JUnit4 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
26To start using `TestParameterInjector` right away, copy the following snippet:
27
28```java
29import com.google.testing.junit.testparameterinjector.TestParameterInjector;
30import com.google.testing.junit.testparameterinjector.TestParameter;
31
32@RunWith(TestParameterInjector.class)
33public class MyTest {
34
35  @TestParameter boolean isDryRun;
36
37  @Test public void test1(@TestParameter boolean enableFlag) {
38    // ...
39  }
40
41  @Test public void test2(@TestParameter MyEnum myEnum) {
42    // ...
43  }
44
45  enum MyEnum { VALUE_A, VALUE_B, VALUE_C }
46}
47```
48
49And add the following dependency to your `.pom` file:
50
51```xml
52<dependency>
53  <groupId>com.google.testparameterinjector</groupId>
54  <artifactId>test-parameter-injector</artifactId>
55  <version>1.4</version>
56</dependency>
57```
58
59or see [this maven.org
60page](https://search.maven.org/artifact/com.google.testparameterinjector/test-parameter-injector)
61for instructions for other build tools.
62
63
64## Basics
65
66### `@TestParameter` for testing all combinations
67
68#### Parameterizing a single test method
69
70The simplest way to use this library is to use `@TestParameter`. For example:
71
72```java
73@RunWith(TestParameterInjector.class)
74public class MyTest {
75
76  @Test
77  public void test(@TestParameter boolean isOwner) {...}
78}
79```
80
81In this example, two tests will be automatically generated by the test framework:
82
83-   One with `isOwner` set to `true`
84-   One with `isOwner` set to `false`
85
86When running the tests, the result will show the following test names:
87
88```
89MyTest#test[isOwner=true]
90MyTest#test[isOwner=false]
91```
92
93#### Parameterizing the whole class
94
95`@TestParameter` can also annotate a field:
96
97```java
98@RunWith(TestParameterInjector.class)
99public class MyTest {
100
101  @TestParameter private boolean isOwner;
102
103  @Test public void test1() {...}
104  @Test public void test2() {...}
105}
106```
107
108In this example, both `test1` and `test2` will be run twice (once for each
109parameter value).
110
111#### Supported types
112
113The following examples show most of the supported types. See the `@TestParameter` javadoc for more details.
114
115```java
116// Enums
117@TestParameter AnimalEnum a; // Implies all possible values of AnimalEnum
118@TestParameter({"CAT", "DOG"}) AnimalEnum a; // Implies AnimalEnum.CAT and AnimalEnum.DOG.
119
120// Strings
121@TestParameter({"cat", "dog"}) String animalName;
122
123// Java primitives
124@TestParameter boolean b; // Implies {true, false}
125@TestParameter({"1", "2", "3"}) int i;
126@TestParameter({"1", "1.5", "2"}) double d;
127
128// Bytes
129@TestParameter({"!!binary 'ZGF0YQ=='", "some_string"}) byte[] bytes;
130```
131
132For non-primitive types (e.g. String, enums, bytes), `"null"` is always parsed as the `null` reference.
133
134#### Multiple parameters: All combinations are run
135
136If there are multiple `@TestParameter`-annotated values applicable to one test
137method, the test is run for all possible combinations of those values. Example:
138
139```java
140@RunWith(TestParameterInjector.class)
141public class MyTest {
142
143  @TestParameter private boolean a;
144
145  @Test public void test1(@TestParameter boolean b, @TestParameter boolean c) {
146    // Run for these combinations:
147    //   (a=false, b=false, c=false)
148    //   (a=false, b=false, c=true )
149    //   (a=false, b=true,  c=false)
150    //   (a=false, b=true,  c=true )
151    //   (a=true,  b=false, c=false)
152    //   (a=true,  b=false, c=true )
153    //   (a=true,  b=true,  c=false)
154    //   (a=true,  b=true,  c=true )
155  }
156}
157```
158
159If you want to explicitly define which combinations are run, see the next
160sections.
161
162### Use a test enum for enumerating more complex parameter combinations
163
164Use this strategy if you want to:
165
166-   Explicitly specify the combination of parameters
167-   or your parameters are too large to be encoded in a `String` in a readable
168    way
169
170Example:
171
172```java
173@RunWith(TestParameterInjector.class)
174class MyTest {
175
176  enum FruitVolumeTestCase {
177    APPLE(Fruit.newBuilder().setName("Apple").setShape(SPHERE).build(), /* expectedVolume= */ 3.1),
178    BANANA(Fruit.newBuilder().setName("Banana").setShape(CURVED).build(), /* expectedVolume= */ 2.1),
179    MELON(Fruit.newBuilder().setName("Melon").setShape(SPHERE).build(), /* expectedVolume= */ 6);
180
181    final Fruit fruit;
182    final double expectedVolume;
183
184    FruitVolumeTestCase(Fruit fruit, double expectedVolume) { ... }
185  }
186
187  @Test
188  public void calculateVolume_success(@TestParameter FruitVolumeTestCase fruitVolumeTestCase) {
189    assertThat(calculateVolume(fruitVolumeTestCase.fruit))
190        .isEqualTo(fruitVolumeTestCase.expectedVolume);
191  }
192}
193```
194
195The enum constant name has the added benefit of making for sensible test names:
196
197```
198MyTest#calculateVolume_success[APPLE]
199MyTest#calculateVolume_success[BANANA]
200MyTest#calculateVolume_success[MELON]
201```
202
203### `@TestParameters` for defining sets of parameters
204
205You can also explicitly enumerate the sets of test parameters via a list of YAML
206mappings:
207
208```java
209@Test
210@TestParameters({
211  "{age: 17, expectIsAdult: false}",
212  "{age: 22, expectIsAdult: true}",
213})
214public void personIsAdult(int age, boolean expectIsAdult) { ... }
215```
216
217The string format supports the same types as `@TestParameter` (e.g. enums). See
218the `@TestParameters` javadoc for more info.
219
220`@TestParameters` works in the same way on the constructor, in which case all
221tests will be run for the given parameter sets.
222
223## Advanced usage
224
225### Dynamic parameter generation for `@TestParameter`
226
227Instead of providing a list of parsable strings, you can implement your own
228`TestParameterValuesProvider` as follows:
229
230```java
231@Test
232public void matchesAllOf_throwsOnNull(
233    @TestParameter(valuesProvider = CharMatcherProvider.class) CharMatcher charMatcher) {
234  assertThrows(NullPointerException.class, () -> charMatcher.matchesAllOf(null));
235}
236
237private static final class CharMatcherProvider implements TestParameterValuesProvider {
238  @Override
239  public List<CharMatcher> provideValues() {
240    return ImmutableList.of(CharMatcher.any(), CharMatcher.ascii(), CharMatcher.whitespace());
241  }
242}
243```
244
245Note that `provideValues()` dynamically construct the returned list, e.g. by
246reading a file. There are no restrictions on the object types returned, but note
247that `toString()` will be used for the test names.
248
249### Dynamic parameter generation for `@TestParameters`
250
251Instead of providing a YAML mapping of parameters, you can implement your own
252`TestParametersValuesProvider` as follows:
253
254```java
255@Test
256@TestParameters(valuesProvider = IsAdultValueProvider.class)
257public void personIsAdult(int age, boolean expectIsAdult) { ... }
258
259static final class IsAdultValueProvider implements TestParametersValuesProvider {
260  @Override public ImmutableList<TestParametersValues> provideValues() {
261    return ImmutableList.of(
262      TestParametersValues.builder()
263        .name("teenager")
264        .addParameter("age", 17)
265        .addParameter("expectIsAdult", false)
266        .build(),
267      TestParametersValues.builder()
268        .name("young adult")
269        .addParameter("age", 22)
270        .addParameter("expectIsAdult", true)
271        .build()
272    );
273  }
274}
275```
276