Mockito的使用

Mockito的使用

1,Mockito的介绍


1.1 什么是mock测试?

Mock测试就在测试过程中,对于某些不容易构造(如HttpServletRquest必须在servlet容器中才能构造出来)或者不容易获取比较复杂的对象(如JDBC中的ResultSet对象),用一个虚拟的对象(Mock对象)来创建以便测试的测试方法。

mock最大功能就是把单元测试的耦合分解开,如果代码中依赖了另外一个类或者接口,它能够模拟出来这些依赖,并且验证所调用的依赖的行为。

比如这样的依赖:

1558925679822-9b415849-0094-4da2-821c-4c106d591a69.jpeg

当我们测试A类的时候,如果没有mock,我们把所有的依赖都构建出来,而使用mock的话,就可以将结构分解开,像下面这样:

1558925737625-8fc60fab-5a23-44f6-b978-065c380e4595.jpeg

mock对象使用的范畴:

  • 真实对象具有不可确定的行为,产生不可预测的效果

  • 真实对象很难被创建的

  • 真实对象的某些行为很难被触发

  • 真实对象实际上还不存在的

1.2 Mockito的介绍

Mockito是一个基于Java开发的模拟测试框架,通过Mockito我们可以创建和配置Mock对象,进而简化有外部依赖的类的测试。

使用Mockito的大致流程:

  • 创建外部依赖的Mock对象,然后将此Mock对象注入到测试类中

  • 执行测试代码

  • 校验测试代码是否执行正确


2 ,Mockito的使用

2.1 Mockito环境的搭建

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.8.5</version>
<scope>test</scope>
</dependency>

2.2 使用Mockito创建mock对象

Mockito提供几种创建mock对象的方式:
1,使用静态方法 mock()
2,使用注解 @Mock

@Mock注解实际上是Mockito.mock() 方法的缩写,同样,我们应该只在测试类中使用它。

我们可以使用 @MockBean 注解将 mock对象添加到Spring的上下文中。
@Mock 将替换Spring上下文中任何相同类型的现有bean,如果没有定义相同类型的bean,将添加一个新的bean。
@MockBean 注解在集成测试中很有用,在集成测试中需要模拟特定的bean,例如外部的service。

下面使用一段代码详细讲解:

@RunWith(SpringRunner.class)
public class MockBeanAnnotationTest {

//mock对象
@MockBean
protected UserRepository mockRepository;

@Autowired
protected ApplicationContext context;

@Test
public void testMockBeanAnnotation() {
// 指定mock对象的行为
Mockito.when(mockRepository.count()).thenReturn(123L);

// 通过应用程序上下文获取Mock的对象
// 也可以直接调用mockRepository.count()方法
UserRepository userRepoFromContext = context.getBean(UserRepository.class);
long userCount = userRepoFromContext.count();

Assert.assertEquals(123L, userCount);
// 验证被调用的就是Mock的对象
Mockito.verify(mockRepository).count();
}
}

2.3 when thenReturn' 的使用

简单来说,when thenReturn 就是指定mock对象的某个方法,让它返回特定的值。

//先创建一个mock对象
UserService userService = Mockito.mock(UserService.class);

//当调用UserService对象的queryUser()方法并且传入任意参数时,指定返回一个User
Mockito.when(userService.queryUser(Mockito.any())).thenReturn(new User("001","张三",18));

//当调用UserService对象的queryUser()方法并且传入 "oo1" 时,指定返回一个User
Mockito.when(userService.queryUser("001")).thenReturn(new User("001","张三",18));

//当调用UserService对象的queryUser()方法并且传入任意字符串时,指定返回一个User
Mockito.when(userService.queryUser(Mockito.anyString())).thenReturn(new User("001","张三",18));

指定方法返回特定值就介绍到这,一般能用到的也就这么多。

2.4 验证方法的调用--verify

下面我们根据例子来讲解 verify 的用法

//先创建一个mock对象
UserService userService = Mockito.mock(UserService.class);

//验证userService的queryUser()方法是否被调用,并且参数时 "001"
Mockito.verify(userService).queryUser("001");

//上面例子,其实更加准确的说法是:验证userService的queryUser()方法得到了一次调用。相当于:
Mockito.verify(userService, Mockito.times(1)).queryUser("001");

上面例子是验证方法被调用了一次,如果想要验证方法被调用多次,只需要把Mockito.times()方法的参数做相应的更改即可。

//先创建一个mock对象
UserService userService = Mockito.mock(UserService.class);

//验证userService的queryUser()方法是否被调用,并且参数时是任意的
Mockito.verify(userService).queryUser(Mockito.any());

//验证userService的queryUser()方法是否被调用,并且参数时是任意字符串
Mockito.verify(userService).queryUser(Mockito.anyString());

3,知识补充 -- spy

最后介绍一个叫做 spy 的东西,前面讲了mock对象的几个功能,其中包括:指定对象的特定行为。但是你会不会疑问,如果我不指定呢,会发生什么呢?答案就是:如果不指定的话,一个mock对象的所有非void方法都返回默认值:int返回0,boolean返回false,对象类型将返回null,而void方法则是什么都不做。

但是往往想要的效果并不如此,希望:除非指定,否则调用这个对象的默认实现,同时又能拥有验证方法调用的功能,这正好是spy对象所能实现的效果,spy的用法如下:

//假如目标类是这样实现的
public class UserService{
public boolean isAdmin(String userName){
return "admin".equals(userName);
}
}

//测试类的写法
@RunWith(SpringRunner.class)
public class UserServiceSpyTest{
//跟创建mock类似,只不过调用的是spy方法,而不是mock方法。spy的用法
UserService userService = Mockito.spy(UserService.class);

//在默认情况下,spy对象会调用这个类的真实逻辑,并返回相应的返回值,这可以对照上面的真实逻辑
userService.isAdmin("admin"); //true
userService.isAdmin("zhangsan"); //false

//spy对象的方法也可以指定特定的行为
Mockito.when(userService.isAdmin(anyString())).thenReturn(true);

//同样的,可以验证spy对象的方法调用情况
userService.isAdmin("admin");
Mockito.verify(userService).isAdmin("admin"); //pass
}

总之,spy 和 mock 的用法非常相似,唯一的区别就是默认行为不一样:spy对象的方法默认调用真实的逻辑,mock对象的方法则是什么都不做,或者是直接返回默认值。

4,小结

这篇文章介绍了mock的概念和Mockito的使用,可能有很多方法没有讲到,但是简单的开发应该是没问题了,如果想要了解Mockito的更详细的用法可以参考:https://www.vogella.com/tutorials/Mockito/article.html
</pre>

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容