标签: pact

当kafka参与微服务架构时,如何实施合同测试?

我目前正在开发一个项目,我们在微服务架构中实现了kafka.您是否成功使用pact-jvm创建mS到kafka主题交互的合同测试用例?

我的实现是microservice1向REST客户端发布消息,然后REST客户端将消息发布到Kafka主题.microservice2使用GET方法从Kafka主题中检索消息.

java jvm apache-kafka microservices pact

12
推荐指数
1
解决办法
3632
查看次数

契约提供者测试的范围应该是什么?

大约半年前,我的组织开始使用Pact来创建/验证用Java编写的REST服务/微服务之间的合同.我们很难决定提供商测试的适当范围或把握应该是什么,并且会喜欢其他协议用户的经验.

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

我们将其归结为两种选择:

1.第一个选项是提供者测试应该是严格的合同测试,并且只运用提供者服务的REST资源类,模拟/删除从那里使用的服务类/协调器等.此合同测试将通过组件测试进行扩充,该组件测试将测试由提供程序测试存根/模拟的部件.

2.第二个选项是使用提供程序测试作为组件测试,该测试将为每个请求执行整个服务组件.只有对其他组件的传递外部调用才会被模拟/存根.

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

选项1的专业版:

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

选项2的专业版:

  • 测试正在运行更多的"真实"代码=>由于糟糕的模拟/存根而导致测试错误的风险降低.

我真的很想知道您的提供商测试通常在这方面的看法.有最好的做法吗?

澄清"组件"的含义:组件是微服务或更大服务应用程序中的模块.我们采用了来自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();
    }
Run Code Online (Sandbox Code Playgroud)

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

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

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

我们创建了一个"测试框架",可以自动模拟任何未在spring上下文中显式声明的Autowired依赖项,因此stubing/mocking对我们来说是一个轻量级的过程.这是运行CustomerResource并启动存根的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 …
Run Code Online (Sandbox Code Playgroud)

java testing unit-testing pact pact-java

9
推荐指数
1
解决办法
1510
查看次数

在 NestJS 应用程序中注入 Mock 以进行合同测试

问题

我正在寻找一种使用模拟提供程序启动 NestJS 应用程序的方法。这对于提供者合同测试是必要的,因为需要单独启动服务。使用 Pact 库,测试提供者假定提供者服务已经在运行。它需要能够针对实际服务器发出 HTTP 请求(如有必要,可以模拟一些依赖项)。契约JS

目前的研究

我查看了 NestJS 的文档,我能找到的最接近的解决方案粘贴在下面。据我所知,这个解决方案告诉模块CatsServicecatsService. 这理论上适用于提供者合同测试目的,但我认为这不允许启动整个应用程序,只是一个模块。文档中没有提到能够使用测试模块在特定端口上启动应用程序。我试图调用app.listen返回的应用程序对象,但它未能命中调用后立即放置的断点。

import * as request from "supertest";
import { Test } from "@nestjs/testing";
import { CatsModule } from "../../src/cats/cats.module";
import { CatsService } from "../../src/cats/cats.service";
import { INestApplication } from "@nestjs/common";

