【一起学Rust · 项目实战】命令行IO项目minigrep——测试驱动开发完善功能

简介: 【一起学Rust · 项目实战】命令行IO项目minigrep——测试驱动开发完善功能



前言

经过前面三节的学习,我们的小工具minigrep已经实现了读取指定文件内容,并且为了后期开发和测试的方便,重构了整个项目,使错误处理规整化,模块规范化。本次我们将采用测试驱动开发(以后简称TDD)的模式进行开发,为程序编写几个程序测试用例,测试程序搜索查询字符串并返回匹配的行示例的功能,这些功能会在后面开发过程中用到。

测试驱动开发,英文全称Test-Driven Development,简称TDD,是一种不同于传统软件开发流程的新型的开发方法。它要求在编写某个功能的代码之前先编写测试代码,然后只编写使测试通过的功能代码,通过测试来推动整个开发的进行。这有助于编写简洁可用和高质量的代码,并加速开发过程。


一、任务目的

了解测试驱动开发模式(TDD),熟悉其开发步骤。使用TDD开发模式,编写我们所需要的测试功能代码,逐步增加软件的功能。

TDD是一个软件开发技术,它遵循如下步骤:

  1. 编写一个失败的测试,并运行它以确保它失败的原因是你所期望的。
  2. 编写或修改足够的代码来使新的测试通过。
  3. 重构刚刚增加或修改的代码,并确保测试仍然能通过。
  4. 从步骤 1 开始重复!

使用TDD开发模式的好处

  1. 有助于驱动代码的设计
  2. 有助于在开发过程中保持高测试覆盖率

二、编写测试失败用例

1.增加测试模块和测试函数

我们仿照创建库时里面自带的测试代码,编写测试模块,在其中我们写了个one_result函数用来测试,其中定义了query搜索关键词和contents内容,模拟我们实际操作中获取到的参数,调用了一个search函数,将刚才的参数传入,并且断言返回的就是关键词那一行的vector。

这里我们传入的关键词是芙蓉,因此,如果search运行正常的话就会返回芙蓉老秋霜,团扇羞网尘。戚姬髡发入舂市,万古共悲辛。

search函数还没写,因此直接编译必然会报错,这里我们希望传入这两个值并且返回关键词所在的行才这么写的,search函数的编写按照我们调用的样子来写。

#[cfg(test)]
mod tests {
use super::*;
#[test]
fn one_result() {
    let query = "芙蓉";
    let contents = "\
中山孺子妾,特以色见珍。虽然不如延年妹,亦是当时绝世人。
桃李出深井,花艳惊上春。一贵复一贱,关天岂由身。
芙蓉老秋霜,团扇羞网尘。戚姬髡发入舂市,万古共悲辛。";
    assert_eq!(vec!["芙蓉老秋霜,团扇羞网尘。戚姬髡发入舂市,万古共悲辛。"], search(query, contents));
    }
}

2.编写search函数

由于这里我们是编写测试错误的用例,要确保程序出错是按照我们所期望的方式出错,因此这里我们在search函数返回一个空的vector,确保代码能够编译,且返回的不是我们所预期的结果,代码如下,

pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    vec![]
}

此时我们运行一下测试,结果返回断言的左值不等于右值,说明我们写的代码是没有问题的,在后面我们会修复这个错误,让代码测试通过,如下图

三、修改代码,让代码测试通过

目前测试之所以会失败是因为我们总是返回一个空的 vector。为了让程序能够通过测试,我们需要完善search函数的逻辑,返回正确的结果。search的程序流程图如下

开始定义存储Vector是否到达尾行?结束是否包含关键词yesno

1. 按行读取

Rust提供了可以按行读取文本的方法lines,他的调用方法是

contents.lines()

该方法返回一个数组,其中每一位元素都是文本内容的一行。我们用for循环来读取每一行,并且对每一行进行操作,所以对search函数这样改动

pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    for line in contents.lines() {
        // 对文本行进行操作
    }
}

2. 检查关键字

检查关键字实际上就是查找字符串,Rust字符串也提供了可以查找字符串的方法contains,他是这么调用的

contents.contains(keyword)

现在我们将他加入search函数中

pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
        for line in contents.lines() {
            // 对文本行进行操作
            if line.contains(query) {
            }
        }
    }

3. 存储搜索结果

现在我们可以遍历完每一行,并且对每一行进行检查是否存在我们要找的关键字,所以现在要考虑的就是怎么把这些包含关键字的行保存并返回。考虑在for循环之外创建一个Vector,每当有符合条件的行就在for循环的判断中加入进去,代码如下

pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    let mut results = Vec::new();
    for line in contents.lines() {
        if line.contains(query) {
            results.push(line);
        }
    }
    results
}

这里定义了一个可变的Vector类型的变量results,然后在for循环中判断,如果有符合条件的行就把这行加到results中,最后返回results

4. 运行测试

现在我们来运行一下这个测试用例,

可见我们写的search函数是符合条件的,通过了测试。

四、在程序中使用代码

我们的项目主要逻辑都是放在run函数中的,因此我们只需要在run函数中调用search函数,并输出每一行的内容就好了,以下是代码

pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
    let contents = fs::read_to_string(config.filename)?;
    for line in search(&config.query, &contents){
        println!("{}", line);
    }
    Ok(())
}

此时运行程序来看看效果,

输入个比较短的关键字,查看是否能找到所有行

输入一个里面不存在的关键字


总结

