• 使用babyapi的简单示例创建初始main.go

  • 使用 CLI 生成测试样板

  • 通过用预期的 JSON 填充占位符来实现每个测试

  • 运行测试并查看它们是否通过!

  • 由于 PUT 是幂等的,因此需要包含所有字段。为了避免这种情况,我们希望添加对使用 PATCH 请求切换 Completed 的支持。我们首先添加一个简单的测试来了解我们期望此功能的外观

  • 此测试失败,因为babyapi默认不支持PATCH。我们可以通过为 TODO 结构实现 Patch 来修复它。由于我们通过两个测试定义了我们的功能,因此我们最简单的实现不仅仅是设置 Completed = true 并且我们必须使用请求中的值

  • 现在我们可以更改 TODO 的已完成状态,但我们仍然无法使用 PATCH 来修改其他字段,如这组新测试所示

  • 更新补丁以设置剩余字段

  • 我们的测试仍然失败,因为我们总是使用请求字段更新 TODO,即使它们是空的。通过更新实现来检查空值来修复此问题

  • 新的 UpdateWithPatch 测试通过,但我们之前的测试失败。由于我们将 Completed 更改为 *bool,因此使用空值创建的 TODO 将显示为 null

  • 为 TODO 实现渲染,这样我们就可以将 nil 视为 false

  • 通过测试驱动开发来实现 PATCH 功能,从而产生了一组强大的测试和良好实现的功能。由于我们首先在测试中定义 PATCH 请求的预期输入和输出,因此很容易看到由于不检查请求中的空值而导致的问题。此外,当将 Completed 类型更改为 *bool 时,我们预先存在的测试能够防止重大更改。

    结论

    测试驱动开发是创建经过充分测试的正确代码的有效方法。通过从测试开始,我们可以确保每段代码都被设计为可测试的,而不是让测试成为事后的想法。

    如果您对采用 TDD 犹豫不决,这里有一些可以开始的想法:

    即使 TDD 不太适合您编写代码的方式,它仍然是您随身携带的强大工具。我鼓励您至少花一些时间尝试一下,看看它如何影响您的开发过程。

    ","image":"http://www.luping.net/uploads/20240730/172232678666a89f02dc4a5.jpg","datePublished":"2024-07-30T16:06:26+08:00","dateModified":"2024-07-30T16:06:26+08:00","author":{"@type":"Person","name":"luping.net","url":"https://www.luping.net/articlelist/0_1.html"}}
    ”工欲善其事,必先利其器。“—孔子《论语.录灵公》
    首页 > 编程 > Go 中的测试驱动 API 开发

    Go 中的测试驱动 API 开发

    发布于2024-07-30
    浏览:327

    Test-driven API Development in Go

    介绍

    测试驱动开发是确保代码经过良好测试和可重构的有效方法。基本思想是通过编写测试开始开发。这些测试清楚地记录了期望并为成功实施创建了标准。如果做得正确,您可以在编写任何代码之前清楚地定义函数的预期输入/输出。这有一些直接的好处:

    • 您仔细考虑与代码交互的界面并将其设计为可测试的
    • 当您开始编写代码时,您的流程不会因手动测试或单步执行执行逻辑来预测结果而中断。相反,您只需运行测试
    • 通过测试成为一个令人满意的目标。将流程分解为一系列明确且可实现的里程碑使工作变得更加愉快
    • 避免实施后的懒惰和过度自信,这可能会阻止您测试代码

    现在您已确信这些好处,您可以按照以下步骤开始测试驱动开发 (TDD):

    1. 编写或修改测试
    2. 检查测试是否失败
    3. 编写最少数量的代码以使测试通过

    这些步骤是循环执行的,因此您总是添加更多测试来挑战当前的实现。

    最后一步,指定编写最少量的代码,如果严格遵循,事情可能会变得乏味。在确定何时适合偏离该规则之前,了解该规则存在的原因非常重要。

    简单的例子

    您的任务是实现函数 Add(x, y int) int。在跳转到实现并返回 x y 之前,编写最简单的测试:1 1 == 2。那么,通过测试的最简单实现是什么?只是返回 2。现在你的测试通过了!

    此时,您意识到需要更多测试,因此您加快了步伐并添加了更多测试:

    • 1 2 == 3
    • 100 5 == 105

    现在您的测试失败了,因此您需要修复实现。这次你不能只返回 3 或返回 105,所以你需要找到一个适用于所有测试的解决方案。这导致了实现: return x y.

    虽然在这个简单的示例中这感觉过于乏味,但严格遵守此方法会导致您编写多个测试而不是仅仅信任您的实现。当然,您最初返回 x y 的想法是可行的,但重点是重新训练自己依赖测试而不是您自己对代码的理解。在现实世界中,您并不是唯一一个处理这段代码的人,并且不可避免地会忘记实现细节。这个过程迫使你编写更多的测试并思考更多的方法来打破简单的实现。

    最终,您将获得经验并学会找到适合您遇到的不同场景的平衡点。您将恢复全速实现功能,并发现错误更少并编写更多可维护的代码。

    HTTP API 的逐步 TDD

    让我们进入一个使用 TDD 实现 HTTP REST API 的更复杂的示例。本分步指南使用我的 Go 框架babyapi,但这些概念可以应用于任何地方。

    babyapi 使用泛型围绕 Go 结构创建完整的 CRUD API,从而使创建完整的 REST API 和客户端 CLI 变得非常容易。除此之外,babytest 包还提供了一些用于创建端到端 API 表测试的工具。在 API 级别使用 TDD 可以一次性全面测试新 API 或功能的 HTTP 和存储层。

    免责声明:由于babyapi 处理大部分实现并且还用于生成测试样板,因此从技术上讲我们并不是从TDD 开始。然而,我们将看到在我们的 API 中添加对 PATCH 请求的支持有多么有益。

    1. 创建一个新的Go项目

    2. 使用babyapi的简单示例创建初始main.go

    3. 使用 CLI 生成测试样板

    4. 通过用预期的 JSON 填充占位符来实现每个测试

    5. 运行测试并查看它们是否通过!

    6. 由于 PUT 是幂等的,因此需要包含所有字段。为了避免这种情况,我们希望添加对使用 PATCH 请求切换 Completed 的支持。我们首先添加一个简单的测试来了解我们期望此功能的外观

    7. 此测试失败,因为babyapi默认不支持PATCH。我们可以通过为 TODO 结构实现 Patch 来修复它。由于我们通过两个测试定义了我们的功能,因此我们最简单的实现不仅仅是设置 Completed = true 并且我们必须使用请求中的值

    8. 现在我们可以更改 TODO 的已完成状态,但我们仍然无法使用 PATCH 来修改其他字段,如这组新测试所示

    9. 更新补丁以设置剩余字段

    10. 我们的测试仍然失败,因为我们总是使用请求字段更新 TODO,即使它们是空的。通过更新实现来检查空值来修复此问题

    11. 新的 UpdateWithPatch 测试通过,但我们之前的测试失败。由于我们将 Completed 更改为 *bool,因此使用空值创建的 TODO 将显示为 null

    12. 为 TODO 实现渲染,这样我们就可以将 nil 视为 false

    通过测试驱动开发来实现 PATCH 功能,从而产生了一组强大的测试和良好实现的功能。由于我们首先在测试中定义 PATCH 请求的预期输入和输出,因此很容易看到由于不检查请求中的空值而导致的问题。此外,当将 Completed 类型更改为 *bool 时,我们预先存在的测试能够防止重大更改。

    结论

    测试驱动开发是创建经过充分测试的正确代码的有效方法。通过从测试开始,我们可以确保每段代码都被设计为可测试的,而不是让测试成为事后的想法。

    如果您对采用 TDD 犹豫不决,这里有一些可以开始的想法:

    • 在函数的输入/输出清晰且实现不太复杂的简单场景中尝试。您可以为可能遇到的各种输入/输出编写一个强大的表测试。清晰地了解不同的场景可以简化实施
    • 如果您正在修复新的错误,那么您已经在测试中发现了差距。首先编写一个可以首先识别此错误的测试。然后,在不破坏任何现有测试的情况下使该测试通过。
    • 与babyapi示例类似,您可以使用TDD进行高级API测试。一旦您定义了预期的请求/响应,您就可以恢复通常的开发流程,以实现更注重细节的部分

    即使 TDD 不太适合您编写代码的方式,它仍然是您随身携带的强大工具。我鼓励您至少花一些时间尝试一下,看看它如何影响您的开发过程。

    版本声明 本文转载于:https://dev.to/calvinmclean/test-driven-api-development-in-go-1fb8?1如有侵犯,请联系[email protected]删除
    最新教程 更多>
    • 如何有效地选择熊猫数据框中的列?
      如何有效地选择熊猫数据框中的列?
      在处理数据操作任务时,在Pandas DataFrames 中选择列时,选择特定列的必要条件是必要的。在Pandas中,选择列的各种选项。选项1:使用列名 如果已知列索引,请使用ILOC函数选择它们。请注意,python索引基于零。 df1 = df.iloc [:,0:2]#使用索引0和1 的 ...
      编程 发布于2025-07-12
    • 如何实时捕获和流媒体以进行聊天机器人命令执行?
      如何实时捕获和流媒体以进行聊天机器人命令执行?
      在开发能够执行命令的chatbots的领域中,实时从命令执行实时捕获Stdout,一个常见的需求是能够检索和显示标准输出(stdout)在cath cath cant cant cant cant cant cant cant cant interfaces in Chate cant inter...
      编程 发布于2025-07-12
    • 为什么尽管有效代码,为什么在PHP中捕获输入?
      为什么尽管有效代码,为什么在PHP中捕获输入?
      在php ;?>" method="post">The intention is to capture the input from the text box and display it when the submit button is clicked.但是,输出...
      编程 发布于2025-07-12
    • Java是否允许多种返回类型:仔细研究通用方法?
      Java是否允许多种返回类型:仔细研究通用方法?
      在Java中的多个返回类型:一种误解类型:在Java编程中揭示,在Java编程中,Peculiar方法签名可能会出现,可能会出现,使开发人员陷入困境,使开发人员陷入困境。 getResult(string s); ,其中foo是自定义类。该方法声明似乎拥有两种返回类型:列表和E。但这确实是如此吗...
      编程 发布于2025-07-12
    • 您如何在Laravel Blade模板中定义变量?
      您如何在Laravel Blade模板中定义变量?
      在Laravel Blade模板中使用Elegance 在blade模板中如何分配变量对于存储以后使用的数据至关重要。在使用“ {{}}”分配变量的同时,它可能并不总是最优雅的解决方案。幸运的是,Blade通过@php Directive提供了更优雅的方法: $ old_section =“...
      编程 发布于2025-07-12
    • 大批
      大批
      [2 数组是对象,因此它们在JS中也具有方法。 切片(开始):在新数组中提取部分数组,而无需突变原始数组。 令ARR = ['a','b','c','d','e']; // USECASE:提取直到索引作...
      编程 发布于2025-07-12
    • 如何有效地转换PHP中的时区?
      如何有效地转换PHP中的时区?
      在PHP 利用dateTime对象和functions DateTime对象及其相应的功能别名为时区转换提供方便的方法。例如: //定义用户的时区 date_default_timezone_set('欧洲/伦敦'); //创建DateTime对象 $ dateTime = ne...
      编程 发布于2025-07-12
    • 如何使用不同数量列的联合数据库表?
      如何使用不同数量列的联合数据库表?
      合并列数不同的表 当尝试合并列数不同的数据库表时,可能会遇到挑战。一种直接的方法是在列数较少的表中,为缺失的列追加空值。 例如,考虑两个表,表 A 和表 B,其中表 A 的列数多于表 B。为了合并这些表,同时处理表 B 中缺失的列,请按照以下步骤操作: 确定表 B 中缺失的列,并将它们添加到表的末...
      编程 发布于2025-07-12
    • 如何将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-12
    • 如何使用FormData()处理多个文件上传?
      如何使用FormData()处理多个文件上传?
      )处理多个文件输入时,通常需要处理多个文件上传时,通常是必要的。 The fd.append("fileToUpload[]", files[x]); method can be used for this purpose, allowing you to send multi...
      编程 发布于2025-07-12
    • HTML格式标签
      HTML格式标签
      HTML 格式化元素 **HTML Formatting is a process of formatting text for better look and feel. HTML provides us ability to format text without us...
      编程 发布于2025-07-12
    • 如何从PHP中的Unicode字符串中有效地产生对URL友好的sl。
      如何从PHP中的Unicode字符串中有效地产生对URL友好的sl。
      为有效的slug生成首先,该函数用指定的分隔符替换所有非字母或数字字符。此步骤可确保slug遵守URL惯例。随后,它采用ICONV函数将文本简化为us-ascii兼容格式,从而允许更广泛的字符集合兼容性。接下来,该函数使用正则表达式删除了不需要的字符,例如特殊字符和空格。此步骤可确保slug仅包含...
      编程 发布于2025-07-12
    • 如何使用Python的请求和假用户代理绕过网站块?
      如何使用Python的请求和假用户代理绕过网站块?
      如何使用Python的请求模拟浏览器行为,以及伪造的用户代理提供了一个用户 - 代理标头一个有效方法是提供有效的用户式header,以提供有效的用户 - 设置,该标题可以通过browser和Acterner Systems the equestersystermery和操作系统。通过模仿像Chro...
      编程 发布于2025-07-12
    • CSS强类型语言解析
      CSS强类型语言解析
      您可以通过其强度或弱输入的方式对编程语言进行分类的方式之一。在这里,“键入”意味着是否在编译时已知变量。一个例子是一个场景,将整数(1)添加到包含整数(“ 1”)的字符串: result = 1 "1";包含整数的字符串可能是由带有许多运动部件的复杂逻辑套件无意间生成的。它也可以是故意从单个真理...
      编程 发布于2025-07-12
    • 反射动态实现Go接口用于RPC方法探索
      反射动态实现Go接口用于RPC方法探索
      在GO 使用反射来实现定义RPC式方法的界面。例如,考虑一个接口,例如:键入myService接口{ 登录(用户名,密码字符串)(sessionId int,错误错误) helloworld(sessionid int)(hi String,错误错误) } 替代方案而不是依靠反射...
      编程 发布于2025-07-12

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

    Copyright© 2022 湘ICP备2022001581号-3