Yomiage
メニュー

Rust実践講座 19:総合演習・回帰テストとリリースビルド

更新 2026/9/27 6:22:11 公開

投稿者: しゅりりん

到達点は、保存を含む振る舞いを繰り返し検証し、実行物を渡せることです。前提は第17・18回です。

実際の保存境界を通す

次をsrc/main.rsの末尾へ追加します。既存のmainを置き換えず、テスト用モジュールを足してください。

#[cfg(test)]
mod tests {
    use super::*;

    fn args(path: &Path, command: &str, value: &str) -> Vec<String> {
        vec![path.to_string_lossy().into_owned(), command.to_owned(), value.to_owned()]
    }

    #[test]
    fn rejects_invalid_model() {
        assert!(Task::new(0, "復習").is_err());
        assert!(Task::new(1, " ").is_err());
        assert!(Task::new(1, "a\nb").is_err());
    }

    #[test]
    fn persists_and_preserves_failed_updates() -> Result<(), Box<dyn Error>> {
        let dir = tempfile::tempdir()?;
        let path = dir.path().join("tasks.json");
        run(&args(&path, "add", "復習"))?;
        run(&args(&path, "done", "1"))?;
        run(&args(&path, "done", "1"))?;
        assert!(load(&path)?[0].done);
        let before = std::fs::read(&path)?;
        assert!(run(&args(&path, "done", "999")).is_err());
        assert_eq!(std::fs::read(&path)?, before);
        std::fs::write(&path, "broken")?;
        assert!(run(&args(&path, "add", "新規")).is_err());
        assert_eq!(std::fs::read_to_string(&path)?, "broken");
        Ok(())
    }
}

cargo testで二つのテストが成功します。tempdirでテストごとに別の領域を作り、終了時に片付けます。通常の利用者のtasks.jsonをテストで書き換えません。

配布時にも前提を明記する

cargo build --release で最適化された実行ファイルを作ります。通常はtarget/releaseに置かれ、Windowsでは拡張子exeが付きます。同じOSやCPU向けにビルドした実行物が、すべての環境でそのまま動くとは限りません。

READMEには必要なツールチェーン、コマンド、保存形式、終了コード、同時更新非対応、保存上限を記録します。Cargo.tomlとCargo.lockを追跡し、生成物と個人の保存データをGitへ入れないようにします。CIではfmt、clippy、testを基本にし、必要なら対象OSごとに検証します。

性能を調べるときはdebugビルドとreleaseビルドを混ぜて比較しないようにします。ただし最適化でテストを省略してよいわけではありません。桁あふれなどの意味はchecked系操作で明示しておくことが再現性にも役立ちます。

練習と解答

練習:ID重複、未知の保存バージョン、ID最大値を持つファイルのテストを追加します。

解答の要点:重複と未知の版はloadで失敗、最大値の後のaddは発番で失敗し、いずれも元のバイト列を維持することを確認します。エラーになった事実だけでなく、データを壊していないことが重要です。

公式資料

Cargoのプロファイルとテストを参照できます。


Rust全20回の目次 | 前の回 | 次の回

このブラウザでは Web Speech API が利用できません。

1 / 16 · 停止中