WireMockを使用してspring-cloud-netflixとFeignを統合テストする方法 質問する

WireMockを使用してspring-cloud-netflixとFeignを統合テストする方法 質問する

マイクロサービス間の通信には 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!"));
    }
}

WireMockFeign がサーバーを見つけて通信できるように、このようなサーバーを 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 (ホストとポート) と一致する必要があります。

おすすめ記事