Mockito使用指南


 

java常见的mock框架

  • easy-mock:已停止维护
  • mockito:主流,功能强大、使用方便,推荐

 

依赖

如果是 springboot 项目,test 中已经包含了 mockito-core,无需额外引入

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

 
其它情况可以手动引入 mockito 的依赖 mockito-core

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>3.3.3</version>
    <scope>test</scope>
</dependency>

 

mockito常用的静态方法

  • Mockito 类的静态方法:when()
  • ArgumentMatchers 类的静态方法:anyXxx()、any()、isA()

可以 import 直接导入这些静态方法,在代码中直接使用方法;也可以 import 导入类,代码中通过 类名.静态方法名来引用。

 

mock对象的创建、初始化

有2种方式创建mock对象:mock、spy

//参数指定要mock的类
UserService userService = Mockito.mock(UserService.class);
OrderService orderService = Mockito.spy(OrderService.class);

 

上面创建 mock 对象的方式太麻烦,通常都是使用注解

@Mock
private UserService userService;

@Spy
private OrderService orderService;

@Before
public void init() {
	//初始化mock对象,使 @Mock、@Spy、@InjectMocks 注解生效
	MockitoAnnotations.initMocks(this);
}

 

也可以使用以下注解,会自动执行 MockitoAnnotations.initMocks(this); 无需手动初始化mock对象

@MockBean
private UserService userService;

@SpyBean
private UserService userService;

如果Mock对象中要注入其它bean,也需要使用 @MockBean、@SpyBean 代替 @Mock、@Spy。

 

说明

  • 如果使用 @RunWith(MockitoJUnitRunner.class),会自动初始化mock对象,可以缺省 MockitoAnnotations.initMocks(this)。但 @RunWith(MockitoJUnitRunner.class) 不能和 @RunWith(SpringRunner.class) 同时使用,而一般都需要 @RunWith(SpringRunner.class) 提供spring容器环境,所以很少用这个注解。
  • 都是对应的:mock() -> @Mock -> @MockBean,spy() -> @Spy -> @SpyBean

 

注入其它mock对象

如果一个mock对象中需要注入其它mock对象,比如要mock UserService,UserService 依赖于另一个mock对象orderService,这时就不能直接对 UserSiervice 使用 @Mock 直接的注解,需要

  • 测试类上加 @TestExecutionListeners(listeners = MockitoTestExecutionListener.class)
  • 标注 @InjectMocks + @Autowired之类的注入注解
@SpringBootTest
@RunWith(SpringRunner.class)
@TestExecutionListeners(listeners = MockitoTestExecutionListener.class)  //step1
public class RuleRpcServiceTest extends KdAbstractJUnit4SpringContextTests {

    @Mock
    private OrderService orderService;

	//step2
    @InjectMocks
    @Resource
    private UserServiceImpl userService;

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
    }
    
}

 

mock、spy的区别

  • mock出来的对象,所有的属性、方法都会被置空,如果直接调用原本方法,会直接返回返回值类型对应的默认初始值,并不会执行方法体,通过 CallRealMethod 才能调用原方法。

  • spy出来的对象,是在目标对象|真实对象的基础上进行包装,可以直接调用原方法,不需要借助 CallRealMethod。
     

  • mock出来的对象可以使用 when…then… 或 do…when;

  • spy出来的对象只能使用 do…when,使用 when…then… 不会报错,但会先执行真实方法,再把 thenReturn 的 mock 数据替代原返回值进行返回,效果不对。

建议 mock 一律使用 when…then,spy 一律使用 do…when,避免混淆。

 

when…then…

满足指定条件时 执行指定操作

Long userId = 10L;

//thenReturn 返回指定数据
when(userService.findById(userId)).thenReturn(new User(userId, null));

//触发上面mock定义的thenReturn
User user1 = userService.findById(userId);
System.out.println(user1);


//thenCallRealMethod 调用mock类原本的方法
when(userService.findById(userId)).thenCallRealMethod();

//触发上面mock定义的thenCallRealMethod
User user2 = userService.findById(userId);
System.out.println(user2);


//thenThrow 直接抛出异常
when(userService.findById(userId)).thenThrow(new RuntimeException("xxx不合法"));

//触发上面mock定义的thenThrow
User user3 = userService.findById(userId);

 

do…when

注意when的写法和上一个有出入

doReturn(new User(userId, null)).when(userService).findById(userId);

doCallRealMethod().when(userService).findById(userId);

doThrow(new RuntimeException("xxx不合法")).when(userService).findById(userId);

 

ArgumentMatchers 参数匹配

上面的示例,在调用 userService.findById(10) 时才会触发,参数要是指定的值。

可以用 ArgumentMatchers 的静态方法限制参数类型,只要参数是指定类型即可

//any系列可以匹配指定类型的任意一个值(除了null),可以使用预定义的类型anyXxx,也可以使用自定义类型 any(Xxx.class)
when(userService.findById(anyLong())).thenReturn(new User(userId, null));
when(userService.findById(any(Long.class))).thenReturn(new User(userId, null));

//isA()和any差不多,但只校验类型、不校验值是否是null,即null也满足
when(userService.findById(isA(Long.class))).thenReturn(new User(userId, null));

一个 any | isA 对应一个参数,有多个参数时使用多个 any | isA 即可。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Mockito是一个用于Java的开源测试框架,用于创建和管理模拟对象(mock objects)。它可以帮助我们进行单元测试,特别是在测试依赖对象时非常有用。 在Mockito中,我们可以使用注解来简化模拟对象的创建。例如,使用`@Mock`注解可以创建一个模拟对象,使用`@InjectMocks`注解可以将模拟对象注入到被测试对象中。 Mockito还提供了一些方法来验证模拟对象的交互和行为。例如,使用`verify`方法可以验证方法是否被调用,使用`times`方法可以指定方法被调用的次数,使用`never`方法可以验证方法是否从未被调用。 另外,Mockito还支持设置模拟对象的行为。我们可以使用`when`方法来设置模拟对象方法的返回值,使用`doReturn`方法来设置模拟对象方法的行为。 总之,Mockito是一个强大的测试框架,可以帮助我们进行单元测试,并且使用注解可以简化模拟对象的创建。通过验证和设置模拟对象的行为,我们可以更好地测试我们的代码。 #### 引用[.reference_title] - *1* *2* *3* [【码农教程】手把手教你Mockito使用](https://blog.csdn.net/AI_Green/article/details/129163693)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值