You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在单个实现类中注入两个Mockito模拟对象?当前仅一个模拟生效,BCryptPasswordEncoder注入出现空指针异常

Got it, let's break down what's going wrong here and fix your test setup step by step.

The Root Causes of Your Issues

  1. Mixed Annotation Usage: You're combining @SpringBootTest (which spins up a full Spring context) with pure Mockito annotations like @Mock instead of Spring Boot's @MockBean. This creates conflicts between Spring-managed beans and Mockito's mocks.
  2. Manual Instance Creation: You're manually instantiating UserServiceImpl while using @InjectMocks—Mockito prefers to create the instance itself to handle dependency injection properly, so your manual new breaks this logic.
  3. Unconfigured Mocks: For BCryptPasswordEncoder, whether you use @Autowired (no Spring context in pure Mockito tests) or @Mock (no behavior set up), you end up with a null reference or an unconfigured mock that returns null when methods are called.

If you're writing a unit test for UserService (no need for a full Spring context), use Mockito's extension to handle mocks and injection:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
public class UserServiceTests {

    // Mock both dependencies
    @Mock
    private BCryptPasswordEncoder passwordEncoder;

    @Mock
    private UserRepository userRepository;

    // Let Mockito create and inject dependencies into UserService
    @InjectMocks
    private UserServiceImpl userService;

    @Test
    void testUserCreation() {
        // Configure mock behaviors to avoid null pointers
        when(passwordEncoder.encode("raw-password")).thenReturn("encoded-password-123");
        when(userRepository.save(any(User.class))).thenReturn(new User(1L, "test@example.com", "encoded-password-123"));

        // Call your service method
        User createdUser = userService.createUser("test@example.com", "raw-password");

        // Add your assertions here
        assert createdUser.getId() == 1L;
        assert createdUser.getPassword().equals("encoded-password-123");
    }
}

Key Notes for This Setup:

  • Remove @SpringBootTest and MockitoAnnotations.initMocks(this)—@ExtendWith(MockitoExtension.class) handles mock initialization automatically.
  • Always configure mock behaviors with when(...).thenReturn(...) (or similar) for any method calls your service makes. Without this, mocks return default values (like null) which cause NPEs.

Solution 2: Spring Boot Integration Test (For Real Bean Dependencies)

If you need to use a real BCryptPasswordEncoder instance (e.g., to test actual password encoding logic), use @SpringBootTest with @MockBean to replace the UserRepository with a mock:

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;

@SpringBootTest
public class UserServiceTests {

    // Inject the real BCryptPasswordEncoder bean from Spring context
    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    // Replace the real UserRepository with a mock in the Spring context
    @MockBean
    private UserRepository userRepository;

    // Inject the Spring-managed UserService instance
    @Autowired
    private UserService userService;

    @Test
    void testPasswordEncoding() {
        String rawPassword = "my-secure-password";
        String encodedPassword = passwordEncoder.encode(rawPassword);

        // Verify the encoding works as expected
        assert passwordEncoder.matches(rawPassword, encodedPassword);
        assert !passwordEncoder.matches("wrong-password", encodedPassword);
    }
}

Key Notes for This Setup:

  • @MockBean tells Spring to create a mock of UserRepository and register it in the context, replacing the real implementation. This lets you test UserService with a real password encoder but a mocked repository.
  • Use this only when you need real Spring-managed beans—unit tests should prefer Solution 1 for speed and isolation.

Final Tips

  • Never mix manual instance creation with @InjectMocks: Let Mockito handle creating the instance for you.
  • Always configure mocks: Unconfigured mocks return default values, which are almost always the cause of NPEs in Mockito tests.
  • Choose the right test type: Unit tests (Mockito only) are faster and more isolated; integration tests (Spring context) are for testing interactions between multiple beans.

内容的提问来源于stack exchange,提问作者Prabagaran Sellamuthu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 06:50:30