单元测试
学习目标
- 掌握
#[test] 属性
- 掌握断言宏
- 理解测试组织结构
核心概念
基本测试
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(add(2, 3), 5);
}
#[test]
fn test_add_negative() {
assert_eq!(add(-1, 1), 0);
}
#[test]
#[should_panic]
fn test_panic() {
panic!("expected panic");
}
#[test]
fn test_with_result() -> Result<(), String> {
let result = add(2, 2);
if result == 4 {
Ok(())
} else {
Err(format!("expected 4, got {}", result))
}
}
}
断言宏
#[cfg(test)]
mod tests {
#[test]
fn assertions() {
assert!(true);
assert_eq!(2 + 2, 4);
assert_ne!(2 + 2, 5);
assert!(true, "should be true");
assert_eq!(2 + 2, 4, "math works");
assert!((0.1_f64 + 0.2 - 0.3).abs() < 1e-10);
}
}
运行测试
cargo test
cargo test test_add
cargo test -- --show-output
cargo test -- --test-threads=1
cargo test --lib
实践练习
练习 1:栈测试
pub struct Stack<T> {
elements: Vec<T>,
}
impl<T> Stack<T> {
pub fn new() -> Self {
Stack { elements: Vec::new() }
}
pub fn push(&mut self, item: T) {
self.elements.push(item);
}
pub fn pop(&mut self) -> Option<T> {
self.elements.pop()
}
pub fn peek(&self) -> Option<&T> {
self.elements.last()
}
pub fn is_empty(&self) -> bool {
self.elements.is_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_stack_is_empty() {
let stack: Stack<i32> = Stack::new();
assert!(stack.is_empty());
}
#[test]
fn test_push_and_pop() {
let mut stack = Stack::new();
stack.push(1);
stack.push(2);
assert_eq!(stack.pop(), Some(2));
assert_eq!(stack.pop(), Some(1));
assert_eq!(stack.pop(), None);
}
#[test]
fn test_peek() {
let mut stack = Stack::new();
stack.push(42);
assert_eq!(stack.peek(), Some(&42));
assert_eq!(stack.pop(), Some(42));
assert_eq!(stack.peek(), None);
}
}
小结
| 语法 | 用途 |
|---|
#[test] | 标记测试函数 |
#[cfg(test)] | 条件编译测试模块 |
assert! | 真值断言 |
assert_eq! | 相等断言 |
#[should_panic] | 期望 panic |
cargo test | 运行测试 |