使用Mockito的Spring Boot服务层单元测试-模拟数据为空

时间:2019-03-01 22:05:28

标签: java spring spring-boot mockito

我试图使用Mockito和JUnit来测试服务层,但是每次运行它时,返回对象都会为空。

更多信息:

  • UserRepository是一个简单的Spring数据存储库,它扩展了CRUDRepository。
  • 用户是普通的JPA实体。

并测试:

@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {

    @Mock
    private UserRepository userRepository;

    @InjectMocks
    private UserService userService = new UserService();

    private User user;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void tesGetUserIdStatus() {

        // given
        user = new User();
        user.setUserName(userName);
        user.setUserId(userId);

        User newUser = new User();

        // when
        Mockito.when(userRepository.findByUserId(userId)).thenReturn(newUser);
        User result = userService.getUserById(user);

        // then
        Assert.assertEquals(newUser, user);
    }

}

该测试最终将使预期的对象值在实际值正确时为空。

我要测试的服务部分如下:

@Component
public class UserService {

    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
    this.userRepository = userRepository;
}

    public User getUserById(User user) throws EntityNotFoundException {


        String userId = user.getUserId();

        user = userRepository.findByUserId(userId);

        return user;
    }
...

3 个答案:

答案 0 :(得分:1)

通过findByUserId(UserId)表示findByUserId(userId)Assert.assertEquals(newUser, user)是指Assert.assertEquals(result, user)?值userName和userId从何而来?

请不要使用@InjectMocks注入UserService

尝试以下方法:

@Autowired
private UserService userService;

或至少

@InjectMock
private UserService userService;

您的测试可能会失败,因为UserService内部的存储库无法正确注入,并且返回的结果为 null

答案 1 :(得分:1)

除了不正确的模拟用户之外,我还看到一个设计问题。 @InjectMocks不是一个好的选择。它的实现有缺陷,这是他们的javadocs所说的。

  
      
  • Mockito将尝试仅通过构造函数注入模拟   注入,*二传手注入或属性注入   如下面所描述的。 *如果以下任何策略失败,则   Mockito 不会报告失败; *即您将拥有   自己提供依赖项。
  •   

我认为应该弃用它,以便开发人员可以很好地进行构造函数注入。看看这种方法;

重构UserService,以便您可以通过UserRepository构造函数注入UserService。 例如:https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-spring-beans-and-dependency-injection.html

然后

@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {

    @Mock
    private UserRepository userRepository;


    private UserService userService;
    private User user;

    @Before
    public void setUp() throws Exception {
       userService = new UserService(userRepository);
    }

    @Test
    public void tesGetUserIdStatus() {
        //your test code
    }

这是一个好习惯,您可以使用正确的模拟和存根隔离测试您的逻辑(服务,助手等)。

但是,如果您想通过spring ioc容器来验证资源的正确注入并希望执行诸如验证之类的操作,则应该考虑适当的Spring / Spring引导测试。看看官方的Spring测试文档-https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html

答案 2 :(得分:0)

您的测试中存在一些问题:

  • UserService由Mockito(@InjectMocks)实例化-请勿使用新的UserService实例对其进行初始化-这就是获得NPE的原因
  • 由于您使用的是MockitoJUnitRunner,因此无需显式调用MockitoAnnotations.initMocks
  • when(userRepository.findByUserId(UserId))-什么是UserId
  • 调用Mockito.when()应该是给定部分的一部分
  • 在then部分中,您应声明在when部分中获得的值