当前位置: 首页 > 知识库问答 >
问题:

如何编写与spring cloud netflix和Faign的集成测试

邹京
2023-03-14

我使用Spring Cloud Netflix在微服务之间进行通信。假设我有两个服务,Foo和Bar,Foo使用Bar的一个RESTendpoint。我使用一个带有@FeignClient注释的界面:

@FeignClient
public interface BarClient {
  @RequestMapping(value = "/some/url", method = "POST")
  void bazzle(@RequestBody BazzleRequest);
}

然后我在Foo中有一个服务类something Service,它调用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!";
      }

    }
}

现在,为了确保服务之间的通信正常工作,我想构建一个测试,使用WireMock之类的东西对假Bar服务器发出真实的HTTP请求。测试应确保feign正确解码服务响应并将其报告给something Service

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服务器注入到eureka中,以便feign能够找到它并与之通信?我需要什么样的注释魔法?

共有3个答案

慎风畔
2023-03-14

过去,对微服务应用程序进行集成测试基本上有两种选择:

  1. 将服务部署到测试环境并进行端到端测试
  2. 模仿其他微服务

第一个选项的明显缺点是部署所有依赖项(其他服务、数据库等)也很麻烦。此外,它的调试速度慢且困难。

第二种选择更快,麻烦更少,但由于可能的代码更改,很容易最终得到与现实不同的存根。因此,当部署到prod时,可能会有成功的测试但失败的应用程序。

更好的解决方案是使用消费者驱动的契约验证,这样可以确保提供者服务的API符合消费者调用。为此,Spring开发者可以使用Spring云契约。对于其他环境,有一个称为PACT的框架。这两种方法也可以用于外国客户。这里有一个关于PACT的例子。

梁丘书
2023-03-14

下面是一个示例,如何使用随机端口(基于Spring-Boot github答案)进行飞度和WireMock的布线。

@RunWith(SpringRunner.class)
@SpringBootTest(properties = "google.url=http://google.com") // emulate application.properties
@ContextConfiguration(initializers = PortTest.RandomPortInitializer.class)
@EnableFeignClients(clients = PortTest.Google.class)
public class PortTest {

    @ClassRule
    public static WireMockClassRule wireMockRule = new WireMockClassRule(
        wireMockConfig().dynamicPort()
    );

    @FeignClient(name = "google", url = "${google.url}")
    public interface Google {    
        @RequestMapping(method = RequestMethod.GET, value = "/")
        String request();
    }

    @Autowired
    public Google google;

    @Test
    public void testName() throws Exception {
        stubFor(get(urlEqualTo("/"))
                .willReturn(aResponse()
                        .withStatus(HttpStatus.OK.value())
                        .withBody("Hello")));

        assertEquals("Hello", google.request());
    }


    public static class RandomPortInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
        @Override
        public void initialize(ConfigurableApplicationContext applicationContext) {

            // If the next statement is commented out, 
            // Feign will go to google.com instead of localhost
            TestPropertySourceUtils
                .addInlinedPropertiesToEnvironment(applicationContext,
                    "google.url=" + "http://localhost:" + wireMockRule.port()
            );
        }
    }
}

或者,你可以尝试使用系统。在测试的@BeforeClass方法中设置属性()。

卫沈义
2023-03-14

这是一个使用WireMock测试SpringBoot配置的示例,该示例带有Faign客户端和Hystrix回退。

如果您使用Eureka作为服务器发现,则需要通过设置属性"eureka.client.enabled=false"来禁用它。

首先,我们需要为我们的应用程序启用FIGN/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();
    }
}

请注意,我们正在为外部客户端指定一个回退类。每次外部客户端调用失败时(例如连接超时),都会调用回退类。

为了让测试正常工作,我们需要配置Ribbon loadbalancer(在发送http请求时将由外部客户端在内部使用):

@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()));
        }
    }
}

Ribbon服务器列表需要与WireMock配置的url(主机和端口)匹配。

 类似资料:
  • 本文向大家介绍怎么编写一个集成测试?相关面试题,主要包含被问及怎么编写一个集成测试?时的应答技巧和注意事项,需要的朋友参考一下 当我们使用 Spring 应用去跑一个集成测试时,我们需要一个 ApplicationContext。 为了使我们开发更简单,SpringBoot 为测试提供一个注解 – @SpringBootTest。这个注释由其 classes 属性指示的配置类创建一个 Applic

  • 然后,test class如下所示(为了简单起见,只显示了2个测试): 最后,这里是存储库实现(CRUD)的示例: 如果我单独运行这些测试,每个测试都没有问题地通过。但是,如果我从运行所有测试,那么我就会遇到随机问题,因为数据库事务没有回滚,而是在测试之间保存和共享数据。 共享固定装置更新: 不幸的是,在批量运行我的代码测试时,结果是相同的(我保存的数据在每次测试后都会递增,而不是丢弃) 我尝试的

  • 问题内容: 假设我有一个简单的应用程序,可以从stdin读取行并将其回显到stdout。例如: 我想编写一个测试案例,该案例写入stdin,然后将输出与输入进行比较。例如: 跑步给我以下内容: 我显然在这里做错了什么。我应该如何测试这种类型的代码? 问题答案: 这是一个写入stdin并从stdout读取的示例。请注意,它不起作用,因为输出首先包含“>”。不过,您可以对其进行修改以适合您的需求。

  • 当我运行命令gradle war integrationTest时,集成测试失败,因为它在服务项目中找不到上下文侦听器。错误消息的片段如下: 对此我们非常感谢您的帮助。提前致谢

  • 我刚来锡库利。我想在我的python(2.7版)单元测试(实际上是selenium webdriver测试)中添加sikuli特性(能够检查网页上是否显示了特定的图像)。有什么建议怎么做吗?我尝试安装,但出现错误(因为它可能需要Cython)。

  • 请指导我完成设置TeamCity的步骤,以便它可以运行我的TestNG测试。 我的目标是:每当我在TeamCity上运行新构建时,它都会自动触发新构建上的testNG套件。 我正在使用以下工具: IDE:Eclipse 自动化工具:Selenium Webdriver 语言:Java 测试运行程序框架:TestNG 任何对链接或网站的引用都会非常有帮助。