我有一个函数如下
pub fn registration(student_id: &T::StudentId, registrar: &T::RegistrarID) {
// More code here.
if num_of_students < student_limit {
Self::function_one(®istrar, &num_of_students);
} else {
Self::function_two(&num_of_students);
}
}
在单元测试中,我打算检查function_one
或function_two
是否被调用。
#[test]
fn registration_more_students_should_call_functon_one() {
with_test_data(
&mut TestBuilder::default().num_of_students(1000).build(),
|| {
//assert_called!(module_name::registration("TV:009", "DF-000-09"));
},
);
}
如何测试如果一个函数在锈叫什么名字?
这是在多个地方使用#[cfg(test)]
一个天真的尝试:
struct Registration {
students: Vec<String>,
#[cfg(test)]
function_1_called: bool,
}
impl Registration {
fn new() -> Self {
Registration {
students: Vec::new(),
#[cfg(test)]
function_1_called: false,
}
}
fn function_1(&mut self, students: Vec<String>) {
self.students.extend(students);
#[cfg(test)]
{
self.function_1_called = true;
}
}
fn function_2(&mut self, students: Vec<String>) {}
fn f(&mut self, students: Vec<String>) {
if students.len() < 100 {
self.function_1(students);
} else {
self.function_2(students);
}
}
}
fn main() {
println!("Hello, world!");
let r = Registration::new();
// won't compile during `run`:
// println!("{}", r.function_1_called);
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_f() {
let mut r = Registration::new();
r.function_1(vec!["Alice".to_string(), "Bob".to_string()]);
assert!(r.function_1_called);
}
}
该代码是松散的基础上,你所提供的片段。有一个Registration
结构保存登记学生学生姓名,两种方法function_1
和function_2
的列表,以及f
和function_1
之间的选择取决于Ø有多少学生有一个功能function_2
。
在测试过程中,Registration
编译时附加的布尔变量function_1_called
。此变量只设置如果function_1
被调用(即这是否代码块还标有#[cfg(test)]
)。
在组合,这使得在测试过程中提供额外的布尔标志,这样就可以使类似以下声明:
assert!(r.function_1_called);
显然,这可以为结构较单一布尔标志更为复杂的工作(这并不都意味着你应该真正做到这一点)。
我不能在这是否是地道的铁锈或发表评论。整个安装感觉好像应该看中宏背后隐藏的,因此,如果这种风格的测试鲁斯特用于在所有的,应该已经是提供这些(或类似)宏板条箱。
强大的舆论警告:你在做你的测试错误。这是在同一水平上的“我怎么测试的私有方法”。你不应该在乎registration
的实施,这种详细程度。
话虽这么说,如果知道哪个if
分支,然后使用依赖注入实际上是很重要的:
fn registration(mut registration: impl Registration, registrar: i32) {
let num_of_students = 0;
let student_limit = 0;
if num_of_students < student_limit {
registration.function_one(registrar, num_of_students);
} else {
registration.function_two(num_of_students);
}
}
trait Registration {
fn function_one(&mut self, registrar: i32, num_of_students: i32);
fn function_two(&mut self, num_of_students: i32);
}
impl<R: Registration> Registration for &'_ mut R {
fn function_one(&mut self, registrar: i32, num_of_students: i32) {
(**self).function_one(registrar, num_of_students)
}
fn function_two(&mut self, num_of_students: i32) {
(**self).function_two(num_of_students)
}
}
/*
// An example implementation for production
struct DatabaseRegistration;
impl Registration for DatabaseRegistration {
fn function_one(&mut self, registrar: i32, num_of_students: i32) {
eprintln!("Do DB work: {}, {}", registrar, num_of_students)
}
fn function_two(&mut self, num_of_students: i32) {
eprintln!("Do DB work: {}", num_of_students)
}
}
*/
#[cfg(test)]
mod test {
use super::*;
#[derive(Debug, Copy, Clone, Default)]
struct TestRegistration {
calls_to_one: usize,
calls_to_two: usize,
}
impl Registration for TestRegistration {
fn function_one(&mut self, _: i32, _: i32) {
self.calls_to_one += 1;
}
fn function_two(&mut self, _: i32) {
self.calls_to_two += 1;
}
}
#[test]
fn calls_the_right_one() {
let mut reg = TestRegistration::default();
registration(&mut reg, 42);
assert_eq!(1, reg.calls_to_two)
}
}
一旦你做到了这一点,那么你就可以看到registration
调用适当的特征函数(如示例所示的测试)。
这可以防止你的生产代码具有特定的测试碎屑四散,同时也让你更加灵活,快速地测试更多案件的能力。
也可以看看: