单元测试与Mockito

科技资讯 投稿 8500 0 评论

单元测试与Mockito

零丶背景

最近在新公司第一次上手写代码,写了一个不是很难的业务逻辑代码,但是在我写单元测试的时候,发现自己对单元测试的理解的就是一坨,整个过程写得慢,还写得臭。造成这种局面我认为是因为:

    对Mockito api是不是很熟悉
  • 没有自己单元测试方法论,不知道怎样写好单元测试。

一丶为什么需要单元测试

在上一份工作,我基本上不咋写单元测试,觉得很麻烦,不如直接postman,swagger开冲,这种显然不容易覆盖到所有的case。

    增强信心

  • 揭示意图

  • 安全重构

  • 快速反馈

  • 定位缺陷

二丶引入依赖&这些依赖的作用

<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.13.2</version>
   <scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-core -->
<dependency>
   <groupId>org.mockito</groupId>
   <artifactId>mockito-core</artifactId>
   <version>5.3.1</version>
   <scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-inline -->
<dependency>
   <groupId>org.mockito</groupId>
   <artifactId>mockito-inline</artifactId>
   <version>3.7.7</version>
   <scope>test</scope>
</dependency>

    junit

  • Mockito 是一种 Java Mock 框架,主要就是用来做 Mock 测试的,可以模拟出一个对象、模拟方法的返回值、模拟抛出异常,模拟静态方法等等,同时也会记录调用这些模拟方法的参数、调用顺序,从而可以校验出这个 Mock 对象是否有被正确的顺序调用,以及按照期望的参数被调用。

  • powermock

三丶Mockito 常用功能

0.从一个例子开始

1.@InjectMocks & @Mock &MockitoAnnotations.openMocks

    @InjectMocks:标记应进行注射的字段,类似于spring的依赖注入,但是这里会使用Mock产生的对象
  • @Mock :将字段标记为模拟字段,我们可以使用Mockito提供的方法来 打桩
  • MockitoAnnotations.openMocks:开启Mockito注解的功能

2.打桩

2.1 指定入参让mock对象返回指定对象——thenReturn

//让client在query入参为1的时候,返回100为key,aaa为value的单键值对的map
Mockito.when(client.query(1.thenReturn(new HashMap<>(Collections.singletonMap(100, "aaaa";
Map<Integer, String> res = client.query(1;
Assert.assertEquals(1, res.size(;
Assert.assertEquals(res.get(100, "aaaa";

2.2 指定入参让mock对象抛出异常——thenThrow

Mockito.when(client.query(2.thenThrow(new RuntimeException("222";
Assert.assertThrows("222", RuntimeException.class, ( -> client.query(2;

2.3 指定任何参数都执行指定操作——Mockito.anyInt(

Mockito.when(client.query(Mockito.anyInt(.thenReturn(new HashMap<>(;
Assert.assertEquals(0, client.query(-1.size(;

2.4 参数匹配器——ArgumentMatcher

有时候,我们希望入参入参符合要的时候,mock对象进行什么操作。

1, 2, 3的时候返回空map

HashSet<Integer> integers = new HashSet<>(Arrays.asList(1, 2, 3;
Mockito.when(client.query(Mockito.argThat(new ArgumentMatcher<Integer>( {
    @Override
    public boolean matches(Integer argument {
        return integers.contains(argument;
    }
}.thenReturn(Collections.emptyMap(;
Assert.assertEquals(0,client.query(2.size(;

2.5 控制mock对象返回结果——thenAnswer

有时候我们希望mock对象可以根据输出的不同返回不同的结果,符合我们要求的结果。

Mockito.when(client.query(Mockito.anyInt(.thenAnswer(new Answer<Object>( {
    @Override
    public Object answer(InvocationOnMock invocation throws Throwable {
        Integer argument = invocation.getArgument(0;
        String str = argument%2==0?"偶数":"奇数";
        return new HashMap<Integer,String>(Collections.singletonMap(argument,str;
    }
};
Assert.assertEquals("偶数", client.query(2.get(2;

2.6 让mock对象调用真实方法——thenCallRealMethod

上面都是说mock对象如何去控制输出,thenCallRealMethod可以让mock对象执行真实的逻辑。

Mockito.when(client.query(-1.thenCallRealMethod(;

2.7 验证——verify

verify可以让我们验证当前mock对象,比如下面验证client至少执行了四次query

//验证 client.query最起码调用了4次
Mockito.verify(client,Mockito.atLeast(4.query(Mockito.anyInt(;

2.8 mock静态方法——mockStatic

有时候静态方法也需要进行mock控制,可以使用

四丶一个有依赖的单元测试

0.还是这个例子

1.确认需要mock什么

上面这个例子中,OtherClient是外部提供给我们的接口,它存在一定的机率失败,在单元测试的过程我们需要mock它的行为,而不是真的去调用外部接口。

2.定义对象,前置准备

3.1mock方法->调用方法->验证方法

3.1 模拟OtherClient抛出异常

3.2 模拟OtherClient返回空Map

3.3模拟OtherClient返回非空Map

编程笔记 » 单元测试与Mockito

赞同 (38) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