WireMock實(shí)戰(zhàn)-1

一.簡(jiǎn)介

1.是什么
WireMock是一個(gè)基于http api的模擬器。有些人可能認(rèn)為它是服務(wù)虛擬化工具或模擬服務(wù)器渊鞋。
它使您能夠在依賴的API不存在或不完整時(shí)保持高效。它的構(gòu)建速度很快,可以將構(gòu)建時(shí)間從幾個(gè)小時(shí)減少到幾分鐘橡淆。

2.能做什么
可以做單元測(cè)試,獨(dú)立的 JAR 可以做前后端分離開發(fā)&聯(lián)調(diào)使用.

二.版本簡(jiǎn)介

WireMock有兩種版本:

  • 一個(gè)標(biāo)準(zhǔn)的JAR只包含WireMock;
  • 一個(gè)獨(dú)立的JAR包含WireMock及其所有依賴項(xiàng).

在某些情況下 WireMock 可能會(huì)與某些代碼中的包產(chǎn)生沖突.
獨(dú)立的 JAR 所依賴的包被隱藏在包中,與項(xiàng)目本身的代碼相對(duì)獨(dú)立.
說(shuō)白了,標(biāo)準(zhǔn)的 WireMock 是與測(cè)試代碼耦合在一起的運(yùn)行在同一個(gè)進(jìn)程同一個(gè)JVM 中.獨(dú)立的WireMock 包是運(yùn)行在另外的進(jìn)程中,也是獨(dú)立的 JVM.

目前召噩,建議您使用獨(dú)立JAR作為Spring引導(dǎo)項(xiàng)目的依賴項(xiàng)。這避免了關(guān)于 Jetty 版本的沖突.

三. MAVEN

要將標(biāo)準(zhǔn)WireMock JAR作為項(xiàng)目依賴項(xiàng)添加到POM的依賴項(xiàng)部分:

<dependency>
    <groupId>com.github.tomakehurst</groupId>
    <artifactId>wiremock</artifactId>
    <version>2.19.0</version>
    <scope>test</scope>
</dependency>

或使用獨(dú)立JAR:

<dependency>
    <groupId>com.github.tomakehurst</groupId>
    <artifactId>wiremock-standalone</artifactId>
    <version>2.19.0</version>
</dependency>

四.JUnit 4.x 用法

JUnit規(guī)則提供了在測(cè)試用例中包含WireMock的方便方法逸爵。它為您處理生命周期具滴,在每個(gè)測(cè)試方法之前啟動(dòng)服務(wù)器,然后停止师倔。

1.基本用法
在默認(rèn)的端口(8080)啟用WireMock.

@Rule
public WireMockRule wireMockRule = new WireMockRule();

WireMockRule 通過(guò)構(gòu)造函數(shù)來(lái)設(shè)置.設(shè)置項(xiàng)通過(guò)Options實(shí)例來(lái)創(chuàng)建:

@Rule
public WireMockRule wireMockRule = new WireMockRule(options().port(8888).httpsPort(8889));

詳細(xì)配置信息[http://wiremock.org/docs/configuration/]

2.不匹配的請(qǐng)求
JUnit規(guī)則將驗(yàn)證在測(cè)試用例過(guò)程中接收到的所有請(qǐng)求都是由配置的存根(而不是默認(rèn)的404)提供服務(wù)的构韵。如果沒(méi)有拋出驗(yàn)證異常,則測(cè)試失敗趋艘。這個(gè)行為可以通過(guò)傳遞一個(gè)額外的構(gòu)造函數(shù)標(biāo)志來(lái)禁用:

@Rule
public WireMockRule wireMockRule = new WireMockRule(options().port(8888), false);

3.其他@Rule配置

@ClassRule
public static WireMockClassRule wireMockRule = new WireMockClassRule(8089);

@Rule
public WireMockClassRule instanceRule = wireMockRule;

4.從規(guī)則訪問(wèn) stub & 驗(yàn)證DSL
除了WireMock類上的靜態(tài)方法外疲恢,還可以通過(guò)規(guī)則對(duì)象直接配置stubs 。
這樣做有兩個(gè)好處:
1)它更快瓷胧,因?yàn)樗苊饬送ㄟ^(guò)HTTP發(fā)送命令;
2)如果你想模擬多個(gè)服務(wù)显拳,你可以為每個(gè)服務(wù)聲明一個(gè)規(guī)則,但不需要為每個(gè)服務(wù)創(chuàng)建一個(gè)客戶端對(duì)象搓萧。

