你知道吗?Mockito-Java开发的绝佳模拟框架,很值得一看
ccwgpt 2024-10-31 12:23 32 浏览 0 评论
前言
Mockito是一个非常不错的模拟框架,它使您可以使用简洁的API编写漂亮的测试。
介绍
本文将展示模拟框架的一些基本概念,为什么我们应该使用它,并逐步介绍一下在Java中应用Mockito的简单方法。
mocking的概念
在软件开发领域之外,术语“ mock”表示模仿。mock因此,可以被认为是替身,冒名顶替者或与软件开发有关的最常见称呼 fake。
伪造通常用作受测类依赖项的替身。
| 术语和定义 | | ------------------------------------------------------------ | | 依赖关系 –依赖关系是指应用程序中的一个类为了执行其预期功能而依赖于另一个类。依赖关系通常存储在依赖类内部的实例变量中。| | | | 被测类 –编写单元测试时,术语“单元”通常是指单个类,尤其是针对其编写测试的类。因此,被测类是被测应用程序类。|
为什么要模拟?
当我们学习编程时,我们的对象通常是独立的。任何动作都不依赖外部类(除了System.out),在学习语言的过程中我们编写的许多其他类也没有依赖。但是,在现实世界中,软件具有依赖性。我们有依赖于服务的操作类和依赖于数据访问对象(DAO)的服务,并且列表继续存在。
!](https://upload-images.jianshu.io/upload_images/15590149-ce6f103528abb3a2?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
单元测试的思想是我们要测试代码而不测试依赖项。该测试使您可以验证所测试的代码是否有效,无论其是否依赖。从理论上讲,如果我编写的代码按设计工作,而我的依赖项按设计工作,那么它们应该按设计一起工作。下面的代码将是一个示例:
1. `import java.util.ArrayList;`
2. `publicclassCounter{`
3. `publicCounter() {`
4. `}`
5. `publicint count(ArrayList items) {`
6. `int results = 0;`
7. `for(Object curItem : items) {`
8. `results ++;`
9. `}`
10. `return results;`
11. `}`
12. `}`
我知道上面的示例与您所获得的一样简单,但是它说明了这一点。如果要测试计数方法,你可以编写测试用例。您并不是要测试ArrayList的工作原理,您唯一的目标是测试对ArrayList的使用。
模拟背后的概念是我们要创建一个代替真实对象的模拟对象。对该模拟对象调用某些方法,它将能返回期望的结果。
模拟概念是什么?
当涉及到mocking时,您只需要关心三件事:存根,设定期望并进行验证。 一些单元测试方案不涉及其中任何一个,其他仅涉及存根,而其他涉及设置期望和验证。
存根
存根是告诉您的假货与之互动时如何表现的过程。通常,您可以对公共属性(具有getter和/或setter的属性)和公共功能进行存根。
当涉及到存根函数时,通常会有很多选择。您可能希望返回特定的值,抛出错误或调度事件。此外,您可能希望指出函数的行为取决于调用方式的不同(即,通过匹配传递给函数的参数的类型或值)。
如果听起来需要做很多工作,可以,但通常不是。许多模拟框架的一大特点是您不需要对void函数进行存根。您也不必在测试执行过程中对任何未调用的功能或未查询的属性进行存根。
设定期望
伪造品的主要功能之一是能够在测试运行时告诉伪造品您期望的内容。例如,您可能希望特定的函数被正确调用3次。您可能希望它永远不会被调用。您可能希望至少调用两次,但不要超过5次。您可能希望使用特定类型的参数或特定值或以上任意组合来调用它。可能性是无止境。
设定期望是告诉您的假货您预期会发生什么的过程。请记住,由于这是假货,因此实际上没有任何反应。但是,您正在测试的课程绝不明智。从它的角度来看,它调用了该函数并期望它完成了应该执行的操作。
值得一提的是,大多数模拟框架都允许您创建接口或公共类的模拟。您不仅限于仅模拟接口。
验证中
设定期望和验证是齐头并进的。设置期望值是在调用被测类上的函数之前完成的。之后进行验证。因此,首先要设定期望,然后验证是否满足期望。
从单元测试的角度来看,如果未达到您的期望,则单元测试将失败。例如,如果您期望应该使用特定的用户名和密码仅一次调用ILoginService.login函数,但是在执行测试期间从未调用过该函数,则伪造品将无法验证,并且测试应失败。
mocking有什么好处?
**
您可以预先创建测试;TDD**
这是更强大的好处之一。如果创建了Mock,则可以在创建服务之前编写服务测试,从而使您能够在开发过程中将测试添加到自动化环境中。换句话说,服务模拟使您能够使用测试驱动开发。
团队可以并行工作
这类似于上面的内容;为不存在的代码创建测试。但是上一点是针对编写测试的开发人员的,这一点是针对测试团队的。当您没有要测试的东西时,团队如何开始创建测试?模拟它并针对模拟编写测试!这意味着质量保证团队实际上可以在准备好要测试服务时准备一整套测试。当一个团队等待另一个团队完成时,我们没有停机时间。这使得嘲弄的财务论点特别强烈。
您可以创建概念或演示的证明。
由于Mocks可以(非常容易地完成)制造,因此非常经济高效,因此可以将Mocks用于创建概念验证,线框或正在考虑构建的产品的演示。这非常强大,为决策是否继续进行开发项目提供了良好的基础,但最重要的是可以进行实际的设计决策。
您可以为无法访问的资源编写测试
这是不属于实际福利类别的福利之一,而是可以起到挽救生命的作用。您是否曾经想测试或使用一项服务,却只是被告知该服务位于防火墙后面,并且无法为您打开该防火墙或您已被授权使用该服务?当您这样做时,将MockService放置在可访问的位置(包括您的本地计算机上)可以节省生命。
模拟可以交付给客户
在某些情况下,有某些原因导致您不允许外部资源(例如合作伙伴或客户)访问测试系统。这些原因可能是访问安全性,信息的敏感性,或者仅仅是测试环境可能无法24/7全天候访问的事实。在这些情况下;您如何为合作伙伴或客户提供测试系统以开始开发或测试?一个简单的解决方案是从您的网络或客户自己的网络提供模拟。soapUI模拟程序非常易于部署,它既可以在soapUI中运行,也可以作为.WAR文件导出并放置在您选择的Java服务器中。
您可以隔离系统
有时,您希望测试系统的一部分,而不会影响其他系统部分。这是因为其他系统会给测试数据增加噪音,并使从收集到的数据中得出良好的结论变得更加困难。使用模拟,您可以删除模拟所有系统的所有依赖项,但您需要在测试中精确定位的系统除外。在进行模拟隔离时,可以使这些模拟极其简单,但可靠,快速且可预测。这为您提供了一个测试环境,在其中消除了所有随机行为,具有可重复的模式并可以很好地监视特定系统。
Mockito框架
Mockito是根据MIT许可证发布的Java开源测试框架。Mockito通过允许开发人员验证被测系统(SUT)的行为而无需事先建立期望,从而将自己与其他模拟框架区分开。[4] 对模拟对象的批评之一是测试代码与被测系统之间的耦合更加紧密。[5] 由于Mockito试图通过消除期望值的规范来消除期望-运行-验证模式[6],因此减少或最小化了耦合。此区别功能的结果是更简单的测试代码,应该更易于阅读和修改。
您可以验证交互:
1. `// mock creation`
2. `List mockedList = mock(List.class);`
3. `<span class="Apple-tab-span" style="white-space: pre;"> `
4. `</span>// using mock object`
5. `mockedList.add("one");`
6. `mockedList.clear();`
7. `// selective and explicit vertification`
8. `verify(mockedList).add("one");`
9. `verify(mockedList).clear(); `
或存根方法调用
1. `// you can mock concrete class, not only interfaces`
2. `LinkedList mockedList = mock(LinkedList.class);`
3. `<span class="Apple-tab-span" style="white-space: pre;"> `
4. `</span>// stubbing - before execution`
5. `when(mockedList.get(0)).thenReturn("first");..`
6. `<span class="Apple-tab-span" style="white-space: pre;"> `
7. `</span>// following prints "first"`
8. `System.out.println(mockedList.get(0));`
9. `<span class="Apple-tab-span" style="white-space: pre;"> `
10. `</span>// following prints "null" because get(999) was not stubbed.`
11. `System.out.println(mockedList.get(999));`
一个使用Mockito的简单Java代码示例
没有模拟框架
使用Mockito框架
步骤1:在Eclipse中创建一个Maven项目
定义 pom.xml如下:
1. `<?xml version="1.0" encoding="UTF-8"?>`
2. `<pre><projectxmlns="http://maven.apache.org/POM/4.0.0"`
3. `xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"`
4. `xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">`
5. `<modelVersion>4.0.0</modelVersion>`
6. `<groupId>vn.com.phatbeo.ut.mockito.demo</groupId>`
7. `<artifactId>demoMockito</artifactId>`
8. `<version>0.0.1-SNAPSHOT</version>`
9. `<packaging>jar</packaging>`
10. `<name>demoMockito</name>`
11. `<url>http://maven.apache.org</url>`
12. `<properties>`
13. `<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>`
14. `</properties>`
15. `<build>`
16. `<sourceDirectory>src</sourceDirectory>`
17. `<testSourceDirectory>test</testSourceDirectory>`
18. `<plugins>`
19. `<plugin>`
20. `<groupId>org.apache.maven.plugins</groupId>`
21. `<artifactId>maven-compiler-plugin</artifactId>`
22. `<version>2.3.1</version>`
23. `<configuration>`
24. `<source>1.6</source>`
25. `<target>1.6</target>`
26. `</configuration>`
27. `</plugin>`
28. `</plugins>`
29. `</build>`
30. `<dependencies>`
31. `<dependency>`
32. `<groupId>junit</groupId>`
33. `<artifactId>junit</artifactId>`
34. `<version>4.8.1</version>`
35. `<scope>test</scope>`
36. `</dependency>`
37. `<dependency>`
38. `<groupId>org.mockito</groupId>`
39. `<artifactId>mockito-all</artifactId>`
40. `<version>1.8.5</version>`
41. `<scope>test</scope>`
42. `</dependency>`
43. `</dependencies>`
44. `</project>`
步骤2:添加Java源代码
类 Person.java
1. `package vn.com.enclave.phatbeo.ut.mockito.demo;`
2. `/**`
3. `* @author Phat (Phillip) H. VU <vuhongphat@hotmail.com>`
4. `*`
5. `*/`
6. `publicclassPerson`
7. `{`
8. `privatefinalInteger personID;`
9. `privatefinalString personName;`
10. `publicPerson( Integer personID, String personName )`
11. `{`
12. `this.personID = personID;`
13. `this.personName = personName;`
14. `}`
15. `publicInteger getPersonID()`
16. `{`
17. `return personID;`
18. `}`
19. `publicString getPersonName()`
20. `{`
21. `return personName;`
22. `}`
23. `}`
接口 PersonDAO.java
1. `package vn.com.enclave.phatbeo.ut.mockito.demo;`
2. `/**`
3. `* @author Phat (Phillip) H. VU <vuhongphat@hotmail.com>`
4. `*`
5. `*/`
6. `publicinterfacePersonDao`
7. `{`
8. `publicPerson fetchPerson( Integer personID );`
9. `publicvoid update( Person person );`
10. `}`
类 PersonService.java
1. `package vn.com.enclave.phatbeo.ut.mockito.demo;`
2. `/**`
3. `* @author Phat (Phillip) H. VU <vuhongphat@hotmail.com>`
4. `*`
5. `*/`
6. `publicclassPersonService`
7. `{`
8. `privatefinalPersonDao personDao;`
9. `publicPersonService( PersonDao personDao )`
10. `{`
11. `this.personDao = personDao;`
12. `}`
13. `publicboolean update( Integer personId, String name )`
14. `{`
15. `Person person = personDao.fetchPerson( personId );`
16. `if( person != null)`
17. `{`
18. `Person updatedPerson = newPerson( person.getPersonID(), name );`
19. `personDao.update( updatedPerson );`
20. `returntrue;`
21. `}`
22. `else`
23. `{`
24. `returnfalse;`
25. `}`
26. `}`
27. `}`
步骤3:添加了单元测试类。
然后,跳转为类编写单元测试用例 PersonService.java
假设类 PersionServiceTest.java如下:
1. `package vn.com.enclave.phatbeo.ut.mockito.demo.test;`
2. `importstatic org.junit.Assert.assertEquals;`
3. `importstatic org.junit.Assert.assertFalse;`
4. `importstatic org.junit.Assert.assertTrue;`
5. `importstatic org.mockito.Mockito.verify;`
6. `importstatic org.mockito.Mockito.verifyNoMoreInteractions;`
7. `importstatic org.mockito.Mockito.verifyZeroInteractions;`
8. `importstatic org.mockito.Mockito.when;`
9. `import org.junit.Before;`
10. `import org.junit.Test;`
11. `import org.mockito.ArgumentCaptor;`
12. `import org.mockito.Mock;`
13. `import org.mockito.MockitoAnnotations;`
14. `/**`
15. `* @author Phat (Phillip) H. VU <vuhongphat@hotmail.com>`
16. `*`
17. `*/`
18. `publicclassPersonServiceTest`
19. `{`
20. `@Mock`
21. `privatePersonDao personDAO;`
22. `privatePersonService personService;`
23. `@Before`
24. `publicvoid setUp()`
25. `throwsException`
26. `{`
27. `MockitoAnnotations.initMocks( this);`
28. `personService = newPersonService( personDAO );`
29. `}`
30. `@Test`
31. `publicvoid shouldUpdatePersonName()`
32. `{`
33. `Person person = newPerson( 1, "Phillip");`
34. `when( personDAO.fetchPerson( 1) ).thenReturn( person );`
35. `boolean updated = personService.update( 1, "David");`
36. `assertTrue( updated );`
37. `verify( personDAO ).fetchPerson( 1);`
38. `ArgumentCaptor<Person> personCaptor = ArgumentCaptor.forClass( Person.class);`
39. `verify( personDAO ).update( personCaptor.capture() );`
40. `Person updatedPerson = personCaptor.getValue();`
41. `assertEquals( "David", updatedPerson.getPersonName() );`
42. `// asserts that during the test, there are no other calls to the mock object.`
43. `verifyNoMoreInteractions( personDAO );`
44. `}`
45. `@Test`
46. `publicvoid shouldNotUpdateIfPersonNotFound()`
47. `{`
48. `when( personDAO.fetchPerson( 1) ).thenReturn( null);`
49. `boolean updated = personService.update( 1, "David");`
50. `assertFalse( updated );`
51. `verify( personDAO ).fetchPerson( 1);`
52. `verifyZeroInteractions( personDAO );`
53. `verifyNoMoreInteractions( personDAO );`
54. `}`
55. `}`
问题:为什么我们在Java开发测试中使用Mockito?
答:好处有很多,最大的好处是团队可以并行工作
相关推荐
- Python Scrapy 项目实战(python scripy)
-
爬虫编写流程首先明确Python爬虫代码编写的流程:先直接打开网页,找到你想要的数据,就是走一遍流程。比如这个项目我要爬取历史某一天所有比赛的赔率数据、每场比赛的比赛结果等。那么我就先打开这个网址...
- 为何大厂后端开发更青睐 Python 而非 Java 进行爬虫开发?
-
在互联网大厂的后端开发领域,爬虫技术广泛应用于数据收集、竞品分析、内容监测等诸多场景。然而,一个有趣的现象是,相较于Java,Python成为了爬虫开发的首选语言。这背后究竟隐藏着怎样的原因呢?让...
- 爬虫小知识,scrapy爬虫框架中爬虫名词的含义
-
在上一篇文章当中学记给大家展示了Scrapy爬虫框架在爬取之前的框架文件该如何设置。在上一篇文章当中,是直接以代码的形式进行描述的,在这篇文章当中学记会解释一下上一篇文章当中爬虫代码当中的一些名词...
- python爬虫神器--Scrapy(python爬虫详细教程)
-
什么是爬虫,爬虫能用来做什么?文章中给你答案。*_*今天我们就开发一个简单的项目,来爬取一下itcast.cn中c/c++教师的职位以及名称等信息。网站链接:http://www.itcast.cn...
- Gradio:从UI库到强大AI框架的蜕变
-
Gradio,这个曾经被简单视为PythonUI库的工具,如今已华丽转身,成为AI应用开发的强大框架。它不仅能让开发者用极少的代码构建交互式界面,更通过一系列独特功能,彻底改变了机器学习应用的开发和...
- 研究人员提出AI模型无损压缩框架,压缩率达70%
-
大模型被压缩30%性能仍与原模型一致,既能兼容GPU推理、又能减少内存和GPU开销、并且比英伟达nvCOMP解压缩快15倍。这便是美国莱斯大学博士生张天一和合作者打造的无损压缩框架...
- 阿里发布Qwen-Agent框架,赋能开发者构建复杂AI智能体
-
IT之家1月4日消息,阿里通义千问Qwen推出全新AI框架Qwen-Agent,基于现有Qwen语言模型,支持智能体执行复杂任务,并提供多种高级功能,赋能开发者构建更强大的AI...
- 向量数仓与大数据平台:企业数据架构的新范式
-
在当前的大模型时代,企业数据架构正面临着前所未有的挑战和机遇。随着大模型的不断发布和多模态模型的发展,AIGC应用的繁荣和生态配套的逐渐完备,企业需要适应这种新的数据环境,以应对行业变革。一、大模型时...
- 干货!大数据管理平台规划设计方案PPT
-
近年来,随着IT技术与大数据、机器学习、算法方向的不断发展,越来越多的企业都意识到了数据存在的价值,将数据作为自身宝贵的资产进行管理,利用大数据和机器学习能力去挖掘、识别、利用数据资产。如果缺乏有效的...
- 阿里巴巴十亿级并发系统设计:实现高并发场景下的稳定性和高性能
-
阿里巴巴的十亿级并发系统设计是其在大规模高并发场景下(如双11、双12等)保持稳定运行的核心技术框架。以下是其关键设计要点及技术实现方案:一、高可用性设计多数据中心与容灾采用多数据中心部署,通过异地容...
- 阿里云云原生一体化数仓—数据治理新能力解读
-
一、数据治理中心产品简介阿里云DataWorks:一站式大数据开发与治理平台架构大图阿里云DataWorks定位于一站式的大数据开发和治理平台,从下图可以看出,DataWorks与MaxCom...
- DeepSeek R1:理解 GRPO 和多阶段训练
-
人工智能在DeepSeekR1的发布后取得了显著进步,这是一个挑战OpenAI的o1的开源模型,在高级推理任务中表现出色。DeepSeekR1采用了创新的组相对策略优化(GroupR...
- 揭秘永久免费视频会议软件平台架构
-
如今视频会议已经成为各个团队线上协同的必备方式之一,视频会议软件的选择直接影响团队效率与成本,觅讯会议凭借永久免费迅速出圈,本文将从技术架构、核心功能和安全体系等维度,深度解析其技术实现与应用价值,为...
- DeepSeek + Kimi = 五分钟打造优质 PPT
-
首先,在DeepSeek中输出提示词,示例如下:为课程《提示词基础-解锁AI沟通的秘密》设计一个PPT大纲,目的是让学生:1.理解提示词的概念、作用和重要性2.掌握构建有效提示词的基本原则和技巧...
- 软件系统如何设计可扩展架构?方法论,Java实战代码
-
软件系统如何设计可扩展架构?方法论,Java实战代码,请关注,点赞,收藏。方法论那先想想方法论部分。扩展性架构的关键点通常包括分层、模块化、微服务、水平扩展、异步处理、缓存、负载均衡、分布式架构等等...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- MVC框架 (46)
- spring框架 (46)
- 框架图 (58)
- bootstrap框架 (43)
- flask框架 (53)
- quartz框架 (51)
- abp框架 (47)
- jpa框架 (47)
- laravel框架 (46)
- express框架 (43)
- springmvc框架 (49)
- 分布式事务框架 (65)
- scrapy框架 (56)
- java框架spring (43)
- grpc框架 (55)
- orm框架有哪些 (43)
- ppt框架 (48)
- 内联框架 (52)
- winform框架 (46)
- gui框架 (44)
- cad怎么画框架 (58)
- ps怎么画框架 (47)
- ssm框架实现登录注册 (49)
- oracle字符串长度 (48)
- oracle提交事务 (47)