CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-springframework-boot--spring-boot-starter-test

Starter for testing Spring Boot applications with libraries including JUnit Jupiter, Hamcrest and Mockito

Pending
Overview
Eval results
Files

mock-integration.mddocs/

Mock Integration

Seamless Mockito integration with Spring context for mocking beans and services in Spring Boot tests.

⚠️ Deprecation Notice: As of Spring Boot 3.4.0, @MockBean and @SpyBean are deprecated for removal. Use @MockitoBean and @MockitoSpyBean from Spring Framework 6.2+ instead:

  • org.springframework.test.context.bean.override.mockito.MockitoBean
  • org.springframework.test.context.bean.override.mockito.MockitoSpyBean

Capabilities

@MockBean Annotation

Creates and injects Mockito mocks into the Spring application context.

/**
 * Annotation that can be used to add mocks to a Spring ApplicationContext
 * @since 1.4.0
 * @deprecated since 3.4.0 for removal in Spring Boot 4.0.0. Use {@code @MockitoBean} from Spring Framework instead.
 */
@SuppressWarnings("removal")
@Deprecated(since = "3.4.0", forRemoval = true)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(MockBeans.class)
public @interface MockBean {
    /**
     * The name of the bean to register or replace
     */
    String name() default "";
    
    /**
     * The classes to mock
     */
    Class<?>[] classes() default {};
    
    /**
     * Extra interfaces that should also be declared on the mock
     */
    Class<?>[] extraInterfaces() default {};
    
    /**
     * The Mockito Answer to use on the mock
     */
    Answers answer() default Answers.RETURNS_DEFAULTS;
    
    /**
     * Whether the mock is serializable
     */
    boolean serializable() default false;
    
    /**
     * When to reset the mock
     */
    MockReset reset() default MockReset.AFTER;
}

/**
 * Container annotation for @MockBean
 * @deprecated since 3.4.0 for removal in Spring Boot 4.0.0. Use {@code @MockitoBean} from Spring Framework instead.
 */
@SuppressWarnings("removal")
@Deprecated(since = "3.4.0", forRemoval = true)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MockBeans {
    MockBean[] value();
}

Usage Examples:

@SpringBootTest
class MockBeanTest {
    
    @MockBean
    private UserService userService;
    
    @MockBean
    private EmailService emailService;
    
    @Autowired
    private UserController userController;
    
    @Test
    void mockBeanIsInjected() {
        // Mock behavior
        User mockUser = new User("test@example.com", "Test User");
        when(userService.findByEmail("test@example.com")).thenReturn(mockUser);
        
        // Test controller using mocked service
        ResponseEntity<User> response = userController.getUser("test@example.com");
        
        assertThat(response.getBody()).isEqualTo(mockUser);
        verify(userService).findByEmail("test@example.com");
    }
    
    @Test
    void mockWithCustomAnswer() {
        // Configure mock with custom answer
        when(userService.findByEmail(anyString()))
            .thenAnswer(invocation -> {
                String email = invocation.getArgument(0);
                return new User(email, "Generated User");
            });
        
        User user = userService.findByEmail("any@example.com");
        assertThat(user.getEmail()).isEqualTo("any@example.com");
        assertThat(user.getName()).isEqualTo("Generated User");
    }
}

// Multiple mocks with container annotation
@MockBeans({
    @MockBean(UserService.class),
    @MockBean(EmailService.class)
})
class MultipleMocksTest {
    // Test implementation
}

@SpyBean Annotation

Creates and injects Mockito spies into the Spring application context.

/**
 * Annotation that can be used to apply Mockito spies to a Spring ApplicationContext
 * @since 1.4.0
 * @deprecated since 3.4.0 for removal in Spring Boot 4.0.0. Use {@code @MockitoSpyBean} from Spring Framework instead.
 */
@SuppressWarnings("removal")
@Deprecated(since = "3.4.0", forRemoval = true)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(SpyBeans.class)
public @interface SpyBean {
    /**
     * The name of the bean to spy upon
     */
    String name() default "";
    
    /**
     * The classes to spy upon
     */
    Class<?>[] classes() default {};
    
    /**
     * When to reset the spy
     */
    MockReset reset() default MockReset.AFTER;
    
    /**
     * Whether the spy should be proxy target aware
     */
    boolean proxyTargetAware() default true;
}

/**
 * Container annotation for @SpyBean
 * @deprecated since 3.4.0 for removal in Spring Boot 4.0.0. Use {@code @MockitoSpyBean} from Spring Framework instead.
 */
@SuppressWarnings("removal")
@Deprecated(since = "3.4.0", forRemoval = true)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SpyBeans {
    SpyBean[] value();
}

Usage Examples:

@SpringBootTest
class SpyBeanTest {
    
    @SpyBean
    private UserService userService;
    
    @Test
    void spyOnRealService() {
        // Real method will be called, but we can verify and stub
        User realUser = userService.findByEmail("real@example.com");
        
        // Verify the real method was called
        verify(userService).findByEmail("real@example.com");
        
        // Stub a method for specific behavior
        doReturn(new User("stubbed@example.com", "Stubbed User"))
            .when(userService).findByEmail("stubbed@example.com");
        
        User stubbedUser = userService.findByEmail("stubbed@example.com");
        assertThat(stubbedUser.getName()).isEqualTo("Stubbed User");
    }
}

Mock Reset Options

Enumeration for controlling when mocks are reset.

/**
 * Options for when to reset mocks
 * @since 1.4.0
 */
