今年の言語はRust その２６


# 今年の言語はRust その２６


Rustを学びます


Rustの日本語ドキュメント 2nd Edition
https://doc.rust-jp.rs/book/second-edition/

オリジナル(英語)
https://doc.rust-lang.org/book/



#### 実行環境

```sh
$ cargo -V
cargo 1.33.0 (f099fe94b 2019-02-12)
$ rustup -V
rustup 1.17.0 (069c88ed6 2019-03-05)
$ rustc --version
rustc 1.33.0 (2aa4c46cf 2019-02-28)

$  cat /proc/version
Linux version 4.14.97-74.72.amzn1.x86_64 (mockbuild@gobi-build-64002) (gcc version 7.2.1 20170915 (Red Hat 7.2.1-2) (GCC)) #1 SMP Tue Feb 5 20:59:30 UTC 2019

$ uname -a
Linux ip-10-100-0-8 4.14.97-74.72.amzn1.x86_64 #1 SMP Tue Feb 5 20:59:30 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

$ cat /etc/\*release
NAME="Amazon Linux AMI"
VERSION="2018.03"
ID="amzn"
ID_LIKE="rhel fedora"
VERSION_ID="2018.03"
PRETTY_NAME="Amazon Linux AMI 2018.03"
ANSI_COLOR="0;33"
CPE_NAME="cpe:/o:amazon:linux:2018.03:ga"
HOME_URL="http://aws.amazon.com/amazon-linux-ami/"
Amazon Linux AMI release 2018.03

```


## 11. 自動テストを書く

やっとテストまで来ました。



### 11.1 テストを書く

Rustは実は、__cargo new__ を使ってプロジェクトを作ると
なにやらテストのテンプレートコードがはいっていたので気になっていた


気になるのは__derive属性__ です。 

関数をテスト関数に変えるには、fnの前に__#[test]__ を付け加えるのです。 


```rust
$ cargo new adder --lib
```

```rust
#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}

```

> 関数本体は、assert_eq!マクロを使用して、2 + 2が4に等しいことをアサーション

```rust
$ cargo test
   Compiling adder v0.1.0 (/home/ec2-user/environment/adder)
    Finished dev [unoptimized + debuginfo] target(s) in 1.95s
     Running target/debug/deps/adder-eb1f67e545695558

running 1 test
test tests::it_works ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

   Doc-tests adder

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
```

うー。標準で実装されていてうれしいー


```rust
#[cfg(test)]
mod tests {
    #[test]
    fn exploration() {
        assert_eq!(2 + 2, 4);
    }
    
    #[test]
    fn anoter() {
        panic!("Make this test fail");
    }
}
```

例にならって__失敗__ させてみます


```rust
$ cargo test
   Compiling adder v0.1.0 (/home/ec2-user/environment/adder)
    Finished dev [unoptimized + debuginfo] target(s) in 0.39s
     Running target/debug/deps/adder-eb1f67e545695558

running 2 tests
test tests::exploration ... ok
test tests::anoter ... FAILED

failures:

---- tests::anoter stdout ----
thread 'tests::anoter' panicked at 'Make this test fail', src/lib.rs:10:9
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.


failures:
    tests::anoter

test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out

error: test failed, to rerun pass '--lib'
```


#### assert!マクロ

```Rust
#[derive(Debug)]
pub struct Rectangle {
    length: u32,
    width: u32,
}


impl Rectangle {
    pub fn can_hold(&self, other: &Rectangle) -> bool {
        self.length > other.length && self.width > other.width
    }
}


#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn larger_can_hold_smaller() {
        let larger = Rectangle { length:8, width:7 };
        let smaller = Rectangle { length:5, width:1 };
        
        assert!(larger.can_hold(&smaller));
    }
}
```


#### assert_eq!とassert_ne!マクロで等値性をテストする

```rust
pub fn add_two(a: i32) -> i32 {
    a + 2
}


#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn it_adds_two() {
        assert_eq!(4, add_two(2));
        assert_ne!(3, add_two(2));
        
    }
}
```

>表面下では、assert_eq!とassert_ne!マクロはそれぞれ、==と!=演算子を使用しています。 アサーションが失敗すると、これらのマクロは引数をデバッグフォーマットを使用して出力するので、 比較対象の値はPartialEqとDebugトレイトを実装していなければなりません。 組み込み型の全部と、標準ライブラリの型はほぼ全てこれらのトレイトを実装しています。 自分で定義した構造体とenumについては、PartialEqを実装して、 その型の値が等しいか等しくないかアサーションする必要があるでしょう。Debugを実装して、 アサーションが失敗した時に値を出力する必要もあるでしょう。 第5章のリスト5-12で触れたように、どちらのトレイトも継承可能トレイトなので、 これは通常、構造体やenum定義に#[derive(PartialEq, Debug)]というアノテーションを追加するくらい率直になります。 これらや他の継承可能トレイトに関する詳細については、付録Cをご覧ください。


#### assert!が失敗した場合のコメント

```rust
pub fn greeting(name: &str) -> String{
    // format!("Hello {}!", name)
    format!("Hello {}", "errro")
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn greeting_coutains_name() {
       let result = greeting("Carol");
       assert!(
            result.contains("Carol"),
            "Greeting did not contain name, value was `{}`", result // <- 失敗時メッセージ
            );
    }
}
```

#### should_panicでパニックを確認



```rust
pub struct Guess {
    value: u32,
}

impl Guess {
    pub fn new(value: u32) -> Guess {
        if value < 1 || value > 100 {
            panic!("");
        }
        
        Guess {
            value
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    #[should_panic]
    fn greater_than_100() {
        Guess::new(200);
    }
}
```

__should_panic(expected= "~~")__ は
失敗メッセージに与えられたテキストが含まれていることを確かめてくれる

```rust
pub struct Guess {
    value: u32,
}

impl Guess {
    pub fn new(value: u32) -> Guess {
        if value < 1 {
            panic!("Guess value must be more than or equal to 0");
        }else if value > 100{
            panic!("Guess value must be less than or equal to 100");
        }
        
        Guess {
            value
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    #[should_panic(expected = "Guess value must be less than or equal to 100")]
    fn greater_than_100() {
        Guess::new(200);
    }
    
    #[test]
    #[should_panic(expected = "Guess value must be more than or equal to 0")]
    fn greater_than_0() {
        Guess::new(0);
    }
}


```

これを使うことで、panicをきちんととれているかわかる.

エラーの文言でかけるのは新鮮


次回ももう少しテスト!!


イエス！