单测PowerMock

如何写一个单测(过程)

在这里插入图片描述

1. 定义被测对象

  1. 直接构建对象
UserService userService = new UserService();
  1. 利用Mockito.spy
    Mockito提供一个spy功能,用于拦截那些尚未实现或不期望被真实调用的方法,默认所有方法都是真实方法,除非主动去模拟对应方法。所以,利用spy功能来定义被测对象,适合于需要模拟被测类自身方法的情况,适用于普通类、接口和虚基类。
UserService userService = Mockito.spy(new UserService());
UserService userService = Mockito.spy(UserService.class);
AbstractOssService ossService = Mockito.spy(AbstractOssService.class);
  1. @spy注解
    @Spy注解跟Mockito.spy方法一样,可以用来定义被测对象,适合于需要模拟被测类自身方法的情况,适用于普通类、接口和虚基类。@Spy注解需要配合@RunWith注解使用。
@RunWith(PowerMockRunner.class)
public class CompanyServiceTest {
    @Spy
    private UserService userService = new UserService();

    ...
}

注意:@Spy注解对象需要初始化。如果是虚基类或接口,可以用Mockito.mock方法实例化

  1. @InjectMocks注解
    @InjectMocks注解用来创建一个实例,并将其它对象(@Mock、@Spy或直接定义的对象)注入到该实例中。所以,@InjectMocks注解本身就可以用来定义被测对象。@InjectMocks注解需要配合@RunWith注解使用。
@RunWith(PowerMockRunner.class)
public class UserServiceTest {
    @InjectMocks
    private UserService userService;
    ...

}

2.模拟依赖对象

  1. 直接创建
Long userId = 1L;
String userName = "admin";
UserDO user = new User();
user.setId(userId);
user.setName(userName);
List userIdList = Arrays.asList(1L, 2L, 3L);
  1. 反序列化
  2. Mockito.mock
    拦截尚未实现或不希望被真是调用的方法,默认所有方法已被模拟——方法为空并返回默认值(null/0),除非执行doCallRealMethod或thenCallRealMethod操作才能调用真实方法。

使用情形:
只使用类实例,不使用类属性;
类属性太多,但使用其中少量属性(可以mock属性返回值);
类是接口或虚基类,并不关心其具体实现类。

MockClass mockClass = Mockito.mock(MockClass.class);
List userIdList = (List)Mockito.mock(List.class);
  1. @Mock注解
    @Mock注解跟Mockito.mock方法一样,可以用来模拟依赖对象,适用于普通类、接口和虚基类。@Mock注解需要配合@RunWith注解使用。
@RunWith(PowerMockRunner.class)
public class UserServiceTest {
    @Mock
    private UserDAO userDAO;
    ...

}
  1. Mockito.spy
    跟Mockito.mock相似,只是Mockito.spy方法默认所有方法都是真实的,除非主动去模拟
  2. @Spy注解
    @Spy注解跟Mockito.spy方法一样,可以用来模拟依赖对象,适用于普通类、接口和虚基类。@Spy注解需要配合@RunWith注解使用
    注意:@Spy注解对象需要初始化。如果是虚基类或接口,可以用Mockito.mock方法实例化。

3.注入依赖对象

  1. 利用Setter方法注入

如果类定义了Setter方法,可以直接调用方法设置字段值。

userService.setMaxCount(100);
userService.setUserDAO(userDAO);
  1. 利用ReflectionTestUtils.setField方法注入

JUnit提供ReflectionTestUtils.setField方法设置属性字段值。

ReflectionTestUtils.setField(userService, "maxCount", 100);
ReflectionTestUtils.setField(userService, "userDAO", userDAO);
  1. 利用Whitebox.setInternalState方法注入

PowerMock提供Whitebox.setInternalState方法设置属性字段值。

Whitebox.setInternalState(userService, "maxCount", 100);
Whitebox.setInternalState(userService, "userDAO", userDAO);
  1. 利用@InjectMocks注解注入

@InjectMocks注解用来创建一个实例,并将其它对象(@Mock、@Spy或直接定义的对象)注入到该实例中。@InjectMocks注解需要配合@RunWith注解使用。

@RunWith(PowerMockRunner.class)
public class UserServiceTest {
    @Mock
    private UserDAO userDAO;
    private Boolean canModify;

    @InjectMocks
    private UserService userService;
    ...
}
  1. 设置静态常量字段值

有时候,我们需要对静态常量对象进行模拟,然后去验证是否执行了对应分支下的方法。比如:需要模拟Lombok的@Slf4j生成的log静态常量。但是,Whitebox.setInternalState方法和@InjectMocks注解并不支持设置静态常量,需要自己实现一个设置静态常量的方法:

public final class FieldHelper {
    public static void setStaticFinalField(Class clazz, String fieldName, Object fieldValue) throws NoSuchFieldException, IllegalAccessException {
        Field field = clazz.getDeclaredField(fieldName);
        FieldUtils.removeFinalModifier(field);
        FieldUtils.writeStaticField(field, fieldValue, true);
    }
}

具体使用方法如下:

FieldHelper.setStaticFinalField(UserService.class, "log", log);

注意:经过测试,该方法对于int、Integer等基础类型并不生效,应该是编译器常量优化导致。

4.模拟依赖方法

4.1 根据返回模拟方法

4.2 根据参数模拟方法

4.模拟其他方法

5.调用被测方法

需要对返回值和异常进行验证
根据有误访问权限介绍如何调用

有访问权限无访问权限
构造方法直接调用、Whitebox.invokeConstructor()Whitebox.invokeConstructor()
普通方法直接调用、Whitebox.invokeMethod、Whitebox.getMethod、PowerMockito.method、method.invokeWhitebox.invokeMethod、Whitebox.getMethod、PowerMockito.method、method.invoke
静态方法直接调用、Whitebox.invokeMethodWhitebox.invokeMethod

6.验证依赖方法

对捕获的参数值进行验证

6.1 根据参数验证方法调用

6.2 验证方法调用次数

6.3 验证方法调用并捕获参数值

6.4 验证其他特殊方法

7.验证数据对象

参考:https://mp.weixin.qq.com/s/hX_RIYs-nBnqVwdq5B4rhg

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Nydia~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值