生锈的单元测试,模拟和特征

问题描述

我目前正在构建一个高度依赖文件IO的应用程序,因此很明显,我的代码很多部分都有File::open(file)

做一些集成测试是可以的,我可以轻松设置文件夹以加载文件和所需的方案。

问题出在我要进行单元测试和代码分支的任何地方。我知道那里有很多声称可以进行模拟的模拟库,但是我觉得我最大的问题是代码设计本身。

例如,我将使用任何面向对象的语言(在示例中为java)执行相同的代码,我可以编写一些接口,并在测试中简单地覆盖我要模拟的默认行为,设置一个假{ {1}},无论是通过固定收益重新实现,还是使用诸如嘲笑之类的模拟框架。

ClientRepository

但是由于我们最终将数据与行为混合在一起,所以我无法在生锈中得到相同的结果。

RefCell documentation上,有一个与我在java上给出的示例类似的示例。一些答案指向特征clojuresconditional compiliation

我们可能会测试一些场景,首先是一些mod.rs中的公共功能


public interface ClientRepository {
   Client getClient(int id)
}

public class ClientRepositoryDB {
   
  private ClientRepository repository;
  
  //getters and setters

  public Client getClientById(int id) {
    Client client = repository.getClient(id);

    //Some data manipulation and validation
  }
}

第二个相同的函数变成一个特征,并通过某些struct实现它。



#[derive(Serialize,Deserialize,Debug,Clone)]
pub struct SomeData {
    pub name: Option<String>,pub address: Option<String>,}


pub fn get_some_data(file_path: PathBuf) -> Option<SomeData> {
    let mut contents = String::new();


    match File::open(file_path) {
        Ok(mut file) => {
            match file.read_to_string(&mut contents) {
                Ok(result) => result,Err(_err) => panic!(
                    panic!("Problem reading file")
                ),};
        }
        Err(err) => panic!("File not find"),}
    
    // using serde for operate on data output
    let some_data: SomeData = match serde_json::from_str(&contents) {
        Ok(some_data) => some_data,Err(err) => panic!(
            "An error occour when parsing: {:?}",err
        ),};

    //we might do some checks or whatever here
    Some(some_data) or None
}


mod test {

    use super::*;
    
    #[test]
    fn test_if_scenario_a_happen() -> std::io::Result<()> {
       //tied with File::open
       let some_data = get_some_data(PathBuf::new);

        assert!(result.is_some());

        Ok(())
    }


    #[test]
    fn test_if_scenario_b_happen() -> std::io::Result<()> {
       //We might need to write two files,and we want to test is the logic,not the file loading itself
       let some_data = get_some_data(PathBuf::new);

        assert!(result.is_none());

        Ok(())
    }
}

在两个示例中,由于要绑定 #[derive(Serialize,Clone)] pub struct SomeData { pub name: Option<String>,} trait GetSomeData { fn get_some_data(&self,file_path: PathBuf) -> Option<SomeData>; } pub struct SomeDataService {} impl GetSomeData for SomeDataService { fn get_some_data(&self,file_path: PathBuf) -> Option<SomeData> { let mut contents = String::new(); match File::open(file_path) { Ok(mut file) => { match file.read_to_string(&mut contents) { Ok(result) => result,Err(_err) => panic!("Problem reading file"),}; } Err(err) => panic!("File not find"),} // using serde for operate on data output let some_data: SomeData = match serde_json::from_str(&contents) { Ok(some_data) => some_data,Err(err) => panic!("An error occour when parsing: {:?}",err),}; //we might do some checks or whatever here Some(some_data) or None } } impl SomeDataService { pub fn do_something_with_data(&self) -> Option<SomeData> { self.get_some_data(PathBuf::new()) } } mod test { use super::*; #[test] fn test_if_scenario_a_happen() -> std::io::Result<()> { //tied with File::open let service = SomeDataService{} let some_data = service.do_something_with_data(PathBuf::new); assert!(result.is_some()); Ok(()) } } ,因此我们很难对其进行测试,并且可以肯定的是,这可能会扩展到任何不确定性函数,例如时间,数据库连接等。

您将如何设计此代码或任何类似的代码,以简化单元测试和更好的设计?

很抱歉,很长的帖子。

~~马铃薯图像~~

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)