describe("Cats", () => {
  let app: INestApplication;
  let catsService = { findAll: () => ["test"] };

  beforeAll(async () => {
    const module = await Test.createTestingModule({
      imports: [CatsModule]
    })
      .overrideProvider(CatsService)
      .useValue(catsService) …
Run Code Online (Sandbox Code Playgroud)

javascript node.js typescript pact nestjs

7
推荐指数
1
解决办法
4818
查看次数

如果所有消费者都以相同的方式使用相同的 API,为什么我们应该为每个消费者拥有 1 个 Pact 文件?

我正在尝试在我们公司引入 Pact 框架,提出的问题之一如下:

场景:这个 xyz API 被 40 个消费者调用,每个消费者当前都需要相同的功能。那么为什么我们应该维护 40 个 Pact 文件而不是只维护一个文件呢?

考虑到契约文件的维护,是否有比为每个消费者拥有一个契约文件更好的方法?

java api pact

5
推荐指数
1
解决办法
691
查看次数

Pact JVM Java 不清楚新手/初学者/教程项目?

是否有一个小而简洁的 jvm 消费者 Java(消费者或提供者)junit 项目可供某人共享,最好是在一个自包含的 zip 文件中,其中包含除 jar 导入之外的所有文件?

当我按照此处的步骤进行操作时: https: //github.com/DiUS/pact-jvm/tree/master/pact-jvm-consumer-junit和“使用基本 ConsumerPactTest”时,我遇到了各种错误,我已经尝试过来一一解决。

然而我相信一定存在一个更简单的“Hello world”类型的示例来描述这个框架。

我之前已经设置过其他微服务模拟框架,但是 Pact 在设置它时显示了太多错误,所以我认为一定是误解了它应该如何以最简单的形式进行设置。

我在上述示例中遇到的最后一个问题是这些导入,我发现没有 jar 文件: import au.com.dius.pact.consumer.exampleclients.ConsumerClient; import au.com.dius.pact.consumer.ConsumerPactTest; import au.com.dius.pact.model.PactFragment;

因此,例如 @Pact 关键字无法解析等。

提前致谢!


更新 - 在创建契约定义时(使用 ./gradlew test ),是否可以不使用契约提供者模拟服务器代码,而是使用“真正的”api 提供者?

例如,在 1) 的示例中,是否可以使用“真实”api 提供者响应来更新(例如使用邮递员中记录的响应)消费者的 @Pact 部分,而不需要在spring boot localhost 模拟服务器?

1)http://the-creative-tester.github.io/Java-Consumer-Driven-Contract-Testing/

感谢您的任何答复!

java junit jvm consumer pact

5
推荐指数
1
解决办法
4610
查看次数

PACT .NET 消费者测试:灵活长度数组

我正在使用 pactNet 来测试一个 API,它应该返回一个灵活长度的数组。

如果我调用“myApi/items/”,它应该返回一个消费者不知道确切尺寸的项目列表。所以答案应该是这样的:

    [
        {
            "id": "1",
            "description": "foo"
        },
        {
            "id": "2",
            "description": "foo2"
        },
        {
            "id": "3",
            "description": "foo3"
        }
    ]
Run Code Online (Sandbox Code Playgroud)

或这个:

    [
        {
            "id": "4",
            "description": "foo4"
        },
        {
            "id": "2",
            "description": "foo2"
        }
    ]
Run Code Online (Sandbox Code Playgroud)

如何为此交互创建合同?

文档是在Ruby中的例子,但是我无法找到C#中的等价物。

我正在使用 pactNet 2.1.1 版。

编辑:这是一个示例,它应该是什么样子。我想知道的是如何声明主体应该包含一个长度灵活的项目数组。

[Test]
    public void GetAllItems()
    {
        //Arrange
        _mockProviderService
            .Given("There are items")
            .UponReceiving("A GET request to retrieve the items")
            .With(new ProviderServiceRequest
            {
                Method = HttpVerb.Get,
                Path = "/items/",
                Headers = new Dictionary<string, object> …
Run Code Online (Sandbox Code Playgroud)

c# contract consumer pact pact-net

5
推荐指数
1
解决办法
1319
查看次数

为什么要在 @PactVerification 中断言?

我不明白断言在@PactVerification. 对我来说,这更像是一种复杂的说法1 == 1。例如:

import static org.assertj.core.api.Assertions.assertThat;
public class PactConsumerDrivenContractUnitTest {
    @Rule
    public PactProviderRuleMk2 mockProvider
      = new PactProviderRuleMk2("test_provider", "localhost", 8080, this);
    @Pact(consumer = "test_consumer")
    public RequestResponsePact createPact(PactDslWithProvider builder) {            
        return builder
          .given("test GET ")
          .uponReceiving("GET REQUEST")
          .path("/")
          .method("GET")
          .willRespondWith()
          .body("{\"condition\": true, \"name\": \"tom\"}")
    }
    @Test
    @PactVerification()
    public void givenGet_whenSendRequest_shouldReturn200WithProperHeaderAndBody() {
        //when
        ResponseEntity<String> response
          = new RestTemplate().getForEntity(mockProvider.getUrl(), String.class);
        //then
        assertThat(response.getBody()).contains("condition", "true", "name", "tom");        
    }
}
Run Code Online (Sandbox Code Playgroud)

所以首先在“createPact”中我们声明

body("{\"condition\": true, \"name\": \"tom\"}")
Run Code Online (Sandbox Code Playgroud)

然后在givenGet_whenSendRequest_shouldReturn200WithProperHeaderAndBody注释中@PactVerification我们这样做

assertThat(response.getBody()).contains("condition", "true", …
Run Code Online (Sandbox Code Playgroud)

pact pact-jvm

5
推荐指数
1
解决办法
1688
查看次数

PACT与Spring Cloud合约测试

我试图了解PACT和Spring Cloud Contract之间更好的工具,以实施消费者驱动程序合同测试。我没有找到任何明显的例子来寻找利弊。

我想实现CDCT,并且在我的项目中不使用Spring。根据我的理解,我认为PACT很好。

欢迎任何信息或建议。谢谢。

spring-cloud-contract pact

5
推荐指数
1
解决办法
2858
查看次数

如何为单个字符串体定义契约规范匹配规则?

我正在为上传文件的放置请求设置测试。我的pact文件中的请求正文包含一个字符串,其中包含一个mime边界,该边界在每次测试运行时都会改变。我正在尝试为请求正文字符串定义一个正则表达式匹配规则,但是不匹配。标头content-type的相似匹配规则确实匹配。

如果主体只是一个字符串,应该如何为主体定义匹配规则?

我正在Rust中使用Pact的参考实现。契约规范版本为3。

"request": {
    "headers": {
        "Content-Length": "206",
        "Host": "127.0.0.1:1234",
        "Connection": "Close",
        "Content-Type": "multipart/form-data; boundary=\"MIME_boundary_4FBA8D0826C707B6\""
    },
    "body": "--MIME_boundary_4FBA8D0826C707B6\r\nContent-Disposition: form-data; name=\"file\"; filename=\"test_file.txt\"\r\nContent-Type: application/octet-stream\r\n\r\nContent of test file.\r\n--MIME_boundary_4FBA8D0826C707B6--\r\n",
    "matchingRules": {
        "header": {
            "$.Content-Type": {
                "matchers": [
                    {
                        "match": "regex",
                        "regex": "multipart/form-data; boundary=\"MIME_boundary_[A-Z0-9]{16}\""
                    }
                ]
            }
        },
        "body": {
            "$": {
                "matchers": [
                    {
                        "match": "regex",
                        "regex": "--MIME_boundary_[A-Z0-9]{16}\r\nContent-Disposition: form-data; name=\"file\"; filename=\"test_file.txt\"\r\nContent-Type: application/octet-stream\r\n\r\nContent of test file.\r\n--MIME_boundary_[A-Z0-9]{16}--\r\n"
                    }
                ]
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的代码是测试中使用的pact文件的一部分。测试导致BodyMismatch错误。比较预期和接收的主体表明它们的mime边界不同,因此正则表达式匹配不起作用。

pact

5
推荐指数
1
解决办法
116
查看次数

将 Pact 与生成的客户端 Api 服务结合使用

我目前正在研究 Pact,作为测试策略开发的一部分。它是一个微服务架构,并且有各种服务器到服务器的连接,我可以看到它非常有用(包括消息队列)。

然而,我无法准确理解它应该如何工作的一个地方是客户端和服务器之间的连接。在我们最常见的模式中,我们有一个 Java 微服务,充当 Typescript/Angular Web 客户端的服务器。服务器采用OpenAPI规范;具体来说,我们手动编写 OpenAPI 规范文件,然后从规范文件生成服务器和客户端代码 - 服务器代码是我们期望实现的控制器的一系列接口,客户端代码是服务和模型库客户端可以使用它向服务器发出请求。客户端上的这种模式使 HTTP 请求变得轻而易举,原因如下:

  1. 模型和控制器在规范文件中定义并在客户端和服务器之间共享,这意味着我们静态执行合约,因此我们在运行测试之前就知道合约是否被破坏
  2. 与服务器交互非常简单,因为生成的控制器服务具有易于使用的 API,可以抽象出主机名、路径等详细信息。

一方面,在此设置中使用 Pact 绝对可以带来一些好处:

  1. pact 文件可用于启动存根服务器,然后该存根服务器可用于支持组件测试。
  2. 它使我们更加倾向于消费者驱动的合同方法(这通常是好的,但前提是我们真正从中受益)。

另一方面,我也有一些担忧:

  1. 我们实际上并不需要 Pact 在测试时提供的语法强制,因为我们在编译时就有了。
  2. 遵循 Pact 文档中建立的准则进行的消费者测试本质上会涉及测试生成的服务代码,这感觉……是错误的。不需要测试生成的代码 - 它应该可以正常工作。而且由于我们的合约测试应该反映实际的客户端行为,因此这些测试之一失败的唯一场景(例如,对 API 进行重大更改)将始终与我们实现中的编译时失败同时发生,从而使测试变得不必要。
  3. 即使我们要编写所有测试,也不清楚我们将在提供商方面采取什么行动。我们可以根据 OpenAPI 定义验证该协议,但我很确定在给定我们的设置的情况下,我们不可能失败这样的验证(除非手动修改协议文件,这似乎是一个很大的禁忌)。诚然,我还没有对提供商方面进行太多调查。

坦率地说,仅第一个积极因素就足以让我承诺加入 Pact。消费者驱动的方法使得生成存根的过程变得更加有意义。话虽这么说,负面影响肯定会让我感到厌烦。感觉工作量很大,其中大部分是引入冗余验证机制,这样我们就可以获取单一利益。

我这样做是错误的吗?我是否可以对这种方法进行简单的改变,以获得相同的好处而不引入冗余?或者我只需要接受这就是方式?

编辑:所以我开始研究使用契约生成存根服务器的工具,结果发现它非常缺乏。内置的 pact 服务器存根不支持以编程方式向正在运行的服务器添加模拟,而且我发现将 pact 转换为与其他服务器存根库一起使用的大多数库都非常小,并且维护得不是特别好。这意味着我们可能必须为存根过程构建我们自己的解决方案,这使得 Pact 的吸引力更小=/

microservices openapi pact

5
推荐指数
1
解决办法
688
查看次数