使用 Stub Runner Boot 應用
Spring Cloud Contract Stub Runner Boot 是一個 Spring Boot 應用,它暴露 REST 端點來觸發訊息標籤並訪問 WireMock 伺服器。
Stub Runner Boot 安全
Stub Runner Boot 應用設計上是不安全的 - 保護它需要為所有 Stub 新增安全性,即使它們實際上不需要。因為這是一個測試工具 - 伺服器**不打算**用於生產環境。
預期**只有受信任的客戶端**才能訪問 Stub Runner Boot 伺服器。您不應該在不受信任的位置將此應用作為 Fat Jar 或 Docker 映象 執行。 |
Stub Runner 伺服器
要使用 Stub Runner 伺服器,請新增以下依賴
compile "org.springframework.cloud:spring-cloud-starter-stub-runner"
然後用 @EnableStubRunnerServer
註解一個類,構建一個 fat jar,它就可以工作了。
有關屬性,請參閱Stub Runner Spring 部分。
Stub Runner Server Fat Jar
您可以從 Maven 下載獨立的 JAR(例如,版本 2.0.1.RELEASE),方法是執行以下命令
$ wget -O stub-runner.jar 'https://search.maven.org/remotecontent?filepath=org/springframework/cloud/spring-cloud-contract-stub-runner-boot/2.0.1.RELEASE/spring-cloud-contract-stub-runner-boot-2.0.1.RELEASE.jar'
$ java -jar stub-runner.jar --stubrunner.ids=... --stubrunner.repositoryRoot=...
Spring Cloud CLI
從 Spring Cloud CLI 專案的 1.4.0.RELEASE
版本開始,您可以透過執行 spring cloud stubrunner
來啟動 Stub Runner Boot。
要傳遞配置,您可以在當前工作目錄、名為 config
的子目錄或 ~/.spring-cloud
中建立 stubrunner.yml
檔案。該檔案可以類似於以下執行本地安裝的 stub 的示例
stubrunner:
stubsMode: LOCAL
ids:
- com.example:beer-api-producer:+:9876
然後您可以從終端視窗呼叫 spring cloud stubrunner
來啟動 Stub Runner 伺服器。它在埠 8750
上可用。
端點
示例
以下示例展示了 Stub Runner Boot 的典型用法
@SpringBootTest(classes = StubRunnerBoot, properties = "spring.cloud.zookeeper.enabled=false")
@ActiveProfiles("test")
class StubRunnerBootSpec {
@Autowired
StubRunning stubRunning
@BeforeEach
void setup() {
RestAssuredMockMvc.standaloneSetup(new HttpStubsController(stubRunning),
new TriggerController(stubRunning))
}
@Test
void 'should return a list of running stub servers in "full ivy port" notation'() {
when:
String response = RestAssuredMockMvc.get('/stubs').body.asString()
then:
def root = new JsonSlurper().parseText(response)
assert root.'org.springframework.cloud.contract.verifier.stubs:bootService:0.0.1-SNAPSHOT:stubs' instanceof Integer
}
@Test
void 'should return a port on which a #stubId stub is running'() {
given:
def stubIds = ['org.springframework.cloud.contract.verifier.stubs:bootService:+:stubs',
'org.springframework.cloud.contract.verifier.stubs:bootService:0.0.1-SNAPSHOT:stubs',
'org.springframework.cloud.contract.verifier.stubs:bootService:+',
'org.springframework.cloud.contract.verifier.stubs:bootService',
'bootService']
stubIds.each {
when:
def response = RestAssuredMockMvc.get("/stubs/${it}")
then:
assert response.statusCode == 200
assert Integer.valueOf(response.body.asString()) > 0
}
}
@Test
void 'should return 404 when missing stub was called'() {
when:
def response = RestAssuredMockMvc.get("/stubs/a:b:c:d")
then:
assert response.statusCode == 404
}
@Test
void 'should return a list of messaging labels that can be triggered when version and classifier are passed'() {
when:
String response = RestAssuredMockMvc.get('/triggers').body.asString()
then:
def root = new JsonSlurper().parseText(response)
assert root.'org.springframework.cloud.contract.verifier.stubs:bootService:0.0.1-SNAPSHOT:stubs'?.containsAll(["return_book_1"])
}
@Test
void 'should trigger a messaging label'() {
given:
StubRunning stubRunning = Mockito.mock(StubRunning)
RestAssuredMockMvc.standaloneSetup(new HttpStubsController(stubRunning), new TriggerController(stubRunning))
when:
def response = RestAssuredMockMvc.post("/triggers/delete_book")
then:
response.statusCode == 200
and:
Mockito.verify(stubRunning).trigger('delete_book')
}
@Test
void 'should trigger a messaging label for a stub with #stubId ivy notation'() {
given:
StubRunning stubRunning = Mockito.mock(StubRunning)
RestAssuredMockMvc.standaloneSetup(new HttpStubsController(stubRunning), new TriggerController(stubRunning))
and:
def stubIds = ['org.springframework.cloud.contract.verifier.stubs:bootService:stubs', 'org.springframework.cloud.contract.verifier.stubs:bootService', 'bootService']
stubIds.each {
when:
def response = RestAssuredMockMvc.post("/triggers/$it/delete_book")
then:
assert response.statusCode == 200
and:
Mockito.verify(stubRunning).trigger(it, 'delete_book')
}
}
@Test
void 'should throw exception when trigger is missing'() {
when:
BDDAssertions.thenThrownBy(() -> RestAssuredMockMvc.post("/triggers/missing_label"))
.hasMessageContaining("Exception occurred while trying to return [missing_label] label.")
.hasMessageContaining("Available labels are")
.hasMessageContaining("org.springframework.cloud.contract.verifier.stubs:loanIssuance:0.0.1-SNAPSHOT:stubs=[]")
.hasMessageContaining("org.springframework.cloud.contract.verifier.stubs:bootService:0.0.1-SNAPSHOT:stubs=")
}
}
結合服務發現使用 Stub Runner Boot
使用 Stub Runner Boot 的一種方式是將其用作“冒煙測試”的 stub 源。這意味著什麼?假設您不想在測試環境中部署 50 個微服務以檢視您的應用是否正常工作。您已經在構建過程中運行了一系列測試,但您還想確保您的應用打包正常。您可以將您的應用部署到環境中,啟動它,並在其上執行少量測試以檢視其是否工作。我們可以將這些測試稱為“冒煙測試”,因為它們的目的只是檢查少數測試場景。
這種方法的問題在於,如果您使用微服務,您很可能也使用服務發現工具。Stub Runner Boot 讓您可以透過啟動所需的 stub 並將其註冊到服務發現工具中來解決此問題。
現在假設我們想啟動此應用以便自動註冊 stub。我們可以透過使用 java -jar ${SYSTEM_PROPS} stub-runner-boot-eureka-example.jar
來執行應用,其中 ${SYSTEM_PROPS}
。
這樣,您部署的應用就可以透過服務發現向已啟動的 WireMock 伺服器傳送請求。最有可能的是,第 1 到 3 點可以在 application.yml
中預設設定,因為它們不太可能更改。這樣,無論何時啟動 Stub Runner Boot,您都可以只提供要下載的 stub 列表。