JUnitValueSource

SUGGESTION

Simplification

View source code on GitHub

Summary

Prefer @ValueSource over a @MethodSource where possible and reasonable

Suppression

Suppress false positives by adding the suppression annotation @SuppressWarnings("JUnitValueSource") to the enclosing element.

Disable this pattern completely by adding -Xep:JUnitValueSource:OFF as compiler argument. Learn more.

Samples

Replacement

Shows the difference in example code before and after the bug pattern is applied.

 import static org.junit.jupiter.params.provider.Arguments.arguments;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import java.util.List;
 import java.util.Set;
 import java.util.stream.DoubleStream;
 import java.util.stream.IntStream;
 import java.util.stream.LongStream;
 import java.util.stream.Stream;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
+import org.junit.jupiter.params.provider.ValueSource;
 
 class A {
   private static final boolean CONST_BOOLEAN = false;
   private static final byte CONST_BYTE = 42;
   private static final char CONST_CHARACTER = 'a';
   private static final short CONST_SHORT = 42;
   private static final int CONST_INTEGER = 42;
   private static final long CONST_LONG = 42;
   private static final float CONST_FLOAT = 42;
   private static final double CONST_DOUBLE = 42;
   private static final String CONST_STRING = "foo";
 
-  private static Stream<Arguments> streamOfBooleanArguments() {
-    return Stream.of(arguments(false), arguments(true), arguments(CONST_BOOLEAN));
-  }
-
   @ParameterizedTest
-  @MethodSource("streamOfBooleanArguments")
+  @ValueSource(booleans = {false, true, CONST_BOOLEAN})
   void primitiveBoolean(boolean b) {}
 
-  private static Stream<Object> streamOfBooleansAndBooleanArguments() {
-    return Stream.of(false, arguments(true), CONST_BOOLEAN);
-  }
-
   @ParameterizedTest
-  @MethodSource("streamOfBooleansAndBooleanArguments")
+  @ValueSource(booleans = {false, true, CONST_BOOLEAN})
   void boxedBoolean(Boolean b) {}
 
-  private static List<Arguments> listOfByteArguments() {
-    return List.of(arguments((byte) 0), arguments((byte) 1), arguments(CONST_BYTE));
-  }
-
   @ParameterizedTest
-  @MethodSource("listOfByteArguments")
+  @ValueSource(bytes = {(byte) 0, (byte) 1, CONST_BYTE})
   void primitiveByte(byte b) {}
 
-  private static List<Object> listOfBytesAndByteArguments() {
-    return List.of((byte) 0, arguments((byte) 1), CONST_BYTE);
-  }
-
   @ParameterizedTest
-  @MethodSource("listOfBytesAndByteArguments")
+  @ValueSource(bytes = {(byte) 0, (byte) 1, CONST_BYTE})
   void boxedByte(Byte b) {}
 
-  private static Set<Arguments> setOfCharacterArguments() {
-    return Set.of(arguments((char) 0), arguments((char) 1), arguments(CONST_CHARACTER));
-  }
-
   @ParameterizedTest
-  @MethodSource("setOfCharacterArguments")
+  @ValueSource(chars = {(char) 0, (char) 1, CONST_CHARACTER})
   void primitiveCharacter(char c) {}
 
-  private static Set<Object> setOfCharactersAndCharacterArguments() {
-    return Set.of((char) 0, arguments((char) 1), CONST_CHARACTER);
-  }
-
   @ParameterizedTest
-  @MethodSource("setOfCharactersAndCharacterArguments")
+  @ValueSource(chars = {(char) 0, (char) 1, CONST_CHARACTER})
   void boxedCharacter(Character c) {}
 
-  private static Arguments[] arrayOfShortArguments() {
-    return new Arguments[] {arguments((short) 0), arguments((short) 1), arguments(CONST_SHORT)};
-  }
-
   @ParameterizedTest
-  @MethodSource("arrayOfShortArguments")
+  @ValueSource(shorts = {(short) 0, (short) 1, CONST_SHORT})
   void primitiveShort(short s) {}
 
-  private static Object[] arrayOfShortsAndShortArguments() {
-    return new Object[] {(short) 0, arguments((short) 1), CONST_SHORT};
-  }
-
   @ParameterizedTest
-  @MethodSource("arrayOfShortsAndShortArguments")
+  @ValueSource(shorts = {(short) 0, (short) 1, CONST_SHORT})
   void boxedShort(Short s) {}
 
-  private static IntStream intStream() {
-    return IntStream.of(0, 1, CONST_INTEGER);
-  }
-
   @ParameterizedTest
-  @MethodSource("intStream")
+  @ValueSource(ints = {0, 1, CONST_INTEGER})
   void primitiveInteger(int i) {}
 
-  private static int[] intArray() {
-    return new int[] {0, 1, CONST_INTEGER};
-  }
-
   @ParameterizedTest
-  @MethodSource("intArray")
+  @ValueSource(ints = {0, 1, CONST_INTEGER})
   void boxedInteger(Integer i) {}
 
-  private static LongStream longStream() {
-    return LongStream.of(0, 1, CONST_LONG);
-  }
-
   @ParameterizedTest
-  @MethodSource("longStream")
+  @ValueSource(longs = {0, 1, CONST_LONG})
   void primitiveLong(long l) {}
 
-  private static long[] longArray() {
-    return new long[] {0, 1, CONST_LONG};
-  }
-
   @ParameterizedTest
-  @MethodSource("longArray")
+  @ValueSource(longs = {0, 1, CONST_LONG})
   void boxedLong(Long l) {}
 
-  private static ImmutableList<Arguments> immutableListOfFloatArguments() {
-    return ImmutableList.of(arguments(0.0F), arguments(1.0F), arguments(CONST_FLOAT));
-  }
-
   @ParameterizedTest
-  @MethodSource("immutableListOfFloatArguments")
+  @ValueSource(floats = {0.0F, 1.0F, CONST_FLOAT})
   void primitiveFloat(float f) {}
 
-  private static Stream<Object> streamOfFloatsAndFloatArguments() {
-    return Stream.of(0.0F, arguments(1.0F), CONST_FLOAT);
-  }
-
   @ParameterizedTest
-  @MethodSource("streamOfFloatsAndFloatArguments")
+  @ValueSource(floats = {0.0F, 1.0F, CONST_FLOAT})
   void boxedFloat(Float f) {}
 
-  private static DoubleStream doubleStream() {
-    return DoubleStream.of(0, 1, CONST_DOUBLE);
-  }
-
   @ParameterizedTest
-  @MethodSource("doubleStream")
+  @ValueSource(doubles = {0, 1, CONST_DOUBLE})
   void primitiveDouble(double d) {}
 
-  private static double[] doubleArray() {
-    return new double[] {0, 1, CONST_DOUBLE};
-  }
-
   @ParameterizedTest
-  @MethodSource("doubleArray")
+  @ValueSource(doubles = {0, 1, CONST_DOUBLE})
   void boxedDouble(Double d) {}
 
-  private static ImmutableSet<Arguments> immutableSetOfStringArguments() {
-    return ImmutableSet.of(arguments("foo"), arguments("bar"), arguments(CONST_STRING));
-  }
-
   @ParameterizedTest
-  @MethodSource("immutableSetOfStringArguments")
+  @ValueSource(strings = {"foo", "bar", CONST_STRING})
   void string(String s) {}
 
-  private static Stream<Class<?>> streamOfClasses() {
-    return Stream.of(Stream.class, java.util.Map.class);
-  }
-
   @ParameterizedTest
-  @MethodSource("streamOfClasses")
+  @ValueSource(classes = {Stream.class, java.util.Map.class})
   void clazz(Class<?> c) {}
 
-  private static Stream<Arguments> sameNameFactoryTestCases() {
-    return Stream.of(arguments(1));
-  }
-
   private static Stream<Arguments> sameNameFactoryTestCases(int overload) {
     return Stream.of(arguments(overload));
   }
 
   @ParameterizedTest
-  @MethodSource("sameNameFactoryTestCases")
+  @ValueSource(ints = 1)
   void sameNameFactory(int i) {}
 }
 

