マイクロサービス間の通信には Spring-Cloud-Netflix を使用します。Foo と Bar という 2 つのサービスがあり、Foo が Bar の REST エンドポイントの 1 つを使用するとします。次のように注釈が付けられたインターフェースを使用します@FeignClient
。
@FeignClient
public interface BarClient {
@RequestMapping(value = "/some/url", method = "POST")
void bazzle(@RequestBody BazzleRequest);
}
SomeService
次に、を呼び出す Foo のサービス クラスを作成しますBarClient
。
@Component
public class SomeService {
@Autowired
BarClient barClient;
public String doSomething() {
try {
barClient.bazzle(new BazzleRequest(...));
return "so bazzle my eyes dazzle";
} catch(FeignException e) {
return "Not bazzle today!";
}
}
}
さて、サービス間の通信が機能することを確認するために、実際のHTTPリクエストを発行するテストを構築したいと思います。偽物Bar サーバー、 を使用しますWireMock
。テストでは、 feign がサービス応答を正しくデコードし、 に報告することを確認する必要がありますSomeService
。
public class SomeServiceIntegrationTest {
@Autowired SomeService someService;
@Test
public void shouldSucceed() {
stubFor(get(urlEqualTo("/some/url"))
.willReturn(aResponse()
.withStatus(204);
String result = someService.doSomething();
assertThat(result, is("so bazzle my eyes dazzle"));
}
@Test
public void shouldFail() {
stubFor(get(urlEqualTo("/some/url"))
.willReturn(aResponse()
.withStatus(404);
String result = someService.doSomething();
assertThat(result, is("Not bazzle today!"));
}
}
WireMock
Feign がサーバーを見つけて通信できるように、このようなサーバーを Eureka に正常に挿入するにはどうすればよいでしょうか?
ベストアンサー1
以下は、WireMock を使用して、Feign クライアントと Hystrix フォールバックを備えた SpringBoot 構成をテストする例です。
Eureka をサーバー検出として使用している場合は、プロパティを設定して無効にする必要があります"eureka.client.enabled=false"
。
まず、アプリケーションで Feign/Hystrix 構成を有効にする必要があります。
@SpringBootApplication
@EnableFeignClients
@EnableCircuitBreaker
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@FeignClient(
name = "bookstore-server",
fallback = BookClientFallback.class,
qualifier = "bookClient"
)
public interface BookClient {
@RequestMapping(method = RequestMethod.GET, path = "/book/{id}")
Book findById(@PathVariable("id") String id);
}
@Component
public class BookClientFallback implements BookClient {
@Override
public Book findById(String id) {
return Book.builder().id("fallback-id").title("default").isbn("default").build();
}
}
Feign クライアントのフォールバック クラスを指定していることに注意してください。フォールバック クラスは、Feign クライアントの呼び出しが失敗するたびに呼び出されます (例: 接続タイムアウト)。
テストを機能させるには、Ribbon ロードバランサー (http リクエストを送信するときに Feign クライアントによって内部的に使用される) を構成する必要があります。
@RunWith(SpringRunner.class)
@SpringBootTest(properties = {
"feign.hystrix.enabled=true"
})
@ContextConfiguration(classes = {BookClientTest.LocalRibbonClientConfiguration.class})
public class BookClientTest {
@Autowired
public BookClient bookClient;
@ClassRule
public static WireMockClassRule wiremock = new WireMockClassRule(
wireMockConfig().dynamicPort()));
@Before
public void setup() throws IOException {
stubFor(get(urlEqualTo("/book/12345"))
.willReturn(aResponse()
.withStatus(HttpStatus.OK.value())
.withHeader("Content-Type", MediaType.APPLICATION_JSON)
.withBody(StreamUtils.copyToString(getClass().getClassLoader().getResourceAsStream("fixtures/book.json"), Charset.defaultCharset()))));
}
@Test
public void testFindById() {
Book result = bookClient.findById("12345");
assertNotNull("should not be null", result);
assertThat(result.getId(), is("12345"));
}
@Test
public void testFindByIdFallback() {
stubFor(get(urlEqualTo("/book/12345"))
.willReturn(aResponse().withFixedDelay(60000)));
Book result = bookClient.findById("12345");
assertNotNull("should not be null", result);
assertThat(result.getId(), is("fallback-id"));
}
@TestConfiguration
public static class LocalRibbonClientConfiguration {
@Bean
public ServerList<Server> ribbonServerList() {
return new StaticServerList<>(new Server("localhost", wiremock.port()));
}
}
}
リボン サーバー リストは、WireMock 構成の URL (ホストとポート) と一致する必要があります。