Close

Spring Core Testing - Using @TestBean

[Last Updated: Feb 12, 2026]

In integration testing, it is often necessary to replace a real application bean with a simplified or controlled version. Traditionally, this required custom test configurations or context hierarchies.

@TestBean provides a concise mechanism to override or define beans specifically for a test. The replacement is applied at context creation time, ensuring that all dependent beans receive the test-specific instance.

Java source and doc

Definition of TestBean

Version: 7.0.4
 package org.springframework.test.context.bean.override.convention;
 @Target(ElementType.FIELD)
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
 @BeanOverride(TestBeanOverrideProcessor.class)
 @Reflective(TestBeanReflectiveProcessor.class)
 public @interface TestBean {
     @AliasFor("name")
     String value() default ""; 1
     @AliasFor("value")
     String name() default ""; 2
     String methodName() default ""; 3
     String contextName() default ""; 4
     boolean enforceOverride() default false; 5
 }
1Alias for #name().
2Name of the bean to override.
3Name of the static factory method that will be used to instantiate the bean to override.
4The name of the context hierarchy level in which this @TestBean should be applied. (Since 6.2.6)
5Whether to require the existence of the bean being overridden.

Bean Resolution


By default, @TestBean determines the bean to override from the type of the annotated field. If multiple beans match, a @Qualifier can be used to resolve the ambiguity. When no @Qualifier is present, the field name is used as a fallback. Alternatively, a specific bean can be targeted by explicitly setting the value or name attribute.

The static Factory Method

The test bean instance is created using a zero-argument static factory method whose return type matches the annotated field. The factory method may be declared in the same class as the @TestBean field, in any superclass, in implemented interfaces, or in an enclosing class when the field is declared in a nested test class.

Alternatively, a factory method can be defined in an external class and referenced using its fully qualified name with the format <fully-qualified-class-name>#<method-name>, for example: @TestBean(methodName = "org.example.TestUtils#createCustomerRepository").

Spring determines the factory method for @TestBean using the following rules.

  • If methodName is specified, Spring looks for a static method with that exact name.
  • Otherwise, Spring searches for a single static method whose name matches either the annotated field name or the explicitly specified bean name.

Example

This example replaces a service bean with a test-specific implementation and verifies that the overridden behavior is used during execution.

Spring App

package com.logicbig.example;

public interface MessageService {
    String message();
}
package com.logicbig.example;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {
    @Bean
    MessageService messageService() {
        return () -> "production message";
    }

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(AppConfig.class);
        MessageService service = context.getBean(MessageService.class);

        System.out.println(service.message());
        context.close();
    }
}

Output

production message

Integration Test

package com.logicbig.example;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.bean.override.convention.TestBean;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = AppConfig.class)
public class MyTest {

    @TestBean
    MessageService messageService;

    static MessageService messageService() {
        return () -> "test message";
    }

    @Test
    void myTestMethod() {
        Assertions.assertEquals("test message", messageService.message());
    }
}

Output

$ mvn test
[INFO] Scanning for projects...
[INFO]
[INFO] -------------------< com.logicbig.example:test-bean >-------------------
[INFO] Building test-bean 1.0-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- resources:3.3.1:resources (default-resources) @ test-bean ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\example-projects\spring-core-testing\test-bean\src\main\resources
[INFO]
[INFO] --- compiler:3.11.0:compile (default-compile) @ test-bean ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- resources:3.3.1:testResources (default-testResources) @ test-bean ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\example-projects\spring-core-testing\test-bean\src\test\resources
[INFO]
[INFO] --- compiler:3.11.0:testCompile (default-testCompile) @ test-bean ---
[INFO] Changes detected - recompiling the module! :source
[WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent!
[INFO] Compiling 1 source file with javac [debug target 21] to target\test-classes
[INFO]
[INFO] --- surefire:3.2.5:test (default-test) @ test-bean ---
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[WARNING] file.encoding cannot be set as system property, use <argLine>-Dfile.encoding=...</argLine> instead
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.logicbig.example.MyTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.683 s -- in com.logicbig.example.MyTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.842 s
[INFO] Finished at: 2026-02-09T11:01:38+08:00
[INFO] ------------------------------------------------------------------------

Conclusion

The output confirms that the service bean used by the application context was replaced by the test-provided instance. This demonstrates how @TestBean simplifies bean overriding without additional configuration classes or XML.

Example Project

Dependencies and Technologies Used:

  • spring-context 7.0.4 (Spring Context)
     Version Compatibility: 6.2.0 - 7.0.4Version List
    ×

    Version compatibilities of spring-context with this example:

    • 6.2.0
    • 6.2.1
    • 6.2.2
    • 6.2.3
    • 6.2.4
    • 6.2.5
    • 6.2.6
    • 6.2.7
    • 6.2.8
    • 6.2.9
    • 6.2.10
    • 6.2.11
    • 6.2.12
    • 6.2.13
    • 6.2.14
    • 6.2.15
    • 6.2.16
    • 7.0.0
    • 7.0.1
    • 7.0.2
    • 7.0.3
    • 7.0.4

    Versions in green have been tested.

  • spring-test 7.0.4 (Spring TestContext Framework)
  • junit-jupiter-engine 6.0.2 (Module "junit-jupiter-engine" of JUnit)
  • JDK 25
  • Maven 3.9.11

Spring Core Testing - Using TestBean Select All Download
  • test-bean
    • src
      • main
        • java
          • com
            • logicbig
              • example
      • test
        • java
          • com
            • logicbig
              • example
                • MyTest.java

    See Also

    Join