文档章节

Mockito(二)--实例篇

chace0120
 chace0120
发布于 2014/04/01 09:59
字数 1149
阅读 752
收藏 1

学习了基本知识后,就可以实战了。Mockito的实际使用还是比较麻烦的。

因为在实际使用中,最常遇到的就是需要模拟第三方类库的行为。

比如现在有一个类FTPFileTransfer,实现了向FTP传输文件的功能。这个类中使用了apache的ftp类

org.apache.commons.net.ftp.FTPClient;

现在测试FTPFileTransfer 这个类中的isFTPConnected方法, 希望模拟无法连接ftp的情况,测试是否记录了错误log:

public class FTPFileTransfer{

  //为了测试当ftp链接不上时,是否真的会记log,我们必须mock一个假的FTPClient对象,用该对象传递/覆盖掉真实的FTPClient对象ftp,并强制让这个假对象返回"无法连接",然后看是否会记log.
 private FTPClient ftp;


 private boolean isFTPConnected(){
 if (!ftp.isConnected()) {
   LOGGER.error("Disconnected from FTP.");
 }
}

因此使用mock需要解决的问题是: 如何用mock的FTP对象覆盖掉真实代码中调用的FTPClient。因此需要将mock对象传递进去。

这里对源代码有一个限制:

源代码中必须使用set和get方法来设置/获得ftp对象,这样测试代码可以使用set来传递mock对象。

或者测试代码中写一个方法覆盖掉源代码中实例化ftp对象的方法,且测试代码中使用mock ftp对象。

 

下面的示例中都假定源代码中使用了get/set。

 

  • 创建一个返回FTPFileTransfer instance的方法。

//使用mock()方法创建一个FTP的mock对象mockedFTP。

FTPClient mockedFTP = mock(FTPClient.class);

//Stub “无法连接”

when(mockedFTP.isConnected())).thenReturn("无法连接");   

//写一个get方法返回FTPFileTransfer的实例用来测试,将mockedFTP作为参数传递进去。同时在这个方法内部用set方法将FTPFileTransfer类中的成员变量FTPClient  ftp更改为mockFTP。

//这样我们就得到了一个FTPFileTransfer的实例,同时里面的ftp已经变成了我们希望的mockFTP。

private FTPFileTransfer getMockTaskFileTransfer(final FTPClientmockedFTP) {
        FTPFileTransfer test = new FTPFileTransfer("127.0.0.1", 8888, "//usr", "username", "password");
        test.setFTPClient(mockedFTP);
        return test;
    }

 

@Test
    public void testTransfer() throws SocketException, IOException{        
        FTPFileTransfer test = getMockTaskFileTransfer();

        //得到这个实例以后,就直接调用这个实例的isFTPConnected方法,然后去log文件里找有没有我们希望的log就行了。注意此时,mockedFTP一定会返回"无法连接",所以isFTPConnected一定会记log。
        test.isFTPConnected();
    }

测试完毕~~~

  • 用subclass-and-override实现

从名字就可以看出,通过创建被测试类的子类,覆盖掉被测试类的getFTPClient()方法,将mock对象传递进去。

 

class MockFTPFileTransfer extends FTPFileTransfer{
        
        public MockFTPFileTransfer(){
            super("127.0.0.1", 8888, "//usr", "username", "password");
        }

         //源代码中必须使用get来获得ftp对象,否则mock不会生效      
        @Override
        public FTPClient getFTPClient(){
            FTPClient mockedFTP = mock(FTPClient.class);
            when(mockedFTP.isConnected()).thenReturn(true);
            return mockedFTP;
        } 
    }

 

@Test
    public void testTransfer() throws SocketException, IOException{        
        FTPFileTransfer test = new MockFTPFileTransfer();
        test.isFTPConnected();
    }

  • 用partial mock实现

partial mock是1.8之后的新功能。通常情况下会使用mock出来的对象完全覆盖掉被模拟的对象,对于那些没有stub的方法,则会返回build-in 类型的默认值。

 

