Moco入門

接口測試

前段時間對系統中所有的接口Web Service添加了測試用例。這些用例在執行的的過程中多少也會受依賴環境的影響。比如RestAssured:

public class RestInterfaceIT {
    @Before
    public void setUp() throws Exception {
        RestAssured.baseURI = "http://host:port";
    }

    @Test
    public void should_get_false_given_header_and_param() {
        String selfHeader = "hello";
        given().header("selfHeader", selfHeader)
                .get("/xxxxx/yyyyy/{param}", "value")
                .then()
                .statusCode(200)
                .body("jobStatusResult.sent", is("false"));
    }
}

通過給Restful傳遞參數,判斷返回值來斷言接口測試。

在編寫過程中發現:
1. 每次本地編寫接口的測試用例時,都會依賴接口的環境。多多少少也對進度有點影響。
2. 編寫每個用例時有部分時間竟然花費在找合適的測試數據上。
3. 當某個接口要升級接口時,還要等待提供方先將升級部署到測試環境。

後來跟Thoughtworks的 coach 取經,對方推薦了Moco 框架。體驗後,不得不說,對於前後端開發、接口開發,這是個神器的框架。


Moco

簡單來說Moco就是類似一個mock的工具框架。在Moco 的github上面有這段話。

Integration, especially based on HTTP protocol, e.g. web service, REST etc, is wildly used in most of our development.
In the old days, we just deployed another WAR to an application server, e.g. Jetty or Tomcat etc. As we all know, it's so boring to develop a WAR and deploy it to any application server, even if we use an embeded server. And the WAR needs to be reassembled even if we just want to change a little bit.

翻譯:
集成,特別是基於HTTP協議的集成,例如web服務、REST等,在我們的大多數開發中都被廣泛使用。

在過去,我們只是將另一場戰爭部署到應用服務器上,例如Jetty或Tomcat等。衆所周知,開發一個WAR包並將其部署到任何應用服務器上是非常枯燥的,即使我們使用的是嵌入式服務器。war包也需要被重新打包即使我們只是想稍微改變一下。


簡單來說,Moco就是解決了開發前端時沒有後端支持,開發接口時依賴沒有到位的尷尬場景。當然Moco的靈活性,讓其有越來越多的應用場景。當然目前也有一些輕量級的服務器供選擇,如HTTP使用的Jetty、Restlet、Roo、Netty和Play等。但個人感覺還是Moco好用:

1.只需要簡單的配置request、response等即可滿足要求,支持http、https、socket。可以說是非常的靈活性。
2.支持在request 中設置 Headers , Cookies , StatusCode等。
3.對GET、POST、PUT、DELETE等請求方式均支持,很適合web開發。
4.無需環境配置,有java環境即可。
5.修改配置後,立刻生效。只需要維護接口,也就是契約即可。
6.對可能用到的數據格式都支持,如json、text、xml、file等。
7.還能與其他工具集成,如Junit、Maven、Gradle等。

安裝

Moco的使用非常簡單,從官網上下載一個jar包。然後相同目錄下創建一個json配置文件即可(例子來自於官網):

[
  {
    "response" :
      {
        "text" : "Hello, Moco"
      }
  }
]
注意,這裏請求配置文件是個數組,也就是說,可以在一個文件中配置多個接口的請求和響應。下載jar包後,在當前目錄運行以下命令:
java -jar moco-runner-0.12.0-standalone.jar http -p 12306 -c foo.json
注意:-p 是指定12306 端口作爲服務使用。

然後在瀏覽器中輸入: http://localhost:12306 即可看到響應。

整個使用步驟與Stubby4j ,Mountebank 很類似。

Moco使用

Moco通過簡單的配置request和response 對象,達到模擬請求效果。

Param和Header

Moco也可以模擬一個請求,同時附加參數。另外也支持在Http header裏面自定義頭部。例如在json配置裏面:

{
    "request":
    {
        "uri": "/hust",
        "queries":
        {
            "param": "zw"
        }
    },
    "response":
    {
        "text": "Hello, Moco",
        "headers":
        {
        	"SelfHeader":"SelfHeader"
        }
    }
}

此時在瀏覽器中輸入:http://localhost:12306/hust?param=zw

即可看到結果。查看請求頭部。


重定向

Moco也可以幫我們模擬重定向,這點可以模擬一些請求攔截、請求驗證失敗等情況。

{
    "request":
    {
        "uri": "/redirect"
    },
    "redirectTo": "http://www.baidu.com"
}

json和file

上邊的例子中,我們設置的都是返回文本 text。Moco也支持返回json和file數據。

{
    "request":
    {
        "uri": "/json"
    },
    "response":
    {
        "json":
        {
            "name": "hustzw"
        }
    }
},
{
    "request":
    {
        "uri": "/file"
    },
    "response":
    {
        "file":"data.json"
    }
}

Https

