Mockito

Mockito

Mockito与PowerMock都是Java流行的一种Mock框架,使用Mock技术能让我们隔离外部依赖以便对我们自己的业务逻辑代码进行单元测试,在编写单元测试时,不需要再进行繁琐的初始化工作,在需要调用某一个接口时,直接模拟一个假方法,并任意指定方法的返回值。
PowerMock则在Mockito原有的基础上做了扩展,通过修改类字节码并使用自定义ClassLoader加载运行的方式来实现mock静态方法、final方法、private方法、系统类的功能。

3.1、Mockito的使用

Mockito一般通过创建mock或spy对象,并制定具体返回规则 来实现 模拟的功能,在调用完成后还可以进行方法调用验证以检验程序逻辑是否正确。mock和spy对象的区别是mock对象对于未指定处理规则的调用会按方法返回值类型返回该类型的默认值(如int、long则返回0,boolean则返回false,对象则返回null,void则什么都不做),而spy对象在未指定处理规则时则会直接调用真实方法。

mock一个对象可以通过如下手动mock

MyClass myclass = Mockito.mock(MyClass.MyClass myclass = Mockito.mock(MyClass.class);

如果所有的 Mock 对象全部通过手工来创建,那就不容易体现出 Mockito 的优越性出来。因此对于被测试对象的创建,Mock 属性的注入应该让 @Mock 和 @InjectMocks这两个注解大显身手了。

  • @Mock:创建一个Mock。
  • @InjectMocks:创建一个实例,其余用@Mock(或@Spy)注解创建的mock将被注入到用该实例中。

以下是mock和spy的使用例子

1.1 Mock例子

实体类

public class public class User {
    String name;
    int age;
    FinalClass finalClass;

    public User(){}

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
	// get set方法
}

操作数据库的类

public class public class UserDao {
    public void save(User user){
        throw new RuntimeException("UserDao.save");
    }

    public User queryByName(String name){
        throw new RuntimeException("UserDao.queryByName");
    }

    public final void saveFinal(User user){
        throw new RuntimeException("UserDao.saveFinal");
    }

    public static void saveStatic(){
        throw new RuntimeException("UserDao.saveStatic");
    }

    public static User query(){
        throw new RuntimeException("UserDao.query");
    }
}

业务类

public class public class UserService {
    private UserDao userDao;

    public UserDao getUserDao() {
        return userDao;
    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void save(User user){
        userDao.save(user);
    }

    public User queryByName(String name){
        return userDao.queryByName(name);
    }

    public final void saveFinal(User user){
        userDao.saveFinal(user);
    }

    public static void saveStatic(){
        UserDao.saveStatic();
    }

    public static User query(){
        return UserDao.query();
    }
}

mock创建的对象的成员为非基本数据类型时,默认值为null

单元测试时调用mock对象null成员的方法不会造成空指针异常,返回的是null,在没有指定处理规则时

@InjectMocks 的顺序
构造函数
setter
该类成员只有1个  匹配类型
该类成员有多个   匹配类型和变量名

总结:单元测试是测自己的业务逻辑代码,也就是自己写的方法的功能,隔离外部的依赖。

1.2 spy

spy对象在未指定处理规则时则会直接调用真实方法

1.3 ArgumentMatchers的any系列

any()、anyInt()、anyString()、anyByte()、anyLong() 还要eq

若一个方法有多个参数,某个参数一旦传入any系列时,其他参数也必须传入any系列,不能直接传值,如果想相等值的,可以用Mockito.eq(1)进行传值判断

1.4 mock对象多次调用

thenReturn(node1)支持链式调用,可以继续thenReturn(thenReturn(node1)支持链式调用,可以继续thenReturn(node2);

1.5 测试异常???

Mocito.doThrow(异常类.class)when(mock对象).方法()

1.6 校验mock调用情况

校验mock对象的调用情况(除Mockito中的never()、times(int)方法外,还有atLeast(int)、atLeastOne()、atMost(int)等方法):

//Mockito类的
//第一个参数为Mock的对象,第二个是模式,有一次没调用过,有调用过几次等
public static  T verify(T mock, VerificationMode mode) {}

1.7 ArgumentCaptor捕获方法参数

@Test
public void save() {
    User user = new User("zhangsan",23);
    userService.save(user);
    ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(User.class);
    Mockito.verify(userDao,Mockito.times(1)).save(argumentCaptor.capture());
    assertEquals(user,argumentCaptor.getValue());
}

// doAnsewr(new An...).when(mock).do(argument);

https://blog.csdn.net/lyabc123456/article/details/89363721

Mockito不支持 final private

Also, this error might show up because you use argument matchers with methods that cannot be mocked.
Following methods cannot be stubbed/verified: final/private/equals()/hashCode().
Mocking methods declared on non-public parent classes is not supported.

1.8模拟void方法

Mockito中,我们可以使用不同的方法来调用实例方法或模拟void方法。根据要求使用其中一个选项:

  • doNothing():完全忽略对void方法的调用,这是默认
  • doAnswer():在调用void方法时执行一些运行时或复杂的操作
  • doThrow():调用模拟的 void方法时引发异常
  • doCallRealMethod():不要模拟并调用真实方法
Mockito.doCallRealMethod().when(userDao).save(Mockito.doCallRealMethod().when(userDao).save(user);
userService.save(user);

1.9 校验0调用和未被验证

MockitoAnnotations.initMocks(MockitoAnnotations.initMocks(this); 效果等于在类上加注解Runwith  否则mock注解没用

总结:

1.mock对象的public void 方法()

  • 验证调用了1次
  • 模拟抛出了异常,断言catch的 和抛出的是一样的

2.mock对象的public void 方法(有参)

  • 验证调用了1次
  • 验证参数

3.mock对象的public 有返回值的方法

  • Mockito.when(userdao.query()).thenReturn(user对象)
修改static final 属性

白盒注入,对象是类.class


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!