public enum MockReset {
    /**
     * Reset the mock before each test method
     */
    BEFORE,
    
    /**
     * Reset the mock after each test method
     */
    AFTER,
    
    /**
     * Don't reset the mock
     */
    NONE
}

Mock Infrastructure

Core classes that handle mock creation and lifecycle management.

/**
 * BeanPostProcessor to handle @MockBean and @SpyBean annotations
 */
public class MockitoPostProcessor implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {
    /**
     * Process bean before instantiation to inject mocks
     */
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName);
}

/**
 * TestExecutionListener that resets mocks according to MockReset configuration
 */
public class ResetMocksTestExecutionListener extends AbstractTestExecutionListener {
    /**
     * Reset mocks before test method if configured
     */
    @Override
    public void beforeTestMethod(TestContext testContext);
    
    /**
     * Reset mocks after test method if configured  
     */
    @Override
    public void afterTestMethod(TestContext testContext);
}

/**
 * TestExecutionListener that handles Mockito setup and cleanup
 */
public class MockitoTestExecutionListener extends AbstractTestExecutionListener {
    /**
     * Initialize Mockito for the test
     */
    @Override
    public void beforeTestMethod(TestContext testContext);
    
    /**
     * Clean up Mockito after the test
     */
    @Override
    public void afterTestMethod(TestContext testContext);
}

/**
 * MockResolver implementation for Spring Boot
 */
public class SpringBootMockResolver implements MockResolver {
    /**
     * Resolve mock instance for the given field
     */
    @Override
    public Object resolve(Field field, Object instance);
}

Advanced Mock Configuration

Advanced patterns for mock configuration and usage.

Usage Examples:

@SpringBootTest
class AdvancedMockTest {
    
    // Mock with specific reset behavior
    @MockBean(reset = MockReset.BEFORE)
    private UserRepository userRepository;
    
    // Mock with extra interfaces
    @MockBean(extraInterfaces = {Serializable.class, Cloneable.class})
    private PaymentService paymentService;
    
    // Mock with custom answer
    @MockBean(answer = Answers.CALLS_REAL_METHODS)
    private AbstractUserService abstractUserService;
    
    @Test
    void advancedMockConfiguration() {
        // Configure mock with fluent API
        when(userRepository.findByEmail(anyString()))
            .thenReturn(Optional.of(new User("test@example.com", "Test")))
            .thenReturn(Optional.empty());
        
        // First call returns user
        Optional<User> first = userRepository.findByEmail("test1@example.com");
        assertThat(first).isPresent();
        
        // Second call returns empty
        Optional<User> second = userRepository.findByEmail("test2@example.com");
        assertThat(second).isEmpty();
        
        // Verify call count
        verify(userRepository, times(2)).findByEmail(anyString());
    }
    
    @Test
    void mockWithCaptor() {
        ArgumentCaptor<User> userCaptor = ArgumentCaptor.forClass(User.class);
        
        // Method under test
        userService.saveUser(new User("save@example.com", "Save User"));
        
        // Capture and verify the argument
        verify(userRepository).save(userCaptor.capture());
        User capturedUser = userCaptor.getValue();
        
        assertThat(capturedUser.getEmail()).isEqualTo("save@example.com");
        assertThat(capturedUser.getName()).isEqualTo("Save User");
    }
}

// Configuration class example for complex mocking
@TestConfiguration
static class MockConfig {
    
    @Bean
    @Primary
    public UserService mockUserService() {
        UserService mock = Mockito.mock(UserService.class);
        
        // Pre-configure common mock behavior
        when(mock.findByEmail(startsWith("admin")))
            .thenReturn(new User("admin@example.com", "Admin"));
            
        when(mock.findByEmail(startsWith("test")))
            .thenReturn(new User("test@example.com", "Test User"));
            
        return mock;
    }
}

Integration with Test Slices

Mock integration works seamlessly with Spring Boot test slices.

Usage Examples:

@WebMvcTest(UserController.class)
class WebMvcMockTest {
    
    @MockBean
    private UserService userService;
    
    @Autowired
    private MockMvc mockMvc;
    
    @Test
    void controllerWithMockedService() throws Exception {
        when(userService.findByEmail("test@example.com"))
            .thenReturn(new User("test@example.com", "Test User"));
        
        mockMvc.perform(get("/users/test@example.com"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.email").value("test@example.com"))
            .andExpect(jsonPath("$.name").value("Test User"));
            
        verify(userService).findByEmail("test@example.com");
    }
}

@DataJpaTest
class JpaRepositoryMockTest {
    
    @TestEntityManager
    private TestEntityManager entityManager;
    
    @Autowired
    private UserRepository userRepository;
    
    @MockBean
    private EmailService emailService; // Mock external service
    
    @Test
    void repositoryWithMockedExternalService() {
        // Save entity using real repository
        User user = new User("test@example.com", "Test User");
        entityManager.persistAndFlush(user);
        
        // Mock external service
        when(emailService.sendWelcomeEmail(anyString())).thenReturn(true);
        
        // Test service method that uses both repository and external service
        boolean result = userService.registerUser("test@example.com", "Test User");
        
        assertThat(result).isTrue();
        verify(emailService).sendWelcomeEmail("test@example.com");
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-org-springframework-boot--spring-boot-starter-test

docs

context-testing.md

core-testing.md

index.md

json-testing.md

mock-integration.md

output-capture.md

test-slices.md

web-testing.md

tile.json