Identification

Shows code lines which will (not) be flagged by this bug pattern.
A //BUG: Diagnostic contains: comment is placed above any violating line.

import static org.junit.jupiter.params.provider.Arguments.arguments;

import java.util.Optional;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

class A {
  private static Stream<Arguments> identificationTestCases() {
    return Stream.of(arguments(1), Arguments.of(2));
  }

  @ParameterizedTest
  // BUG: Diagnostic contains:
  @MethodSource("identificationTestCases")
  void identification(int foo) {}

  private static int[] identificationWithParensTestCases() {
    return new int[] {1, 2};
  }

  @ParameterizedTest
  // BUG: Diagnostic contains:
  @MethodSource("identificationWithParensTestCases()")
  void identificationWithParens(int foo) {}

  @ParameterizedTest
  @MethodSource("valueFactoryMissingTestCases")
  void valueFactoryMissing(int foo) {}

  private static Stream<Arguments> multipleUsagesTestCases() {
    return Stream.of(arguments(1), Arguments.of(2));
  }

  @ParameterizedTest
  @MethodSource("multipleUsagesTestCases")
  void multipleUsages1(int foo) {}

  @ParameterizedTest
  @MethodSource("multipleUsagesTestCases()")
  void multipleUsages2(int bar) {}

  private static Stream<Arguments> valueFactoryRepeatedTestCases() {
    return Stream.of(arguments(1), arguments(2));
  }