现在我们就基本完成了这个小工具的开发,创建了个属于自己的小工具,学习了如何组织程序,驱动测试开发的开发方法,还有一些文件输入输出、生命周期、测试和命令行解析的内容。

到现在为止,这个小工具的主要功能就算是开发完毕了,后续我们将优化处理环境变量和输出标准内容,待续。

作业

到现在为止你已经基本完成这个小案列,请思考以下内容:

  • 对于字符串的操作,比如字符串分割,字符串替换等怎么用Rust来写。
  • 测试驱动开发有什么优点,有哪些步骤。
目录
相关文章
|
10月前
|
JSON 测试技术 API
Apipost与Apifox测试功能对决,谁更适合开发者?
在API开发中,调试工具的选择至关重要。本文对比了国产工具Apipost与Apifox的功能差异,涵盖调试能力、环境管理、团队协作、文档生成、自动化测试等方面。Apifox在细节处理、协作支持及生态集成上表现更优,适合复杂项目与团队开发;而Apipost则适合基础调试需求。通过全面评估,开发者可依据项目特点选择合适工具,提升开发效率与质量。
Apipost与Apifox测试功能对决,谁更适合开发者?
|
10月前
|
人工智能 测试技术 项目管理
测试不再碎片化:AI智能体平台「项目资料套件」功能上线!
在实际项目中,需求文档分散、整理费时、测试遗漏等问题常困扰测试工作。霍格沃兹推出AI智能体测试平台全新功能——项目资料套件,可将多个关联文档打包管理,并一键生成测试用例,提升测试完整性与效率。支持套件创建、文档关联、编辑删除及用例生成,适用于复杂项目、版本迭代等场景,助力实现智能化测试协作,让测试更高效、更专业。
|
10月前
|
存储 人工智能 测试技术
用AI提升测试效率:智能体平台的「需求文档管理」功能上线啦!
霍格沃兹测试开发学社推出AI智能体测试平台,全新「需求文档管理」功能助力高效测试准备。集中管理需求文档,支持多种上传方式,智能生成测试用例,提升测试效率与准确性,助力迈向智能化测试新时代。
|
11月前
|
算法 IDE Java
Java 项目实战之实际代码实现与测试调试全过程详解
本文详细讲解了Java项目的实战开发流程,涵盖项目创建、代码实现(如计算器与汉诺塔问题)、单元测试(使用JUnit)及调试技巧(如断点调试与异常排查),帮助开发者掌握从编码到测试调试的完整技能,提升Java开发实战能力。
913 0
|
10月前
|
人工智能 自然语言处理 前端开发
深度解析Playwright MCP:功能、优势与挑战,AI如何提升测试效率与覆盖率
Playwright MCP通过AI与浏览器交互,实现自然语言驱动的自动化测试。它降低门槛、提升效率,助力测试工程师聚焦高价值工作,是探索性测试与快速验证的新利器。
|
10月前
|
测试技术
自动化测试登录后的功能
在自动化测试的时候,往往许多功能需要登录以后才可以进行操作的,在这里我介绍一种方法,在登录以后将Cookies信息存入本地文件,在测试登录以后操作的时候再从本地文件把信息调出来存入Cookies
175 4
|
12月前
|
敏捷开发 运维 数据可视化
DevOps看板工具中的协作功能:如何打破开发、测试与运维之间的沟通壁垒
在DevOps实践中,看板工具通过可视化任务管理和自动化流程,提升开发与运维团队的协作效率。它支持敏捷开发、持续交付,助力团队高效应对需求变化,实现跨职能协作与流程优化。
|
人工智能 自然语言处理 JavaScript
测试工程师要失业?Magnitude:开源AI Agent驱动的端到端测试框架,让Web测试更智能,自动完善测试用例!
Magnitude是一个基于视觉AI代理的开源端到端测试框架,通过自然语言构建测试用例,结合推理代理和视觉代理实现智能化的Web应用测试,支持本地运行和CI/CD集成。
2518 15
测试工程师要失业?Magnitude:开源AI Agent驱动的端到端测试框架,让Web测试更智能,自动完善测试用例!
|
12月前
|
安全 Java 测试技术
Java 项目实战中现代技术栈下代码实现与测试调试的完整流程
本文介绍基于Java 17和Spring技术栈的现代化项目开发实践。项目采用Gradle构建工具,实现模块化DDD分层架构,结合Spring WebFlux开发响应式API,并应用Record、Sealed Class等新特性。测试策略涵盖JUnit单元测试和Testcontainers集成测试,通过JFR和OpenTelemetry实现性能监控。部署阶段采用Docker容器化和Kubernetes编排,同时展示异步处理和反应式编程的性能优化。整套方案体现了现代Java开发的最佳实践,包括代码实现、测试调试
381 0
|
存储 网络协议 安全
Java网络编程,多线程,IO流综合小项目一一ChatBoxes
**项目介绍**:本项目实现了一个基于TCP协议的C/S架构控制台聊天室,支持局域网内多客户端同时聊天。用户需注册并登录,用户名唯一,密码格式为字母开头加纯数字。登录后可实时聊天,服务端负责验证用户信息并转发消息。 **项目亮点**: - **C/S架构**:客户端与服务端通过TCP连接通信。 - **多线程**:采用多线程处理多个客户端的并发请求,确保实时交互。 - **IO流**:使用BufferedReader和BufferedWriter进行数据传输,确保高效稳定的通信。 - **线程安全**:通过同步代码块和锁机制保证共享数据的安全性。
665 23