【问题标题】:Spring Boot Mockito - @InjectMocks - How to mock selected dependencies onlySpring Boot Mockito - @InjectMocks - 如何仅模拟选定的依赖项
【发布时间】:2021-11-19 13:34:39
【问题描述】:

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

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

我的服务类如下所示:

@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);
    }
}

现在,这是我的测试课:

@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 依赖项。

这是可行的吗?如果是这样,怎么做?请指教。

谢谢, 斯里拉姆

【问题讨论】:

    标签: java spring-boot unit-testing mockito


    【解决方案1】:

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

    样式 1 - 弹簧集成测试

    这是 Spring Boot 在其上下文中创建 bean 并将它们注入测试类的时候。

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

    样式 2 - 单元测试

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

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

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

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

    注意如果UserRepository是spring-data repo,则不能手动创建。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-04-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多