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

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

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

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]删除
最新教程 更多>
  • 为什么Microsoft Visual C ++无法正确实现两台模板的实例?
    为什么Microsoft Visual C ++无法正确实现两台模板的实例?
    The Mystery of "Broken" Two-Phase Template Instantiation in Microsoft Visual C Problem Statement:Users commonly express concerns that Micro...
    编程 发布于2025-03-12
  • UTF-8 vs. Latin-1:字符编码大揭秘!
    UTF-8 vs. Latin-1:字符编码大揭秘!
    [utf-8和latin1 在他们的应用中,出现了一个基本问题:什么辨别特征区分了这两个编码?超出其字符表现能力,UTF-8具有额外的几个优势。从历史上看,MySQL对UTF-8的支持仅限于每个字符的三个字节,这阻碍了基本多语言平面(BMP)之外的字符的表示。但是,随着MySQL 5.5的出现,...
    编程 发布于2025-03-12
  • 大批
    大批
    [2 数组是对象,因此它们在JS中也具有方法。 切片(开始):在新数组中提取部分数组,而无需突变原始数组。 令ARR = ['a','b','c','d','e']; // USECASE:提取直到索引作...
    编程 发布于2025-03-12
  • 如何在Java字符串中有效替换多个子字符串?
    如何在Java字符串中有效替换多个子字符串?
    在java 中有效地替换多个substring,需要在需要替换一个字符串中的多个substring的情况下,很容易求助于重复应用字符串的刺激力量。 However, this can be inefficient for large strings or when working with nu...
    编程 发布于2025-03-12
  • Part SQL注入系列:高级SQL注入技巧详解
    Part SQL注入系列:高级SQL注入技巧详解
    [2 Waymap pentesting工具:单击此处 trixsec github:单击此处 trixsec电报:单击此处 高级SQL注入利用 - 第7部分:尖端技术和预防 欢迎参与我们SQL注入系列的第7部分!该分期付款将攻击者采用的高级SQL注入技术 1。高...
    编程 发布于2025-03-12
  • 为什么PYTZ最初显示出意外的时区偏移?
    为什么PYTZ最初显示出意外的时区偏移?
    与pytz 最初从pytz获得特定的偏移。例如,亚洲/hong_kong最初显示一个七个小时37分钟的偏移: 差异源利用本地化将时区分配给日期,使用了适当的时区名称和偏移量。但是,直接使用DateTime构造器分配时区不允许进行正确的调整。 example pytz.timezone(...
    编程 发布于2025-03-12
  • 如何修复\“常规错误:2006 MySQL Server在插入数据时已经消失\”?
    如何修复\“常规错误:2006 MySQL Server在插入数据时已经消失\”?
    How to Resolve "General error: 2006 MySQL server has gone away" While Inserting RecordsIntroduction:Inserting data into a MySQL database can...
    编程 发布于2025-03-12
  • 我们如何保护有关恶意内容的文件上传?
    我们如何保护有关恶意内容的文件上传?
    对文件上载上传到服务器的安全性问题可以引入重大的安全风险,因为用户可能会提供潜在的恶意内容。了解这些威胁并实施有效的缓解策略对于维持应用程序的安全性至关重要。用户可以将文件名操作以绕过安全措施。避免将其用于关键目的或使用其原始名称保存文件。用户提供的MIME类型可能不可靠。使用服务器端检查确定实际...
    编程 发布于2025-03-12
  • 如何使用JavaScript中的正则表达式从字符串中删除线路断裂?
    如何使用JavaScript中的正则表达式从字符串中删除线路断裂?
    在此代码方案中删除从字符串在JavaScript中解决此问题,根据操作系统的编码,对线断裂的识别不同。 Windows使用“ \ r \ n”序列,Linux采用“ \ n”,Apple系统使用“ \ r。” 来满足各种线路断裂的变化,可以使用以下正则表达式: [&& && &&&&&&&&&&&...
    编程 发布于2025-03-12
  • 为什么使用Firefox后退按钮时JavaScript执行停止?
    为什么使用Firefox后退按钮时JavaScript执行停止?
    导航历史记录问题:JavaScript使用Firefox Back Back 此行为是由浏览器缓存JavaScript资源引起的。要解决此问题并确保在后续页面访问中执行脚本,Firefox用户应设置一个空功能。 警报'); }; alert('inline Alert')...
    编程 发布于2025-03-12
  • 如何使用PHP将斑点(图像)正确插入MySQL?
    如何使用PHP将斑点(图像)正确插入MySQL?
    essue VALUES('$this->image_id','file_get_contents($tmp_image)')";This code builds a string in PHP, but the function call ...
    编程 发布于2025-03-12
  • 我可以将加密从McRypt迁移到OpenSSL,并使用OpenSSL迁移MCRYPT加密数据?
    我可以将加密从McRypt迁移到OpenSSL,并使用OpenSSL迁移MCRYPT加密数据?
    将我的加密库从mcrypt升级到openssl 问题:是否可以将我的加密库从McRypt升级到OpenSSL?如果是这样,如何?答案:是的,可以将您的Encryption库从McRypt升级到OpenSSL。可以使用openssl。附加说明: [openssl_decrypt()函数要求iv参...
    编程 发布于2025-03-12
  • 在Java中使用for-to-loop和迭代器进行收集遍历之间是否存在性能差异?
    在Java中使用for-to-loop和迭代器进行收集遍历之间是否存在性能差异?
    For Each Loop vs. Iterator: Efficiency in Collection TraversalIntroductionWhen traversing a collection in Java, the choice arises between using a for-...
    编程 发布于2025-03-12
  • 如何检查对象是否具有Python中的特定属性?
    如何检查对象是否具有Python中的特定属性?
    方法来确定对象属性存在寻求一种方法来验证对象中特定属性的存在。考虑以下示例,其中尝试访问不确定属性会引起错误: >>> a = someClass() >>> A.property Trackback(最近的最新电话): 文件“ ”,第1行, AttributeError: SomeClass...
    编程 发布于2025-03-12
  • Java HashSet/LinkedHashSet随机元素获取方法详解
    Java HashSet/LinkedHashSet随机元素获取方法详解
    在编程中找到一个随机元素,在编程中找到一个随机元素,从集合(例如集合)中选择一个随机元素很有用。 Java提供了多种类型的集合,包括障碍物和链接HASHSET。本文将探讨如何从这些特定集合实现的过程中选择一个随机元素。的java的hashset和linkedhashset a HashSet代表...
    编程 发布于2025-03-12

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

Copyright© 2022 湘ICP备2022001581号-3