mockito中两种部分mock的实现,spy、callRealMethod

简介: 什么是类的部分mock(partial mock)?A:部分mock是说一个类的方法有些是实际调用,有些是使用mockito的stubbing(桩实现)。   为什么需要部分mock? A:当需要测试一个组合方法(一个方法需要其它多个方法协作)的时候,某个叶子方法(只供别人调用,自己不依赖其它反复)已经被测试过,我们其实不需要再次测试这个叶子方法,so,让叶子打桩实现返回结果,上层方法实际调用并测试。

 

什么是类的部分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

 

目录
相关文章
|
XML Java Maven
MockedStatic 用于模拟静态方法
`MockedStatic` 是 Mockito 3.4.0 版本引入的一个功能,用于模拟静态方法。在之前的 Mockito 版本中,模拟静态方法是一项困难的任务,通常需要借助其他工具如 PowerMockito。但是,从 Mockito 3.4.0 开始,你可以使用 `MockedStatic` 类轻松地模拟静态方法。 以下是如何使用 `MockedStatic` 模拟静态方法的示例: 1. 首先,确保你已经添加了 Mockito 的依赖项。对于 Maven 项目,添加以下依赖项: ```xml <dependency> <groupId>org.mockito</groupId
3966 9
PowerMock mock私有方法
import java.util.Random; public class CodeWithPrivateMethod { public void meaningfulPublicApi() { if (doTheGamble("Whateve...
4636 0
|
4月前
|
人工智能 测试技术
CLI为什么突然爆了?一文讲清 Skill、MCP、CLI 的真实关系
本文解析AI从“能聊天”到“能干活”的关键跃迁,聚焦CLI(命令行接口)、Skill(内嵌能力)与MCP(标准化连接协议)三大执行层技术。厘清三者本质差异与协同关系:Skill解决“懂什么”,MCP解决“怎么接”,CLI解决“怎么做”,揭示企业推动CLI落地的核心动因——让AI真正融入业务、自动执行任务。
|
监控
基于videoPlayer实现视频播放联动文字播报功能
基于videoPlayer实现视频播放联动文字播报功能
490 0
|
SQL 关系型数据库 MySQL
mysql多表查询(一口气解决掉:自连接 左右连接 满连接等)
多表查询,也称为关联查询,指两个或更多个表一起完成查询操作。 前提条件:这些一起查询的表之间是有关系的(一对一、一对多),它们之间一定是有关联字段,这个关联字段可能建立了外键,也可能没有建立外键。比如:员工表和部门表,这两个表依靠“部门编号”进行关联。
mysql多表查询(一口气解决掉:自连接 左右连接 满连接等)
|
9月前
|
机器学习/深度学习 数据挖掘 Python
Mac 安装 Anaconda3-2020.02.dmg 教程(从下载到 conda 可用)
Anaconda是流行的Python数据科学平台,支持数据分析、机器学习等。本文介绍其在Mac上的安装步骤:下载.dmg文件,拖拽安装至应用程序,配置终端环境变量,并通过conda命令或Anaconda Navigator验证安装是否成功。
|
算法 安全 PHP
Hash算法详细介绍与实现(一)
Hash表(HashTable)又称散列表,通过把关键字Key映射到数组中的一个位置来访问记录,以加快查找速度,这个映射函数称为Hash函数,存放记录的数组称为Hash表.散列表是散列函数的一个主要应用(注意:关键字不是像在加密中所使用的那样是秘密的,但它们都是用来"解锁"或者访问数据的。)例如,在英语字典中的关键字是英文单词,和它们相关的记录包含这些单词的定义。在这种情况下,散列函数必须把按照字母顺序排列的字符串映射到为散列表的内部数组所创建的索引上。
1019 1
|
Arthas 负载均衡 网络协议
Tomcat连接之KeepAlive逻辑分析
Tomcat连接之KeepAlive逻辑分析
1056 1
|
存储
阿里云盘企业版收费标准:不同人数、存储空间价格表
2024年最新阿里云盘企业版收费标准发布,企业网盘新规格上线,首月免费试用,最高可节省87%费用。提供5人至100人的多种存储方案,具体价格表和详细对比请见文章。
4312 10
|
编解码 前端开发 算法
基于OpenCV的双目摄像头测距(误差小)
首先进行双目摄像头定标,获取双目摄像头内部的参数后,进行测距;本文的双目视觉测距是基于BM算法。注意:双目定标的效果会影响测距的精准度,建议大家在做双目定标时,做好一些(尽量让误差小)。
13046 3
基于OpenCV的双目摄像头测距(误差小)

热门文章

最新文章