[[integration-testing-annotations-junit4]] = Spring JUnit 4 Testing Annotations [WARNING] ==== JUnit 4 support is deprecated since Spring Framework 7.0 in favor of the xref:testing/testcontext-framework/support-classes.adoc#testcontext-junit-jupiter-extension[`SpringExtension`] and JUnit Jupiter. ==== The following annotations are supported only when used in conjunction with the xref:testing/testcontext-framework/support-classes.adoc#testcontext-junit4-runner[SpringRunner], xref:testing/testcontext-framework/support-classes.adoc#testcontext-junit4-rules[Spring's JUnit 4 rules], or xref:testing/testcontext-framework/support-classes.adoc#testcontext-support-classes-junit4[Spring's JUnit 4 support classes]: * xref:testing/annotations/integration-junit4.adoc#integration-testing-annotations-junit4-ifprofilevalue[`@IfProfileValue`] * xref:testing/annotations/integration-junit4.adoc#integration-testing-annotations-junit4-profilevaluesourceconfiguration[`@ProfileValueSourceConfiguration`] * xref:testing/annotations/integration-junit4.adoc#integration-testing-annotations-junit4-timed[`@Timed`] * xref:testing/annotations/integration-junit4.adoc#integration-testing-annotations-junit4-repeat[`@Repeat`] [[integration-testing-annotations-junit4-ifprofilevalue]] == `@IfProfileValue` `@IfProfileValue` indicates that the annotated test class or test method is enabled for a specific testing environment. If the configured `ProfileValueSource` returns a matching `value` for the provided `name`, the test is enabled. Otherwise, the test is disabled and, effectively, ignored. You can apply `@IfProfileValue` at the class level, the method level, or both. Class-level usage of `@IfProfileValue` takes precedence over method-level usage for any methods within that class or its subclasses. Specifically, a test is enabled if it is enabled both at the class level and at the method level. The absence of `@IfProfileValue` means the test is implicitly enabled. This is analogous to the semantics of JUnit 4's `@Ignore` annotation, except that the presence of `@Ignore` always disables a test. The following example shows a test that has an `@IfProfileValue` annotation: [tabs] ====== Java:: + [source,java,indent=0,subs="verbatim,quotes"] ---- @IfProfileValue(name="java.vendor", value="Oracle Corporation") // <1> @Test public void testProcessWhichRunsOnlyOnOracleJvm() { // some logic that should run only on Java VMs from Oracle Corporation } ---- <1> Run this test only when the Java vendor is "Oracle Corporation". Kotlin:: + [source,kotlin,indent=0,subs="verbatim,quotes"] ---- @IfProfileValue(name="java.vendor", value="Oracle Corporation") // <1> @Test fun testProcessWhichRunsOnlyOnOracleJvm() { // some logic that should run only on Java VMs from Oracle Corporation } ---- <1> Run this test only when the Java vendor is "Oracle Corporation". ====== Alternatively, you can configure `@IfProfileValue` with a list of `values` (with `OR` semantics) to achieve TestNG-like support for test groups in a JUnit 4 environment. Consider the following example: [tabs] ====== Java:: + [source,java,indent=0,subs="verbatim,quotes"] ---- @IfProfileValue(name="test-groups", values={"unit-tests", "integration-tests"}) // <1> @Test public void testProcessWhichRunsForUnitOrIntegrationTestGroups() { // some logic that should run only for unit and integration test groups } ---- <1> Run this test for unit tests and integration tests. Kotlin:: + [source,kotlin,indent=0,subs="verbatim,quotes"] ---- @IfProfileValue(name="test-groups", values=["unit-tests", "integration-tests"]) // <1> @Test fun testProcessWhichRunsForUnitOrIntegrationTestGroups() { // some logic that should run only for unit and integration test groups } ---- <1> Run this test for unit tests and integration tests. ====== [[integration-testing-annotations-junit4-profilevaluesourceconfiguration]] == `@ProfileValueSourceConfiguration` `@ProfileValueSourceConfiguration` is an annotation that can be applied to a test class to specify what type of `ProfileValueSource` to use when retrieving profile values configured through the `@IfProfileValue` annotation. If `@ProfileValueSourceConfiguration` is not declared for a test, `SystemProfileValueSource` is used by default. The following example shows how to use `@ProfileValueSourceConfiguration`: [tabs] ====== Java:: + [source,java,indent=0,subs="verbatim,quotes"] ---- @ProfileValueSourceConfiguration(CustomProfileValueSource.class) // <1> public class CustomProfileValueSourceTests { // class body... } ---- <1> Use a custom profile value source. Kotlin:: + [source,kotlin,indent=0,subs="verbatim,quotes"] ---- @ProfileValueSourceConfiguration(CustomProfileValueSource::class) // <1> class CustomProfileValueSourceTests { // class body... } ---- <1> Use a custom profile value source. ====== [[integration-testing-annotations-junit4-timed]] == `@Timed` `@Timed` indicates that the annotated test method must finish execution in a specified time period (in milliseconds). If the text execution time exceeds the specified time period, the test fails. The time period includes running the test method itself, any repetitions of the test (see `@Repeat`), as well as any setting up or tearing down of the test fixture. The following example shows how to use it: [tabs] ====== Java:: + [source,java,indent=0,subs="verbatim,quotes"] ---- @Timed(millis = 1000) // <1> public void testProcessWithOneSecondTimeout() { // some logic that should not take longer than 1 second to run } ---- <1> Set the time period for the test to one second. Kotlin:: + [source,kotlin,indent=0,subs="verbatim,quotes"] ---- @Timed(millis = 1000) // <1> fun testProcessWithOneSecondTimeout() { // some logic that should not take longer than 1 second to run } ---- <1> Set the time period for the test to one second. ====== Spring's `@Timed` annotation has different semantics than JUnit 4's `@Test(timeout=...)` support. Specifically, due to the manner in which JUnit 4 handles test execution timeouts (that is, by executing the test method in a separate `Thread`), `@Test(timeout=...)` preemptively fails the test if the test takes too long. Spring's `@Timed`, on the other hand, does not preemptively fail the test but rather waits for the test to complete before failing. [[integration-testing-annotations-junit4-repeat]] == `@Repeat` `@Repeat` indicates that the annotated test method must be run repeatedly. The number of times that the test method is to be run is specified in the annotation. The scope of execution to be repeated includes execution of the test method itself as well as any setting up or tearing down of the test fixture. When used with the xref:testing/testcontext-framework/support-classes.adoc#testcontext-junit4-rules[`SpringMethodRule`], the scope additionally includes preparation of the test instance by `TestExecutionListener` implementations. The following example shows how to use the `@Repeat` annotation: [tabs] ====== Java:: + [source,java,indent=0,subs="verbatim,quotes"] ---- @Repeat(10) // <1> @Test public void testProcessRepeatedly() { // ... } ---- <1> Repeat this test ten times. Kotlin:: + [source,kotlin,indent=0,subs="verbatim,quotes"] ---- @Repeat(10) // <1> @Test fun testProcessRepeatedly() { // ... } ---- <1> Repeat this test ten times. ======