文档章节

Mockito(二)--实例篇

chace0120
 chace0120
发布于 2014/04/01 09:59
字数 1149
阅读 749
收藏 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
粉丝 37
博文 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

没有更多内容

加载失败,请刷新页面

加载更多

下一页

流量劫持是如何产生的?

流量劫持,这种古老的攻击沉寂了一段时间后,最近又开始闹的沸沸扬扬。众多知名品牌的路由器相继爆出存在安全漏洞,引来国内媒体纷纷报道。只要用户没改默认密码,打开一个网页甚至帖子,路由...

谢思华
12分钟前
0
0
Hadoop Client无法使用maven下载源码

最近在学习hadoop,使用maven的时候想看一下源码的注释,结果IDEA一直提示无法下载 搞得我一度以为maven坏掉了。 但是通过搜索,发现在maven仓库里确实没有源码.... 而2.8.1以及之前的版本是...

Iceberg_XTY
13分钟前
0
0
为什么程序员千万不要重写代码?

你所做的事情,也许暂时看不到成果,但不要灰心或焦虑,你不是没有成长,而是在扎根。 图片来自网络 0 前言 程序员都有一颗工程师的心,所以当他们到一片新的场地想做的第一件事就是,将旧的...

Java小铺
15分钟前
0
0
VUE集成AdminLte

1. 安装需要到插件 npm i admin-lte -Snpm i jquery -Snpm i axios -Snpm i vue-router -S 2. 配置webpack.config.js 2.1 module.exports.module.rules修改字体loader: {test: /\.(p......

Pasenger
53分钟前
0
0
Spring Aop原理之切点表达式解析

在前面的文章(Spring AOP切点表达式详解)中,我们总结了Spring Aop切点表达式的用法,而在上文(Spring Aop原理之Advisor过滤)中我们讲到,切点表达式的解析主要是在PatternParser.parse...

爱宝贝丶
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部