Bug: 195120269

Clone this repo:
  1. a92af87 Use Truth library built from source. by Krzysztof Kosiński · 5 weeks ago main master
  2. 94c416d Add support for custom test annotations and test sorting. am: f48709d253 am: 1bd71e2521 am: e1a7bbf4c1 am: 75c56b9a9e am: 1d2a7b8c03 am: 912440cd7e am: c54264257c by Jonathan Scott · 2 years, 1 month ago android13-d2-release android13-d3-s1-release android13-d4-release android13-d4-s1-release android13-d4-s2-release android13-dev android13-frc-adbd-release android13-frc-art-release android13-frc-cellbroadcast-release android13-frc-conscrypt-release android13-frc-documentsui-release android13-frc-extservices-release android13-frc-ipsec-release android13-frc-media-release android13-frc-media-swcodec-release android13-frc-networking-release android13-frc-neuralnetworks-release android13-frc-odp-release android13-frc-os-statsd-release android13-frc-permission-release android13-frc-resolv-release android13-frc-scheduling-release android13-mainline-adbd-release android13-mainline-adservices-release android13-mainline-appsearch-release android13-mainline-art-release android13-mainline-cellbroadcast-release android13-mainline-conscrypt-release android13-mainline-extservices-release android13-mainline-go-adbd-release android13-mainline-go-adservices-release android13-mainline-go-appsearch-release android13-mainline-go-art-release android13-mainline-go-cellbroadcast-release android13-mainline-go-conscrypt-release android13-mainline-go-documentsui-release android13-mainline-go-extservices-release android13-mainline-go-ipsec-release android13-mainline-go-media-release android13-mainline-go-media-swcodec-release android13-mainline-go-mediaprovider-release android13-mainline-go-networking-release android13-mainline-go-neuralnetworks-release android13-mainline-go-odp-release android13-mainline-go-os-statsd-release android13-mainline-go-permission-release android13-mainline-go-resolv-release android13-mainline-go-scheduling-release android13-mainline-go-sdkext-release android13-mainline-go-tethering-release android13-mainline-go-tzdata4-release android13-mainline-go-uwb-release android13-mainline-go-wifi-release android13-mainline-ipsec-release android13-mainline-media-release android13-mainline-media-swcodec-release android13-mainline-mediaprovider-release android13-mainline-networking-release android13-mainline-os-statsd-release android13-mainline-permission-release android13-mainline-resolv-release android13-mainline-scheduling-release android13-mainline-sdkext-release android13-mainline-tethering-release android13-mainline-tzdata4-release android13-mainline-uwb-release android13-mainline-wifi-release android13-qpr1-release android13-qpr1-s1-release android13-qpr1-s2-release android13-qpr1-s3-release android13-qpr1-s4-release android13-qpr1-s5-release android13-qpr1-s6-release android13-qpr1-s7-release android13-qpr1-s8-release android13-qpr2-b-s1-release android13-qpr2-release android13-qpr2-s1-release android13-qpr2-s10-release android13-qpr2-s11-release android13-qpr2-s12-release android13-qpr2-s2-release android13-qpr2-s3-release android13-qpr2-s5-release android13-qpr2-s6-release android13-qpr2-s7-release android13-qpr2-s8-release android13-qpr2-s9-release android13-qpr3-c-s1-release android13-qpr3-c-s10-release android13-qpr3-c-s11-release android13-qpr3-c-s12-release android13-qpr3-c-s2-release android13-qpr3-c-s3-release android13-qpr3-c-s4-release android13-qpr3-c-s5-release android13-qpr3-c-s6-release android13-qpr3-c-s7-release android13-qpr3-c-s8-release android13-qpr3-release android13-qpr3-s1-release android13-qpr3-s10-release android13-qpr3-s11-release android13-qpr3-s12-release android13-qpr3-s13-release android13-qpr3-s2-release android13-qpr3-s3-release android13-qpr3-s4-release android13-qpr3-s5-release android13-qpr3-s6-release android13-qpr3-s7-release android13-qpr3-s8-release android13-qpr3-s9-release main-16k main-16k-with-phones aml_adb_331011040 aml_adb_331011050 aml_adb_331113120 aml_adb_331314020 aml_adb_331610000 aml_ads_331131000 aml_ads_331418080 aml_ads_331511020 aml_ads_331611190 aml_ads_331710270 aml_ads_331814200 aml_ads_331920180 aml_art_331012050 aml_art_331113000 aml_art_331314010 aml_art_331413030 aml_art_331612010 aml_art_331711080 aml_art_331813010 aml_art_331813100 aml_ase_331011020 aml_ase_331112000 aml_ase_331311020 aml_cbr_330810000 aml_cbr_330911010 aml_cbr_331013010 aml_cbr_331111030 aml_cbr_331310010 aml_cbr_331411000 aml_cbr_331510000 aml_cbr_331610010 aml_cbr_331710020 aml_cbr_331810000 aml_cbr_331910000 aml_con_331011010 aml_con_331115000 aml_con_331312000 aml_con_331411000 aml_con_331413000 aml_doc_331120000 aml_ext_331012020 aml_ext_331112010 aml_ext_331312000 aml_ext_331412000 aml_ext_331814220 aml_go_adb_330913000 aml_go_ads_330913000 aml_go_ads_330915000 aml_go_ads_330915100 aml_go_art_330913000 aml_go_ase_330913000 aml_go_cbr_330912000 aml_go_con_330913000 aml_go_doc_330912000 aml_go_ext_330912000 aml_go_ips_330911000 aml_go_med_330913000 aml_go_mpr_330912000 aml_go_net_330913000 aml_go_neu_330912000 aml_go_odp_330912000 aml_go_odp_330913000 aml_go_per_330912000 aml_go_res_330912000 aml_go_sch_330911000 aml_go_sdk_330810000 aml_go_sta_330911000 aml_go_swc_330913000 aml_go_tet_330914010 aml_go_tz4_330912000 aml_go_uwb_330912000 aml_go_wif_330911000 aml_ips_331014020 aml_ips_331111030 aml_ips_331310000 aml_ips_331312000 aml_ips_331910010 aml_med_331012020 aml_med_331115000 aml_med_331318000 aml_med_331410000 aml_med_331511000 aml_med_331612000 aml_med_331712010 aml_med_331911000 aml_mpr_330811020 aml_mpr_330911040 aml_mpr_331011070 aml_mpr_331112030 aml_mpr_331112050 aml_mpr_331311080 aml_mpr_331412040 aml_mpr_331512020 aml_mpr_331613010 aml_mpr_331711020 aml_mpr_331812020 aml_mpr_331918000 aml_net_330811010 aml_net_330910010 aml_net_331011030 aml_net_331110020 aml_net_331313010 aml_net_331313030 aml_net_331412000 aml_net_331610000 aml_net_331710000 aml_net_331812010 aml_net_331910030 aml_neu_331113000 aml_neu_331310000 aml_per_330811030 aml_per_330912010 aml_per_331019040 aml_per_331115020 aml_per_331313010 aml_per_331411000 aml_per_331512020 aml_per_331611010 aml_per_331710050 aml_per_331812030 aml_per_331913010 aml_res_330810000 aml_res_330910000 aml_res_331011050 aml_res_331114000 aml_res_331314010 aml_res_331512000 aml_res_331611010 aml_res_331820000 aml_sch_331111000 aml_sch_331113000 aml_sdk_330810010 aml_sdk_330810050 aml_sdk_331111000 aml_sdk_331310010 aml_sdk_331410000 aml_sdk_331412000 aml_sdk_331811000 aml_sdk_331811100 aml_sdk_331812000 aml_sta_330910000 aml_sta_331010010 aml_sta_331311000 aml_sta_331410000 aml_sta_331511000 aml_sta_331610000 aml_sta_331711010 aml_sta_331811000 aml_sta_331910000 aml_swc_331012020 aml_swc_331116000 aml_swc_331318000 aml_swc_331410000 aml_swc_331511000 aml_swc_331612000 aml_swc_331712000 aml_swc_331911000 aml_tet_330812150 aml_tet_330911010 aml_tet_331012080 aml_tet_331117000 aml_tet_331312080 aml_tet_331412030 aml_tet_331511000 aml_tet_331511160 aml_tet_331711040 aml_tet_331820050 aml_tet_331910040 aml_tz4_331012000 aml_tz4_331012040 aml_tz4_331012050 aml_tz4_331314010 aml_tz4_331314020 aml_tz4_331314030 aml_tz4_331910000 aml_uwb_330810010 aml_uwb_331015040 aml_uwb_331115000 aml_uwb_331310030 aml_uwb_331410010 aml_uwb_331611010 aml_uwb_331613010 aml_uwb_331820070 aml_uwb_331910010 aml_wif_330810040 aml_wif_330910030 aml_wif_331016070 aml_wif_331112000 aml_wif_331310070 aml_wif_331414000 aml_wif_331511020 aml_wif_331613000 aml_wif_331710030 aml_wif_331810010 aml_wif_331910020 android-13.0.0_r16 android-13.0.0_r17 android-13.0.0_r18 android-13.0.0_r19 android-13.0.0_r20 android-13.0.0_r21 android-13.0.0_r22 android-13.0.0_r23 android-13.0.0_r24 android-13.0.0_r27 android-13.0.0_r28 android-13.0.0_r29 android-13.0.0_r30 android-13.0.0_r32 android-13.0.0_r33 android-13.0.0_r34 android-13.0.0_r35 android-13.0.0_r36 android-13.0.0_r37 android-13.0.0_r38 android-13.0.0_r39 android-13.0.0_r40 android-13.0.0_r41 android-13.0.0_r42 android-13.0.0_r43 android-13.0.0_r44 android-13.0.0_r45 android-13.0.0_r46 android-13.0.0_r47 android-13.0.0_r48 android-13.0.0_r49 android-13.0.0_r50 android-13.0.0_r51 android-13.0.0_r52 android-13.0.0_r53 android-13.0.0_r54 android-13.0.0_r55 android-13.0.0_r56 android-13.0.0_r57 android-13.0.0_r58 android-13.0.0_r59 android-13.0.0_r60 android-13.0.0_r61 android-13.0.0_r62 android-13.0.0_r63 android-13.0.0_r64 android-13.0.0_r65 android-13.0.0_r66 android-13.0.0_r67 android-13.0.0_r68 android-13.0.0_r69 android-13.0.0_r70 android-13.0.0_r71 android-13.0.0_r72 android-13.0.0_r73 android-13.0.0_r74 android-13.0.0_r75 android-13.0.0_r76 android-13.0.0_r77 android-13.0.0_r78 android-13.0.0_r79 android-13.0.0_r80 android-13.0.0_r81 android-13.0.0_r82 android-u-beta-1-gpl t_frc_adb_330444000 t_frc_art_330443060 t_frc_ase_330444010 t_frc_cbr_330443000 t_frc_con_330443020 t_frc_doc_330443000 t_frc_doc_330443060 t_frc_doc_330543000 t_frc_ext_330443000 t_frc_ips_330443010 t_frc_med_330443030 t_frc_net_330443000 t_frc_neu_330443000 t_frc_neu_330443030 t_frc_odp_330442000 t_frc_odp_330442040 t_frc_per_330444010 t_frc_res_330443000 t_frc_sch_330443010 t_frc_sch_330443040 t_frc_sta_330443010 t_frc_swc_330443010 t_frc_swc_330443040 t_frc_tz4_330443010
  3. c542642 Add support for custom test annotations and test sorting. am: f48709d253 am: 1bd71e2521 am: e1a7bbf4c1 am: 75c56b9a9e am: 1d2a7b8c03 am: 912440cd7e by Jonathan Scott · 2 years, 1 month ago
  4. 912440c Add support for custom test annotations and test sorting. am: f48709d253 am: 1bd71e2521 am: e1a7bbf4c1 am: 75c56b9a9e am: 1d2a7b8c03 by Jonathan Scott · 2 years, 1 month ago android12-qpr3-release android12-qpr3-s1-release android12-qpr3-s2-release android12-qpr3-s3-release android12-qpr3-s4-release android12-qpr3-s5-release android12-qpr3-s6-release android12-qpr3-s7-release android12L-dev android-12.1.0_r10 android-12.1.0_r11 android-12.1.0_r19 android-12.1.0_r20 android-12.1.0_r21 android-12.1.0_r22 android-12.1.0_r7 android-12.1.0_r8 android-12.1.0_r9
  5. 8310856 Add support for custom test annotations and test sorting. am: f48709d253 am: 1bd71e2521 am: e1a7bbf4c1 am: 75c56b9a9e am: 1d2a7b8c03 by Jonathan Scott · 2 years, 1 month ago

TestParameterInjector

Link to Javadoc.

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 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

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

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:

<dependency>
  <groupId>com.google.testparameterinjector</groupId>
  <artifactId>test-parameter-injector</artifactId>
  <version>1.4</version>
</dependency>

or see this maven.org page 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:

@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:

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

// 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:

@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:

@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:

@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:

@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<CharMatcher> 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:

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

static final class IsAdultValueProvider implements TestParametersValuesProvider {
  @Override public ImmutableList<TestParametersValues> 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()
    );
  }
}