构建一个rust生产应用读书笔记四(实战1)

我们需要从访客那里收集哪些信息,以便将其登记为电子邮件通讯的订阅者?

  1. 电子邮件地址:这是最基本的要求,因为我们需要通过电子邮件地址向订阅者发送内容。
  2. 姓名:虽然这不是强制性的,但我们希望收集一个名字,以便在电子邮件中个性化问候(例如,“您好 {{subscriber.name}}!”)。这有助于增加邮件的亲和力和互动性。

为什么收集这些信息?

  • 电子邮件地址:这是发送消息的唯一标识符。
  • 姓名:用于个性化邮件,使订阅者感到更亲切。我们不强制要求真实姓名,允许用户使用任何他们喜欢的标识符(例如,coderLZ)。

表单提交的编码方式

假设数据是通过HTML表单收集的,并通过POST请求传递给后端API,表单数据的编码方式可以选择 application/x-www-form-urlencoded。这是最常见的表单数据编码方式,适用于大多数简单的表单提交场景。

示例HTML表单

<form action="/subscribe" method="post">
  <label for="email">电子邮件地址:</label>
  <input type="email" id="email" name="email" required>
  
  <label for="name">姓名 (可选):</label>
  <input type="text" id="name" name="name">
  
  <button type="submit">订阅</button>
</form>

后端API接收的数据格式

当表单提交时,数据将以 application/x-www-form-urlencoded 格式编码,并通过POST请求的请求体(body)传递给后端API,比如

email=example%40example.com&name=DenverCoder9

通常在URL编码中使用%20替换空格,%40替换@符号,以确保URL的标准化、兼容性和安全性。通过URL编码,可以确保各种字符在URL中正确传输和解析。

将需求转化为测试用例,在实际开发过程中也是如此,测试先行

测试用例

  1. 验证电子邮件地址的有效性
    1. 描述:确保用户提供的电子邮件地址是有效的。
    2. 测试用例:
      1. 输入:email=example@example.com
      2. 期望输出:订阅成功。
      3. 输入:email=invalidemail
      4. 期望输出:显示错误消息,提示电子邮件格式无效。
  2. 验证姓名字段的灵活性
    1. 描述:确保用户可以使用任何形式的姓名,包括空值。
    2. 测试用例:
      1. 输入:email=example@example.com&name=John Doe
      2. 期望输出:订阅成功。
      3. 输入:email=example@example.com&name=DenverCoder9
      4. 期望输出:订阅成功。
      5. 输入:email=example@example.com&name=
      6. 期望输出:订阅成功,姓名字段为空。
  3. 验证表单提交的编码方式
    1. 描述:确保表单数据以 application/x-www-form-urlencoded 格式正确编码。
    2. 测试用例:
    3. 输入:email=example%40example.com&name=John%20Doe
    4. 期望输出:订阅成功,电子邮件地址和姓名正确解析。
  4. 验证重复订阅
    1. 描述:确保同一电子邮件地址不能多次订阅。
    2. 测试用例:
      1. 输入:第一次订阅 email=example@example.com&name=John Doe
      2. 期望输出:订阅成功。
      3. 输入:第二次订阅 email=example@example.com&name=John Doe
      4. 期望输出:显示错误消息,提示该电子邮件地址已订阅。
  5. 验证错误处理
    1. 描述:确保系统能够正确处理各种错误情况。
    2. 测试用例:
      1. 输入:email=example@example.com&name=
      2. 期望输出:订阅成功,姓名字段为空。
      3. 输入:email=&name=John Doe
      4. 期望输出:显示错误消息,提示电子邮件地址不能为空。
      5. 输入:email=example@example.com&name=<>
      6. 期望输出:显示错误消息,提示姓名字段包含非法字符。

编写测试用例代码

本文结合表驱动测试(Table-Driven Testing)方法,它通过使用一个数据表来组织测试用例。每个测试用例通常包含输入数据、预期输出结果以及可能的其他信息,如测试描述或标签。这种方法使得测试代码更加简洁、易于理解和维护,同时也方便扩展新的测试用例。

表驱动测试的优势

  1. 代码简洁:通过将测试用例组织成表格形式,可以避免大量的重复代码,使测试逻辑更加清晰。
  2. 易于维护:当需要添加新的测试用例或修改现有测试用例时,只需更新表格中的数据,而不需要改动测试逻辑。
  3. 便于扩展:可以轻松地向表格中添加新的行,以涵盖更多的测试场景。
  4. 更好的可读性:将测试用例组织成表格形式,使得测试意图更加明确,更容易理解。
///! src/health_check.rs
#[tokio::test]
async fn subscribe_returns_a_200_for_valid_form_data() {
    let app_address = spawn_app();
    let client = reqwest::Client::new();

    let body = "name=le%20guin&email=ursula_le_guin%40gmail.com";
    let response = client
        .post(&format!("{}/subscriptions", &app_address))
        .header("Content-Type", "application/x-www-form-urlencoded")
        .body(body)
        .send()
        .await
        .expect("Failed to execute request .");
    //此处我们希望返回200,但是很明显/subscriptions路径根本不存在,应该返回404
    assert_eq!(200, response.status().as_u16());
}

