記事ディレクトリ
序文
前の 3 つのセクションでの検討の後、私たちの小さなツール minigrep は指定されたファイル コンテンツの読み取りを実現し、その後の開発とテストの便宜のために、プロジェクト全体を再構築してエラー処理を標準化し、モジュールを標準化しました。今回は测试驱动开发(以后简称TDD)
同じパターンで開発を行い、プログラムのテストケースをいくつか書いて、クエリ文字列を検索し、一致する行の例を返すプログラムの機能をテストし、後の開発プロセスで使用します。
テスト駆動開発、英語の正式名称テスト駆動開発は、TDD と呼ばれ、従来のソフトウェア開発プロセスとは異なる新しい開発方法です。ある関数のコードを書く前にテストコードを書き、テストをパスする関数コードだけを書き、テストを通して開発全体を進める必要があります。これにより、クリーンで使いやすく高品質なコードを記述し、開発プロセスをスピードアップできます。
1. 課題の目的
测试驱动开发模式(TDD)
その開発手順を理解し、熟知してください。TDD 開発モデルを使用して、必要なテスト機能コードを記述し、ソフトウェアの機能を徐々に増やします。
TDD は、次の手順に従うソフトウェア開発手法です。
- 失敗するテストを作成し、それを実行して、期待どおりに失敗することを確認します。
- 新しいテストに合格するのに十分なコードを作成または変更します。
- 追加または変更されたばかりのコードをリファクタリングし、テストが引き続き成功することを確認します。
- ステップ1からやり直し!
TDD 開発モデルを使用する利点
- コード設計の推進を支援
- 開発中に高いテスト カバレッジを維持するのに役立ちます
2. テストの失敗例を書く
1. テスト モジュールとテスト機能を追加する
ライブラリ作成時に同梱されていたテストコードを模倣し、テスト用の関数を記述したテストモジュールを記述し、one_result
クエリの検索キーワードと内容を定義し、実際の運用で得られたパラメータをシミュレートして呼び出しました。search
今パラメータを渡して、断言
キーワードを含む行のベクトルを返す関数。
ここで渡すキーワードは である芙蓉
ため、search
正しく機能すると が返されます芙蓉老秋霜,团扇羞网尘。戚姬髡发入舂市,万古共悲辛。
。
search
関数はまだ書かれていないので, 直接コンパイルすると必然的にエラーが報告されます. ここで, これら2つの値を渡し, キーワードが配置されている行を返すことを望みます. 関数は呼び出した方法に従って書かれていますsearch
.それ。
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn one_result() {
let query = "芙蓉";
let contents = "\
中山孺子妾,特以色见珍。虽然不如延年妹,亦是当时绝世人。
桃李出深井,花艳惊上春。一贵复一贱,关天岂由身。
芙蓉老秋霜,团扇羞网尘。戚姬髡发入舂市,万古共悲辛。";
assert_eq!(vec!["芙蓉老秋霜,团扇羞网尘。戚姬髡发入舂市,万古共悲辛。"], search(query, contents));
}
}
2. 検索関数を書く
ここではテスト エラーのユース ケースを作成しているため、プログラム エラーが想定どおりであることを確認する必要があります。そのため、検索関数で空のベクトルを返し、コードがコンパイルされ、返される結果が次のようになることを確認します。私たちが期待したものではありません.コードは以下のように表示されます,
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
vec![]
}
At this point, we run the test, and the result returns an assertion 左值不等于右值
, shown that the code we written is correct. このエラーは後で修正し、コード テストをパスさせます (下の図を参照)。
3. コードを変更し、コードのテストに合格する
現在、常に空のベクターを返すため、テストは失敗します。プログラムがテストに合格するには、search
関数のロジックを改善して正しい結果を返す必要があります。search
プログラムのフローチャートは次のとおりです。
1. 行単位で読む
Rust はテキストを 1 行ずつ読み取るメソッドを提供しており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
4番目に、プログラムでコードを使用します
プロジェクトのメイン ロジックは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 を使用して記述する方法。
- テスト駆動開発の利点とその手順について教えてください。