gpt4 book ai didi

java - Pact 提供者测试的范围应该是什么?

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:20:21 27 4
gpt4 key购买 nike

大约半年前,我的组织开始使用 Pact 在用 Java 编写的 REST 服务/微服务之间创建/验证契约(Contract)。
我们很难决定提供者测试的适当范围或掌握应该是什么,并且希望从其他契约用户的经验中获得一些意见。

基本上讨论围绕在提供程序测试中模拟/ stub 的位置展开。在服务中,您至少必须模拟对其他服务的外部调用,但您也可以选择更接近 REST 资源类的模拟。

我们把它归结为两个选项:

1. 第一个选项是提供者测试应该是严格的契约测试,并且只执行提供者服务的 REST 资源类,模拟/ stub 从那里使用的服务类/编排器等。这个契约测试将通过组件测试来增强,这些测试将测试由提供者测试 stub /模拟的部分。

2. 第二种选择是使用提供者测试作为组件测试,为每个请求执行整个服务组件。只有对其他组件的可传递外部调用才会被模拟/ stub 。

这些是专业人士对每个选项的想法

选项 1 的专业版:

  • 测试将更容易实现并且占用空间更小
    => 更高的隔离度。
  • 无论如何,我们可能需要其他组件测试来覆盖消费者通常未涵盖的用例
    预期(错误流等)。这样我们就不会混合不同的
    各种组件测试(Pact 和其他)在一个包中,使测试套件更容易理解。

  • 选项 2 的专业版:
  • 测试正在执行更多的“真实”代码 => 测试风险更低
    由于错误的模拟/ stub 而导致的错误。

  • 我真的很想听听您的提供者测试在这方面的典型情况。有最佳实践吗?

    澄清我们所说的“组件”的含义:
    组件是更大的服务应用程序中的微服务或模块。我们从 Martin Fowlers http://martinfowler.com/articles/microservice-testing/ 中获取了“组件”的定义。 .

    提供者服务/组件通常在 Jersey 资源类中有一个 REST 端点。此端点是 Pact 提供程序测试的提供程序端点。一个例子:
    @Path("/customer")
    public class CustomerResource {

    @Autowired private CustomerOrchestrator customerOrchestrator;

    @GET
    @Path("/{customerId}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response get(@PathParam("customerId") String id) {
    CustomerId customerId = CustomerIdValidator.validate(id);
    return Response.ok(toJson(customerOrchestrator.getCustomer(customerId))).build();
    }

    在上面的示例中,@Autowired(我们使用 spring)CustomerOrchestrator 可以在运行提供程序测试时被模拟,或者您可以注入(inject)真正的“Impl”类。如果您选择注入(inject)真正的“CustomerOrchestratorImpl.class”,它将具有额外的@Autowired bean 依赖项,而这些依赖项又可能具有其他……等等。最后,依赖项将最终出现在将进行数据库调用的 DAO 对象中或一个 REST 客户端,它将对其他下游服务/组件执行 HTTP 调用。

    如果我们在上面的例子中采用我的“选项 1”解决方案,我们将模拟 CustomerResource 中的 customerOrchestrator 字段,如果我们采用“选项 2”,我们将为 CustomerResource 中的每个依赖项注入(inject) Impl 类(真正的类)依赖图并创建模拟数据库条目和模拟下游服务。

    作为旁注,我应该提到我们很少在提供者测试中实际使用真正的数据库。在我们采用“选项 2”的情况下,我们模拟了 DAO 类层而不是模拟实际的数据库数据,以减少测试中移动部件的数量。

    我们创建了一个“测试框架”,可以自动模拟任何未在 spring 上下文中明确声明的 Autowired 依赖项,因此 stub /模拟对我们来说是一个轻量级的过程。这是执行 CustomerResource 并启动 stub CustomerOrchestrator bean 的提供程序测试的摘录:
    @RunWith(PactRunner.class)
    @Provider("customer-rest-api")
    @PactCachedLoader(CustomerProviderContractTest.class)
    public class CustomerProviderContractTest {

    @ClassRule
    public static PactJerseyWebbAppDescriptorRule webAppRule = buildWebAppDescriptorRule();

    @Rule
    public PactJerseyTestRule jersyTestRule = new PactJerseyTestRule(webAppRule.appDescriptor);

    @TestTarget public final Target target = new HttpTarget(jersyTestRule.port);

    private static PactJerseyWebbAppDescriptorRule buildWebAppDescriptorRule() {
    return PactJerseyWebbAppDescriptorRule.Builder.getBuilder()
    .withContextConfigLocation("classpath:applicationContext-test.xml")
    .withRestResourceClazzes(CustomerResource.class)
    .withPackages("api.rest.customer")
    .build();
    }

    @State("that customer with id 1111111 exists")
    public void state1() throws Exception {
    CustomerOrchestrator customerOrchestratorStub = SpringApplicationContext.getBean(CustomerOrchestrator.class)
    when(customerOrchestratorStub.getCustomer(eq("1111111"))).thenReturn(createMockedCustomer("1111111));

    }
    ...

    最佳答案

    这是一个经常出现的问题,我的回答是“为每项服务做有意义的事情”。使用pact 的第一个微服务非常小而简单,最容易测试整个服务而无需任何模拟或 stub 。调用真实服务和调用验证测试之间的唯一区别是我们使用 sqlite 进行测试。当然,我们截断了对下游服务的调用。

    如果设置真实数据比 stub 更复杂,那么我会使用 stub 。 然而 !如果您打算这样做,那么您需要确保您 stub 的调用以与协议(protocol)相同的方式进行验证。使用某种共享的fixture,并确保对于您在pact provider 测试中 stub 的每个调用,您都有一个匹配的测试,以确保行为符合您的预期。这就像您将协作/契约(Contract)测试链接在一起,如下所示:
    enter image description here

    关于java - Pact 提供者测试的范围应该是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40984580/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com