Skip to content

テストを書いてみよう

テストを書く前に、テスト対象になる処理が必要です。今回は、「与えられた City のリストから国ごとの人口の和」を計算する処理を書いてみます。

ヒント
  • 国ごとにデータを分けて持つには std::collections::HashMap を使えばいいでしょう
  • 国単位で集計するので map の key は country_code を使うといいでしょう
  • country_code が空文字列である City は、和を計算せず無視してください
参考実装
rs
use std::collections::HashMap;

//与えられた City のリストから国ごとの人口の和を計算する
pub fn sum_population_by_country(cities: Vec<City>) -> HashMap<String, i32> {
    let mut map = HashMap::new();
    for city in cities {
        if city.country_code.is_empty() {
            continue;
        }
        let entry = map.entry(city.country_code).or_insert(0);
        *entry += city.population;
    }
    map
}

このメソッドが期待した値を返すかどうか、テストを書いて確認していきましょう。

メソッド 1 つなど、小さい単位でのテストは、ユニットテストと呼ばれます。 ユニットテストは同じファイル内にテストを書くのが一般的です。

同じファイル内の一番下にテストを書いていきます。

rs
// #[cfg(test)] 属性を追加したモジュールはテストモジュールとして扱われる
#[cfg(test)] 
mod tests { 
    use super::{sum_population_by_country, City}; 
    use std::collections::HashMap; 

    fn test_sum_population_by_country() { 
        // ここにテストを追加する
    } 
} 

まずは、空のリストを渡したときに、空のマップが返ってくることをテストしてみましょう。

rs
// #[cfg(test)] 属性を追加したモジュールはテストモジュールとして扱われる
#[cfg(test)]
mod tests {
    use super::{sum_population_by_country, City};
    use std::collections::HashMap;

    #[test]
    fn test_sum_population_by_country() {
        // ここにテストを追加する
        let cities = vec![]; 
        let result = sum_population_by_country(cities); 
        assert!(result.is_empty()); 
    }
}

書き終わったら、関数の左上またはモジュールの左上にある run test を押して、テストを実行してみましょう。

すると、VSCode の Output にテストの結果が表示されます。

テストが正常に終了したことがわかります。

様々なケースをテストしてみよう

次に、 sum_population_by_country のテストをもう少し充実させてみましょう。

これから複数のテストを書くため、先ほどのテストの関数名を変更します。

rs
// #[cfg(test)] 属性を追加したモジュールはテストモジュールとして扱われる
#[cfg(test)]
mod tests {
    use super::{sum_population_by_country, City};
    use std::collections::HashMap;

    #[test]
    fn test_sum_population_by_country_empty() { 
        // ここにテストを追加する
        let cities = vec![];
        let result = sum_population_by_country(cities);
        assert!(result.is_empty());
    }
}

課題

次のテストを実装してください。

  • 1 つの国のみのデータが入っている場合
  • 複数の国のデータが入っている場合
  • 空文字列の country_code が入っている場合
答え

1 つの国のみのデータが入っている場合

rs
#[test]
fn test_sum_population_by_country_single() {
    let cities = vec![
        City {
            id: Some(1),
            name: "Tokyo".to_string(),
            country_code: "JPN".to_string(),
            district: "Tokyo".to_string(),
            population: 100,
        },
        City {
            id: Some(2),
            name: "Osaka".to_string(),
            country_code: "JPN".to_string(),
            district: "Osaka".to_string(),
            population: 200,
        },
    ];

    let mut expected = HashMap::new();
    expected.insert("JPN".to_string(), 300);

    let result = sum_population_by_country(cities);

    assert_eq!(result, expected);
}

複数の国のデータが入っている場合

rs
#[test]
fn test_sum_population_by_country_multiple() {
    let cities = vec![
        City {
            id: Some(1),
            name: "Tokyo".to_string(),
            country_code: "JPN".to_string(),
            district: "Tokyo".to_string(),
            population: 100,
        },
        City {
            id: Some(2),
            name: "Osaka".to_string(),
            country_code: "JPN".to_string(),
            district: "Osaka".to_string(),
            population: 200,
        },
        City {
            id: Some(3),
            name: "New York".to_string(),
            country_code: "USA".to_string(),
            district: "New York".to_string(),
            population: 300,
        },
        City {
            id: Some(4),
            name: "Los Angeles".to_string(),
            country_code: "USA".to_string(),
            district: "California".to_string(),
            population: 400,
        },
    ];

    let mut expected = HashMap::new();
    expected.insert("JPN".to_string(), 300);
    expected.insert("USA".to_string(), 700);

    let result = sum_population_by_country(cities);

    assert_eq!(result, expected);
}

空文字列の country_code が入っている場合

rs
#[test]
fn test_sum_population_by_country_empty_country_code() {
    let cities = vec![
        City {
            id: Some(1),
            name: "Tokyo".to_string(),
            country_code: "JPN".to_string(),
            district: "Tokyo".to_string(),
            population: 100,
        },
        City {
            id: Some(2),
            name: "Osaka".to_string(),
            country_code: "".to_string(),
            district: "Osaka".to_string(),
            population: 200,
        },
    ];

    let mut expected = HashMap::new();
    expected.insert("JPN".to_string(), 100);

    let result = sum_population_by_country(cities);

    assert_eq!(result, expected);
}

実装が終わったら、モジュールの左上にある run test を押して、テストを実行してみましょう。

モジュール内の全てのテストが成功したことを確認できます。