consumer driven contractsで rest api/マイクロサービスをテスト #m3tech
TRANSCRIPT
Consumer Driven ContractsでREST API/マイクロサービスをテスト
Toshiaki Maki (@making)Sr. Solutions Architect @Pivotal2016-06-08 M3 Tech Meetup
Who am I ?•Toshiaki Maki (@making)•https://blog.ik.am•Sr. Solutions Architect•Spring Framework enthusiast
SpringFramework
徹底⼊⾨(Coming Soon?)
パーフェクトJava EE(Coming Soon?)
Background
REST API/マイクロサービスのテストどうしてますか?
図はhttp://codearte.github.io/accurestより
REST API/マイクロサービスのテストどうしてますか?•全サービスをDeploy?•各サービスをMock化?•テスト書いてない!?
全サービスをDeploy•メリット•本番環境をシミュレートできる•サービス間が実際の通信
•デメリット•全サービスのデプロイ/DBの準備が⼤変•テストに時間がかかる•デバッグし⾟い
各サービスをMock化•メリット•テストが速い•環境セットアップ不要
•デメリット•意味のないスタブを作りがち•本番環境では結局エラー
図はhttp://codearte.github.io/accurestより
テスト書いてない
Team BTeam A
現実世界(とあるトイレでの会話)
😕 😗
Team BTeam A
現実世界(とあるトイレでの会話)
😕 😗
おたくのチームのAPI使ってテストするのに時間かかったよ〜
Team BTeam A
現実世界(とあるトイレでの会話)
😕 😗
おたくのチームのAPI使ってテストするのに時間かかったよ〜
お、いいね。でも、さっきAPI変え
ちゃったよ。
Team BTeam A
現実世界(とあるトイレでの会話)
😕 😗
おたくのチームのAPI使ってテストするのに時間かかったよ〜
お、いいね。でも、さっきAPI変え
ちゃったよ。
😡
あの💢
Consumer Driven Contract
Consumer Driven Contract (CDC)
• http://martinfowler.com/articles/consumerDrivenContracts.html•アーキテクチャレベルのTDD• "Contract"を通じて、ConsumerがProviderに期待内容を共有する•ProviderのContract違反をProvider側のテストで検出
Consumer ProviderContract
CDCの流れ1. Consumerは期待するリクエスト/レスポンスをContractと
して定義(DSLなどを利⽤)
2. ProviderはConsumerとContractを合意(Pull Requestなどを利⽤)
3. ProviderはContractが守られていることを⽰すテストを実施ConsumerはContractを前提にモック化してテストを実施
CDC⽤ライブラリ• Pact-JVM• https://github.com/DiUS/pact-jvm• Pactは多⾔語(Ruby, .NET, Go, JS, Swift, etc)に対応
• Accurest• https://github.com/Codearte/accurest• Spring MVC向け• Eureka, Spring Integration, Spring Cloud Streamにも対応している• 今後Spring Cloud Contractという名前になるかも?
Accurest
Accurest•DSLにGroovyを使⽤• Provider向けにRestAssuredとJSON Assertを使ったテストを⽣成(JUnit or Spock)• Consumer向けにWireMock⽤のスタブファイルを⽣成• Consumerのテストにスタブサーバーを組み込める 図は
http://codearte.github.io/accurestより
ContractDSL
Consumer Provider
期待するリクエスト/レスポンスを定義
ContractDSL
テストケース
スタブファイル
Consumer Provider
RestAssured + JSON Assertなコード⽣成
WireMock⽤のスタブファイルを⽣成
ContractDSL
テストケース
スタブファイル
Consumer Provider
RestAssured + JSON Assertなコード⽣成
WireMock⽤のスタブファイルを⽣成
Providerの破壊的な変更によるContract違反を検出可能
Accurest Maven Plugin
$ mvn accurest:convert
$ mvn accurest:generateTests
$ mvn accurest:run
$ mvn accurest:generateStubs
Provider向け
Consumer向け
テストコードを⽣成
WireMock形式に変換
モックサーバーを起動モックのjarを⽣成
io.codearte.accurest.dsl.GroovyDsl.make {request {
method 'GET'urlPath '/foos'
}response {
status 200body("""[ {
"value" : 42}, {
"value" : 100} ]""")
headers {header('Content-Type': 'application/json;charset=UTF-8')
}}}
Contract DSL
public class AccurestTest extends MvcTest{@Test public void validate_requestForFoos() throws Exception {
MockMvcRequestSpecification request = given();ResponseOptions response = given().spec(request).get("/foos");
assertThat(response.statusCode()).isEqualTo(200);assertThat(response.header("Content-Type"))
.isEqualTo("application/json;charset=UTF-8");
DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
assertThatJson(parsedJson).array().contains("value").isEqualTo(42);
assertThatJson(parsedJson).hasSize(2);assertThatJson(parsedJson).array().contains("value")
.isEqualTo(100);}}
テストコードを⽣成Provider側
public class AccurestTest extends MvcTest{@Test public void validate_requestForFoos() throws Exception {
MockMvcRequestSpecification request = given();ResponseOptions response = given().spec(request).get("/foos");
assertThat(response.statusCode()).isEqualTo(200);assertThat(response.header("Content-Type"))
.isEqualTo("application/json;charset=UTF-8");
DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
assertThatJson(parsedJson).array().contains("value").isEqualTo(42);
assertThatJson(parsedJson).hasSize(2);assertThatJson(parsedJson).array().contains("value")
.isEqualTo(100);}}
テストコードを⽣成
親クラスを指定可能
Provider側
public class MvcTest {@Beforepublic void setup() {
RestAssuredMockMvc.standaloneSetup(
new FooController());}
}
テストコードを⽣成Provider側
public class MvcTest {@Beforepublic void setup() {
RestAssuredMockMvc.standaloneSetup(
new FooController());}
}
テストコードを⽣成Provider側
MockMVCでも組み込みサーバーでも可
{"uuid" : "d0c6c40b-47a8-4504-967d-b470f382d820","request" : {"urlPath" : "/foos","method" : "GET"
},"response" : {"status" : 200,"body" : "[{¥"value¥":42},{¥"value¥":100}]","headers" : {
"Content-Type" : "application/json;charset=UTF-8"}
}}
WireMock形式に変換Consumer側
$ mvn accurest:convert accurest:run
Consumer側
$ mvn accurest:generateStubs install or deploy
Consumer側
myprovider-0.0.1-SNAPSHOT-stubs.jarがMavenレポジトリにデプロイされる
Consumer側
Consumer
Provider/foos /foos
{...}Got "{...}"
テストしたい
classifier
Consumer側
stubrunner.stubs.ids=com.example:myprovider:+:stubs:9999
src/test/resources/application.properties
groupId artifactId version
port
Consumer側
Consumer
Provider/foos /foos
{...}Got "{...}"
通常の組み込みサーバーテスト
WireMockのスタブサーバー
Consumer側
Consumer
Provider/foos /foos
{...}Got "{...}"
通常の組み込みサーバーテスト
WireMockのスタブサーバー
Consumerだけでテストできる🍺
DEMOhttps://github.com/making/microservices-accurest
CDCのメリット•クライアントが求めているリクエスト/レスポンスを知れる• Contractに違反があれば(APIの互換性が崩れたら)テストが失敗する•テストが⾃動⽣成されるためメンテナンスしやすい•新しいAPIが追加されればすぐにモックサーバーに反映できる
CDC(Accurest)のデメリット• Consumer側のテストが、 WireMock起動のため重くなりやすい→テストがちょっと億劫に•まだ開発途上で、時々⽣成されたコードが壊れている→issueをあげよう
References• Consumer Driven Contractsについて• http://martinfowler.com/articles/consumerDrivenContracts.html• http://www.slideshare.net/MarcinGrzejszczak/stick-to-the-rules-consumer-driven-contracts-201507-confitura• http://toomuchcoding.com/blog/2016/04/30/accurest-and-stub-runner-1-dot-1-0-dot-m3/
• CDC⽤ライブラリ• http://codearte.github.io/accurest/
•サンプル• https://github.com/making/microservices-accurest• https://github.com/Codearte/accurest-samples
Announcehttp://pivotal-japan.connpass.com
Pivotal Japan Technical Meetup2016/06/29(Wed) 18:30-