junit-team/junit5 · error · PreconditionViolationException

Constructor injection is not supported for @ParameterizedCla

Error message

Constructor injection is not supported for @ParameterizedClass classes with @TestInstance(Lifecycle.PER_CLASS)

What it means

Thrown by ParameterizedClassExtension.createClassContext() when a @ParameterizedClass is combined with @TestInstance(Lifecycle.PER_CLASS) and constructor injection is detected. PER_CLASS creates a single test instance reused across all parameter sets, but constructor injection requires a new instance per parameter set — the two are fundamentally incompatible.

Source

Thrown at junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedClassExtension.java:119

			return false;
		}

		store.put(DECLARATION_CONTEXT_KEY,
			createClassContext(extensionContext, extensionContext.getRequiredTestClass(), annotation.get()));

		return true;
	}

	private static ParameterizedClassContext createClassContext(ExtensionContext extensionContext, Class<?> testClass,
			ParameterizedClass annotation) {

		TestInstance.Lifecycle lifecycle = extensionContext.getTestInstanceLifecycle() //
				.orElseThrow(() -> new PreconditionViolationException("TestInstance.Lifecycle not present"));

		ParameterizedClassContext classContext = new ParameterizedClassContext(testClass, annotation, lifecycle);

		if (lifecycle == PER_CLASS && classContext.getInjectionType() == CONSTRUCTOR) {
			throw new PreconditionViolationException(
				"Constructor injection is not supported for @ParameterizedClass classes with @TestInstance(Lifecycle.PER_CLASS)");
		}

		return classContext;
	}

	private ParameterizedClassContext getDeclarationContext(ExtensionContext extensionContext) {
		return requireNonNull(getStore(extensionContext)//
				.get(DECLARATION_CONTEXT_KEY, ParameterizedClassContext.class));
	}

	private Store getStore(ExtensionContext context) {
		return context.getStore(Namespace.create(ParameterizedClassExtension.class, context.getRequiredTestClass()));
	}

}

View on GitHub (pinned to 956246301e)

Solutions

  1. Switch to @TestInstance(Lifecycle.PER_METHOD) (the default) and remove @TestInstance(PER_CLASS) from the class
  2. If PER_CLASS is required, switch from constructor injection to field injection by annotating fields with @Parameter instead of using constructor parameters
  3. Move the parameterized parameters to a @ParameterizedTest method inside the class instead of using @ParameterizedClass

Example fix

// before
@ParameterizedClass
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@CsvSource("1, 2")
class MyTest {
    MyTest(int a, int b) { } // constructor injection
}

// after (field injection with PER_CLASS)
@ParameterizedClass
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@CsvSource("1, 2")
class MyTest {
    @Parameter(0) int a;
    @Parameter(1) int b;
}
Defensive patterns

Strategy: validation

Validate before calling

// Before combining @ParameterizedClass with PER_CLASS, check injection type:
boolean isPerClass = lifecycle == TestInstance.Lifecycle.PER_CLASS;
boolean usesConstructorInjection = Arrays.stream(testClass.getDeclaredConstructors())
    .anyMatch(c -> c.getParameterCount() > 0);
if (isPerClass && usesConstructorInjection) {
    throw new IllegalStateException(
        "Cannot use @ParameterizedClass with PER_CLASS and constructor injection");
}

Prevention

When it happens

Trigger: Annotating a class with both @ParameterizedClass and @TestInstance(TestInstance.Lifecycle.PER_CLASS) where the class constructor declares parameters (i.e., the injection type resolved to CONSTRUCTOR). ParameterizedClassContext determines the injection type by inspecting whether the constructor has parameters.

Common situations: Migrating a @ParameterizedTest class to @ParameterizedClass while keeping @TestInstance(PER_CLASS) (often used to share state across test methods or for @BeforeAll/@AfterAll non-static methods). Copying a PER_CLASS pattern from a regular test class to a parameterized class.

Related errors


AI-assisted analysis of junit-team/junit5@956246301e (2026-08-04). Data as JSON: /data/errors/4511c82b50a13304.json. Report an issue: GitHub.