Giter Club home page Giter Club logo

testparameterinjector's Introduction

TestParameterInjector

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.1</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;

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()
    );
  }
}

testparameterinjector's People

Contributors

nymanjens avatar

Watchers

James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.