Mockito.mock() vs @Mock vs @MockBean

2023/05/10

1. 概述

在这个快速教程中,我们将介绍使用Mockito和Spring mock支持创建mock对象的三种不同方法。我们还将讨论它们之间的区别。

延伸阅读

Mockito参数匹配器

了解如何使用ArgumentMatcher以及它与ArgumentCaptor的区别。

阅读更多

使用Mockito Mock异常抛出

学习配置方法调用以在Mockito中抛出异常。

阅读更多

2. Mockito.mock()

Mockito.mock()方法允许我们创建类或接口的mock对象。

然后,我们可以使用该mock对其方法的返回值进行stub,并验证它们是否被调用。

让我们看一个例子:

@Entity
@Table(name = "users")
public class User {

    @Id
    @GeneratedValue
    private Integer id;
    private String name;
    private Integer status;
    
    // constructors getters and setters ... 
}
@Repository("userRepository")
public interface UserRepository extends JpaRepository<User, Integer> {
}
@Test
public void givenCountMethodMocked_whenCountInvoked_thenMockedValueReturned() {
    UserRepository localMockRepository = Mockito.mock(UserRepository.class);
    Mockito.when(localMockRepository.count()).thenReturn(111L);
    
    long userCount = localMockRepository.count();
    
    assertEquals(111L, userCount);
    Mockito.verify(localMockRepository).count();
}

在使用它之前,我们不需要对此方法执行任何其他操作。我们可以使用它来创建mock类字段,以及方法中的局部mock。

3. Mockito中的@Mock注解

此注解是Mockito.mock()方法的简写。重要的是要注意我们应该只在测试类中使用它。与mock()方法不同,我们需要启用Mockito注解支持才能使用此注解。

在JUnit 5中,我们可以通过使用MockitoExtension来运行测试,或者通过显式调用MockitoAnnotations.initMocks()方法来做到这一点。

让我们看一个使用MockitoExtension的示例:

@ExtendWith(MockitoExtension.class)
public class MockAnnotationUnitTest {
    
    @Mock
    private UserRepository mockRepository;

    @Test
    void givenCountMethodMocked_whenCountInvoked_thenMockValueReturned() {
        Mockito.when(mockRepository.count()).thenReturn(123L);
        
        long userCount = mockRepository.count();
        
        assertEquals(123L, userCount);
        Mockito.verify(mockRepository).count();
    }
}

除了使代码更具可读性之外,@Mock注解还可以在失败的情况下更轻松地找到出现问题的mock,因为字段的名称出现在异常消息中

Wanted but not invoked:
mockRepository.count();
-> at cn.tuyucheng.taketoday.mockito.MockAnnotationUnitTest.givenCountMethodMocked_whenCountInvoked_thenMockValueReturned(MockAnnotationUnitTest.java:31)
Actually, there were zero interactions with this mock.

此外,当与@InjectMocks结合使用时,它可以显著减少设置代码的数量。

4. Spring Boot的@MockBean注解

我们可以使用@MockBean将mock对象添加到Spring应用程序上下文中。该mock将替换应用程序上下文中任何现有的相同类型的bean。

如果没有定义相同类型的bean,则只是会添加一个新的。在需要mock特定bean(如外部服务)的集成测试中,此注解非常有用。

要使用这个注解,我们必须使用SpringExtension来运行测试:

@ExtendWith(SpringExtension.class)
public class MockBeanAnnotationIntegrationTest {
    
    @MockBean
    UserRepository mockRepository;

    @Autowired
    ApplicationContext context;

    @Test
    public void givenCountMethodMocked_whenCountInvoked_thenMockValueReturned() {
        Mockito.when(mockRepository.count()).thenReturn(123L);
        
        UserRepository userRepositoryFromContext = context.getBean(UserRepository.class);
        long userCount = userRepositoryFromContext.count();
        assertEquals(123L, userCount);
        
        Mockito.verify(mockRepository).count();
    }
}

当我们在字段上使用@MockBean注解时,mock将被注入到字段中,并在应用程序上下文中注册。

这在上面的代码中很明显。这里我们使用注入的UserRepository mock来stub count()方法。然后我们从Spring容器中获取一个UserRepository类型的bean,使用该bean来验证它是否确实是mock的bean。

5. 总结

在本文中,我们研究了创建mock对象的三种方法,以及我们如何使用它们中的每一种。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章