Close

Spring Core Testing - Understanding @MockitoSpyBean

[Last Updated: Feb 12, 2026]

The @MockitoSpyBean annotation wraps an existing bean in the Spring test's ApplicationContext with a Mockito spy. Unlike mocks that replace the entire bean, spies allow partial mocking where you can override specific methods while keeping the real implementation for others.

Why Use @MockitoSpyBean?

Spies are useful when you want to test a component with mostly real behavior but need to control or verify specific method calls:

  • Wraps real beans instead of replacing them
  • Allows selective stubbing of specific methods
  • Keeps original implementation for non-stubbed methods
  • Enables verification of method calls on real objects

Java source and doc

Definition of MockitoSpyBean

Version: 7.0.4
 package org.springframework.test.context.bean.override.mockito;
 @Target({ ElementType.FIELD, ElementType.TYPE })
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
 @Repeatable(MockitoSpyBeans.class)
 @BeanOverride(MockitoBeanOverrideProcessor.class)
 public @interface MockitoSpyBean {
     @AliasFor("name")
     String value() default ""; 1
     @AliasFor("value")
     String name() default ""; 2
     Class<?>[] types() default {}; 3
     String contextName() default ""; 4
     MockReset reset() default MockReset.AFTER; 5
 }
1Alias for #name().
2Name of the bean to spy.
3One or more types to spy. (Since 6.2.3)
4The name of the context hierarchy level in which this @MockitoSpyBean should be applied. (Since 6.2.6)
5The reset mode to apply to the spied bean.

Example

Service Classes

First, let's create a calculator service and a wrapper service:

package com.logicbig.example;

import org.springframework.stereotype.Component;

@Component
public class Calculator {

    public int add(int a, int b) {
        return a + b;
    }

    public int multiply(int a, int b) {
        return a * b;
    }
}
package com.logicbig.example;

import org.springframework.stereotype.Service;

@Service
public class MathService {
    private final Calculator calculator;

    public MathService(Calculator calculator) {
        this.calculator = calculator;
    }

    public int performAddition(int a, int b) {
        return calculator.add(a, b);
    }

    public int performMultiplication(int a, int b) {
        return calculator.multiply(a, b);
    }
}

Configuration

The configuration class registers our beans:

package com.logicbig.example;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
public class AppConfig {
}

Test with @MockitoSpyBean

Now we'll test by spying on the calculator to override one method:

package com.logicbig.example;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.bean.override.mockito.MockitoSpyBean;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.doReturn;

@SpringJUnitConfig(AppConfig.class)
public class MockitoSpyBeanTest {

    @MockitoSpyBean
    Calculator calculator;

    @Autowired
    MathService mathService;

    @Test
    public void testWithSpiedCalculator() {
        doReturn(100).when(calculator).add(5, 10);

        int addResult = mathService.performAddition(5, 10);
        System.out.println("Add result: " + addResult);
        assertEquals(100, addResult);

        int multiplyResult = mathService.performMultiplication(4, 5);
        System.out.println("Multiply result: " + multiplyResult);
        assertEquals(20, multiplyResult);
    }
}

Output

$ mvn test
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------< com.logicbig.example:mockito-spy-bean >----------------
[INFO] Building mockito-spy-bean 1.0-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- dependency:3.6.1:properties (default) @ mockito-spy-bean ---
[INFO]
[INFO] --- resources:3.3.1:resources (default-resources) @ mockito-spy-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\mockito-spy-bean\src\main\resources
[INFO]
[INFO] --- compiler:3.13.0:compile (default-compile) @ mockito-spy-bean ---
[INFO] Nothing to compile - all classes are up to date.
[INFO]
[INFO] --- resources:3.3.1:testResources (default-testResources) @ mockito-spy-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\mockito-spy-bean\src\test\resources
[INFO]
[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ mockito-spy-bean ---
[INFO] Nothing to compile - all classes are up to date.
[INFO]
[INFO] --- surefire:3.2.5:test (default-test) @ mockito-spy-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.MockitoSpyBeanTest
Add result: 100
Multiply result: 20
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.989 s -- in com.logicbig.example.MockitoSpyBeanTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 9.888 s
[INFO] Finished at: 2026-02-10T07:53:20+08:00
[INFO] ------------------------------------------------------------------------

Conclusion

The output demonstrates that @MockitoSpyBean wrapped the real Calculator bean with a spy. The add method used the stubbed value (100) while the multiply method executed the real implementation (20). This shows how spies enable partial mocking, allowing us to control specific behaviors while preserving the original implementation for other methods.

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)
  • mockito-core 5.20.0 (Mockito mock objects library core API and implementation)
  • JDK 21
  • Maven 3.9.11

Spring Core Testing - Understanding @MockitoSpyBean Select All Download
  • mockito-spy-bean
    • src
      • main
        • java
          • com
            • logicbig
              • example
      • test
        • java
          • com
            • logicbig
              • example
                • MockitoSpyBeanTest.java

    See Also

    Join