测试工程实践-Mock及Mock框架.ppt
- 文档编号:30860029
- 上传时间:2024-04-18
- 格式:PPT
- 页数:49
- 大小:1.63MB
测试工程实践-Mock及Mock框架.ppt
《测试工程实践-Mock及Mock框架.ppt》由会员分享,可在线阅读,更多相关《测试工程实践-Mock及Mock框架.ppt(49页珍藏版)》请在冰豆网上搜索。
一级工程实践单元测试本节课主要内容:
Mock及Mock框架依赖注入的概念Junit的数据驱动单元测试外部依赖某个函数,方法调用其他资源,如网络、数据库、容器等。
例子:
1.1.一个函数的功能:
当文件系统满了会返回错误提示。
2.2.某段代码要连第三方的支付接口。
3.3.在某个系统初始化过程中,需要连接22个数据库,11个监控平台。
调用就产生了依赖,我们管这些叫做外部依赖。
单元测试什么是MOCK?
mockmock的英文释义是“仿制品”,顾名思义,我们要在代码中提供外部依赖的“仿制品”来模拟外部依赖项的数据或者行为。
单元测试为什么要MOCK?
依赖越多,不可控制的因素就越多,在其上建立起来的测试就会越复杂、也越不稳定。
很多外部依赖是很昂贵的,无法长期用来调试。
外部依赖有可能无法在项目初期得到,难道就不干活了?
调用的资源越多,速度就会越慢。
还记得单元测试与接口测试的区别么?
单元测试什么是MOCK框架?
我们能够自己用代码从头编写Mock,但是这样会很麻烦。
幸运的是,现在有很多现成的Mock框架可以使用。
Mock框架可以帮助我们迅速的搭建起所需的“仿制品”。
单元测试课程所使用的Mock框架课程将使用Mockito官方网址为:
http:
/mockito.org/使用方法:
在Maven等构建工具中添加依赖项,或者直接引用Jar包单元测试Mockito的一个例子单元测试上页解读:
importimportstaticstaticorg.mockito.Mockito.*;org.mockito.Mockito.*;所有MockitoMockito的常用方法都在这个包里,静态引用让我们使用起来更方便。
还记得junitjunit中assertassert也是被静态引用的么?
LinkedListmockedList=LinkedListmockedList=mock(LinkedList.class);mock(LinkedList.class);使用mockmock方法创建mockmock对象,注意,我们将LinkedListLinkedList的类型当做参数传了进去。
这里边一定用了反射技术。
whenwhen(mockedList.get(0).(mockedList.get(0).thenReturnthenReturn(first);(first);使用whenwhen和thenReturenthenReturen方法,其作用不言而明。
发现问题了没有?
单元测试参数通配符get(0),get
(1),get(999)参数全部要输入具体的值。
能否有通配符一类的东西?
mockito提供了这一特性看下列代码:
注意anyInt()方法。
单元测试如何模拟抛出异常?
whenwhen(mockedList.get(3).(mockedList.get(3).thenThrowthenThrow(new(newRuntimeException();RuntimeException();如果没有模拟,则返回nullnullSystem.out.println(mockedList.get(4);System.out.println(mockedList.get(4);单元测试如何模拟没有返回值的方法抛出异常?
先设定规则:
doThrowdoThrow(new(newRuntimeException().RuntimeException().whenwhen(mockedList).clear();(mockedList).clear();再触发规则mockedList.clear();mockedList.clear();单元测试如何查看方法是否被调用,以及被调用的次数?
注意verify方法的使用。
如何检验方法被调用的顺序?
首先需要引入一个包:
importorg.mockito.InOrder;InOrderinOrder=inOrder(singleMock);保证了mock调用的顺序被记住。
inOrder.verify()方法来检查方法是否被按照顺序被mock调用。
单元测试如何验证一个方法从来没有被调用?
verify(mockedList,never().clear()单元测试如何验证一个MockMock类所有方法都没有被调用过?
verifyZeroInteractions(ml2);单元测试我希望我的代码可读性更强一些。
能让我一眼便知道哪些是MockMock出来的东西。
importimportorg.mockito.Mock;org.mockito.Mock;MockMockprivateLinkedListshortMockedList;privateLinkedListshortMockedList;在JunitJunit下要让测试类使用MockitoJunitRunnerMockitoJunitRunnerRunWith(MockitoJUnitRunner.class)RunWith(MockitoJUnitRunner.class),否则产生空指针异常。
单元测试如何模拟连续操作一个函数返回不同结果?
(stack出栈)when(stack.pop().thenReturn(thelastone).thenThrow(newjava.util.EmptyStackException();熟悉的whenthenthen.then语法。
可以在后面加任意个then。
单元测试如何模拟连续操作一个函数返回不同结果?
-语法糖一个thenReturnthenReturn可以接变化长度的参数。
when(stack.pop().when(stack.pop().thenReturn(one,two,three);thenReturn(one,two,three);单元测试如何只MOCKMOCK类的一部分?
雇佣间谍(spy):
Listspy=spy(list);单元测试雇佣SPYSPY的时候需要注意什么?
查看下面的代码:
Listlist=newLinkedList();Listlist=newLinkedList();Listspy=spy(list);Listspy=spy(list);when(spy.get(0).thenReturn(foo);when(spy.get(0).thenReturn(foo);这样有问题么?
单元测试雇佣SPYSPY的时候需要注意什么?
在某些无法直接调用真实对象方法的时候(上页的代码会抛出异常,为什么?
)使用dodo系列的语法。
doReturn(foo)doReturn(foo).when(spy).get(0);.when(spy).get(0);单元测试MockMock的参数:
CALLS_REAL_METHODSCALLS_REAL_METHODS也是为了局部mock单元测试其它mock框架jmockhttp:
/jmock.org/easymockhttp:
/easymock.org/powermock/googlemock(c+)几乎每一种语言都会有mock框架,有需要的时候google它们。
动态语言的mock框架更加有意思,有余力可以去看一下。
单元测试我有了非常好的单元测试框架,又有了MOCKMOCK框架这种利器,是否就能在单元测试过程中无往不利了呢?
单元测试被测代码的badsmellsbadsmells重复代码(DuplicatedCode)长方法(LongMethod)条件逻辑过于复杂(ConditionalComplexity)基本类型偏执(PrimitiveObsession)不恰当的暴露(IndecentExposure)解决方案蔓延(SolutionSprawl)异曲同工的类(AlternativeClasseswithDifferentInterfaces)懒惰的类(LazyClass)巨大的类(LargeClass)Switch语句(SwitchStatements)-command模式组合爆炸(combinatorialexplosion)怪异解决方案(OddballSolution)被测代码本身越复杂,越长,越怪异,就越难以测试。
单元测试遇到上述情况怎么办?
说服开发人员重构!
单元测试参考书目:
单元测试面向接口编程和依赖注入工作中,几乎每一段代码都会依赖其它的类,对象等。
想对一段代码测试,把这些依赖隔离开来方便(实际操作中不见得全部隔离)。
但是,如果这些被依赖项以硬编码的形式被写到被测代码片段中,就不好办了。
单元测试面向接口编程和依赖注入publicinterfaceEnginepublicclassSlowEngineimplementsEnginepublicclassFastEngineimplementsEnginepublicclassMooseEngineimplementsEnginepublicclassCarprivateMooseEngineengine;publicbooleanStartEngine()returnengine.start();如果我想测试StartEngine()方法?
紧耦合紧耦合单元测试面向接口编程和依赖注入publicclassCarprivateEngineengine;.有什么不同?
publicclassCarprivateEngineengine=newMooseEngine();这不还是紧耦合么?
这不还是紧耦合么?
单元测试面向接口编程和依赖注入publicclassCarprivateEngineengine;publicCar(Engineengine)this.engine=engine;基于构造函数基于构造函数的依赖注入的依赖注入单元测试面向接口编程和依赖注入publicclassCreatCarpublicclassCreatCarpublicstaticvoidmain(Stringargs)publicstaticvoidmain(Stringargs)CarmyGreatCar=CarmyGreatCar=newCar(newMooseEngine();newCar(newMooseEngine();CarhisCrappyCar=CarhisCrappyCar=newCar(newSlowEngine();newCar(newSlowEngine();我们可以随便创建Car类型了。
单元测试上两页的代码跟改造前的代码有什么不同?
变成松耦合了。
好莱坞原则:
你别找我,我去找你。
将类型绑定延迟到了运行时(非常重要,有兴趣可以看一下SpringSpring框架)下两页将介绍依赖注入的两种变体:
基于SetterSetter的依赖注入,基于接口的依赖注入单元测试publicclassCarpublicclassCarprivateEngineengine;privateEngineengine;publicvoidsetEngine(Engineengine)publicvoidsetEngine(Engineengine)this.engine=engine;this.engine=engine;基于基于Setter的的依赖注入依赖注入单元测试publicclassTestpublicclassTestpublicstaticvoidmain(Stringargs)publicstaticvoidmain(Stringargs)CarmyGreatCar=newCar();CarmyGreatCar=newCar();myGreatCar.myGreatCar.setEnginesetEngine(newMooseEngine();(newMooseEngine();CarhisCrappyCar=newCar();CarhisCrappyCar=newCar();hisCrappyCar.hisCrappyCar.setEnginesetEngine(newSlowEngine();(newSlowEngine();通过调用方法通过调用方法实现依赖注入实现依赖注入单元测试publicinterfaceInjectFinderpublicinterfaceInjectFindervoidInjectDependency(Engineeng);voidInjectDependency(Engineeng);publicCarimplementInjectFinderpublicCarimplementInjectFinderprivateEngineengine;privateEngineengine;InjectDependency(Engineeng)InjectDependency(Engineeng)this.engine=eng;this.engine=eng;定义一个接口,接口定义注入的依赖,类继承这个接口,实现方法注入依赖。
单元测试拓展阅读:
马丁福勒的的最经典定义一篇不错的介绍依赖注入的文章:
单元测试这个跟单元测试有神马关系?
看一段代码片段:
publicclassUserpublicclassUserprivateStringaddr;privateStringaddr;publicStringlogin(StringunamepublicStringlogin(Stringuname,Stringpasswd)Stringpasswd)RemoteServerremoteSrv=newRemoteServer(this.addr);RemoteServerremoteSrv=newRemoteServer(this.addr);if(uname=)|(passwd=)if(uname=)|(passwd=)return“return“用户名密码为空”;”;elseelsebooleanlogin=remoteSrv.loginImp(uname,passwd);booleanlogin=remoteSrv.loginImp(uname,passwd);ifif(login)returnlogin)return登录成功;elsereturnelsereturn用户名密码错误;如何测试loginlogin这个方法?
测试重点是?
RemoteServerRemoteServer如果此时不可用呢?
单元测试如何测试loginlogin这个方法?
使用JunitJunit工具。
newnew出UserUser类,调用loginlogin方法。
测试重点是?
loginlogin方法的内部算法。
不关注RemoteServerRemoteServer的实现。
RemoteServerRemoteServer如果此时不可用呢?
MockMock掉它!
ButBut,howhow?
单元测试publicclassUserpublicclassUserprivateStringaddr;privateStringaddr;publicStringlogin(Stringuname,Stringpasswd)publicStringlogin(Stringuname,Stringpasswd)RemoteServermser=mock(RemoteServer.class);RemoteServermser=mock(RemoteServer.class);if(uname=)|(passwd=)if(uname=)|(passwd=)return“return“用户名密码为空”;”;elseelsewhen(mser.loginImp(xgliu,123).thenReturn(true);when(mser.loginImp(xgliu,123).thenReturn(true);when(mser.loginImp(xgliu,321).thenReturn(false);when(mser.loginImp(xgliu,321).thenReturn(false);booleanlogin=remoteSrv.loginImp(uname,passwd);booleanlogin=remoteSrv.loginImp(uname,passwd);ifif(login)returnlogin)return登录成功;elsereturnelsereturn用户名密码错误;Testpublicvoidtestlogin()Testpublicvoidtestlogin()Userusr=newUserUserusr=newUser();AssertThat(usr.login(xgliu,123)AssertThat(usr.login(xgliu,123),is(is(登录成功););有什么问题?
有什么问题?
单元测试问题在哪里?
为了测试,我修改了源码!
单元测试的原则是:
不修改任何被测代码代码;测试代码绝不写到被测代码里去。
单元测试publicclassUserpublicclassUserprivateStringaddr;privateStringaddr;publicStringlogin(StringunamepublicStringlogin(Stringuname,StringpasswdStringpasswd,RemoteServerrmtRemoteServerrmt)if(uname=)|(passwd=)if(uname=)|(passwd=)return“return“用户名密码为空”;”;elseelsebooleanlogin=booleanlogin=rmt.loginImp(uname,passwd);rmt.loginImp(uname,passwd);ifif(login)returnlogin)return登录成功;elsereturnelsereturn用户名密码错误;TestpublicvoidtestLogin()TestpublicvoidtestLogin()RemoteServermser=mock(RemoteServer.class);RemoteServermser=mock(RemoteServer.class);when(mser.loginImp(xgliu,123).thenReturn(true);when(mser.loginImp(xgliu,123).thenReturn(true);Userusr=newUserUserusr=newUser();AssertThat(usr.login(xgliu,123,AssertThat(usr.login(xgliu,123,msermser),is(is(登录成功););实现了非入侵mock单元测试练习:
1.编写逻辑覆盖率全的测试用例甚为重要。
在理解需求的前提下编写测试用例,使得我掌握了多种测试用例编写方法,更让我对产品的需求有更加深入的理解,须知对需求是否理解透彻决定了能否有效、全面地对产品进行测试;2.要站在用户角度对系统进行测试。
从一些项目中出现的未能及时发现的bug中,我认识到用户体验的重要性,现在能够越来越多的从这方面来执行测试;3.对拿到手的项目有较清晰的思路,能够更加快速、准确地发现问题;4.越来越规范的工作流程的让我们的工作有条不紊的进行,让我深刻认识到工作的规范性是多么的重要,并且从中学习如何从文档和流程上规范工作。
5.同事间的沟通很重要。
现在不管遇到什么不确定或疑惑,都与开发人员、产品经理等及时沟通,大大提高了工作的效率。
只有不断的提高自己各种的能力,才能胜任越来越艰巨的任务,因此在工作相对不饱和的时候,我自己进行了一些学习。
为提高对“用户体验”的理解,我学习了下一站用户体验,书中一些经验确实让我获益匪浅。
不能总拿别人的用户体验去改进自己的产品,但是有一些却是通用的,比如:
太多弹出框、按钮会给用户带来愤怒感,要适当的给页面减肥等等。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 测试 工程 实践 Mock 框架