  @ParameterizedTest
  @MethodSource({"valueFactoryRepeatedTestCases", "valueFactoryRepeatedTestCases"})
  void valueFactoryRepeated(int foo) {}

  private static Stream<Arguments> multipleParametersTestCases() {
    return Stream.of(arguments(1, 2), arguments(3, 4));
  }

  @ParameterizedTest
  @MethodSource("multipleParametersTestCases")
  void multipleParameters(int first, int second) {}

  private static int[] arrayWithoutInitializersTestCases() {
    return new int[1];
  }

  @ParameterizedTest
  @MethodSource("arrayWithoutInitializersTestCases")
  void arrayWithoutInitializers(int foo) {}

  private static Stream<Arguments> runtimeValueTestCases() {
    int second = 2;
    return Stream.of(arguments(1), arguments(second));
  }

  @ParameterizedTest
  @MethodSource("runtimeValueTestCases")
  void runtimeValue(int foo) {}

  private static Stream<Arguments> streamChainTestCases() {
    return Stream.of(1, 2).map(Arguments::arguments);
  }

  @ParameterizedTest
  @MethodSource("streamChainTestCases")
  void streamChain(int number) {}

  private static Stream<Arguments> multipleReturnsTestCases() {
    if (true) {
      return Stream.of(arguments(1), arguments(2));
    } else {
      return Stream.of(arguments(3), arguments(4));
    }
  }

  @ParameterizedTest
  @MethodSource("multipleReturnsTestCases")
  void multipleReturns(int number) {}

  private static Stream<Arguments> multipleFactoriesFooTestCases() {
    return Stream.of(arguments(1));
  }

  private static Stream<Arguments> multipleFactoriesBarTestCases() {
    return Stream.of(arguments(1));
  }

  @ParameterizedTest
  @MethodSource({"multipleFactoriesFooTestCases", "multipleFactoriesBarTestCases"})
  void multipleFactories(int i) {}

  private static Stream<Arguments> extraArgsTestCases() {
    return Stream.of(arguments(1), arguments(1, 2));
  }

  @ParameterizedTest
  @MethodSource("extraArgsTestCases")
  void extraArgs(int... i) {}

  private static Stream<Arguments> localClassTestCases() {
    class Foo {
      Stream<Arguments> foo() {
        return Stream.of(arguments(1), arguments(2));
      }
    }
    return Stream.of(arguments(1), arguments(2));
  }

  @ParameterizedTest
  // BUG: Diagnostic contains:
  @MethodSource("localClassTestCases")
  void localClass(int i) {}

  private static Stream<Arguments> lambdaReturnTestCases() {
    int foo =
        Optional.of(10)
            .map(
                i -> {
                  return i / 2;
                })
            .orElse(0);
    return Stream.of(arguments(1), arguments(1));
  }

  @ParameterizedTest
  // BUG: Diagnostic contains:
  @MethodSource("lambdaReturnTestCases")
  void lambdaReturn(int i) {}

  @ParameterizedTest
  @MethodSource("tech.picnic.errorprone.Foo#fooTestCases")
  void staticMethodReference(int foo) {}

  private static Stream<Arguments> valueFactoryWithArgumentTestCases(int amount) {
    return Stream.of(arguments(1), arguments(2));
  }

  @ParameterizedTest
  // BUG: Diagnostic contains:
  @MethodSource("valueFactoryWithArgumentTestCases")
  void valueFactoryWithArgument(int foo) {}

  private static Arguments[] emptyArrayValueFactoryTestCases() {
    return new Arguments[] {};
  }

  @ParameterizedTest
  @MethodSource("emptyArrayValueFactoryTestCases")
  void emptyArrayValueFactory(int foo) {}

  private static Stream<Arguments> emptyStreamValueFactoryTestCases() {
    return Stream.of();
  }

  @ParameterizedTest
  @MethodSource("emptyStreamValueFactoryTestCases")
  void emptyStreamValueFactory(int foo) {}

  private static Arguments[] invalidValueFactoryArgumentsTestCases() {
    return new Arguments[] {arguments(1), arguments(new Object() {})};
  }

  @ParameterizedTest
  @MethodSource("invalidValueFactoryArgumentsTestCases")
  void invalidValueFactoryArguments(int foo) {}
}

Copyright © 2017-2024 Picnic Technologies BV