@Rule
public WireMockRule service1 = new WireMockRule(8081);

@Rule
public WireMockRule service2 = new WireMockRule(8082);

@Test
public void bothServicesDoStuff() {
    service1.stubFor(get(urlEqualTo("/blah")).....);
    service2.stubFor(post(urlEqualTo("/blap")).....);

    ...
}

五.JUnit 4.x 實(shí)戰(zhàn)

測(cè)試標(biāo)準(zhǔn)的 WireMock 包,原理是啟動(dòng)測(cè)試模塊之前先啟動(dòng)一個(gè)內(nèi)置的 MockServer.

寫個(gè) Service 要調(diào)用遠(yuǎn)程服務(wù),地址為 http://127.0.0.1:8080/hello

import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

/**
 * <p>
 * 創(chuàng)建時(shí)間為 下午2:52-2018/11/21
 * 項(xiàng)目名稱 SpringBootWireMock
 * </p>
 *
 * @author shao
 * @version 0.0.1
 * @since 0.0.1
 */


@Service
public class RemoteService {

    private RestTemplate restTemplate = new RestTemplate();

    public String access(){
        ResponseEntity<String> result = restTemplate.getForEntity("http://127.0.0.1:8080/hello", String.class);
        System.out.println(result);
        return result.getBody();
    }

}

編寫單元測(cè)試

import com.github.tomakehurst.wiremock.junit.WireMockClassRule;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.get;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;


/**
 * <p>
 * 創(chuàng)建時(shí)間為 下午2:53-2018/11/21
 * 項(xiàng)目名稱 SpringBootWireMock
 * </p>
 *
 * @author shao
 * @version 0.0.1
 * @since 0.0.1
 */

@RunWith(SpringRunner.class)
@SpringBootTest
//@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class RemoteServiceTest {

    // Start WireMock on some dynamic port
    // for some reason `dynamicPort()` is not working properly
    @ClassRule
    public static WireMockClassRule wiremock = new WireMockClassRule(options().port(8080));
    // A service that calls out over HTTP to localhost:${wiremock.port}
    @Autowired
    private RemoteService service;

    @Test
    public void access() throws Exception {
        // Stubbing WireMock
        wiremock.stubFor(get(urlEqualTo("/hello"))
            .willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!")));
        // We're asserting if WireMock responded properly
        System.out.println(service.access());

    }

}

測(cè)試結(jié)果

2018-11-21 16:10:32.096  INFO 2105 --- [           main] c.h.s.service.RemoteServiceTest          : Started RemoteServiceTest in 7.554 seconds (JVM running for 12.989)
2018-11-21 16:10:32.662  INFO 2105 --- [qtp609887969-18] o.e.j.s.handler.ContextHandler.ROOT      : RequestHandlerClass from context returned com.github.tomakehurst.wiremock.http.StubRequestHandler. Normalized mapped under returned 'null'
<200,Hello World!,{Content-Type=[text/plain], Matched-Stub-Id=[a00a6350-bf66-4d89-969d-c5a8cb49c3c0], Vary=[Accept-Encoding, User-Agent], Transfer-Encoding=[chunked], Server=[Jetty(9.4.12.v20180830)]}>
Hello World!
2018-11-21 16:10:33.013  INFO 2105 --- [           main] o.e.jetty.server.AbstractConnector       : Stopped NetworkTrafficServerConnector@797501a{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}