@Test
    public void testTransfer() throws SocketException, IOException{
        //模拟一个FTPClient对象,同时stub行为。

        FTPClient mockedFTP = mock(FTPClient.class);
        when(mockedFTP.isConnected()).thenReturn(true);

 

        //spy可以模拟一个real object

        //这里的可以认为是spy在real object上包了一层,除了getFTPClient()被覆盖掉以外,其他方法仍然是真实对象的。

        //这就是partial mock的概念: 仅仅用mock对象覆盖源对象的一部分,而不是全部。
        FTPFileTransfer spyFTP= spy(new FTPFileTransfer("127.0.0.1", "//usr", "username", "password"));
        when(spyFTP.getFTPClient()).thenReturn(mockedFTP);
        
        spyFTP.setFTPClient(mockedFTP);
        spyFTP.isFTPConnected();
    }

 

完毕!

大家都明白了吗?如果没有明白可以回帖,我会回答的。

------------------------------------------------------------------------------------------------------------------------------------

应要求发一个完整的UT


import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;

import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.transform.stream.StreamSource;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentMatcher;

import static org.junit.Assert.*;
import org.apache.commons.io.FileUtils;


import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.*;


public class ASAPSoapMessageTest {
    
    ASAPSoapMessage testASAPSoapMessage= new ASAPSoapMessage();
    String testSOAPRequest = "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema\"><LoginRequest xmlns=\"http://asap.schemas.tfn.thomsonreuters.com/Messages/Base/2010-03-01/\"/></s:Body></s:Envelope>";
    File testFile = new File("testFile.xml");
    String testSOAPAction = "http://fackSOAPAction/";
    String testWebService = "http://fackWebService/";
    String testReply = "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body><LoginResponse xmlns=\"http://asap.schemas.tfn.thomsonreuters.com/Messages/Base/2010-03-01/\"/></s:Body></s:Envelope>";
    MessageFactory mf;
    SOAPMessage SOAPRequestTest;
    SOAPMessage replySOAPRequestTest;
    
    @Before 
    public void testUp() throws SOAPException{
        mf = MessageFactory.newInstance();
        SOAPRequestTest = mf.createMessage();
        replySOAPRequestTest = mf.createMessage();
    }
    
    @Test
    public void testGetSoapContent() throws IOException, SOAPException{
        
        String soapContentString = "";
            
        StreamSource prepMsg = new StreamSource(new StringReader(testSOAPRequest));
        SOAPPart sp = SOAPRequestTest.getSOAPPart();
        sp.setContent(prepMsg);
        soapContentString = testASAPSoapMessage.getSoapContent(SOAPRequestTest);
              
        assertTrue(soapContentString.equalsIgnoreCase(testSOAPRequest));
    }
    
    @Test
    public void testPrepareSOAPMessage() throws IOException{
        FileUtils.writeStringToFile(this.testFile,this.testSOAPRequest);
        assertTrue(testASAPSoapMessage.prepareSOAPMessage("testFile.xml").equalsIgnoreCase(testSOAPRequest));        
    }
    
    @Test
    public void testSendSOAPMessage() throws SOAPException, IOException{
        
        SOAPPart sp = replySOAPRequestTest.getSOAPPart();
        StreamSource prepMsg = new StreamSource(new StringReader(testReply));
        sp.setContent(prepMsg);
        
        SOAPConnection mockedSOAPConnection = mock(SOAPConnection.class);  
        when(mockedSOAPConnection.call(argThat(new IsSOAPMessage()), anyObject())).thenReturn(replySOAPRequestTest); 
        
        ASAPSoapMessage spyASAPSoapMessage = spy(new ASAPSoapMessage());
        when(spyASAPSoapMessage.getSoapConnection()).thenReturn(mockedSOAPConnection); 
        
        SOAPMessage replySOAPMessage= spyASAPSoapMessage.sendSOAPMessage(testSOAPRequest, testWebService, testSOAPAction);
        assertTrue(spyASAPSoapMessage.getSoapContent(replySOAPMessage).equalsIgnoreCase(testReply));     
    }
    
