• 使用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
    浏览:448

    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]删除
    最新教程 更多>
    • 插入数据时如何修复“常规错误:2006 MySQL 服务器已消失”?
      插入数据时如何修复“常规错误:2006 MySQL 服务器已消失”?
      插入记录时如何解决“一般错误:2006 MySQL 服务器已消失”介绍:将数据插入 MySQL 数据库有时会导致错误“一般错误:2006 MySQL 服务器已消失”。当与服务器的连接丢失时会出现此错误,通常是由于 MySQL 配置中的两个变量之一所致。解决方案:解决此错误的关键是调整wait_tim...
      编程 发布于2024-12-19
    • 如何在 PHP 中组合两个关联数组,同时保留唯一 ID 并处理重复名称?
      如何在 PHP 中组合两个关联数组,同时保留唯一 ID 并处理重复名称?
      在 PHP 中组合关联数组在 PHP 中,将两个关联数组组合成一个数组是一项常见任务。考虑以下请求:问题描述:提供的代码定义了两个关联数组,$array1和$array2。目标是创建一个新数组 $array3,它合并两个数组中的所有键值对。 此外,提供的数组具有唯一的 ID,而名称可能重合。要求是构...
      编程 发布于2024-12-19
    • 尽管代码有效,为什么 POST 请求无法捕获 PHP 中的输入?
      尽管代码有效,为什么 POST 请求无法捕获 PHP 中的输入?
      解决 PHP 中的 POST 请求故障在提供的代码片段中:action=''而不是:action="<?php echo $_SERVER['PHP_SELF'];?>";?>"检查 $_POST数组:表单提交后使用 var_dump 检查 $_POST 数...
      编程 发布于2024-12-19
    • 在 Go 中使用 WebSocket 进行实时通信
      在 Go 中使用 WebSocket 进行实时通信
      构建需要实时更新的应用程序(例如聊天应用程序、实时通知或协作工具)需要一种比传统 HTTP 更快、更具交互性的通信方法。这就是 WebSockets 发挥作用的地方!今天,我们将探讨如何在 Go 中使用 WebSocket,以便您可以向应用程序添加实时功能。 在这篇文章中,我们将介绍: WebSoc...
      编程 发布于2024-12-19
    • 如何使用 MySQL 查找今天生日的用户?
      如何使用 MySQL 查找今天生日的用户?
      如何使用 MySQL 识别今天生日的用户使用 MySQL 确定今天是否是用户的生日涉及查找生日匹配的所有行今天的日期。这可以通过一个简单的 MySQL 查询来实现,该查询将存储为 UNIX 时间戳的生日与今天的日期进行比较。以下 SQL 查询将获取今天有生日的所有用户: FROM USERS ...
      编程 发布于2024-12-19
    • 如何修复 macOS 上 Django 中的“配置不正确:加载 MySQLdb 模块时出错”?
      如何修复 macOS 上 Django 中的“配置不正确:加载 MySQLdb 模块时出错”?
      MySQL配置不正确:相对路径的问题在Django中运行python manage.py runserver时,可能会遇到以下错误:ImproperlyConfigured: Error loading MySQLdb module: dlopen(/Library/Python/2.7/site-...
      编程 发布于2024-12-19
    • 使用“list.List”是创建带有字符串键和列表值的 Go 映射的最佳方法吗?
      使用“list.List”是创建带有字符串键和列表值的 Go 映射的最佳方法吗?
      创建字符串到列表的映射问题:您想要创建一个带有字符串类型键的映射和列表类型的值。以下代码片段是否是正确的方法:package main import ( "fmt" "container/list" ) func main() { x ...
      编程 发布于2024-12-19
    • 大批
      大批
      方法是可以在对象上调用的 fns 数组是对象,因此它们在 JS 中也有方法。 slice(begin):将数组的一部分提取到新数组中,而不改变原始数组。 let arr = ['a','b','c','d','e']; // Usecase: Extract till index p...
      编程 发布于2024-12-19
    • 除了“if”语句之外:还有什么地方可以在不进行强制转换的情况下使用具有显式“bool”转换的类型?
      除了“if”语句之外:还有什么地方可以在不进行强制转换的情况下使用具有显式“bool”转换的类型?
      无需强制转换即可上下文转换为 bool您的类定义了对 bool 的显式转换,使您能够在条件语句中直接使用其实例“t”。然而,这种显式转换提出了一个问题:“t”在哪里可以在不进行强制转换的情况下用作 bool?上下文转换场景C 标准指定了四种值可以根据上下文转换为的主要场景bool:语句:if、whi...
      编程 发布于2024-12-19
    • Bootstrap 4 Beta 中的列偏移发生了什么?
      Bootstrap 4 Beta 中的列偏移发生了什么?
      Bootstrap 4 Beta:列偏移的删除和恢复Bootstrap 4 在其 Beta 1 版本中引入了重大更改柱子偏移了。然而,随着 Beta 2 的后续发布,这些变化已经逆转。从 offset-md-* 到 ml-auto在 Bootstrap 4 Beta 1 中, offset-md-*...
      编程 发布于2024-12-19
    • 使用 html css 和 javascript 幻觉的 Tic-Tac-Toe 游戏 https://www.instagram.com/webstreet_code/
      使用 html css 和 javascript 幻觉的 Tic-Tac-Toe 游戏 https://www.instagram.com/webstreet_code/
      在 Instagram 上关注我们:https://www.instagram.com/webstreet_code/ ?✨ 带有玻璃效果的井字游戏! ✨? 我刚刚使用 HTML、CSS 和 JavaScript 构建了一款经典的 Tic-Tac-Toe 游戏,具有时尚的玻璃态设计。观看视频,看看如...
      编程 发布于2024-12-19
    • TB 级数据库的 MySQL 与 NoSQL:聚集索引何时是正确的解决方案?
      TB 级数据库的 MySQL 与 NoSQL:聚集索引何时是正确的解决方案?
      MySQL:探索数据库设计迷宫优化大型数据库时,必须考虑数据库设计策略以提高性能。在给定的场景中,包含线程的 TB 级数据库由于其庞大的规模而面临性能挑战。本文探讨了 MySQL 和 NoSQL 之间的选择,重点介绍了 MySQL 的 innodb 引擎及其聚集索引的优势。了解 MySQL 的 In...
      编程 发布于2024-12-19
    • 为什么我的 Spring Boot 应用程序不自动创建数据库架构?
      为什么我的 Spring Boot 应用程序不自动创建数据库架构?
      在 Spring Boot 中自动创建数据库架构启动 Spring Boot 应用程序时,可能会遇到自动创建数据库架构的问题。以下故障排除步骤旨在解决此问题:1.实体类包:确保实体类位于使用@EnableAutoConfiguration注解的类的同一个包或子包中。否则,Spring 将不会检测实体...
      编程 发布于2024-12-18
    • CSS3 过渡是否提供事件来检测起点和终点?
      CSS3 过渡是否提供事件来检测起点和终点?
      了解 CSS3 过渡事件CSS3 过渡允许在 Web 元素上实现流畅的动画和视觉效果。为了增强用户体验并使操作与这些转换同步,监控其进度非常重要。本文解决了 CSS3 是否提供事件来检查过渡何时开始或结束的问题。W3C CSS 过渡草案W3C CSS 过渡草案规定CSS 转换会触发相应的 DOM 事...
      编程 发布于2024-12-18
    • Java 中可以手动释放内存吗?
      Java 中可以手动释放内存吗?
      Java 中的手动内存释放与垃圾回收与 C 不同,Java 采用托管内存框架来处理内存分配和释放由垃圾收集器 (GC) 自动执行。这种自动化方法可以提高内存利用率并防止困扰 C 程序的内存泄漏。Java 中可以手动释放内存吗?由于 Java 的内存管理是由GC,它没有提供像 C 中的 free() ...
      编程 发布于2024-12-18

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

    Copyright© 2022 湘ICP备2022001581号-3