mockito中两种部分mock的实现,spy、callRealMethod
什么是类的部分mock(partial mock)?
A:部分mock是说一个类的方法有些是实际调用,有些是使用mockito的stubbing(桩实现)。
为什么需要部分mock?
A:当需要测试一个组合方法(一个方法需要其它多个方法协作)的时候,某个叶子方法(只供别人调用,自己不依赖其它反复)已经被测试过,我们其实不需要再次测试这个叶子方法,so,让叶子打桩实现返回结果,上层方法实际调用并测试。
mockito实现部分mock的两种方式:spy和callRealMethod()
spy实现:
package spy; import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.util.LinkedList;
import java.util.List; import org.junit.Test; public class SpyDemo { @Test
public void spy_Simple_demo(){
List<String> list = new LinkedList<String>();
List<String> spy = spy(list);
when(spy.size()).thenReturn(100); spy.add("one");
spy.add("two"); /* spy的原理是,如果不打桩默认都会执行真实的方法,如果打桩则返回桩实现。
可以看出spy.size()通过桩实现返回了值100,而spy.get(0)则返回了实际值*/
assertEquals(spy.get(0), "one");
assertEquals(100, spy.size());
} @Test
public void spy_Procession_Demo() {
Jack spyJack = spy(new Jack());
//使用spy的桩实现实际还是会调用stub的方法,只是返回了stub的值
when(spyJack.go()).thenReturn(false);
assertFalse(spyJack.go()); //不会调用stub的方法
doReturn(false).when(spyJack).go();
assertFalse(spyJack.go());
} } class Jack {
public boolean go() {
System.out.println("I say go go go!!");
return true;
}
}
Spy类就可以满足我们的要求。如果一个方法定制了返回值或者异常,那么就会按照定制的方式被调用执行;如果一个方法没被定制,那么调用的就是真实类的方法。
如果我们定制了一个方法A后,再下一个测试方法中又想调用真实方法,那么只需在方法A被调用前,调用Mockito.reset(spyObject);就行了。
package spy;
import static org.mockito.Mockito.when;
import org.mockito.Mockito;
public class TestMockObject {
public static void main(String[] args) {
TestMockObject mock = Mockito.mock(TestMockObject.class);
System.out.println(mock.test1());
System.out.println(mock.test2());
TestMockObject spy = Mockito.spy(new TestMockObject());
System.out.println(spy.test1());
System.out.println(spy.test2());
when(spy.test1()).thenReturn(100);
System.out.println(spy.test1());
Mockito.reset(spy);
System.out.println(spy.test1());
System.out.println(spy.test2());
when(spy.test1()).thenReturn(104);
System.out.println(spy.test1());
}
public int test1() {
System.out.print("RealTest1()!!! - ");
return 1;
}
public int test2() {
System.out.print("RealTest2()!!! - ");
return 2;
}
}
输出为:
0
0
RealTest1()!!! - 1
RealTest2()!!! - 2
RealTest1()!!! - 100
RealTest1()!!! - 1
RealTest2()!!! - 2
RealTest1()!!! - 104
要注意的是,对Spy对象的方法定制有时需要用另一种方法:
===============================================================================
Importantgotcha on spying real objects!
Sometimes it's impossible to usewhen(Object) for stubbing spies. Example:
List list = new LinkedList();
List spy = spy(list);
//Impossible: real method is called so spy.get(0) throwsIndexOutOfBoundsException (the list is yet empty)
when(spy.get(0)).thenReturn("foo");
//You have to use doReturn() for stubbing
doReturn("foo").when(spy).get(0);
===============================================================================
因为用when(spy.f1())会导致f1()方法被真正执行,所以就需要另一种写法。
http://blog.csdn.net/dc_726/article/details/8568537
callRealMethod()实现
Use doCallRealMethod() when you want to call the real implementation of a method.
As usual you are going to read the partial mock warning: Object oriented programming is more less tackling complexity by dividing the complexity into separate, specific, SRPy objects. How does partial mock fit into this paradigm? Well, it just doesn't... Partial mock usually means that the complexity has been moved to a different method on the same object. In most cases, this is not the way you want to design your application.
However, there are rare cases when partial mocks come handy: dealing with code you cannot change easily (3rd party interfaces, interim refactoring of legacy code etc.) However, I wouldn't use partial mocks for new, test-driven & well-designed code.
See also javadoc Mockito.spy(Object) to find out more about partial mocks. Mockito.spy() is a recommended way of creating partial mocks. The reason is it guarantees real methods are called against correctly constructed object because you're responsible for constructing the object passed to spy() method.
Example:
Foo mock = mock(Foo.class);
doCallRealMethod().when(mock).someVoidMethod();
// this will call the real implementation of Foo.someVoidMethod()
mock.someVoidMethod();
See examples in javadoc for Mockito class
- Returns:
- stubber - to select a method for stubbing
package callRealMethod; import org.junit.Test;
import static org.mockito.Mockito.*; public class CallMethodDemo {
@Test
public void callRealMethodTest() {
Jerry jerry = mock(Jerry.class); doCallRealMethod().when(jerry).goHome();
doCallRealMethod().when(jerry).doSomeThingB(); jerry.goHome(); verify(jerry).doSomeThingA();
verify(jerry).doSomeThingB();
}
} class Jerry {
public void goHome() {
doSomeThingA();
doSomeThingB();
} // real invoke it.
public void doSomeThingB() {
System.out.println("good day"); } // auto mock method by mockito
public void doSomeThingA() {
System.out.println("you should not see this message."); }
}
通过代码可以看出Jerry是一个mock对象, goHome()和doSomeThingB()是使用了实际调用技术,而doSomeThingA()被mockito执行了默认的answer行为(这里是个void方法,so,什么也不干)。
总结:
spy和callrealmethod都可以实现部分mock,唯一不同的是通过spy做的桩实现仍然会调用实际方法(我都怀疑这是不是作者的bug)。
★ 批注:spy方法需要使用doReturn方法才不会调用实际方法。
mock技术是实施TDD过程必备的装备,熟练掌握mockito(或者其他工具)可以更有效的进行测试。虽然mockito作者也觉得部分测试不是好的设计,但是在java这样一个不是完全面向对象技术的平台上,我们其实没必要过分纠结这些细节,简洁,可靠的代码才是我们需要的。
http://heipark.iteye.com/blog/1496603
mockito中两种部分mock的实现,spy、callRealMethod的更多相关文章
- jsp中两种include的区别【转】
引用文章:http://www.ibm.com/developerworks/cn/java/j-jsp04293/ http://www.cnblogs.com/lazycoding/archive ...
- OC中两种单例实现方式
OC中两种单例实现方式 写在前面 前两天探索了一下C++ 的单例,领悟深刻了许多.今天来看看OC中的单例又是怎么回事.查看相关资料,发现在OC中一般有两种实现单例的方式,一种方式是跟C++ 中类似的常 ...
- JAVA 中两种判断输入的是否是数字的方法__正则化_
JAVA 中两种判断输入的是否是数字的方法 package t0806; import java.io.*; import java.util.regex.*; public class zhengz ...
- 关于js中两种定时器的设置及清除(转载)
1.JS中的定时器有两种: window.setTimeout([function],[interval]) 设置一个定时器,并且设定了一个等待的时间[interval],当到达时间后,执行对应的方法 ...
- mybatis中两种取值方式?谈谈Spring框架理解?
1.mybatis中两种取值方式? 回答:Mybatis中取值方式有几种?各自区别是什么? Mybatis取值方式就是说在Mapper文件中获取service传过来的值的方法,总共有两种方式,通过 $ ...
- JavaScript中两种类型的全局对象/函数【转】
Snandy Stop, thinking is the essence of progress. JavaScript中两种类型的全局对象/函数 这里所说的JavaScript指浏览器环境中的包括宿 ...
- Python中两种处理错误方法的比较
我所说的处理错误的方法,其实是try:,except和raise这两种. 首先抛出一个实例, dictt={'a':1,'b':2,'c':3} try: if dictt['d']>1: #字 ...
- JavaScript中两种类型的全局对象/函数
这里所说的JavaScript指浏览器环境中的包括宿主环境在内的. 第一种是ECMAScript Global Object,第二种是宿主环境(Host)下的全局对象/函数. 一.核心JavaScri ...
- SPSS中两种重复测量资料分析过程的比较
在SPSS中,有两个过程可以对重复测量资料进行分析:一种是一般线性模型的重复度量:一种是混合线性模型,对于同样的数据资料,使用两种过程分析出的内容不大一样,注意是内容而不是结果,只要操作正确,结果应该 ...
随机推荐
- iOS开发之第三方登录微信-- 史上最全最新第三方登录微信方式实现
项目地址 : https://github.com/zhonggaorong/weixinLoginDemo 最新版本的微信登录实现步骤实现: 1.在进行微信OAuth2.0授权登录接入之前,在 ...
- vim 多文件编辑【超实用】
vim 多文件编辑(偶的linux笔记) http://blog.csdn.net/lcj_cjfykx/article/details/18805721 通过vim打开的每个文件都对应着一个buff ...
- 【Linux命令】数据库mysql配置命令
# 检查MySQL服务器系统进程 ~ ps -aux|grep mysql mysql 1103 0.0 0.3 492648 51780 ? Ssl 14:04 0:21 /usr/sbin/mys ...
- java代码获取ip地址
public class IpTool { public static void main(String[] args) { IpTool ipTool=new IpTool(); System.ou ...
- C#学习日记之数据库连接
一.webconfig设置和参数解释 在C#中新建一个网站时,webconfig文件中会有一个默认的数据库连接语句,如下 <connectionStrings> <add name= ...
- codeforces 629D. Babaei and Birthday Cake
题目链接 大意就是给出一个序列, 然后让你从中找出一个严格递增的数列, 使得这一数列里的值加起来最大. 用线段树, 先将数列里的值离散,然后就是线段树单点更新, 区间查询最值. 具体看代码. #inc ...
- .net MVC 使用 JSON JavaScriptSerializer 进行序列化或反序列化时出错,字符串的长度超过了为 maxJsonLength 属性设置的值
在.net mvc的controller中,方法返回JsonResult,一般我们这么写: [HttpPost] public JsonResult QueryFeature(string url, ...
- nginx的 CPU参数worker_processes和worker_cpu_affinity使用说明
官方说明: http://wiki.nginx.org/NginxChsHttpMainModule#worker_cpu_affinity http://wiki.nginx.org/NginxCh ...
- KMP算法与一个经典概率问题
考虑一个事件,它有两种概率均等的结果.比如掷硬币,出现正面和反面的机会是相等的.现在我们希望知道,如果我不断抛掷硬币,需要多长时间才能得到一个特定的序列. 序列一:反面.正面.反面序列二:反面.正面. ...
- 如何使用W5300实现ADSL连接(一)
在介绍W5300连接ADSL之前,先给大家简单介绍一下WIZnet W5300这款芯片. W5300是WIZnet公司的一款单芯片器件,采用0.18μmCMOS工艺,内部集成10/100M以太网控制器 ...