WireMock服務(wù)器可以在自己的進(jìn)程中運(yùn)行杂数,并通過(guò)Java API、HTTP或JSON文件對(duì)其進(jìn)行配置矛绘。

下載地址
http://repo1.maven.org/maven2/com/github/tomakehurst/wiremock-standalone/2.19.0/wiremock-standalone-2.19.0.jar

Once you have downloaded the standalone JAR you can run it simply by doing this:

$ java -jar wiremock-standalone-2.19.0.jar

命令行選項(xiàng)
以下可以在命令行中指定:
--port:設(shè)置HTTP端口號(hào)耍休,例如端口9999。使用--port 0來(lái)動(dòng)態(tài)確定端口.
--https-port:如果指定货矮,則在提供的端口上啟用HTTPS.
--bind-address:WireMock服務(wù)器應(yīng)該提供的IP地址羊精。如果未指定,則綁定到所有本地網(wǎng)絡(luò)適配器囚玫。
--https-keystore:包含用于HTTPS的SSL證書的密鑰存儲(chǔ)文件的路徑喧锦。密鑰存儲(chǔ)庫(kù)的密碼必須為“password”。此選項(xiàng)僅在指定--https-port時(shí)才有效抓督。如果沒(méi)有使用此選項(xiàng)燃少,WireMock將默認(rèn)為它自己的自簽名證書。

六.與 SpringBoot 整合

Spring Cloud Contract 已經(jīng)創(chuàng)建了一個(gè)庫(kù)來(lái)支持使用“ambient”HTTP服務(wù)器運(yùn)行WireMock铃在。它還簡(jiǎn)化了配置的某些方面阵具,并消除了在同時(shí)運(yùn)行Spring引導(dǎo)和WireMock時(shí)出現(xiàn)的一些常見問(wèn)題。

場(chǎng)景描述:項(xiàng)目有兩個(gè)模塊 A&B, 現(xiàn)在需要我負(fù)責(zé)模塊 A,B 模塊由另外一個(gè)人負(fù)責(zé), 整個(gè)項(xiàng)目的運(yùn)行需要 A 調(diào)用 B 的接口模塊.但是運(yùn)行單元測(cè)試的時(shí)候就需要 B 能夠調(diào)通, 這個(gè)時(shí)候需要一個(gè)模塊能夠模擬 B 的接口.

1.首先添加依賴,屬于 SpringCloud,可以直接添加 SpringCloud 依賴,會(huì)自動(dòng)整合合適的版本.

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-wiremock</artifactId>
    <scope>test</scope>
</dependency>

2.編寫Controller代碼

@RestController
public class WireMockController {

    @Autowired
    private RemoteService service;

    @GetMapping("get")
    public String get() {
        return service.access();
    }

}

3.編寫 Service 代碼
這個(gè)部分會(huì)通過(guò) RestTemplate 調(diào)用遠(yuǎn)程摸個(gè)模塊.

@Service
public class RemoteService {

    @Autowired
    private RestTemplate restTemplate;

    @Value("${remote}")
    private String url;

    public String access() {
        ResponseEntity<String> result = restTemplate.getForEntity(url, String.class);
        System.out.println(result);
        return result.getBody();
    }

}

4.編寫單元測(cè)試

@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("dev")
@RunWith(SpringRunner.class)
@AutoConfigureWireMock(stubs="classpath:/mappings")
public class WireMockControllerTest {

    @Autowired
    private MockMvc mvc;

    @Rule
    public WireMockRule service1 = new WireMockRule(8090);

    @Test
    public void bothServicesDoStuff() throws Exception  {
        this.mvc.perform(MockMvcRequestBuilders.get("/get"))
            .andExpect(status().isOk())
            .andExpect(content().string("Hello World"));
    }
}

重點(diǎn)來(lái)了,
運(yùn)行 dev 配置文件:
application-dev.properties

remote=http://127.0.0.1:8080/hello

