Spring Boot Mockito - @InjectMocks - 如何仅模拟选定的依赖项

Spring Boot Mockito - @InjectMocks - How to mock selected dependencies only

我有一个名为 UserServiceImpl@Service,它依赖于另外两个 bean。一个是 UserRepository bean,另一个是名为 SessionService.

的 bean

我的要求是在测试 UserServiceImpl class 期间,我必须能够注入 SessionService 依赖项的模拟,但保持 UserRepository 依赖项原样。

我的服务 class 看起来像这样:

@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Autowired
    private UserRepository userRepository;
    
    @Autowired
    private SessionService sessionService;
    
    
    @Override
    public User create(User user) {
        log.info("User Creation at Service");
        // ... Do some validations .. //

        // This needs to be mocked in Unit Tests
        String returnValue = sessionService.doSomethingThatIDontWantInTests(); 

        user.setInternalKey(returnValue);

        // .. Do some more Validations .. //

        return userRepository.save(user);
    }
}

现在,这是我的测试 Class:

@SpringBootTest
class UserServiceTest {
    
    @InjectMocks
    private UserServiceImpl userService;
    
    @Mock
    private SessionService sessionService;
    
    
    @Test
    void CreateUserTest() {
        Mockito.when(sessionService.doSomethingThatIDontWantInTests()).thenReturn("abcxyz123321");
        User user = new User();
        user.setName("John Doe");
        user.setEmail("john.doe@example.com");
        User savedUser = userService.create(user);
        
        assertNotNull(savedUser.getUserId());

    }
}

当我 运行 这个测试时,Mockito 成功模拟了 SessionService 调用。但是,UserServiceImpl.createUser() 仍然失败并显示消息:

java.lang.NullPointerException: Cannot invoke "com.myproject.data.repos.UserRepository.save(User)" because "this.userRepository" is null

我是否也应该将 UserRepository 作为模拟注入并使用 Mockito 模拟 UserRepository.save() 方法?

我只想模拟 SessionService 依赖项,而不是 UserRepository 依赖项。

这是可行的吗?如果是这样,如何?请指教

谢谢, 斯里拉姆

您正在混合不同的测试风格。

样式 1 - spring 集成测试

此时 Spring Boot 在其上下文中创建 bean,然后将它们注入到测试中 class。

  • 使用@SpringBootTest
  • 使用 @Autowired 将 bean 注入到您的测试中
  • 使用 @MockBean 将 Spring 上下文中的 bean 替换为 mocks

样式 2 - 单元测试

这不使用 Spring DI。在这种风格中,通常会模拟所有依赖项。

  • 使用@ExtendWith(MockitoExtension.class)
  • 将依赖项注释为@Mock
  • @InjectMocks
  • 注释 SUT

也可以使用真正的依赖项,但在那种情况下您需要手动构建 SUT - Mockito 不支持部分注入。

单元测试往往更轻量且不那么脆弱,另一方面,集成测试覆盖了应用程序的大部分内容。

请注意,如果 UserRepository 是 spring-data repo,则无法手动创建。

您必须使用 @SpyBean (https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/mock/mockito/SpyBean.html),它将注入原始 bean,但您可以验证调用和参数。