1. 程式人生 > >junit使用stub進行單元測試

junit使用stub進行單元測試

stub是程式碼的一部分,我們要對某一方法做單元測試時,可能涉及到呼叫第三方web服務。假如當前該服務不存在或不可用咋辦?好辦,寫一段stub程式碼替代它。

stub 技術就是把某一部分程式碼與環境隔離起來(比如,通過替換 Web伺服器、檔案系統、資料庫等手段)從而進行單元測試的。

下面演示一個例子,利用jetty編寫相關的stub充當web伺服器,返回適當內容。

環境: idea + spring boot + jetty

關於jetty伺服器,對比tomcat更輕量級,可輕鬆嵌入java程式碼啟動它。

如何在專案中啟動一個jetty伺服器?

package com.lhy.junitkaifa.stubs;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ResourceHandler;

/**
 * @author xusucheng
 * @create 2018-12-20
 **/
public class JettySample {
    public static void main(String[] args) throws Exception {
        Server server = new Server( 8081 );

        ContextHandler context = new ContextHandler(server,"/");
        //預設為專案根目錄
        context.setResourceBase(".");
        context.setHandler(new ResourceHandler());

        server.setStopAtShutdown( true );
        server.start();
    }
}

請求:http://localhost:8081

 

 

編寫一個獲取url內容的工具方法叫WebClient

package com.lhy.junitkaifa.stubs;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * 讀取指定URL內容
 * @author xusucheng
 * @create 2018-12-20
 **/
public class WebClient {
    public String getContent( URL url )
    {
        StringBuffer content = new StringBuffer();
        try
        {
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setDoInput( true );
            InputStream is = connection.getInputStream();
            byte[] buffer = new byte[2048];
            int count;
            while ( -1 != ( count = is.read( buffer ) ) )
            {
                content.append( new String( buffer, 0, count ) );
            }
        }
        catch ( IOException e )
        {
            return null;
        }
        return content.toString();
    }

    public static void main(String[] args) throws Exception{
        WebClient wc = new WebClient();
        String content = wc.getContent(new URL("http://www.baidu.com/"));

        System.out.println(content);
    }
}

 

編寫測試類TestWebClient

package com.lhy.junitkaifa.stubs;

import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.ByteArrayISO8859Writer;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.http.HttpHeaders;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;

/**
 * @author xusucheng
 * @create 2018-12-20
 **/
public class TestWebClient {
    private WebClient client = new WebClient();
    private static final int PORT=8081;

    @BeforeClass
    public static void setUp() throws Exception{
        System.out.println("====================Befor Class=====================");

        Server server = new Server(PORT);
        TestWebClient t = new TestWebClient();

        ContextHandler contentOkContext = new ContextHandler(server,"/testGetContentOk");
        contentOkContext.setHandler(t.new TestGetContentOkHandler());

        ContextHandler contentErrorContext = new ContextHandler(server,"/testGetContentError");
        contentErrorContext.setHandler(t.new TestGetContentServerErrorHandler());

        ContextHandler contentNotFoundContext = new ContextHandler(server,"/testGetContentNotFound");
        contentNotFoundContext.setHandler(t.new TestGetContentNotFoundHandler());

        HandlerList handlers = new HandlerList();
        handlers.setHandlers(new Handler[] { contentOkContext, contentErrorContext, contentNotFoundContext});
        server.setHandler(handlers);

        server.setStopAtShutdown( true );
        server.start();
    }

    @Test
    public void testGetContentOk()
            throws Exception
    {
        String result = client.getContent( new URL( "http://localhost:"+PORT+"/testGetContentOk" ) );
        assertEquals( "It works", result );
    }

    @Test
    public void testGetContentError()
            throws Exception
    {
        String result = client.getContent( new URL( "http://localhost:"+PORT+"/testGetContentError/" ) );
        assertNull( result );
    }

    @Test
    public void testGetContentNotFound()
            throws Exception
    {
        String result = client.getContent( new URL( "http://localhost:"+PORT+"/testGetContentNotFound" ) );
        assertNull( result );
    }

    @AfterClass
    public static void tearDown()
    {
        // Do nothing becuase the Jetty server is configured
        // to stop at shutdown.
        System.out.println("====================After Class=====================");
    }

    /**
     * 正常請求處理器
     */
    private class TestGetContentOkHandler
            extends AbstractHandler
    {

        @Override
        protected void doStart() throws Exception {
            super.doStart();
        }

        @Override
        public void setServer(Server server) {
            super.setServer(server);
        }

        @Override
        public void handle(String s, Request request, HttpServletRequest httpServletRequest, HttpServletResponse response) throws IOException, ServletException {
            System.out.println("======================TestGetContentOkHandler=======================");
            OutputStream out = response.getOutputStream();
            ByteArrayISO8859Writer writer = new ByteArrayISO8859Writer();
            writer.write( "It works" );
            writer.flush();
            response.setIntHeader( HttpHeaders.CONTENT_LENGTH, writer.size() );
            writer.writeTo( out );
            out.flush();
            request.setHandled(true);
        }
    }

    /**
     * 異常請求處理器
     */
    private class TestGetContentServerErrorHandler
            extends AbstractHandler
    {
        @Override
        public void handle(String s, Request request, HttpServletRequest httpServletRequest, HttpServletResponse response) throws IOException, ServletException {
            response.sendError( HttpServletResponse.SC_SERVICE_UNAVAILABLE );
        }
    }

    /**
     * 404處理器
     */
    private class TestGetContentNotFoundHandler
            extends AbstractHandler
    {

        @Override
        public void handle(String s, Request request, HttpServletRequest httpServletRequest, HttpServletResponse response) throws IOException, ServletException {
            response.sendError( HttpServletResponse.SC_NOT_FOUND );
        }
    }
}

 

直接執行該類,結果為: