我具有以下功能
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"));
},
);
}
如何测试是否在Rust中调用了函数?
答案 0 :(得分:8)
强烈建议:您的测试错误。这与“我如何测试私有方法”处于同一级别。您不必关心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
调用了适当的trait函数(如示例测试中所示)。
这可以防止在生产代码中散布特定于测试的碎屑,同时还使您能够更灵活地快速测试更多案例。
另请参阅:
答案 1 :(得分:4)
这是在多个地方简单使用#[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);
显然,这可以用于比单个布尔标志复杂得多的结构(这并不意味着您实际上应该这样做)。
我无法评论这在Rust中是否是惯用的。整个设置看起来好像应该隐藏在花哨的宏后面,因此,如果完全在Rust中使用这种测试风格,则应该已经有提供这些(或类似)宏的板条箱。