把遠(yuǎn)程訪問(wèn)的地址改為本地
在 resources 下面
建立mappings文件夾,里面存入如下信息,文件以 .json 結(jié)尾:

{
  "request" : {
    "urlPath" : "/hello",
    "method" : "GET"
  },
  "response" : {
    "status" : 200,
    "body" : "Hello World"
  }
}

@AutoConfigureWireMock(stubs="classpath:/mappings")表示在classpath:/mappings文件夾下添加一些映射,每個(gè) json 文件都是一個(gè)映射. json文件可以指定訪問(wèn)方式,訪問(wèn)的路徑,返回?cái)?shù)據(jù),狀態(tài)碼等等.

六.代碼路徑

https://github.com/shaopro/SpringBootWireMock

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末定铜,一起剝皮案震驚了整個(gè)濱河市阳液,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌揣炕,老刑警劉巖帘皿,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異畸陡,居然都是意外死亡鹰溜,警方通過(guò)查閱死者的電腦和手機(jī)虽填,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)曹动,“玉大人斋日,你說(shuō)我怎么就攤上這事∧钩拢” “怎么了桑驱?”我有些...
    開封第一講書人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)跛蛋。 經(jīng)常有香客問(wèn)我熬的,道長(zhǎng),這世上最難降的妖魔是什么赊级? 我笑而不...
    開封第一講書人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任押框,我火速辦了婚禮,結(jié)果婚禮上理逊,老公的妹妹穿的比我還像新娘橡伞。我一直安慰自己,他們只是感情好晋被,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開白布兑徘。 她就那樣靜靜地躺著,像睡著了一般羡洛。 火紅的嫁衣襯著肌膚如雪挂脑。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評(píng)論 1 299
  • 那天欲侮,我揣著相機(jī)與錄音崭闲,去河邊找鬼。 笑死威蕉,一個(gè)胖子當(dāng)著我的面吹牛刁俭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播韧涨,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼牍戚,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了虑粥?” 一聲冷哼從身側(cè)響起如孝,我...
    開封第一講書人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎舀奶,沒(méi)想到半個(gè)月后暑竟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體斋射,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡育勺,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年但荤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片涧至。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡腹躁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出南蓬,到底是詐尸還是另有隱情纺非,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布赘方,位于F島的核電站烧颖,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏窄陡。R本人自食惡果不足惜炕淮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望跳夭。 院中可真熱鬧涂圆,春花似錦、人聲如沸币叹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)颈抚。三九已至踩衩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間贩汉,已是汗流浹背九妈。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留雾鬼,地道東北人萌朱。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像策菜,于是被迫代替她去往敵國(guó)和親晶疼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 前言 在Java項(xiàng)目開發(fā)中又憨,項(xiàng)目的編譯翠霍、測(cè)試、打包等是比較繁瑣的蠢莺,屬于重復(fù)勞動(dòng)的工作寒匙,浪費(fèi)人力和時(shí)間成本。以往開發(fā)...
    JourWon閱讀 1,121評(píng)論 0 1
  • Gradle用戶指南 版權(quán)所有?2007-2017 Hans Dockter,Adam Murdoch 本文檔的副...
    丑男李狗蛋閱讀 2,286評(píng)論 0 1
  • Maven的基本了解 什么是Maven锄弱? Maven就是Apache下的一個(gè)開源項(xiàng)目考蕾。它是用純java開發(fā)的。是一...
    Bcome閱讀 2,814評(píng)論 0 7
  • spring官方文檔:http://docs.spring.io/spring/docs/current/spri...
    牛馬風(fēng)情閱讀 1,670評(píng)論 0 3
  • 時(shí)間是一個(gè)最稀缺的資源会宪。每個(gè)人的時(shí)間都有限肖卧! 已經(jīng)進(jìn)入倒計(jì)時(shí)特別珍惜和感恩!在這90天踐行中掸鹅!我相信很多人都有收獲...
    Josie_ZHANG閱讀 184評(píng)論 0 0