#[tokio::test]
async fn subscribe_returns_a_400_when_data_is_missing() {
    let app_address = spawn_app();
    let client = reqwest::Client::new();
///```test_cases:定义了一个包含多个测试用例的向量。每个测试用例是一个元组,包含两个字符串:
///   invalid_body:无效的请求体,用于模拟缺少某些必要字段的情况。
///```error_message:描述该测试用例的错误信息,用于在断言失败时提供更详细的错误信息。
    let test_cases = vec![
        ("name=le%20guin", "missing the email"),
        ("email=ursula_le_guin%40gmail.com", "missing the name"),
        ("", "missing both name and email"),
    ];

    for (invalid_body, error_message) in test_cases {
        let response = client
            .post(&format!("{}/subscriptions", &app_address))
            .header("Content-Type", "application/x-www-form-urlencoded")
            .body(invalid_body)
            .send()
            .await
            .expect("Failed to execute request.");
        assert_eq!(
            400,
            response.status().as_u16(),
            "The API did not fail with 400 bad Request when the payload was {}.",
            error_message
        );
    }
}

这段代码通过表驱动测试的方法,验证了一个 HTTP API 在接收到缺少必要数据的请求时是否会正确返回 400 Bad Request 状态码。每个测试用例都包含一个无效的请求体和一个描述性的错误信息,以便在断言失败时提供详细的错误提示。虽然并没有覆盖到所有的测试用例,但是这种测试方法不仅提高了代码的可读性和可维护性,还确保了 API 的健壮性。

下一节我们将开始实现/subscriptions 功能

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/938725.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Qt】显示类控件:QLabel、QLCDNumber、QProgressBar、QCalendarWidget

目录 QLabel QFrame 例子&#xff1a; textFormat pixmap、scaledContents alignment wordWrap、indent、margin buddy QLCDNumber 例子&#xff1a; QTimer QProgressBar 例子&#xff1a; QCalendarWidget 例子&#xff1a; QLabel 标签控件&#xff0c;用来显示…

0001.基于springmvc简易酒店管理系统后台

一.系统架构 springmvcjsplayuimysql 二.功能特性 简单易学习&#xff0c;虽然版本比较老但是部署方便&#xff0c;tomcat环境即可启用&#xff1b;代码简洁&#xff0c;前后端代码提供可统一学习&#xff1b;祝愿您能成尽快为一位合格的程序员&#xff0c;愿世界没有BUG; …

Wallpaper壁纸制作学习记录12

角色表 创建人偶变形动画的更高级方法可以使用角色表来完成。角色表要求您使用角色的切割版本&#xff0c;将您的角色分成不同肢体/部分。这允许创建更复杂、更准确的动画&#xff0c;因为部分可以自由移动和重叠&#xff0c;而不会使图像失真。使用操控变形不一定能获得良好的…

【Python项目】基于Django的语音和背景音乐分离系统

【Python项目】基于Django的语音和背景音乐分离系统 技术简介&#xff1a;采用Python技术、Django框架、B/S结构&#xff0c;MYSQL数据库等实现。 系统简介&#xff1a;系统完成在线的音频上传&#xff0c;并且通过计算机的神经网络算法来对系统中的背景音乐和人声进行分离操作…

负载均衡oj项目:介绍

目录 项目介绍 项目演示 项目介绍 负载均衡oj是一个基于bs模式的项目。 用户使用浏览器向oj模块提交代码&#xff0c;oj模块会在所有在线的后端主机中选择一个负载情况最低的主机&#xff0c;将用户的代码提交给该主机&#xff0c;该主机进行编译运行&#xff0c;将结果返回…

【鸿睿创智开发板试用】移植OpenCV 4到OpenHarmony 4.1

目录 目录 引言 编译系统镜像 (1) 下载代码后解压SDK (2) 下载docker镜像   (3) 编译OH 编译OpenCV 下载OpenCV源代码 构建编译配置文件 执行编译命令 安装库和头文件 测试 结语 引言 最近有个需求是在基于RK3568的OpenHarmony 4.1系统中使用OpenCV&#xff0c…

【HarmonyOS之旅】HarmonyOS开发基础知识(一)

目录 1 -> 应用基础知识 1.1 -> 用户应用程序 1.2 -> 用户应用程序包结构 1.3 -> Ability 1.4 -> 库文件 1.5 -> 资源文件 1.6 -> 配置文件 1.7 -> pack.info 1.8 -> HAR 2 -> 配置文件简介 2.1 -> 配置文件的组成 3 -> 配置文…

【机器人】Graspness 端到端抓取点估计 | 环境搭建 | 模型推理测试

