Mockito(二)--实例篇

学习了基本知识后,就可以实战了。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;
        }
    }
}

你可能感兴趣的:(apache,object,测试,Class)