test 속성(attribute)이 어노테이션된 함수
속성(attribute)
: 러스트 코드 조각에 대한 메타데이터#[derive(Debug)]
의 derive도 속성 중 하나 cargo test 명령어로 실행
되며, 이 명령을 실행하면 테스트 실행 바이너리를 빌드
$ cargo new adder --lib
Created library `adder` project
$ cd adder
cargo new adder --lib
명령어를 사용하여 새 라이브러리 프로젝트를 생성하면, 일반 프로젝트와는 몇 가지 차이점이 있습니다. 프로젝트 타입:
디렉토리 구조:
src
디렉토리 안에 lib.rs
파일이 생성lib.rs
파일은 라이브러리의 루트 파일로, 모듈과 함수를 정의하는 데 사용my_library/
├── Cargo.toml
└── src
└── lib.rs
src
디렉토리 안에 main.rs
파일이 생성main.rs
파일은 프로그램의 진입점(엔트리 포인트)으로 사용my_project/
├── Cargo.toml
└── src
└── main.rs
컴파일 출력:
.rlib
파일이 생성Cargo.toml
파일에 의존성으로 추가하여 사용할 수 있음#[cfg(test)]
mod tests {
#[test]
fn it_works() {
let result = 2 + 2;
assert_eq!(result, 4);
}
}
$ cargo test
Compiling adder v0.1.0 (file:///projects/adder)
Finished test [unoptimized + debuginfo] target(s) in 0.57s
Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)
running 1 test
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests adder
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests adder
: 문서 테스트 결과를 나타냄#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn larger_can_hold_smaller() {
let larger = Rectangle {
width: 8,
height: 7,
};
let smaller = Rectangle {
width: 5,
height: 1,
};
assert!(larger.can_hold(&smaller));
}
}
use super::*;
assert!(!smaller.can_hold(&larger));
에서 smaller 앞의 ! 문법 가능assert_eq!(4, add_two(2));
assert_eq!, assert_ne! 매크로
는 각각 ==, != 연산자를 사용합니다. PartialEq, Debug 트레이트
를 구현해야 합니다.PartialEq, Debug 두 트레이트 모두 파생 가능한 트레이트
이기 때문에, println!("{:?}", rectangle);
#[test]
fn greeting_contains_name() {
let result = greeting("Carol");
assert!(
result.contains("Carol"),
"Greeting did not contain name, value was `{}`",
result
);
}
#[should_panic]
)// --생략--
impl Guess {
pub fn new(value: i32) -> 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 = "less than or equal to 100")]
fn greater_than_100() {
Guess::new(200);
}
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() -> Result<(), String> {
if 2 + 2 == 4 {
Ok(())
} else {
Err(String::from("two plus two does not equal four"))
}
}
}
? 연산자
를 사용할 수 있기 때문에, 내부 작업이 Err를 반환할 경우 실패해야 하는 테스트를 작성하기 편리
? 연산자
use std::fs::File;
use std::io::{self, Read};
fn read_username_from_file() -> Result<String, io::Error> {
let mut username_file = File::open("hello.txt")?;
let mut username = String::new();
username_file.read_to_string(&mut username)?;
Ok(username)
}
assert!(value.is_err())
를 사용하세요.모든 테스트를 병렬로 실행하고 테스트가 수행되는 동안 발생된 출력을 캡처하는 것
$ cargo test -- --test-threads=1
$ cargo test -- --show-output
테스트 함수 이름을 전달
하여 해당 테스트만 실행할 수 있음$ cargo test one_hundred
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
명령어를 사용하면 무시된 테스트만 실행할 수 있습니다.cargo test -- --include-ignored
를 실행할 수 있습니다.유닛 테스트 (unit test, 단위 테스트라고도 함)
, 통합 테스트 (integration test)
두 종류로 나눕니다. 각 코드 단위를 나머지 코드와 분리
제대로 작동하지 않는 코드가 어느 부분인지 빠르게 파악하는 것
tests 모듈
을 만들고, cfg(test)를 어노테이션하는 게 일반적인 관례cargo build 명령어
가 아닌 cargo test 명령어
실행 시에만 컴파일 및 실행될 것을 러스트에게 전달#[cfg(test)]
mod tests {
#[test]
fn it_works() {
let result = 2 + 2;
assert_eq!(result, 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));
}
}
adder
├── Cargo.lock
├── Cargo.toml
├── src
│ └── lib.rs
└── tests
└── integration_test.rs
use adder;
#[test]
fn it_adds_two() {
assert_eq!(4, adder::add_two(2));
}
tests/integration_test.rs 내 코드는 #[cfg(test)]가 필요 없습니다.
$ cargo test
Compiling adder v0.1.0 (file:///projects/adder)
Finished test [unoptimized + debuginfo] target(s) in 1.31s
Running unittests src/lib.rs (target/debug/deps/adder-1082c4b063a8fbe6)
running 1 test
test tests::internal ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running tests/integration_test.rs (target/debug/deps/integration_test-1082c4b063a8fbe6)
running 1 test
test it_adds_two ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests adder
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
├── Cargo.lock
├── Cargo.toml
├── src
│ └── lib.rs
└── tests
├── common
│ └── mod.rs
└── integration_test.rs
use adder;
mod common;
#[test]
fn it_adds_two() {
common::setup();
assert_eq!(4, adder::add_two(2));
}