スライド: https://hackmd.io/@hyrodium/HJ-iV8oIw
assert
, assert_eq
, ..should_panic
$ cargo new adder --lib
以下が生成されてる.
これはcargo new hello
のようにサンプルコードをつくってくれる.
--lib
はsrc/lib.rs
を作ることを意味する.
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}
簡単なテストが最初から入っている
#[cfg(test)]
は謎だが, 以下のが詳しいらしい(?)
https://doc.rust-jp.rs/book/second-edition/ch11-03-test-organization.html#aテストモジュールとcfgtest
#[test]
でテスト時に実行することを明示する.
テスト結果:
it_works
関数でのテストが成功してることが確認できる
#[cfg(test)]
mod tests {
#[test]
fn it_works2() {
assert_eq!(2 + 2, 4);
assert_eq!(2 * 3, 6);
}
#[test]
fn it_works3() {
assert_ne!(0, 0 * 2);
assert_ne!(1, 1 * 2);
assert_ne!(2, 2 * 2);
assert_ne!(3, 3 * 2);
}
}
it_works2
で成功, it_works3
で失敗.
(どの行数でコケたかまでは教えてくれない.)
assert!
#[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));
}
#[test]
fn smaller_cannot_hold_larger() {
let larger = Rectangle {
length: 8,
width: 7,
};
let smaller = Rectangle {
length: 5,
width: 1,
};
assert!(!smaller.can_hold(&larger));
}
}
assert!
は真偽値(bool
)に対するテスト
assert_eq!
pub fn add_two(a: i32) -> i32 {
a + 2
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_adds_two() {
assert!(5 == add_two(2));
}
}
assert_eq!
pub fn add_two(a: i32) -> i32 {
a + 2
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_adds_two() {
assert_eq!(5, add_two(2));
}
}
assert_ne!
は等しくない評価
pub fn greeting(name: &str) -> String {
format!("Hello {}!", name)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn greeting_contains_name() {
let result = greeting("Carol");
assert!(result.contains("Carol"));
}
}
pub fn greeting(name: &str) -> String {
format!("Hello {}!", name)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn greeting_contains_name() {
let result = greeting("Carl");
assert!(result.contains("Carol"));
}
}
pub fn greeting(name: &str) -> String {
format!("Hello {}!", name)
}
#[test]
fn greeting_contains_name() {
let result = greeting("Carl");
assert!(
result.contains("Carol"),
"Greeting did not contain name, value was `{}`",
result
);
}
should_panic
#[derive(Debug)]
pub struct Guess {
value: u32,
}
impl Guess {
pub fn new(value: u32) -> Guess {
if value < 1 || value > 100 {
//予想値は1から100の間でなければなりません
panic!("Guess value must be between 1 and 100, got {}.", value);
}
Guess { value }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_panic]
fn greater_than_100() {
Guess::new(200);
}
}
should_panic
#[derive(Debug)]
pub struct Guess {
value: u32,
}
impl Guess {
pub fn new(value: u32) -> Guess {
if value < 1 {
panic!(
"Guess value must be greater than or equal to 1, got {}.",
value
);
} else if value > 100 {
panic!(
"Guess value must be less than or equal to 100, got {}.",
value
);
}
Guess { value }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_panic]
fn greater_than_100() {
Guess::new(200);
}
}
should_panic
#[derive(Debug)]
pub struct Guess {
value: u32,
}
impl Guess {
pub fn new(value: u32) -> Guess {
if value < 1 {
panic!(
"Guess value must be greater than or equal to 1, got {}.",
value
);
} else if value > 100 {
panic!(
"Guess value must be less than or equal to 100, got {}.",
value
);
}
Guess { value }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_panic]
fn greater_than_100() {
Guess::new(50);
}
}
should_panic
greater_than_100
ではないが..
#[derive(Debug)]
pub struct Guess {
value: u32,
}
impl Guess {
pub fn new(value: u32) -> Guess {
if value < 1 {
panic!(
"Guess value must be greater than or equal to 1, got {}.",
value
);
} else if value > 100 {
panic!(
"Guess value must be less than or equal to 100, got {}.",
value
);
}
Guess { value }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_panic]
fn greater_than_100() {
Guess::new(0);
}
}
should_panic
#[derive(Debug)]
pub struct Guess {
value: u32,
}
impl Guess {
pub fn new(value: u32) -> Guess {
if value < 1 {
panic!(
"Guess value must be greater than or equal to 1, got {}.",
value
);
} else if value > 100 {
panic!(
"Guess value must be less than or equal to 100, got {}.",
value
);
}
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(0);
}
}
$ cargo test -- --test-threads=1
標準では勝手に並列して処理してくれる
複数のテストで同一のtmpファイルを操作する場合に有効
#[allow(dead_code)]
fn prints_and_returns_10(a: i32) -> i32 {
println!("I got the value {}", a);
10
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn this_test_will_pass() {
let value = prints_and_returns_10(4);
assert_eq!(10, value);
}
#[test]
fn this_test_will_fail() {
let value = prints_and_returns_10(8);
assert_eq!(5, value);
}
}
$ cargo test -- --nocapture
pub fn add_two(a: i32) -> i32 {
a + 2
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn add_two_and_two() {
assert_eq!(4, add_two(2));
}
#[test]
fn add_three_and_two() {
assert_eq!(5, add_two(3));
}
#[test]
fn one_hundred() {
assert_eq!(102, add_two(100));
}
}
one_hundred
関数のみテスト
$ cargo test one_hundred
名前にadd
を関数のみテスト
$ cargo test add
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
#[test]
#[ignore]
fn expensive_test() {
// code that takes an hour to run
}
詳細にテスト
$ cargo test -- --ignored
testsモジュールの#[cfg(test)]という注釈は、コンパイラにcargo buildを走らせた時ではなく、cargo testを走らせた時にだけ、 テストコードをコンパイルし走らせるよう指示します。
私の環境ではcargo build
でテストが走らないようでした(謎)
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}
pub fn add_two(a: i32) -> i32 {
internal_adder(a, 2)
}
fn internal_adder(a: i32, b: i32) -> i32 {
a + b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn internal() {
assert_eq!(4, internal_adder(2, 2));
}
}
├── Cargo.lock
├── Cargo.toml
├── src
│ └── lib.rs
├── tests
│ └── integration_test.rs
...
integration_test.rs
extern crate adder;
#[test]
fn it_adds_two() {
assert_eq!(4, adder::add_two(2));
}
$ cargo test
それぞれ単体テスト、結合テスト、ドックテスト
(テストファイルが複数ある場合など)
(ちょっとよく分かりませんでした)