    class IsSOAPMessage extends ArgumentMatcher<SOAPMessage> {
        public boolean matches(Object soapMessage) {
            return soapMessage instanceof SOAPMessage;
        }
    }
}

本文转载自:http://blog.csdn.net/onlyqi/article/details/6546589

共有 人打赏支持
chace0120
粉丝 38
博文 48
码字总数 41091
作品 0
安阳
程序员
Mockito(三)--完整功能介绍

回到官网:http://mockito.org/,打开documentation可以看到原文。 强烈建议不熟悉Mockito的同学先看看我写的Mockito(一)入门篇和(二)实例篇之后再来看这篇文章。 因为只有看了前两篇文章才明...

chace0120
2014/04/01
0
0
5分钟了解Mockito

一、什么是mock测试,什么是mock对象? 先来看看下面这个示例: 从上图可以看出如果我们要对A进行测试,那么就要先把整个依赖树构建出来,也就是BCDE的实例。 一种替代方案就是使用mocks 从图...

闪电
2016/09/25
22
0
Kotlin 写 Android 单元测试(四),Robolectric 在 JVM 上测试安卓相关代码

Kotlin 写 Android 单元测试系列: Kotlin 写 Android 单元测试(一),单元测试是什么以及为什么需要 Kotlin 写 Android 单元测试(二),JUnit 4 测试框架和 kotlin.test 库的使用 Kotlin...

JohnnyShieh
2017/12/20
0
0
Mockito 中文文档 三

27. 委托调用真实实例 (Since 1.9.5) 当使用常规的 spy API 去 mock 或者 spy 一个对象很困难时可以用 delegate 来 spy 或者 mock 对象的某一部分。 从 Mockito 的 1.10.11 版本开始, dele...

张贴在
2016/06/27
0
0
JAVA单元测试mock框架

JAVA单元测试mock框架 无标题2016-07-17298 阅读 JAVA 一.概述 最近在做代码重构,发现系统中的UT很少,重构没有UT的话,全部得人工测试,逻辑覆盖不一定全部能覆盖到,因此UT还是很有必要存...

无标题
2016/07/17
0
0

没有更多内容

加载失败,请刷新页面

加载更多

VS code编辑器安装 php7.2 NTS 版本 Xdebug

本文使用的是 phpstudy 一键安装包(windows32位) php 版本是 php7.2 NTS 1、在 phpstudy 面板中开启 phpdebug 扩展 // 其他选项菜单-> php 扩展与设置-> php 扩展 2、官方下载 Xdebug // ...

削个椰子皮_给个梨
3分钟前
0
0
Swagger中配置了@ApiModelProperty的allowableValues属性但不显示的问题

现在用Swagger来生成API文档的例子已经非常多了,今天碰到开发同事问了一个问题,帮着看了一下,主要还是配置方法的问题,所以记录一下。如果您也碰到了同样的问题,希望本文对您有用。 问题...

程序猿DD
34分钟前
1
0
sql 命令

show variables like '%general%'; show variables like '%log_output%'; show variables like '%quer%'; show global status like '%slow%';...

JavaSon712
41分钟前
2
0
Django修改默认数据库引擎

Django默认数据库引擎为sqlite3,除了sqlite3,还支持postgresql、mysql、oracle 配置如下:其中postgresql_psycopg2为postgresql的适配器。 'django.db.backends.postgresql' 'django.db.bac......

MichaelShu
47分钟前
0
0
动画源码解析

目录介绍 1.Animation和Animator区别 2.Animation运行原理和源码分析 2.1 基本属性介绍 2.2 如何计算动画数据 2.3 什么是动画更新函数 2.4 动画数据如何存储 2.5 Animation的调用 3.Animator...

潇湘剑雨
53分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部