Moco能模擬Http的請求,也支持Https請求。我們知道Https是需要證書cert的驗證。一般這個要像證書中心(CA)申請的,而且是要收費的。不過一些小的公司或者開發中可以自己生成。Java環境自帶的keytool 工具就能幫我們生成這個證書jks。

Keytool

Keytool 是一個JAVA環境下的安全鑰匙與證書的管理工具,位於%JAVA_HOME%\bin\keytool.exe。Keytool將密鑰(key)和證書(certificates)存在一個稱爲keystore 的文件(受密碼保護)中。可以用它生成密鑰庫文件。

keytool 命令如下:


參考上邊命令,執行以下命令就可以生成我們的密鑰了。

keytool -genkey -keyalg RSA -keysize 1024 -validity 365 -dname "CN=hustzw, OU=hust,O=zw, L=zhuhai, ST=guangdong, C=CN" -alias my_key -keypass 123456 -keystore my.jks -storepass 123456

之後你就能在當前目錄下看到密鑰庫文件,my.jsk了。

然後在啓動Moco時指定密鑰文件即可。

java -jar moco-runner-0.12.0-standalone.jar https -p 12306 -c foo.json --https my.jks --cert 123456 --keystore 123456

此時打開瀏覽器輸入:https://localhost:12306/json

可以看到頁面變成下面這樣。然後添加信任改頁面即可。


Junit

Moco 是一個搭建模擬服務器的工具,其支持 API 和獨立運行兩種方式。上邊我們都是通過一個jar包開啓服務,模擬一個後臺請求服務器的。其實Moco也提供API的用法,且能很好的與Junit和Maven等集成。

看下官網的例子,先爲項目添加以下依賴:

	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.11</version>
		</dependency>

		<dependency>
			<groupId>com.github.dreamhead</groupId>
			<artifactId>moco-core</artifactId>
			<version>0.12.0</version>
		</dependency>

		<dependency>
			<groupId>org.apache.httpcomponents</groupId>
			<artifactId>fluent-hc</artifactId>
			<version>4.5</version>
		</dependency>

		<!--other dependency-->
	</dependencies>
這裏利用了fluent-hc 的jar做客戶端請求。

下面這個是github的例子:

package com.oocl;

import com.github.dreamhead.moco.HttpServer;
import com.github.dreamhead.moco.Runnable;
import org.apache.http.client.fluent.Content;
import org.apache.http.client.fluent.Request;
import org.junit.Test;

import java.io.IOException;

import static com.github.dreamhead.moco.Moco.httpServer;
import static com.github.dreamhead.moco.Runner.running;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
public class TestMoco {
	
	@Test
	public void should_response_as_expected() throws Exception {
	    // prepare a mock server
	    HttpServer server = httpServer(12306);
	    server.response("foo");
	 
	    running(server, new Runnable() {
	        public void run() throws IOException {
	            Content content = Request.Get("http://localhost:12306").execute().returnContent();
	            assertThat(content.asString(), is("foo"));
	        }
	    });
	}
}

步驟很明瞭,先利用Moco準備一個Server,設置它的返回值。然後驗證請求返回的Content。

而實際應用中,我們會有大量請求。這樣會讓測試代碼變多。因此還是回到上邊的foo.json。這裏要引入新的jar包。

		<!-- https://mvnrepository.com/artifact/com.github.dreamhead/moco-junit -->
		<dependency>
			<groupId>com.github.dreamhead</groupId>
			<artifactId>moco-junit</artifactId>
			<version>0.12.0</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/com.github.dreamhead/moco-runner -->
		<dependency>
			<groupId>com.github.dreamhead</groupId>
			<artifactId>moco-runner</artifactId>
			<version>0.12.0</version>
		</dependency>

這樣我們就能通過runner加載foo.json的配置。然後只需要編寫測試代碼即可。

import com.github.dreamhead.moco.Moco;
import com.github.dreamhead.moco.junit.MocoJunitRunner;
import org.apache.http.HttpResponse;
import org.apache.http.client.fluent.Content;
import org.apache.http.client.fluent.Request;
import org.junit.Rule;
import org.junit.Test;

import java.io.IOException;

import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;

public class MocoTest {
    @Rule
    public MocoJunitRunner runner = MocoJunitRunner.jsonHttpRunner(12306, Moco.pathResource("foo.json"));

    @Test
    public void testNoUri() throws IOException {
        Content content = Request.Get("http://localhost:12306").execute().returnContent();
        assertThat(content.asString(), is("Hello, Moco"));
    }

    @Test
    public void testWithParamAndHeader() throws IOException {
        HttpResponse httpResponse = Request.Get("http://localhost:12306/hust?param=zw").execute().returnResponse();
        assertThat(httpResponse.getFirstHeader("SelfHeader").getValue(), is("SelfHeader"));
    }
}

目錄結構如下:


MocoJunitRunner加載resources下的配置文件,然後自動構建一個mock的服務器。更多用法可以參考文檔

所有代碼


發佈了96 篇原創文章 · 獲贊 29 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章