”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 消费者驱动的合同测试指南

消费者驱动的合同测试指南

发布于2024-10-31
浏览:961

A Guide to Consumer-Driven Contract Testing
在现代微服务架构中,应用程序严重依赖服务间通信(通常通过 API)。确保这些 API 在开发期间和更改后继续按预期工作至关重要。实现这一目标的一种有效方法是通过消费者驱动的契约测试(CDCT)。 CDCT 是一种确保服务(生产者)遵守使用其 API 的服务(消费者)设定的期望的方法。

在本指南中,我们将探讨 CDCT 是什么、它是如何工作的、它在确保可靠的微服务交互方面的重要性,以及如何使用 Pact 等工具来实现它。

什么是消费者驱动的契约测试?
消费者驱动的合同测试是一种测试策略,可确保分布式架构中的服务之间的通信遵守商定的合同。它与传统的 API 测试不同,它关注消费者的需求,而不仅仅是确保 API 本身正常运行。 API 消费者和提供者之间的契约是由消费者的期望定义的,并且该契约根据提供者的实现进行验证。

关键术语:
• 消费者:使用API​​ 的服务。
• Provider(生产者):提供API的服务。
• 合同:消费者和提供商之间的正式协议,指定预期的 API 行为。

它是如何工作的?

  1. 消费者定义合约: 消费者定义其对提供商 API 应如何表现的期望(例如,其期望的端点、数据格式和响应状态代码)。
  2. 合同是共享的: 消费者与提供商共享此合同。该合同作为提供商必须满足的规范。
  3. 提供商验证合同: 提供商根据消费者的合同进行自我测试,确保其满足消费者的期望。
  4. 持续反馈循环: 提供商 API 的任何重大更改都将被尽早发现,因为提供商必须根据所有消费者的合约进行验证。这创建了一个安全网,以确保提供商的变化不会对消费者产生负面影响。

消费者驱动的合约测试的重要性
在分布式架构中,尤其是微服务,管理服务之间的依赖关系变得更加复杂。 CDCT 通过多种方式帮助减轻这种复杂性:

1.防止生产中的损坏
由于消费者定义了他们的需求,因此供应商 API 的更改如果不满足消费者的期望,就会在开发流程的早期被捕获。这降低了由于不兼容的更改而破坏生产系统的风险。

2.解耦开发
消费者驱动的契约测试允许消费者和提供商独立开发。当团队或服务单独发展时,这尤其有用。合约充当接口,确保集成按预期工作,无需在每个开发周期进行完整的集成测试。

3.更快的开发周期
通过 CDCT,消费者和提供商都可以并行开发和测试,从而加快开发速度。即使在消费者完全实现其功能之前,提供商也可以针对消费者的合约进行测试。

4。及早发现合同违规行为
在开发过程的早期检测到违反合同的提供商变更,使开发人员能够在问题变得严重之前解决问题。

如何实施消费者驱动的合约测试
有多种工具可用于实施 CDCT,其中 Pact 是最流行的工具之一。 Pact 允许消费者定义他们的合同并允许提供商验证它们。

以下是使用 Pact 实施 CDCT 的分步指南:
第 1 步: 定义消费者期望
首先,在消费者服务中,定义契约。这通常包括以下内容:
• 消费者将调用的端点。
• 请求方法(GET、POST、PUT 等)。
• 预期的请求正文或参数。
• 预期的响应正文和状态代码。
以下是在 JavaScript 中使用 Pact 在消费者测试中定义合约的示例:

const { Pact } = require('@pact-foundation/pact');
const path = require('path');

const provider = new Pact({
    consumer: 'UserService',
    provider: 'UserAPI',
    port: 1234,
    log: path.resolve(process.cwd(), 'logs', 'pact.log'),
    dir: path.resolve(process.cwd(), 'pacts'),
});

describe('Pact Consumer Test', () => {
    beforeAll(() => provider.setup());

    afterAll(() => provider.finalize());

    it('should receive user details from the API', async () => {
        // Define the expected interaction
        await provider.addInteraction({
            state: 'user exists',
            uponReceiving: 'a request for user details',
            withRequest: {
                method: 'GET',
                path: '/users/1',
                headers: {
                    Accept: 'application/json',
                },
            },
            willRespondWith: {
                status: 200,
                headers: {
                    'Content-Type': 'application/json',
                },
                body: {
                    id: 1,
                    name: 'John Doe',
                },
            },
        });

        // Make the actual request and test
        const response = await getUserDetails(1);
        expect(response).toEqual({ id: 1, name: 'John Doe' });
    });
});

在此示例中,消费者 (UserService) 希望提供者 (UserAPI) 在向 /users/1 发出 GET 请求时返回用户详细信息。

第2步:发布合约
一旦消费者测试通过,Pact 就会生成一个可以与提供者共享的合约文件(Pact 文件)。该合约可以存储在 Pact Broker 或版本控制系统中,以便提供商可以使用它进行验证。

第 3 步:提供商验证合同
提供商检索合同并验证其是否符合消费者的期望。这是通过在提供商端运行 Pact 测试来完成的。下面是用 Java 验证 Pact 合约的示例:

public class ProviderTest {

    @Test
    public void testProviderAgainstPact() {
        PactVerificationResult result = new PactVerifier()
            .verifyProvider("UserAPI", "pacts/UserService-UserAPI.json");

        assertThat(result, instanceOf(PactVerificationResult.Ok.class));
    }
}

提供商运行此测试以确保其遵守消费者指定的合同。

第四步:持续集成
一旦 CDCT 集成到您的 CI/CD 管道中,每次合同更改时,提供商都可以自动验证合同。这确保 API 更改不会打破消费者的期望,为两个团队提供安全网。

CDCT 最佳实践

  1. 小型、集中的合同: 确保您的合同规模较小,并且仅关注消费者的需求。这可以防止合同中不必要的复杂性并简化验证。
  2. 合同版本控制: 始终对合同进行版本控制。这允许提供商处理同一合同的多个版本,帮助您支持处于不同开发阶段的不同消费者。
  3. 独立部署: 确保 CDCT 是 CI/CD 管道的一部分。对消费者或提供商的任何更改都应触发合同测试,以避免破坏生产环境。
  4. 使用 Pact Broker: Pact Broker 是一个中央存储库,用于存储您的合同并允许消费者和提供商检索它们。它还提供了一个用于可视化合约版本和依赖项的 UI。

何时使用消费者驱动的契约测试
CDCT 在以下情况下特别有用:
• 您拥有具有多个交互服务的微服务或分布式架构。
• 从事不同服务的团队需要独立开发,无需频繁的集成测试。
• API 合同可能会经常更改,您希望避免打破消费者的期望。
• 您需要快速反馈循环来在开发过程的早期检测合同违规行为。

结论
消费者驱动的契约测试提供了一种可靠的方法来确保分布式系统中的服务有效通信而不破坏更改。通过关注消费者的期望并根据这些期望验证提供商,CDCT 帮助团队独立开发,同时确保稳定性。无论您是构建微服务、基于 API 的应用程序还是分布式系统,将 CDCT 纳入您的测试策略都将提高服务的可靠性和可扩展性。

版本声明 本文转载于:https://dev.to/keploy/a-guide-to-consumer-driven-contract-testing-2dho?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 如何在GO编译器中自定义编译优化?
    如何在GO编译器中自定义编译优化?
    在GO编译器中自定义编译优化 GO中的默认编译过程遵循特定的优化策略。 However, users may need to adjust these optimizations for specific requirements.Optimization Control in Go Compi...
    编程 发布于2025-07-14
  • 对象拟合:IE和Edge中的封面失败,如何修复?
    对象拟合:IE和Edge中的封面失败,如何修复?
    To resolve this issue, we employ a clever CSS solution that solves the problem:position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%)...
    编程 发布于2025-07-14
  • 如何使用node-mysql在单个查询中执行多个SQL语句?
    如何使用node-mysql在单个查询中执行多个SQL语句?
    Multi-Statement Query Support in Node-MySQLIn Node.js, the question arises when executing multiple SQL statements in a single query using the node-mys...
    编程 发布于2025-07-14
  • 反射动态实现Go接口用于RPC方法探索
    反射动态实现Go接口用于RPC方法探索
    在GO 使用反射来实现定义RPC式方法的界面。例如,考虑一个接口,例如:键入myService接口{ 登录(用户名,密码字符串)(sessionId int,错误错误) helloworld(sessionid int)(hi String,错误错误) } 替代方案而不是依靠反射...
    编程 发布于2025-07-14
  • 人脸检测失败原因及解决方案:Error -215
    人脸检测失败原因及解决方案:Error -215
    错误处理:解决“ error:((-215)!empty()in Function Multultiscale中的“ openCV 要解决此问题,必须确保提供给HAAR CASCADE XML文件的路径有效。在提供的代码片段中,级联分类器装有硬编码路径,这可能对您的系统不准确。相反,OPENCV提...
    编程 发布于2025-07-14
  • Java中假唤醒真的会发生吗?
    Java中假唤醒真的会发生吗?
    在Java中的浪费唤醒:真实性或神话?在Java同步中伪装唤醒的概念已经是讨论的主题。尽管存在这种行为的潜力,但问题仍然存在:它们实际上是在实践中发生的吗? Linux的唤醒机制根据Wikipedia关于伪造唤醒的文章,linux实现了pthread_cond_wait()功能的Linux实现,利用...
    编程 发布于2025-07-14
  • Python环境变量的访问与管理方法
    Python环境变量的访问与管理方法
    Accessing Environment Variables in PythonTo access environment variables in Python, utilize the os.environ object, which represents a mapping of envir...
    编程 发布于2025-07-14
  • 如何将PANDAS DataFrame列转换为DateTime格式并按日期过滤?
    如何将PANDAS DataFrame列转换为DateTime格式并按日期过滤?
    Transform Pandas DataFrame Column to DateTime FormatScenario:Data within a Pandas DataFrame often exists in various formats, including strings.使用时间数据时...
    编程 发布于2025-07-14
  • Python元类工作原理及类创建与定制
    Python元类工作原理及类创建与定制
    python中的metaclasses是什么? Metaclasses负责在Python中创建类对象。就像类创建实例一样,元类也创建类。他们提供了对类创建过程的控制层,允许自定义类行为和属性。在Python中理解类作为对象的概念,类是描述用于创建新实例或对象的蓝图的对象。这意味着类本身是使用类关...
    编程 发布于2025-07-14
  • 如何使用PHP从XML文件中有效地检索属性值?
    如何使用PHP从XML文件中有效地检索属性值?
    从php PHP陷入困境。使用simplexmlelement :: attributes()函数提供了简单的解决方案。此函数可访问对XML元素作为关联数组的属性: - > attributes()为$ attributeName => $ attributeValue){ echo ...
    编程 发布于2025-07-14
  • 如何处理PHP文件系统功能中的UTF-8文件名?
    如何处理PHP文件系统功能中的UTF-8文件名?
    在PHP的Filesystem functions中处理UTF-8 FileNames 在使用PHP的MKDIR函数中含有UTF-8字符的文件很多flusf-8字符时,您可能会在Windows Explorer中遇到comploreer grounder grounder grounder gro...
    编程 发布于2025-07-14
  • C++成员函数指针正确传递方法
    C++成员函数指针正确传递方法
    如何将成员函数置于c [&& && && && && && && && && && &&&&&&&&&&&&&&&&&&&&&&&华仪的函数时,在接受成员函数指针的函数时,要在函数上既要提供指针又可以提供指针和指针到函数的函数。需要具有一定签名的功能指针。要通过成员函数,您需要同时提供对象指针(此...
    编程 发布于2025-07-14
  • 编译器报错“usr/bin/ld: cannot find -l”解决方法
    编译器报错“usr/bin/ld: cannot find -l”解决方法
    错误:“ usr/bin/ld:找不到-l “ 此错误表明链接器在链接您的可执行文件时无法找到指定的库。为了解决此问题,我们将深入研究如何指定库路径并将链接引导到正确位置的详细信息。添加库搜索路径的一个可能的原因是,此错误是您的makefile中缺少库搜索路径。要解决它,您可以在链接器命令中添加...
    编程 发布于2025-07-14
  • 如何检查对象是否具有Python中的特定属性?
    如何检查对象是否具有Python中的特定属性?
    方法来确定对象属性存在寻求一种方法来验证对象中特定属性的存在。考虑以下示例,其中尝试访问不确定属性会引起错误: >>> a = someClass() >>> A.property Trackback(最近的最新电话): 文件“ ”,第1行, attributeError:SomeClass实...
    编程 发布于2025-07-14
  • C++20 Consteval函数中模板参数能否依赖于函数参数?
    C++20 Consteval函数中模板参数能否依赖于函数参数?
    [ consteval函数和模板参数依赖于函数参数在C 17中,模板参数不能依赖一个函数参数,因为编译器仍然需要对非contexexpr futcoriations contim at contexpr function进行评估。 compile time。 C 20引入恒定函数,必须在编译时进行...
    编程 发布于2025-07-14

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3