在复杂场景中实现抓取检测&#xff0c;Graspness是一种端到端的方法&#xff1b; 输入点云数据&#xff0c;输出抓取角度、抓取深度、夹具宽度等信息。 开源地址&#xff1a;https://github.com/rhett-chen/graspness_implementation?tabreadme-ov-file 论文地址&#xff1…

B站bilibili视频转文字字幕下载方法

本文将讲述介绍一种使用本地工具如何快速的下载B站的字幕为本地文本文件的方法。 通常获取B站字幕需要在浏览器中安装第三方插件&#xff0c;通过插件获取字幕。随着大模型&#xff0c;生成式AI&#xff0c;ChatGPT的应用&#xff0c;B站也提供了AI小助手对视频的内容进行总结…

CSS3 实现火焰-小火苗效果

创建 CSS3 火焰效果可以通过组合 CSS 动画、伪元素 和 渐变 来实现。以下是一个简单的实现步骤&#xff0c;展示如何制作动态火焰效果 1. HTML 结构 我们只需要一个简单的 div 容器&#xff1a; <div class"fire"></div>2. CSS 实现 基础样式 使用 …

新能源汽车充电需求攀升,智慧移动充电服务有哪些实际应用场景?

在新能源汽车行业迅猛发展的今天&#xff0c;智慧充电桩作为支持这一变革的关键基础设施&#xff0c;正在多个实际应用场景中发挥着重要作用。从公共停车场到高速公路服务区&#xff0c;从企业园区到住宅小区&#xff0c;智慧充电桩不仅提供了便捷的充电服务&#xff0c;还通过…

git remote -v(--verbose)显示你的 Git 仓库配置的远程仓库的详细信息

git remote -v 是一个 Git 命令&#xff0c;用于显示你的 Git 仓库配置的远程仓库的详细信息。 当你执行 git remote -v 命令时&#xff0c;你会看到类似以下的输出&#xff1a; origin https://github.com/your-username/your-repo.git (fetch) origin https://github.com…

Java Web项目部署教程简单实用

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c; 忍不住分享一下给大家。点击跳转到网站 学习总结 1、掌握 JAVA入门到进阶知识(持续写作中……&#xff09; 2、学会Oracle数据库入门到入土用法(创作中……&#xff09; 3、手把…

【爬虫一】python爬虫基础合集一

【爬虫一】python爬虫基础合集一 1. 网络请求了解1.1. 请求的类型1.2. 网络请求协议1.3. 网络请求过程简单图解1.4. 网络请求Headers(其中的关键字释义)&#xff1a;请求头、响应头 2. 网络爬虫的基本工作节点2.1. 了解简单网络请求获取响应数据的过程所涉及要点 1. 网络请求了…

清理C盘小记

突然C盘就爆满了&#xff0c;想当初还是给他预留了120G的空间&#xff0c;感觉到现在也不够用了&#xff0c;担心出现死机的情况就赶紧进行了清理。有一说一&#xff0c;清理回收站是真的有用。 参考&#xff1a;C盘清理指南&#xff0c;清理出30G起&#xff0c;超详细总结&am…

Ansible playbook 详解与实战操作

一、概述 playbook 与 ad-hoc 相比,是一种完全不同的运用 ansible 的方式&#xff0c;类似与 saltstack 的 state 状态文件。ad-hoc 无法持久使用&#xff0c;playbook 可以持久使用。 playbook 是由一个或多个 play 组成的列表&#xff0c;play 的主要功能在于将事先归并为一…

seata-2阶段提交-笔记3

本文属于B站图灵课堂springcloud笔记系列。 前面整理过2篇:seata 2阶段提交实现代码-笔记1-CSDN博客 扫描GlobalTransactional注解 seata 2阶段提交实现代码-笔记2-CSDN博客 TC生成XID&#xff0c;并保存到global_table表。 本篇继续整理 执行业务逻辑&#xff0c;提交本地…

Docker如何运行一个Java的jar包程序

Docker如何运行一个Java的jar包程序 1、jar包程序 2、start.sh运行jar包脚本 #!/bin/bash #进入目录 cd /app #1.下载SDK并安装 java -jar SDKDown1.4.jar #2.加载环境变量 export LD_LIBRARY_PATH/opt/casb/CipherSuiteSdk_linux/lib echo $LD_LIBRARY_PATH #3.执行SDK java …

Pycharm访问MongoDB数据库

MongoDB的基础操作 1. 创建连接 #导入pymongo中的用于操作数据库的客户端 from pymongo import MongoClient #创建客户端对象&#xff0c;连接MongoDB服务器 client MongoClient(mongodb://admin:admin123456localhost:27017) 2. 数据的增删改查 2.1 数据的写入 from mon…

【Python】编写一个函数,将指定的罗马字符转换为数字的形式。

#编写一个函数&#xff0c;将指定的罗马字符转换为数字的形式。R2N {I:1, V:5, X:10, L:50, C:100, D:500, M:1000}def roman2num(s):r 0n len(s)for i, ch in enumerate(s):v R2N[ch]if i < n-1 and v < R2N[s[i1]]:r - velse:r vreturn r;s input("请输入一…